@agirails/sdk 2.0.0-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +183 -0
  2. package/dist/ACTPClient.d.ts +52 -0
  3. package/dist/ACTPClient.d.ts.map +1 -0
  4. package/dist/ACTPClient.js +120 -0
  5. package/dist/ACTPClient.js.map +1 -0
  6. package/dist/abi/ACTPKernel.json +1340 -0
  7. package/dist/abi/ERC20.json +38 -0
  8. package/dist/abi/EscrowVault.json +64 -0
  9. package/dist/builders/DeliveryProofBuilder.d.ts +37 -0
  10. package/dist/builders/DeliveryProofBuilder.d.ts.map +1 -0
  11. package/dist/builders/DeliveryProofBuilder.js +165 -0
  12. package/dist/builders/DeliveryProofBuilder.js.map +1 -0
  13. package/dist/builders/QuoteBuilder.d.ts +68 -0
  14. package/dist/builders/QuoteBuilder.d.ts.map +1 -0
  15. package/dist/builders/QuoteBuilder.js +255 -0
  16. package/dist/builders/QuoteBuilder.js.map +1 -0
  17. package/dist/builders/index.d.ts +3 -0
  18. package/dist/builders/index.d.ts.map +1 -0
  19. package/dist/builders/index.js +10 -0
  20. package/dist/builders/index.js.map +1 -0
  21. package/dist/config/networks.d.ts +27 -0
  22. package/dist/config/networks.d.ts.map +1 -0
  23. package/dist/config/networks.js +103 -0
  24. package/dist/config/networks.js.map +1 -0
  25. package/dist/errors/index.d.ts +38 -0
  26. package/dist/errors/index.d.ts.map +1 -0
  27. package/dist/errors/index.js +87 -0
  28. package/dist/errors/index.js.map +1 -0
  29. package/dist/index.d.ts +19 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +68 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/protocol/ACTPKernel.d.ts +30 -0
  34. package/dist/protocol/ACTPKernel.d.ts.map +1 -0
  35. package/dist/protocol/ACTPKernel.js +261 -0
  36. package/dist/protocol/ACTPKernel.js.map +1 -0
  37. package/dist/protocol/EASHelper.d.ts +23 -0
  38. package/dist/protocol/EASHelper.d.ts.map +1 -0
  39. package/dist/protocol/EASHelper.js +106 -0
  40. package/dist/protocol/EASHelper.js.map +1 -0
  41. package/dist/protocol/EscrowVault.d.ts +24 -0
  42. package/dist/protocol/EscrowVault.d.ts.map +1 -0
  43. package/dist/protocol/EscrowVault.js +114 -0
  44. package/dist/protocol/EscrowVault.js.map +1 -0
  45. package/dist/protocol/EventMonitor.d.ts +18 -0
  46. package/dist/protocol/EventMonitor.d.ts.map +1 -0
  47. package/dist/protocol/EventMonitor.js +92 -0
  48. package/dist/protocol/EventMonitor.js.map +1 -0
  49. package/dist/protocol/MessageSigner.d.ts +23 -0
  50. package/dist/protocol/MessageSigner.d.ts.map +1 -0
  51. package/dist/protocol/MessageSigner.js +178 -0
  52. package/dist/protocol/MessageSigner.js.map +1 -0
  53. package/dist/protocol/ProofGenerator.d.ts +22 -0
  54. package/dist/protocol/ProofGenerator.d.ts.map +1 -0
  55. package/dist/protocol/ProofGenerator.js +64 -0
  56. package/dist/protocol/ProofGenerator.js.map +1 -0
  57. package/dist/protocol/QuoteBuilder.d.ts +2 -0
  58. package/dist/protocol/QuoteBuilder.d.ts.map +1 -0
  59. package/dist/protocol/QuoteBuilder.js +7 -0
  60. package/dist/protocol/QuoteBuilder.js.map +1 -0
  61. package/dist/types/eip712.d.ts +106 -0
  62. package/dist/types/eip712.d.ts.map +1 -0
  63. package/dist/types/eip712.js +84 -0
  64. package/dist/types/eip712.js.map +1 -0
  65. package/dist/types/escrow.d.ts +18 -0
  66. package/dist/types/escrow.d.ts.map +1 -0
  67. package/dist/types/escrow.js +3 -0
  68. package/dist/types/escrow.js.map +1 -0
  69. package/dist/types/index.d.ts +6 -0
  70. package/dist/types/index.d.ts.map +1 -0
  71. package/dist/types/index.js +22 -0
  72. package/dist/types/index.js.map +1 -0
  73. package/dist/types/message.d.ts +109 -0
  74. package/dist/types/message.d.ts.map +1 -0
  75. package/dist/types/message.js +3 -0
  76. package/dist/types/message.js.map +1 -0
  77. package/dist/types/state.d.ts +19 -0
  78. package/dist/types/state.d.ts.map +1 -0
  79. package/dist/types/state.js +49 -0
  80. package/dist/types/state.js.map +1 -0
  81. package/dist/types/transaction.d.ts +36 -0
  82. package/dist/types/transaction.d.ts.map +1 -0
  83. package/dist/types/transaction.js +3 -0
  84. package/dist/types/transaction.js.map +1 -0
  85. package/dist/utils/IPFSClient.d.ts +37 -0
  86. package/dist/utils/IPFSClient.d.ts.map +1 -0
  87. package/dist/utils/IPFSClient.js +128 -0
  88. package/dist/utils/IPFSClient.js.map +1 -0
  89. package/dist/utils/NonceManager.d.ts +34 -0
  90. package/dist/utils/NonceManager.d.ts.map +1 -0
  91. package/dist/utils/NonceManager.js +114 -0
  92. package/dist/utils/NonceManager.js.map +1 -0
  93. package/dist/utils/ReceivedNonceTracker.d.ts +35 -0
  94. package/dist/utils/ReceivedNonceTracker.d.ts.map +1 -0
  95. package/dist/utils/ReceivedNonceTracker.js +196 -0
  96. package/dist/utils/ReceivedNonceTracker.js.map +1 -0
  97. package/dist/utils/canonicalJson.d.ts +4 -0
  98. package/dist/utils/canonicalJson.d.ts.map +1 -0
  99. package/dist/utils/canonicalJson.js +21 -0
  100. package/dist/utils/canonicalJson.js.map +1 -0
  101. package/dist/utils/computeTypeHash.d.ts +3 -0
  102. package/dist/utils/computeTypeHash.d.ts.map +1 -0
  103. package/dist/utils/computeTypeHash.js +30 -0
  104. package/dist/utils/computeTypeHash.js.map +1 -0
  105. package/dist/utils/validation.d.ts +6 -0
  106. package/dist/utils/validation.d.ts.map +1 -0
  107. package/dist/utils/validation.js +46 -0
  108. package/dist/utils/validation.js.map +1 -0
  109. package/package.json +73 -0
  110. package/src/ACTPClient.ts +276 -0
  111. package/src/__tests__/ProofGenerator.test.ts +124 -0
  112. package/src/__tests__/QuoteBuilder.test.ts +516 -0
  113. package/src/__tests__/StateMachine.test.ts +82 -0
  114. package/src/__tests__/builders/DeliveryProofBuilder.test.ts +581 -0
  115. package/src/__tests__/integration/ACTPClient.test.ts +263 -0
  116. package/src/__tests__/integration.test.ts +289 -0
  117. package/src/__tests__/protocol/EASHelper.test.ts +472 -0
  118. package/src/__tests__/protocol/EventMonitor.test.ts +382 -0
  119. package/src/__tests__/security/ACTPKernel.security.test.ts +1167 -0
  120. package/src/__tests__/security/EscrowVault.security.test.ts +570 -0
  121. package/src/__tests__/security/MessageSigner.security.test.ts +286 -0
  122. package/src/__tests__/security/NonceReplay.security.test.ts +501 -0
  123. package/src/__tests__/security/validation.security.test.ts +376 -0
  124. package/src/__tests__/utils/IPFSClient.test.ts +262 -0
  125. package/src/__tests__/utils/NonceManager.test.ts +205 -0
  126. package/src/__tests__/utils/canonicalJson.test.ts +153 -0
  127. package/src/abi/ACTPKernel.json +1340 -0
  128. package/src/abi/ERC20.json +40 -0
  129. package/src/abi/EscrowVault.json +66 -0
  130. package/src/builders/DeliveryProofBuilder.ts +326 -0
  131. package/src/builders/QuoteBuilder.ts +483 -0
  132. package/src/builders/index.ts +17 -0
  133. package/src/config/networks.ts +165 -0
  134. package/src/errors/index.ts +130 -0
  135. package/src/index.ts +108 -0
  136. package/src/protocol/ACTPKernel.ts +625 -0
  137. package/src/protocol/EASHelper.ts +197 -0
  138. package/src/protocol/EscrowVault.ts +237 -0
  139. package/src/protocol/EventMonitor.ts +161 -0
  140. package/src/protocol/MessageSigner.ts +336 -0
  141. package/src/protocol/ProofGenerator.ts +119 -0
  142. package/src/protocol/QuoteBuilder.ts +15 -0
  143. package/src/types/eip712.ts +175 -0
  144. package/src/types/escrow.ts +26 -0
  145. package/src/types/index.ts +10 -0
  146. package/src/types/message.ts +145 -0
  147. package/src/types/state.ts +77 -0
  148. package/src/types/transaction.ts +54 -0
  149. package/src/utils/IPFSClient.ts +248 -0
  150. package/src/utils/NonceManager.ts +293 -0
  151. package/src/utils/ReceivedNonceTracker.ts +397 -0
  152. package/src/utils/canonicalJson.ts +38 -0
  153. package/src/utils/computeTypeHash.ts +50 -0
  154. package/src/utils/validation.ts +82 -0
