@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,40 @@
1
+ [
2
+ {
3
+ "inputs": [
4
+ {"name": "spender", "type": "address"},
5
+ {"name": "amount", "type": "uint256"}
6
+ ],
7
+ "name": "approve",
8
+ "outputs": [{"name": "", "type": "bool"}],
9
+ "stateMutability": "nonpayable",
10
+ "type": "function"
11
+ },
12
+ {
13
+ "inputs": [
14
+ {"name": "account", "type": "address"}
15
+ ],
16
+ "name": "balanceOf",
17
+ "outputs": [{"name": "", "type": "uint256"}],
18
+ "stateMutability": "view",
19
+ "type": "function"
20
+ },
21
+ {
22
+ "inputs": [
23
+ {"name": "owner", "type": "address"},
24
+ {"name": "spender", "type": "address"}
25
+ ],
26
+ "name": "allowance",
27
+ "outputs": [{"name": "", "type": "uint256"}],
28
+ "stateMutability": "view",
29
+ "type": "function"
30
+ },
31
+ {
32
+ "inputs": [],
33
+ "name": "decimals",
34
+ "outputs": [{"name": "", "type": "uint8"}],
35
+ "stateMutability": "view",
36
+ "type": "function"
37
+ }
38
+ ]
39
+
40
+
@@ -0,0 +1,66 @@
1
+ [
2
+ {
3
+ "inputs": [
4
+ {"name": "kernel", "type": "address"},
5
+ {"name": "txId", "type": "bytes32"},
6
+ {"name": "token", "type": "address"},
7
+ {"name": "amount", "type": "uint256"},
8
+ {"name": "beneficiary", "type": "address"}
9
+ ],
10
+ "name": "createEscrow",
11
+ "outputs": [{"name": "escrowId", "type": "bytes32"}],
12
+ "stateMutability": "nonpayable",
13
+ "type": "function"
14
+ },
15
+ {
16
+ "inputs": [
17
+ {"name": "escrowId", "type": "bytes32"},
18
+ {"name": "recipients", "type": "address[]"},
19
+ {"name": "amounts", "type": "uint256[]"}
20
+ ],
21
+ "name": "disburse",
22
+ "outputs": [],
23
+ "stateMutability": "nonpayable",
24
+ "type": "function"
25
+ },
26
+ {
27
+ "inputs": [
28
+ {"name": "escrowId", "type": "bytes32"}
29
+ ],
30
+ "name": "escrows",
31
+ "outputs": [
32
+ {"name": "kernel", "type": "address"},
33
+ {"name": "txId", "type": "bytes32"},
34
+ {"name": "token", "type": "address"},
35
+ {"name": "amount", "type": "uint256"},
36
+ {"name": "beneficiary", "type": "address"},
37
+ {"name": "released", "type": "bool"}
38
+ ],
39
+ "stateMutability": "view",
40
+ "type": "function"
41
+ },
42
+ {
43
+ "anonymous": false,
44
+ "inputs": [
45
+ {"indexed": true, "name": "escrowId", "type": "bytes32"},
46
+ {"indexed": true, "name": "kernel", "type": "address"},
47
+ {"indexed": true, "name": "txId", "type": "bytes32"},
48
+ {"indexed": false, "name": "token", "type": "address"},
49
+ {"indexed": false, "name": "amount", "type": "uint256"}
50
+ ],
51
+ "name": "EscrowCreated",
52
+ "type": "event"
53
+ },
54
+ {
55
+ "anonymous": false,
56
+ "inputs": [
57
+ {"indexed": true, "name": "escrowId", "type": "bytes32"},
58
+ {"indexed": false, "name": "recipients", "type": "address[]"},
59
+ {"indexed": false, "name": "amounts", "type": "uint256[]"}
60
+ ],
61
+ "name": "EscrowReleased",
62
+ "type": "event"
63
+ }
64
+ ]
65
+
66
+
@@ -0,0 +1,326 @@
1
+ /**
2
+ * DeliveryProofBuilder - AIP-4 Delivery Proof Construction
3
+ * Reference: AIP-4 §9.1
4
+ *
5
+ * Builds complete delivery proofs with:
6
+ * - IPFS upload of result data
7
+ * - EAS attestation creation
8
+ * - EIP-712 signature
9
+ * - Canonical JSON hashing
10
+ */
11
+
12
+ import { Signer, verifyTypedData } from 'ethers';
13
+ import { EAS, SchemaEncoder } from '@ethereum-attestation-service/eas-sdk';
14
+ import { computeResultHash } from '../utils/canonicalJson';
15
+ import { IPFSClient } from '../utils/IPFSClient';
16
+ import { NonceManager } from '../utils/NonceManager';
17
+ import { DeliveryProofMessage } from '../types/message';
18
+ import { AIP4DeliveryProofTypes, AIP4DeliveryProofData, EIP712Domain } from '../types/eip712';
19
+
20
+ /**
21
+ * AGIRAILS Delivery Schema UID (Base Sepolia)
22
+ * TODO: Update after schema deployment
23
+ */
24
+ export const AGIRAILS_DELIVERY_SCHEMA_UID = '0x0000000000000000000000000000000000000000000000000000000000000000'; // PENDING
25
+
26
+ /**
27
+ * Delivery proof build parameters
28
+ */
29
+ export interface DeliveryProofParams {
30
+ txId: string; // bytes32 (0x-prefixed)
31
+ provider: string; // DID (e.g., "did:ethr:84532:0x...")
32
+ consumer: string; // DID
33
+ resultData: any; // Service result data (will be uploaded to IPFS)
34
+ metadata?: {
35
+ executionTime?: number;
36
+ outputFormat?: string;
37
+ outputSize?: number;
38
+ notes?: string;
39
+ };
40
+ chainId: number; // 84532 (Base Sepolia) or 8453 (Base Mainnet)
41
+ kernelAddress: string; // ACTPKernel contract address
42
+ }
43
+
44
+ // IPFSClient and NonceManager interfaces imported from utils
45
+
46
+ /**
47
+ * DeliveryProofBuilder - Main Builder Class
48
+ */
49
+ export class DeliveryProofBuilder {
50
+ constructor(
51
+ private ipfs: IPFSClient,
52
+ private signer: Signer,
53
+ private nonceManager: NonceManager,
54
+ private eas: EAS
55
+ ) {}
56
+
57
+ /**
58
+ * Build complete delivery proof
59
+ * Reference: AIP-4 §5.1 (Provider workflow steps 1-9)
60
+ *
61
+ * @param params - Delivery proof parameters
62
+ * @returns Delivery proof message, IPFS CID, and attestation UID
63
+ */
64
+ async build(params: DeliveryProofParams): Promise<{
65
+ deliveryProof: DeliveryProofMessage;
66
+ deliveryProofCID: string;
67
+ attestationUID: string;
68
+ }> {
69
+ // Step 1: Upload result to IPFS
70
+ const resultCID = await this.ipfs.add(JSON.stringify(params.resultData));
71
+ await this.ipfs.pin(resultCID); // Permanent pinning
72
+
73
+ // Step 2: Compute result hash (canonical JSON)
74
+ const resultHash = computeResultHash(params.resultData);
75
+
76
+ // Step 3: Create EAS attestation on-chain
77
+ const deliveredAt = Math.floor(Date.now() / 1000);
78
+
79
+ const schemaEncoder = new SchemaEncoder(
80
+ 'bytes32 txId,string resultCID,bytes32 resultHash,uint256 deliveredAt'
81
+ );
82
+
83
+ // Extract Ethereum address from consumer DID
84
+ const consumerAddress = this.extractAddressFromDID(params.consumer);
85
+
86
+ const encodedData = schemaEncoder.encodeData([
87
+ { name: 'txId', value: params.txId, type: 'bytes32' },
88
+ { name: 'resultCID', value: resultCID, type: 'string' },
89
+ { name: 'resultHash', value: resultHash, type: 'bytes32' },
90
+ { name: 'deliveredAt', value: deliveredAt, type: 'uint256' }
91
+ ]);
92
+
93
+ const tx = await this.eas.attest({
94
+ schema: AGIRAILS_DELIVERY_SCHEMA_UID,
95
+ data: {
96
+ recipient: consumerAddress,
97
+ expirationTime: 0n, // No expiration (use bigint)
98
+ revocable: false,
99
+ data: encodedData
100
+ }
101
+ });
102
+
103
+ const receipt = await tx.wait();
104
+ // EAS SDK returns attestation UID directly in newAttestationUID
105
+ const attestationUID = (receipt as any).newAttestationUID || (receipt as any);
106
+
107
+ // Step 4: Build delivery proof message (unsigned)
108
+ const deliveryProof: DeliveryProofMessage = {
109
+ type: 'agirails.delivery.v1',
110
+ version: '1.0.0',
111
+ txId: params.txId,
112
+ provider: params.provider,
113
+ consumer: params.consumer,
114
+ resultCID,
115
+ resultHash,
116
+ metadata: params.metadata || {},
117
+ easAttestationUID: attestationUID,
118
+ deliveredAt,
119
+ chainId: params.chainId,
120
+ nonce: this.nonceManager.getNextNonce('agirails.delivery.v1'),
121
+ signature: '' // Filled in next step
122
+ };
123
+
124
+ // Step 5: Sign with EIP-712
125
+ const signature = await this.signDeliveryProof(deliveryProof, params.kernelAddress);
126
+ deliveryProof.signature = signature;
127
+
128
+ // Step 6: Upload delivery proof to IPFS
129
+ const deliveryProofCID = await this.ipfs.add(JSON.stringify(deliveryProof));
130
+ await this.ipfs.pin(deliveryProofCID); // Permanent
131
+
132
+ // Record nonce usage
133
+ this.nonceManager.recordNonce('agirails.delivery.v1', deliveryProof.nonce);
134
+
135
+ return {
136
+ deliveryProof,
137
+ deliveryProofCID,
138
+ attestationUID
139
+ };
140
+ }
141
+
142
+ /**
143
+ * Verify delivery proof signature and integrity
144
+ * Reference: AIP-4 §5.2 (Consumer verification)
145
+ *
146
+ * @param deliveryProof - Delivery proof message
147
+ * @param resultData - Actual result data (from IPFS)
148
+ * @param kernelAddress - ACTPKernel contract address
149
+ * @returns true if valid, throws error otherwise
150
+ */
151
+ async verify(
152
+ deliveryProof: DeliveryProofMessage,
153
+ resultData: any,
154
+ kernelAddress: string
155
+ ): Promise<boolean> {
156
+ // 1. Verify signature
157
+ const recoveredAddress = await this.recoverDeliveryProofSigner(deliveryProof, kernelAddress);
158
+ const expectedAddress = this.extractAddressFromDID(deliveryProof.provider);
159
+
160
+ if (recoveredAddress.toLowerCase() !== expectedAddress.toLowerCase()) {
161
+ throw new Error('Invalid signature: recovered address does not match provider');
162
+ }
163
+
164
+ // 2. Verify result hash
165
+ const computedHash = computeResultHash(resultData);
166
+
167
+ if (computedHash !== deliveryProof.resultHash) {
168
+ throw new Error('Result hash mismatch - data may be tampered');
169
+ }
170
+
171
+ // 3. Verify EAS attestation exists and is valid
172
+ const attestation = await this.eas.getAttestation(deliveryProof.easAttestationUID);
173
+
174
+ if (!attestation) {
175
+ throw new Error('Attestation not found on EAS');
176
+ }
177
+
178
+ if (attestation.schema !== AGIRAILS_DELIVERY_SCHEMA_UID) {
179
+ throw new Error(`Invalid attestation schema: expected ${AGIRAILS_DELIVERY_SCHEMA_UID}, got ${attestation.schema}`);
180
+ }
181
+
182
+ // Check if attestation is revoked (property may not exist in all EAS SDK versions)
183
+ if ('revoked' in attestation && (attestation as any).revoked) {
184
+ throw new Error('Attestation was revoked');
185
+ }
186
+
187
+ if ('revocationTime' in attestation && (attestation as any).revocationTime > 0) {
188
+ throw new Error('Attestation was revoked');
189
+ }
190
+
191
+ // 4. Verify attestation data matches delivery proof
192
+ const schemaEncoder = new SchemaEncoder(
193
+ 'bytes32 txId,string resultCID,bytes32 resultHash,uint256 deliveredAt'
194
+ );
195
+ const decodedData = schemaEncoder.decodeData(attestation.data);
196
+
197
+ const attestationTxId = decodedData.find((d) => d.name === 'txId')?.value.value;
198
+ const attestationResultCID = decodedData.find((d) => d.name === 'resultCID')?.value.value;
199
+ const attestationResultHash = decodedData.find((d) => d.name === 'resultHash')?.value.value;
200
+
201
+ if (attestationTxId !== deliveryProof.txId) {
202
+ throw new Error('Attestation txId mismatch');
203
+ }
204
+
205
+ if (attestationResultCID !== deliveryProof.resultCID) {
206
+ throw new Error('Attestation resultCID mismatch');
207
+ }
208
+
209
+ if (attestationResultHash !== deliveryProof.resultHash) {
210
+ throw new Error('Attestation resultHash mismatch');
211
+ }
212
+
213
+ return true;
214
+ }
215
+
216
+ /**
217
+ * Sign delivery proof with EIP-712
218
+ * Reference: AIP-4 §3.3
219
+ *
220
+ * @param deliveryProof - Delivery proof message (unsigned)
221
+ * @param kernelAddress - ACTPKernel contract address
222
+ * @returns EIP-712 signature (0x-prefixed, 130 chars)
223
+ */
224
+ private async signDeliveryProof(
225
+ deliveryProof: DeliveryProofMessage,
226
+ kernelAddress: string
227
+ ): Promise<string> {
228
+ const domain: EIP712Domain = {
229
+ name: 'AGIRAILS',
230
+ version: '1',
231
+ chainId: deliveryProof.chainId,
232
+ verifyingContract: kernelAddress
233
+ };
234
+
235
+ const message: AIP4DeliveryProofData = {
236
+ txId: deliveryProof.txId,
237
+ provider: deliveryProof.provider,
238
+ consumer: deliveryProof.consumer,
239
+ resultCID: deliveryProof.resultCID,
240
+ resultHash: deliveryProof.resultHash,
241
+ easAttestationUID: deliveryProof.easAttestationUID,
242
+ deliveredAt: deliveryProof.deliveredAt,
243
+ chainId: deliveryProof.chainId,
244
+ nonce: deliveryProof.nonce
245
+ };
246
+
247
+ // Sign using ethers v6 signTypedData API
248
+ // ethers v6 uses signTypedData() (without underscore)
249
+ if ('signTypedData' in this.signer && typeof (this.signer as any).signTypedData === 'function') {
250
+ const signature = await (this.signer as any).signTypedData(
251
+ domain,
252
+ AIP4DeliveryProofTypes,
253
+ message
254
+ );
255
+ return signature;
256
+ }
257
+
258
+ throw new Error('Signer does not support EIP-712 typed data signing (ethers v6+)');
259
+
260
+ }
261
+
262
+ /**
263
+ * Recover signer address from delivery proof signature
264
+ *
265
+ * @param deliveryProof - Delivery proof message
266
+ * @param kernelAddress - ACTPKernel contract address
267
+ * @returns Recovered Ethereum address
268
+ */
269
+ private async recoverDeliveryProofSigner(
270
+ deliveryProof: DeliveryProofMessage,
271
+ kernelAddress: string
272
+ ): Promise<string> {
273
+ const domain: EIP712Domain = {
274
+ name: 'AGIRAILS',
275
+ version: '1',
276
+ chainId: deliveryProof.chainId,
277
+ verifyingContract: kernelAddress
278
+ };
279
+
280
+ const message: AIP4DeliveryProofData = {
281
+ txId: deliveryProof.txId,
282
+ provider: deliveryProof.provider,
283
+ consumer: deliveryProof.consumer,
284
+ resultCID: deliveryProof.resultCID,
285
+ resultHash: deliveryProof.resultHash,
286
+ easAttestationUID: deliveryProof.easAttestationUID,
287
+ deliveredAt: deliveryProof.deliveredAt,
288
+ chainId: deliveryProof.chainId,
289
+ nonce: deliveryProof.nonce
290
+ };
291
+
292
+ // Recover address using ethers.js verifyTypedData
293
+ // Wrap in try-catch to handle low-level cryptographic errors gracefully
294
+ try {
295
+ const recoveredAddress = verifyTypedData(
296
+ domain,
297
+ AIP4DeliveryProofTypes,
298
+ message,
299
+ deliveryProof.signature
300
+ );
301
+
302
+ return recoveredAddress;
303
+ } catch (error: any) {
304
+ // Wrap low-level cryptographic errors in meaningful error message
305
+ throw new Error(`Invalid signature: ${error.message || 'signature verification failed'}`);
306
+ }
307
+ }
308
+
309
+ /**
310
+ * Extract Ethereum address from DID
311
+ * Supports: did:ethr:0x... and did:ethr:84532:0x...
312
+ *
313
+ * @param did - DID string
314
+ * @returns Ethereum address (0x-prefixed, checksummed)
315
+ */
316
+ private extractAddressFromDID(did: string): string {
317
+ const parts = did.replace('did:ethr:', '').split(':');
318
+ const address = parts.length === 2 ? parts[1] : parts[0];
319
+
320
+ if (!address.startsWith('0x') || address.length !== 42) {
321
+ throw new Error(`Invalid DID format: ${did}`);
322
+ }
323
+
324
+ return address;
325
+ }
326
+ }