@@ -0,0 +1,336 @@
1
+ import { Signer, ethers, AbiCoder } from 'ethers';
2
+ import { ACTPMessage, DeliveryProof } from '../types';
3
+ import { SignatureVerificationError } from '../errors';
4
+ import {
5
+ EIP712Domain,
6
+ getMessageTypes,
7
+ QuoteRequestData,
8
+ QuoteResponseData,
9
+ DeliveryProofData,
10
+ deliveryProofDataFromProof
11
+ } from '../types/eip712';
12
+ import { IReceivedNonceTracker } from '../utils/ReceivedNonceTracker';
13
+
14
+ // Legacy generic ACTP message types moved to types/eip712.ts
15
+
16
+ /**
17
+ * TypeScript interface for ethers v6 Signer with signTypedData method
18
+ *
19
+ * Note: ethers v6 uses signTypedData() (without underscore), not _signTypedData().
20
+ * This interface properly types the method for v6 compatibility.
21
+ */
22
+ interface SignerWithTypedData extends Signer {
23
+ signTypedData(
24
+ domain: EIP712Domain,
25
+ types: Record<string, any>,
26
+ value: Record<string, any>
27
+ ): Promise<string>;
28
+ }
29
+
30
+ /**
31
+ * MessageSigner - Cryptographic signing for ACTP messages with EIP-712
32
+ * Reference: Yellow Paper §11.4.2
33
+ *
34
+ * V4 Security Enhancement: Optional nonce replay protection via ReceivedNonceTracker
35
+ */
36
+ export class MessageSigner {
37
+ private domain: EIP712Domain | null = null;
38
+
39
+ constructor(
40
+ private readonly signer: Signer,
41
+ private readonly nonceTracker?: IReceivedNonceTracker
42
+ ) {}
43
+
44
+ /**
45
+ * Initialize EIP-712 domain (must be called before signing)
46
+ * @param kernelAddress - Address of ACTP Kernel contract
47
+ * @param chainId - Optional chainId (defaults to signer's chainId or 84532 for Base Sepolia)
48
+ */
49
+ async initDomain(kernelAddress: string, chainId?: number): Promise<void> {
50
+ let resolvedChainId: number;
51
+
52
+ if (chainId !== undefined) {
53
+ resolvedChainId = chainId;
54
+ } else {
55
+ try {
56
+ // ethers v6: signer.provider might be null, check first
57
+ if (this.signer.provider) {
58
+ const network = await this.signer.provider.getNetwork();
59
+ resolvedChainId = Number(network.chainId);
60
+ } else {
61
+ // Fallback to Base Sepolia for testing without provider
62
+ resolvedChainId = 84532;
63
+ }
64
+ } catch (error) {
65
+ // Fallback to Base Sepolia for testing without provider
66
+ resolvedChainId = 84532;
67
+ }
68
+ }
69
+
70
+ this.domain = {
71
+ name: 'ACTP',
72
+ version: '1.0',
73
+ chainId: resolvedChainId,
74
+ verifyingContract: kernelAddress
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Sign ACTP message using EIP-712 typed data
80
+ * Uses ECDSA (secp256k1) with domain separation per Yellow Paper §11.4.2
81
+ *
82
+ * Generic ACTPMessage format (backward compatible).
83
+ * For strict typed AIP messages, use signQuoteRequest/signQuoteResponse/signDeliveryProof
84
+ */
85
+ async signMessage(message: ACTPMessage): Promise<string> {
86
+ if (!this.domain) {
87
+ throw new Error('Domain not initialized. Call initDomain() first.');
88
+ }
89
+
90
+ const { type, version, from, to, timestamp, nonce, signature, ...payload } = message;
91
+
92
+ // Generic ACTPMessage with payload encoding (backward compatible)
93
+ const abiCoder = AbiCoder.defaultAbiCoder();
94
+ const payloadBytes = abiCoder.encode(
95
+ ['string'],
96
+ [this.canonicalizePayload(payload)]
97
+ );
98
+
99
+ const typedMessage = {
100
+ type,
101
+ version,
102
+ from,
103
+ to,
104
+ timestamp,
105
+ nonce,
106
+ payload: payloadBytes
107
+ };
108
+
109
+ // Use generic ACTPMessage types
110
+ const messageTypes = getMessageTypes('default');
111
+
112
+ // Sign using EIP-712 (ethers v6 API)
113
+ const signer = this.signer as SignerWithTypedData;
114
+ const sig = await signer.signTypedData(this.domain, messageTypes, typedMessage);
115
+
116
+ return sig;
117
+ }
118
+
119
+ /**
120
+ * Sign typed QuoteRequest message
121
+ */
122
+ async signQuoteRequest(data: QuoteRequestData): Promise<string> {
123
+ if (!this.domain) {
124
+ throw new Error('Domain not initialized. Call initDomain() first.');
125
+ }
126
+
127
+ const messageTypes = getMessageTypes('quote.request');
128
+ const signer = this.signer as SignerWithTypedData;
129
+ return await signer.signTypedData(this.domain, messageTypes, data);
130
+ }
131
+
132
+ /**
133
+ * Sign typed QuoteResponse message
134
+ */
135
+ async signQuoteResponse(data: QuoteResponseData): Promise<string> {
136
+ if (!this.domain) {
137
+ throw new Error('Domain not initialized. Call initDomain() first.');
138
+ }
139
+
140
+ const messageTypes = getMessageTypes('quote.response');
141
+ const signer = this.signer as SignerWithTypedData;
142
+ return await signer.signTypedData(this.domain, messageTypes, data);
143
+ }
144
+
145
+ /**
146
+ * Sign typed DeliveryProof message
147
+ */
148
+ async signDeliveryProof(data: DeliveryProofData): Promise<string> {
149
+ if (!this.domain) {
150
+ throw new Error('Domain not initialized. Call initDomain() first.');
151
+ }
152
+
153
+ const messageTypes = getMessageTypes('delivery.proof');
154
+ const signer = this.signer as SignerWithTypedData;
155
+ return await signer.signTypedData(this.domain, messageTypes, data);
156
+ }
157
+
158
+ /**
159
+ * Convenience helper to sign a DeliveryProof generated by ProofGenerator
160
+ */
161
+ async signGeneratedDeliveryProof(proof: DeliveryProof): Promise<string> {
162
+ const typedData = deliveryProofDataFromProof(proof);
163
+ return await this.signDeliveryProof(typedData);
164
+ }
165
+
166
+ /**
167
+ * Verify message signature using EIP-712
168
+ * Uses generic ACTPMessage types (backward compatible)
169
+ *
170
+ * V4 Security: If nonceTracker is configured, validates nonce for replay protection
171
+ */
172
+ async verifySignature(message: ACTPMessage, signature: string): Promise<boolean> {
173
+ if (!this.domain) {
174
+ throw new Error('Domain not initialized. Call initDomain() first.');
175
+ }
176
+
177
+ const { type, version, from, to, timestamp, nonce, signature: _, ...payload } = message;
178
+
179
+ const abiCoder = AbiCoder.defaultAbiCoder();
180
+ const payloadBytes = abiCoder.encode(
181
+ ['string'],
182
+ [this.canonicalizePayload(payload)]
183
+ );
184
+
185
+ const typedMessage = {
186
+ type,
187
+ version,
188
+ from,
189
+ to,
190
+ timestamp,
191
+ nonce,
192
+ payload: payloadBytes
193
+ };
194
+
195
+ // Use generic ACTPMessage types (backward compatible)
196
+ const messageTypes = getMessageTypes('default');
197
+ const recoveredAddress = ethers.verifyTypedData(
198
+ this.domain,
199
+ messageTypes,
200
+ typedMessage,
201
+ signature
202
+ );
203
+
204
+ const expectedAddress = this.didToAddress(from);
205
+
206
+ // Verify signature matches sender
207
+ if (recoveredAddress.toLowerCase() !== expectedAddress.toLowerCase()) {
208
+ return false;
209
+ }
210
+
211
+ // V4 Security: Validate nonce for replay protection (if tracker configured)
212
+ if (this.nonceTracker) {
213
+ const nonceValidation = this.nonceTracker.validateAndRecord(from, type, nonce);
214
+ if (!nonceValidation.valid) {
215
+ // Nonce replay detected - return false
216
+ return false;
217
+ }
218
+ }
219
+
220
+ return true;
221
+ }
222
+
223
+ /**
224
+ * Verify signature and throw if invalid
225
+ * V4 Security: Throws specific error for nonce replay detection
226
+ */
227
+ async verifySignatureOrThrow(message: ACTPMessage, signature: string): Promise<void> {
228
+ if (!this.domain) {
229
+ throw new Error('Domain not initialized');
230
+ }
231
+
232
+ const { type, version, from, to, timestamp, nonce, signature: _, ...payload } = message;
233
+
234
+ const abiCoder = AbiCoder.defaultAbiCoder();
235
+ const payloadBytes = abiCoder.encode(
236
+ ['string'],
237
+ [this.canonicalizePayload(payload)]
238
+ );
239
+
240
+ const typedMessage = { type, version, from, to, timestamp, nonce, payload: payloadBytes };
241
+
242
+ const messageTypes = getMessageTypes('default');
243
+ const recoveredAddress = ethers.verifyTypedData(
244
+ this.domain,
245
+ messageTypes,
246
+ typedMessage,
247
+ signature
248
+ );
249
+
250
+ const expectedAddress = this.didToAddress(from);
251
+
252
+ // Check signature validity first
253
+ if (recoveredAddress.toLowerCase() !== expectedAddress.toLowerCase()) {
254
+ throw new SignatureVerificationError(expectedAddress, recoveredAddress);
255
+ }
256
+
257
+ // V4 Security: Validate nonce for replay protection (if tracker configured)
258
+ if (this.nonceTracker) {
259
+ const nonceValidation = this.nonceTracker.validateAndRecord(from, type, nonce);
260
+ if (!nonceValidation.valid) {
261
+ // Throw specific error for nonce replay
262
+ throw new Error(
263
+ `Nonce replay attack detected: ${nonceValidation.reason}. ` +
264
+ `Received nonce: ${nonceValidation.receivedNonce}. ` +
265
+ (nonceValidation.expectedMinimum ? `Expected minimum: ${nonceValidation.expectedMinimum}` : '')
266
+ );
267
+ }
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Canonicalize payload to deterministic string (recursively sorted keys)
273
+ * Prevents JSON serialization ambiguity across different JS runtimes
274
+ * Recursively handles nested objects and arrays
275
+ */
276
+ private canonicalizePayload(payload: Record<string, any>): string {
277
+ return JSON.stringify(this.recursiveSort(payload));
278
+ }
279
+
280
+ /**
281
+ * Recursively sort object keys for deterministic JSON encoding
282
+ */
283
+ private recursiveSort(obj: any): any {
284
+ if (obj === null || obj === undefined) {
285
+ return obj;
286
+ }
287
+
288
+ // Handle arrays: recursively sort each element
289
+ if (Array.isArray(obj)) {
290
+ return obj.map((item) => this.recursiveSort(item));
291
+ }
292
+
293
+ // Handle objects: sort keys and recursively sort values
294
+ if (typeof obj === 'object' && obj.constructor === Object) {
295
+ const sortedKeys = Object.keys(obj).sort();
296
+ const canonical: Record<string, any> = {};
297
+
298
+ for (const key of sortedKeys) {
299
+ canonical[key] = this.recursiveSort(obj[key]);
300
+ }
301
+
302
+ return canonical;
303
+ }
304
+
305
+ // Primitives (string, number, boolean)
306
+ return obj;
307
+ }
308
+
309
+ /**
310
+ * Convert DID to Ethereum address
311
+ * MVP: Simple did:ethr → address conversion
312
+ */
313
+ private didToAddress(did: string): string {
314
+ if (did.startsWith('did:ethr:')) {
315
+ return did.replace('did:ethr:', '');
316
+ }
317
+
318
+ // If already an address, return as-is
319
+ if (ethers.isAddress(did)) {
320
+ return did;
321
+ }
322
+
323
+ throw new Error(`Invalid DID format: ${did}`);
324
+ }
325
+
326
+ /**
327
+ * Convert Ethereum address to DID
328
+ */
329
+ addressToDID(address: string): string {
330
+ if (!ethers.isAddress(address)) {
331
+ throw new Error(`Invalid Ethereum address: ${address}`);
332
+ }
333
+
334
+ return `did:ethr:${address}`;
335
+ }
336
+ }
@@ -0,0 +1,119 @@
1
+ import { keccak256, toUtf8Bytes, AbiCoder, BytesLike } from 'ethers';
2
+ import { DeliveryProof } from '../types';
3
+ import { DeliveryProofData, deliveryProofDataFromProof } from '../types/eip712';
4
+
5
+ /**
6
+ * ProofGenerator - Content hashing and delivery proofs
7
+ * Reference: Yellow Paper §11.4.1
8
+ */
9
+ export class ProofGenerator {
10
+ /**
11
+ * Hash deliverable content
12
+ * Uses Keccak256 per Yellow Paper §11.4.1
13
+ */
14
+ hashContent(content: string | Buffer): string {
15
+ const buffer = typeof content === 'string' ? toUtf8Bytes(content) : content;
16
+
17
+ return keccak256(buffer);
18
+ }
19
+
20
+ /**
21
+ * Generate delivery proof (AIP-4)
22
+ * Reference: Yellow Paper §8.2
23
+ * Complete schema with type field for AIP compliance
24
+ * Computed fields (size, mimeType) cannot be overwritten
25
+ */
26
+ generateDeliveryProof(params: {
27
+ txId: string;
28
+ deliverable: string | Buffer;
29
+ deliveryUrl?: string;
30
+ metadata?: Record<string, any>;
31
+ }): DeliveryProof {
32
+ const { txId, deliverable, deliveryUrl, metadata = {} } = params;
33
+
34
+ const contentHash = this.hashContent(deliverable);
35
+ const size =
36
+ typeof deliverable === 'string'
37
+ ? Buffer.from(deliverable).length
38
+ : deliverable.length;
39
+
40
+ // Spread user metadata first, then enforce computed fields
41
+ // This prevents users from spoofing size/mimeType
42
+ const { size: _ignoredSize, mimeType: _ignoredMimeType, ...userMetadata } = metadata;
43
+
44
+ return {
45
+ type: 'delivery.proof', // Required per AIP-4
46
+ txId,
47
+ contentHash,
48
+ timestamp: Date.now(),
49
+ deliveryUrl, // Optional: IPFS/Arweave link
50
+ metadata: {
51
+ ...userMetadata, // User-supplied fields (excluding reserved)
52
+ size, // Enforced: computed from deliverable
53
+ mimeType: metadata.mimeType || 'application/octet-stream' // Enforced with fallback
54
+ }
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Convert a generated delivery proof into typed EIP-712 data
60
+ */
61
+ toDeliveryProofTypedData(proof: DeliveryProof): DeliveryProofData {
62
+ return deliveryProofDataFromProof(proof);
63
+ }
64
+
65
+ /**
66
+ * Encode proof for on-chain submission
67
+ */
68
+ encodeProof(proof: DeliveryProof): BytesLike {
69
+ const abiCoder = AbiCoder.defaultAbiCoder();
70
+ return abiCoder.encode(
71
+ ['bytes32', 'bytes32', 'uint256'],
72
+ [proof.txId, proof.contentHash, proof.timestamp]
73
+ );
74
+ }
75
+
76
+ /**
77
+ * Decode proof from on-chain data
78
+ */
79
+ decodeProof(proofData: BytesLike): {
80
+ txId: string;
81
+ contentHash: string;
82
+ timestamp: number;
83
+ } {
84
+ const abiCoder = AbiCoder.defaultAbiCoder();
85
+ const [txId, contentHash, timestamp] = abiCoder.decode(
86
+ ['bytes32', 'bytes32', 'uint256'],
87
+ proofData
88
+ );
89
+
90
+ return {
91
+ txId,
92
+ contentHash,
93
+ timestamp: Number(timestamp)
94
+ };
95
+ }
96
+
97
+ /**
98
+ * Verify deliverable matches expected hash
99
+ */
100
+ verifyDeliverable(deliverable: string | Buffer, expectedHash: string): boolean {
101
+ const actualHash = this.hashContent(deliverable);
102
+ return actualHash.toLowerCase() === expectedHash.toLowerCase();
103
+ }
104
+
105
+ /**
106
+ * Generate content hash from URL (for IPFS/Arweave)
107
+ */
108
+ async hashFromUrl(url: string): Promise<string> {
109
+ // In browser/Node.js environment with fetch
110
+ try {
111
+ const response = await fetch(url);
112
+ const arrayBuffer = await response.arrayBuffer();
113
+ const buffer = Buffer.from(arrayBuffer);
114
+ return this.hashContent(buffer);
115
+ } catch (error) {
116
+ throw new Error(`Failed to fetch content from ${url}: ${error}`);
117
+ }
118
+ }
119
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * QuoteBuilder - AIP-2 Price Quote Construction
3
+ *
4
+ * This module re-exports the full QuoteBuilder implementation from builders/
5
+ * Reference: AIP-2 §6.1
6
+ *
7
+ * @deprecated Import from builders/QuoteBuilder directly
8
+ */
9
+
10
+ export {
11
+ QuoteBuilder,
12
+ QuoteMessage,
13
+ QuoteParams,
14
+ AIP2QuoteTypes
15
+ } from '../builders/QuoteBuilder';
@@ -0,0 +1,175 @@
1
+ import { DeliveryProof } from './message';
2
+
3
+ /**
4
+ * EIP-712 Type Definitions for ACTP Messages
5
+ * Reference: Yellow Paper §11.4.2
6
+ *
7
+ * Each AIP message has explicit typed data for cross-language compatibility
8
+ */
9
+
10
+ /**
11
+ * EIP-712 Domain for ACTP
12
+ */
13
+ export interface EIP712Domain {
14
+ name: string;
15
+ version: string;
16
+ chainId: number;
17
+ verifyingContract: string;
18
+ }
19
+
20
+ /**
21
+ * QuoteRequest (AIP-2)
22
+ * Reference: Yellow Paper §4.2
23
+ */
24
+ export const QuoteRequestTypes = {
25
+ QuoteRequest: [
26
+ { name: 'from', type: 'string' }, // DID
27
+ { name: 'to', type: 'string' }, // DID
28
+ { name: 'timestamp', type: 'uint256' },
29
+ { name: 'nonce', type: 'bytes32' },
30
+ { name: 'serviceType', type: 'string' },
31
+ { name: 'requirements', type: 'string' },
32
+ { name: 'deadline', type: 'uint256' },
33
+ { name: 'disputeWindow', type: 'uint256' }
34
+ ]
35
+ };
36
+
37
+ export interface QuoteRequestData {
38
+ from: string;
39
+ to: string;
40
+ timestamp: number;
41
+ nonce: string;
42
+ serviceType: string;
43
+ requirements: string;
44
+ deadline: number;
45
+ disputeWindow: number;
46
+ }
47
+
48
+ /**
49
+ * QuoteResponse (AIP-2)
50
+ * Reference: Yellow Paper §4.2
51
+ */
52
+ export const QuoteResponseTypes = {
53
+ QuoteResponse: [
54
+ { name: 'from', type: 'string' },
55
+ { name: 'to', type: 'string' },
56
+ { name: 'timestamp', type: 'uint256' },
57
+ { name: 'nonce', type: 'bytes32' },
58
+ { name: 'requestId', type: 'bytes32' },
59
+ { name: 'price', type: 'uint256' },
60
+ { name: 'currency', type: 'address' },
61
+ { name: 'deliveryTime', type: 'uint256' },
62
+ { name: 'terms', type: 'string' }
63
+ ]
64
+ };
65
+
66
+ export interface QuoteResponseData {
67
+ from: string;
68
+ to: string;
69
+ timestamp: number;
70
+ nonce: string;
71
+ requestId: string;
72
+ price: string; // BigNumber as string
73
+ currency: string;
74
+ deliveryTime: number;
75
+ terms: string;
76
+ }
77
+
78
+ /**
79
+ * DeliveryProof (AIP-4) - DEPRECATED
80
+ * @deprecated Use AIP4DeliveryProofTypes instead (AIP-4 v1.1)
81
+ */
82
+ export const DeliveryProofTypes = {
83
+ DeliveryProof: [
84
+ { name: 'txId', type: 'bytes32' },
85
+ { name: 'contentHash', type: 'bytes32' },
86
+ { name: 'timestamp', type: 'uint256' },
87
+ { name: 'deliveryUrl', type: 'string' },
88
+ { name: 'size', type: 'uint256' },
89
+ { name: 'mimeType', type: 'string' }
90
+ ]
91
+ };
92
+
93
+ export interface DeliveryProofData {
94
+ txId: string;
95
+ contentHash: string;
96
+ timestamp: number;
97
+ deliveryUrl: string;
98
+ size: number;
99
+ mimeType: string;
100
+ }
101
+
102
+ export function deliveryProofDataFromProof(proof: DeliveryProof): DeliveryProofData {
103
+ return {
104
+ txId: proof.txId,
105
+ contentHash: proof.contentHash,
106
+ timestamp: proof.timestamp,
107
+ deliveryUrl: proof.deliveryUrl || '',
108
+ size: proof.metadata.size,
109
+ mimeType: proof.metadata.mimeType
110
+ };
111
+ }
112
+
113
+ /**
114
+ * AIP-4 Delivery Proof (v1.1)
115
+ * Reference: AIP-4 §3.3
116
+ */
117
+ export const AIP4DeliveryProofTypes = {
118
+ DeliveryProof: [
119
+ { name: 'txId', type: 'bytes32' },
120
+ { name: 'provider', type: 'string' },
121
+ { name: 'consumer', type: 'string' },
122
+ { name: 'resultCID', type: 'string' },
123
+ { name: 'resultHash', type: 'bytes32' },
124
+ { name: 'easAttestationUID', type: 'bytes32' },
125
+ { name: 'deliveredAt', type: 'uint256' },
126
+ { name: 'chainId', type: 'uint256' },
127
+ { name: 'nonce', type: 'uint256' }
128
+ ]
129
+ };
130
+
131
+ export interface AIP4DeliveryProofData {
132
+ txId: string;
133
+ provider: string;
134
+ consumer: string;
135
+ resultCID: string;
136
+ resultHash: string;
137
+ easAttestationUID: string;
138
+ deliveredAt: number;
139
+ chainId: number;
140
+ nonce: number;
141
+ }
142
+
143
+ /**
144
+ * Generic ACTPMessage (fallback for custom AIPs)
145
+ */
146
+ export const ACTPMessageTypes = {
147
+ ACTPMessage: [
148
+ { name: 'type', type: 'string' },
149
+ { name: 'version', type: 'string' },
150
+ { name: 'from', type: 'string' },
151
+ { name: 'to', type: 'string' },
152
+ { name: 'timestamp', type: 'uint256' },
153
+ { name: 'nonce', type: 'bytes32' },
154
+ { name: 'payload', type: 'bytes' }
155
+ ]
156
+ };
157
+
158
+ /**
159
+ * Message type registry
160
+ */
161
+ export const MESSAGE_TYPES = {
162
+ 'quote.request': QuoteRequestTypes,
163
+ 'quote.response': QuoteResponseTypes,
164
+ 'delivery.proof': DeliveryProofTypes,
165
+ // Fallback for custom/future AIPs
166
+ default: ACTPMessageTypes
167
+ };
168
+
169
+ /**
170
+ * Get EIP-712 types for message type
171
+ */
172
+ export function getMessageTypes(messageType: string): Record<string, any> {
173
+ return MESSAGE_TYPES[messageType as keyof typeof MESSAGE_TYPES] || MESSAGE_TYPES.default;
174
+ }
175
+
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Escrow creation parameters
3
+ */
4
+ export interface CreateEscrowParams {
5
+ kernelAddress: string;
6
+ txId: string;
7
+ token: string;
8
+ amount: bigint;
9
+ beneficiary: string;
10
+ }
11
+
12
+ /**
13
+ * Escrow state
14
+ */
15
+ export interface Escrow {
16
+ escrowId: string;
17
+ kernel: string;
18
+ txId: string;
19
+ token: string;
20
+ amount: bigint;
21
+ beneficiary: string;
22
+ createdAt: number;
23
+ released: boolean;
24
+ }
25
+
26
+
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Type exports
3
+ */
4
+
5
+ export * from './state';
6
+ export * from './transaction';
7
+ export * from './escrow';
8
+ export * from './message';
9
+ export * from './eip712';
10
+