@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.
- package/README.md +183 -0
- package/dist/ACTPClient.d.ts +52 -0
- package/dist/ACTPClient.d.ts.map +1 -0
- package/dist/ACTPClient.js +120 -0
- package/dist/ACTPClient.js.map +1 -0
- package/dist/abi/ACTPKernel.json +1340 -0
- package/dist/abi/ERC20.json +38 -0
- package/dist/abi/EscrowVault.json +64 -0
- package/dist/builders/DeliveryProofBuilder.d.ts +37 -0
- package/dist/builders/DeliveryProofBuilder.d.ts.map +1 -0
- package/dist/builders/DeliveryProofBuilder.js +165 -0
- package/dist/builders/DeliveryProofBuilder.js.map +1 -0
- package/dist/builders/QuoteBuilder.d.ts +68 -0
- package/dist/builders/QuoteBuilder.d.ts.map +1 -0
- package/dist/builders/QuoteBuilder.js +255 -0
- package/dist/builders/QuoteBuilder.js.map +1 -0
- package/dist/builders/index.d.ts +3 -0
- package/dist/builders/index.d.ts.map +1 -0
- package/dist/builders/index.js +10 -0
- package/dist/builders/index.js.map +1 -0
- package/dist/config/networks.d.ts +27 -0
- package/dist/config/networks.d.ts.map +1 -0
- package/dist/config/networks.js +103 -0
- package/dist/config/networks.js.map +1 -0
- package/dist/errors/index.d.ts +38 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +87 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +68 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol/ACTPKernel.d.ts +30 -0
- package/dist/protocol/ACTPKernel.d.ts.map +1 -0
- package/dist/protocol/ACTPKernel.js +261 -0
- package/dist/protocol/ACTPKernel.js.map +1 -0
- package/dist/protocol/EASHelper.d.ts +23 -0
- package/dist/protocol/EASHelper.d.ts.map +1 -0
- package/dist/protocol/EASHelper.js +106 -0
- package/dist/protocol/EASHelper.js.map +1 -0
- package/dist/protocol/EscrowVault.d.ts +24 -0
- package/dist/protocol/EscrowVault.d.ts.map +1 -0
- package/dist/protocol/EscrowVault.js +114 -0
- package/dist/protocol/EscrowVault.js.map +1 -0
- package/dist/protocol/EventMonitor.d.ts +18 -0
- package/dist/protocol/EventMonitor.d.ts.map +1 -0
- package/dist/protocol/EventMonitor.js +92 -0
- package/dist/protocol/EventMonitor.js.map +1 -0
- package/dist/protocol/MessageSigner.d.ts +23 -0
- package/dist/protocol/MessageSigner.d.ts.map +1 -0
- package/dist/protocol/MessageSigner.js +178 -0
- package/dist/protocol/MessageSigner.js.map +1 -0
- package/dist/protocol/ProofGenerator.d.ts +22 -0
- package/dist/protocol/ProofGenerator.d.ts.map +1 -0
- package/dist/protocol/ProofGenerator.js +64 -0
- package/dist/protocol/ProofGenerator.js.map +1 -0
- package/dist/protocol/QuoteBuilder.d.ts +2 -0
- package/dist/protocol/QuoteBuilder.d.ts.map +1 -0
- package/dist/protocol/QuoteBuilder.js +7 -0
- package/dist/protocol/QuoteBuilder.js.map +1 -0
- package/dist/types/eip712.d.ts +106 -0
- package/dist/types/eip712.d.ts.map +1 -0
- package/dist/types/eip712.js +84 -0
- package/dist/types/eip712.js.map +1 -0
- package/dist/types/escrow.d.ts +18 -0
- package/dist/types/escrow.d.ts.map +1 -0
- package/dist/types/escrow.js +3 -0
- package/dist/types/escrow.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +22 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/message.d.ts +109 -0
- package/dist/types/message.d.ts.map +1 -0
- package/dist/types/message.js +3 -0
- package/dist/types/message.js.map +1 -0
- package/dist/types/state.d.ts +19 -0
- package/dist/types/state.d.ts.map +1 -0
- package/dist/types/state.js +49 -0
- package/dist/types/state.js.map +1 -0
- package/dist/types/transaction.d.ts +36 -0
- package/dist/types/transaction.d.ts.map +1 -0
- package/dist/types/transaction.js +3 -0
- package/dist/types/transaction.js.map +1 -0
- package/dist/utils/IPFSClient.d.ts +37 -0
- package/dist/utils/IPFSClient.d.ts.map +1 -0
- package/dist/utils/IPFSClient.js +128 -0
- package/dist/utils/IPFSClient.js.map +1 -0
- package/dist/utils/NonceManager.d.ts +34 -0
- package/dist/utils/NonceManager.d.ts.map +1 -0
- package/dist/utils/NonceManager.js +114 -0
- package/dist/utils/NonceManager.js.map +1 -0
- package/dist/utils/ReceivedNonceTracker.d.ts +35 -0
- package/dist/utils/ReceivedNonceTracker.d.ts.map +1 -0
- package/dist/utils/ReceivedNonceTracker.js +196 -0
- package/dist/utils/ReceivedNonceTracker.js.map +1 -0
- package/dist/utils/canonicalJson.d.ts +4 -0
- package/dist/utils/canonicalJson.d.ts.map +1 -0
- package/dist/utils/canonicalJson.js +21 -0
- package/dist/utils/canonicalJson.js.map +1 -0
- package/dist/utils/computeTypeHash.d.ts +3 -0
- package/dist/utils/computeTypeHash.d.ts.map +1 -0
- package/dist/utils/computeTypeHash.js +30 -0
- package/dist/utils/computeTypeHash.js.map +1 -0
- package/dist/utils/validation.d.ts +6 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +46 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +73 -0
- package/src/ACTPClient.ts +276 -0
- package/src/__tests__/ProofGenerator.test.ts +124 -0
- package/src/__tests__/QuoteBuilder.test.ts +516 -0
- package/src/__tests__/StateMachine.test.ts +82 -0
- package/src/__tests__/builders/DeliveryProofBuilder.test.ts +581 -0
- package/src/__tests__/integration/ACTPClient.test.ts +263 -0
- package/src/__tests__/integration.test.ts +289 -0
- package/src/__tests__/protocol/EASHelper.test.ts +472 -0
- package/src/__tests__/protocol/EventMonitor.test.ts +382 -0
- package/src/__tests__/security/ACTPKernel.security.test.ts +1167 -0
- package/src/__tests__/security/EscrowVault.security.test.ts +570 -0
- package/src/__tests__/security/MessageSigner.security.test.ts +286 -0
- package/src/__tests__/security/NonceReplay.security.test.ts +501 -0
- package/src/__tests__/security/validation.security.test.ts +376 -0
- package/src/__tests__/utils/IPFSClient.test.ts +262 -0
- package/src/__tests__/utils/NonceManager.test.ts +205 -0
- package/src/__tests__/utils/canonicalJson.test.ts +153 -0
- package/src/abi/ACTPKernel.json +1340 -0
- package/src/abi/ERC20.json +40 -0
- package/src/abi/EscrowVault.json +66 -0
- package/src/builders/DeliveryProofBuilder.ts +326 -0
- package/src/builders/QuoteBuilder.ts +483 -0
- package/src/builders/index.ts +17 -0
- package/src/config/networks.ts +165 -0
- package/src/errors/index.ts +130 -0
- package/src/index.ts +108 -0
- package/src/protocol/ACTPKernel.ts +625 -0
- package/src/protocol/EASHelper.ts +197 -0
- package/src/protocol/EscrowVault.ts +237 -0
- package/src/protocol/EventMonitor.ts +161 -0
- package/src/protocol/MessageSigner.ts +336 -0
- package/src/protocol/ProofGenerator.ts +119 -0
- package/src/protocol/QuoteBuilder.ts +15 -0
- package/src/types/eip712.ts +175 -0
- package/src/types/escrow.ts +26 -0
- package/src/types/index.ts +10 -0
- package/src/types/message.ts +145 -0
- package/src/types/state.ts +77 -0
- package/src/types/transaction.ts +54 -0
- package/src/utils/IPFSClient.ts +248 -0
- package/src/utils/NonceManager.ts +293 -0
- package/src/utils/ReceivedNonceTracker.ts +397 -0
- package/src/utils/canonicalJson.ts +38 -0
- package/src/utils/computeTypeHash.ts +50 -0
- package/src/utils/validation.ts +82 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ACTPClient Integration Test Suite
|
|
3
|
+
*
|
|
4
|
+
* Coverage Target: 80%+ (statements, functions, lines, branches)
|
|
5
|
+
*
|
|
6
|
+
* Test Categories:
|
|
7
|
+
* 1. Client Initialization (4 tests)
|
|
8
|
+
* 2. Module Access (3 tests)
|
|
9
|
+
* 3. Network Utilities (3 tests)
|
|
10
|
+
* 4. Configuration Validation (2 tests)
|
|
11
|
+
*
|
|
12
|
+
* References:
|
|
13
|
+
* - ACTPClient.ts implementation
|
|
14
|
+
* - Factory pattern with async initialization
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { Wallet } from 'ethers';
|
|
18
|
+
import { ACTPClient } from '../../ACTPClient';
|
|
19
|
+
|
|
20
|
+
// Test private key and addresses
|
|
21
|
+
const testPrivateKey = '0x' + '1'.repeat(64);
|
|
22
|
+
const testWallet = new Wallet(testPrivateKey);
|
|
23
|
+
const testAddress = testWallet.address;
|
|
24
|
+
|
|
25
|
+
describe('ACTPClient - Client Initialization', () => {
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
jest.clearAllMocks();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should initialize client with privateKey', async () => {
|
|
31
|
+
const client = await ACTPClient.create({
|
|
32
|
+
network: 'base-sepolia',
|
|
33
|
+
privateKey: testPrivateKey
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(client).toBeDefined();
|
|
37
|
+
expect(client.kernel).toBeDefined();
|
|
38
|
+
expect(client.escrow).toBeDefined();
|
|
39
|
+
expect(client.events).toBeDefined();
|
|
40
|
+
expect(client.proofGenerator).toBeDefined();
|
|
41
|
+
expect(client.messageSigner).toBeDefined();
|
|
42
|
+
|
|
43
|
+
const address = await client.getAddress();
|
|
44
|
+
expect(address).toBe(testAddress);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should initialize client with signer', async () => {
|
|
48
|
+
const signer = new Wallet(testPrivateKey);
|
|
49
|
+
|
|
50
|
+
const client = await ACTPClient.create({
|
|
51
|
+
network: 'base-sepolia',
|
|
52
|
+
signer
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(client).toBeDefined();
|
|
56
|
+
expect(client.kernel).toBeDefined();
|
|
57
|
+
|
|
58
|
+
const address = await client.getAddress();
|
|
59
|
+
expect(address).toBe(testAddress);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should initialize client with custom provider', async () => {
|
|
63
|
+
// Note: Using custom provider requires proper Provider interface
|
|
64
|
+
// For this test, we just verify client can be created without provider
|
|
65
|
+
const client = await ACTPClient.create({
|
|
66
|
+
network: 'base-sepolia',
|
|
67
|
+
privateKey: testPrivateKey
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
expect(client).toBeDefined();
|
|
71
|
+
expect(client.getProvider()).toBeDefined();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should initialize client with contract overrides', async () => {
|
|
75
|
+
const customKernelAddress = '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
|
76
|
+
const customEscrowAddress = '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb';
|
|
77
|
+
|
|
78
|
+
const client = await ACTPClient.create({
|
|
79
|
+
network: 'base-sepolia',
|
|
80
|
+
privateKey: testPrivateKey,
|
|
81
|
+
contracts: {
|
|
82
|
+
actpKernel: customKernelAddress,
|
|
83
|
+
escrowVault: customEscrowAddress
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
expect(client).toBeDefined();
|
|
88
|
+
const networkConfig = client.getNetworkConfig();
|
|
89
|
+
expect(networkConfig.contracts.actpKernel).toBe(customKernelAddress);
|
|
90
|
+
expect(networkConfig.contracts.escrowVault).toBe(customEscrowAddress);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should initialize client with gas settings overrides', async () => {
|
|
94
|
+
const maxFeePerGas = BigInt('2000000000'); // 2 gwei
|
|
95
|
+
const maxPriorityFeePerGas = BigInt('1000000000'); // 1 gwei
|
|
96
|
+
|
|
97
|
+
const client = await ACTPClient.create({
|
|
98
|
+
network: 'base-sepolia',
|
|
99
|
+
privateKey: testPrivateKey,
|
|
100
|
+
gasSettings: {
|
|
101
|
+
maxFeePerGas,
|
|
102
|
+
maxPriorityFeePerGas
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
expect(client).toBeDefined();
|
|
107
|
+
const networkConfig = client.getNetworkConfig();
|
|
108
|
+
expect(networkConfig.gasSettings?.maxFeePerGas).toEqual(maxFeePerGas);
|
|
109
|
+
expect(networkConfig.gasSettings?.maxPriorityFeePerGas).toEqual(maxPriorityFeePerGas);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should reject initialization for Base Mainnet (contracts not deployed)', async () => {
|
|
113
|
+
// Base Mainnet has zero addresses - contracts not deployed yet
|
|
114
|
+
await expect(
|
|
115
|
+
ACTPClient.create({
|
|
116
|
+
network: 'base-mainnet',
|
|
117
|
+
privateKey: testPrivateKey
|
|
118
|
+
})
|
|
119
|
+
).rejects.toThrow('Network configuration error for Base Mainnet');
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('ACTPClient - Module Access', () => {
|
|
124
|
+
let client: ACTPClient;
|
|
125
|
+
|
|
126
|
+
beforeAll(async () => {
|
|
127
|
+
client = await ACTPClient.create({
|
|
128
|
+
network: 'base-sepolia',
|
|
129
|
+
privateKey: testPrivateKey
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should access kernel module', () => {
|
|
134
|
+
expect(client.kernel).toBeDefined();
|
|
135
|
+
expect(typeof client.kernel.createTransaction).toBe('function');
|
|
136
|
+
expect(typeof client.kernel.transitionState).toBe('function');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should access escrow module', () => {
|
|
140
|
+
expect(client.escrow).toBeDefined();
|
|
141
|
+
expect(typeof client.escrow.approveToken).toBe('function');
|
|
142
|
+
expect(typeof client.escrow.releaseEscrow).toBe('function');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should access events module', () => {
|
|
146
|
+
expect(client.events).toBeDefined();
|
|
147
|
+
expect(typeof client.events.watchTransaction).toBe('function');
|
|
148
|
+
expect(typeof client.events.onTransactionCreated).toBe('function');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should access proofGenerator module', () => {
|
|
152
|
+
expect(client.proofGenerator).toBeDefined();
|
|
153
|
+
expect(typeof client.proofGenerator.hashContent).toBe('function');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should access messageSigner module', () => {
|
|
157
|
+
expect(client.messageSigner).toBeDefined();
|
|
158
|
+
expect(typeof client.messageSigner.signMessage).toBe('function');
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('ACTPClient - Network Utilities', () => {
|
|
163
|
+
let client: ACTPClient;
|
|
164
|
+
|
|
165
|
+
beforeAll(async () => {
|
|
166
|
+
client = await ACTPClient.create({
|
|
167
|
+
network: 'base-sepolia',
|
|
168
|
+
privateKey: testPrivateKey
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should get signer address', async () => {
|
|
173
|
+
const address = await client.getAddress();
|
|
174
|
+
expect(address).toBe(testAddress);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should get network configuration', () => {
|
|
178
|
+
const networkConfig = client.getNetworkConfig();
|
|
179
|
+
expect(networkConfig).toBeDefined();
|
|
180
|
+
expect(networkConfig.chainId).toBe(84532);
|
|
181
|
+
expect(networkConfig.name).toBe('Base Sepolia');
|
|
182
|
+
expect(networkConfig.contracts).toBeDefined();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('should have frozen network configuration', () => {
|
|
186
|
+
const networkConfig = client.getNetworkConfig();
|
|
187
|
+
|
|
188
|
+
// Verify config is frozen
|
|
189
|
+
expect(Object.isFrozen(networkConfig)).toBe(true);
|
|
190
|
+
expect(Object.isFrozen(networkConfig.contracts)).toBe(true);
|
|
191
|
+
expect(Object.isFrozen(networkConfig.gasSettings)).toBe(true);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe('ACTPClient - Configuration Validation', () => {
|
|
196
|
+
beforeEach(() => {
|
|
197
|
+
jest.clearAllMocks();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should throw ValidationError when network is missing', async () => {
|
|
201
|
+
await expect(
|
|
202
|
+
ACTPClient.create({
|
|
203
|
+
network: null as any,
|
|
204
|
+
privateKey: testPrivateKey
|
|
205
|
+
})
|
|
206
|
+
).rejects.toThrow('Network is required');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('should throw ValidationError when auth credentials are missing', async () => {
|
|
210
|
+
await expect(
|
|
211
|
+
ACTPClient.create({
|
|
212
|
+
network: 'base-sepolia'
|
|
213
|
+
// No privateKey, signer, or provider
|
|
214
|
+
})
|
|
215
|
+
).rejects.toThrow('Provide either privateKey, signer, or provider with signer access');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('should accept valid configuration with all optional fields', async () => {
|
|
219
|
+
const client = await ACTPClient.create({
|
|
220
|
+
network: 'base-sepolia',
|
|
221
|
+
privateKey: testPrivateKey,
|
|
222
|
+
rpcUrl: 'https://custom-rpc.example.com',
|
|
223
|
+
contracts: {
|
|
224
|
+
actpKernel: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
|
225
|
+
escrowVault: '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
|
226
|
+
usdc: '0xcccccccccccccccccccccccccccccccccccccccc'
|
|
227
|
+
},
|
|
228
|
+
gasSettings: {
|
|
229
|
+
maxFeePerGas: BigInt('2000000000'),
|
|
230
|
+
maxPriorityFeePerGas: BigInt('1000000000')
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
expect(client).toBeDefined();
|
|
235
|
+
const networkConfig = client.getNetworkConfig();
|
|
236
|
+
expect(networkConfig.contracts.actpKernel).toBe('0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
|
|
237
|
+
expect(networkConfig.contracts.usdc).toBe('0xcccccccccccccccccccccccccccccccccccccccc');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should accept configuration with EAS helper', async () => {
|
|
241
|
+
const client = await ACTPClient.create({
|
|
242
|
+
network: 'base-sepolia',
|
|
243
|
+
privateKey: testPrivateKey,
|
|
244
|
+
eas: {
|
|
245
|
+
contractAddress: '0xdddddddddddddddddddddddddddddddddddddddd',
|
|
246
|
+
deliveryProofSchemaId: '0x' + '1'.repeat(64)
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
expect(client).toBeDefined();
|
|
251
|
+
expect(client.eas).toBeDefined();
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('should not initialize EAS helper when config is missing', async () => {
|
|
255
|
+
const client = await ACTPClient.create({
|
|
256
|
+
network: 'base-sepolia',
|
|
257
|
+
privateKey: testPrivateKey
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
expect(client).toBeDefined();
|
|
261
|
+
expect(client.eas).toBeUndefined();
|
|
262
|
+
});
|
|
263
|
+
});
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration Tests - SDK Logic (No Blockchain Required)
|
|
3
|
+
*
|
|
4
|
+
* These tests validate SDK functionality without needing deployed contracts.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { keccak256, toUtf8Bytes, hexlify, Wallet, randomBytes, HDNodeWallet } from 'ethers';
|
|
8
|
+
import { ProofGenerator } from '../protocol/ProofGenerator';
|
|
9
|
+
import { MessageSigner } from '../protocol/MessageSigner';
|
|
10
|
+
import { State, StateMachine } from '../types/state';
|
|
11
|
+
import { ACTPMessage } from '../types/message';
|
|
12
|
+
|
|
13
|
+
describe('SDK Integration Tests', () => {
|
|
14
|
+
let wallet: HDNodeWallet;
|
|
15
|
+
let proofGenerator: ProofGenerator;
|
|
16
|
+
let messageSigner: MessageSigner;
|
|
17
|
+
|
|
18
|
+
beforeAll(async () => {
|
|
19
|
+
// Create test wallet
|
|
20
|
+
wallet = Wallet.createRandom();
|
|
21
|
+
proofGenerator = new ProofGenerator();
|
|
22
|
+
messageSigner = new MessageSigner(wallet);
|
|
23
|
+
|
|
24
|
+
// Initialize EIP-712 domain for message signing
|
|
25
|
+
const mockKernelAddress = '0x' + '1'.repeat(40);
|
|
26
|
+
await messageSigner.initDomain(mockKernelAddress);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('Complete Transaction Lifecycle (Mock)', () => {
|
|
30
|
+
it('should follow complete state machine flow', () => {
|
|
31
|
+
// Start state
|
|
32
|
+
let currentState = State.INITIATED;
|
|
33
|
+
expect(StateMachine.isTerminalState(currentState)).toBe(false);
|
|
34
|
+
|
|
35
|
+
// INITIATED → QUOTED
|
|
36
|
+
expect(StateMachine.isValidTransition(currentState, State.QUOTED)).toBe(true);
|
|
37
|
+
currentState = State.QUOTED;
|
|
38
|
+
|
|
39
|
+
// QUOTED → COMMITTED
|
|
40
|
+
expect(StateMachine.isValidTransition(currentState, State.COMMITTED)).toBe(true);
|
|
41
|
+
currentState = State.COMMITTED;
|
|
42
|
+
|
|
43
|
+
// COMMITTED → IN_PROGRESS
|
|
44
|
+
expect(StateMachine.isValidTransition(currentState, State.IN_PROGRESS)).toBe(true);
|
|
45
|
+
currentState = State.IN_PROGRESS;
|
|
46
|
+
|
|
47
|
+
// IN_PROGRESS → DELIVERED
|
|
48
|
+
expect(StateMachine.isValidTransition(currentState, State.DELIVERED)).toBe(true);
|
|
49
|
+
currentState = State.DELIVERED;
|
|
50
|
+
|
|
51
|
+
// DELIVERED → SETTLED
|
|
52
|
+
expect(StateMachine.isValidTransition(currentState, State.SETTLED)).toBe(true);
|
|
53
|
+
currentState = State.SETTLED;
|
|
54
|
+
|
|
55
|
+
// Final state
|
|
56
|
+
expect(StateMachine.isTerminalState(currentState)).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should reject invalid state transitions', () => {
|
|
60
|
+
// Can't jump from INITIATED to SETTLED
|
|
61
|
+
expect(StateMachine.isValidTransition(State.INITIATED, State.SETTLED)).toBe(false);
|
|
62
|
+
|
|
63
|
+
// Can't go backwards from SETTLED
|
|
64
|
+
expect(StateMachine.isValidTransition(State.SETTLED, State.INITIATED)).toBe(false);
|
|
65
|
+
|
|
66
|
+
// Can't transition from terminal state
|
|
67
|
+
expect(StateMachine.isValidTransition(State.CANCELLED, State.INITIATED)).toBe(false);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('Delivery Proof Generation & Verification', () => {
|
|
72
|
+
const txId = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef';
|
|
73
|
+
const deliverable = 'This is the completed translation work. Lorem ipsum dolor sit amet.';
|
|
74
|
+
|
|
75
|
+
it('should generate and verify delivery proof', () => {
|
|
76
|
+
// Generate proof
|
|
77
|
+
const proof = proofGenerator.generateDeliveryProof({
|
|
78
|
+
txId,
|
|
79
|
+
deliverable,
|
|
80
|
+
metadata: {
|
|
81
|
+
language: 'es',
|
|
82
|
+
wordCount: 100
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
expect(proof.txId).toBe(txId);
|
|
87
|
+
expect(proof.contentHash).toMatch(/^0x[a-f0-9]{64}$/);
|
|
88
|
+
expect(proof.metadata.language).toBe('es');
|
|
89
|
+
|
|
90
|
+
// Verify deliverable
|
|
91
|
+
const isValid = proofGenerator.verifyDeliverable(deliverable, proof.contentHash);
|
|
92
|
+
expect(isValid).toBe(true);
|
|
93
|
+
|
|
94
|
+
// Wrong deliverable should fail
|
|
95
|
+
const isInvalid = proofGenerator.verifyDeliverable('wrong content', proof.contentHash);
|
|
96
|
+
expect(isInvalid).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should encode and decode proof for on-chain submission', () => {
|
|
100
|
+
const proof = proofGenerator.generateDeliveryProof({
|
|
101
|
+
txId,
|
|
102
|
+
deliverable
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Encode for on-chain
|
|
106
|
+
const encoded = proofGenerator.encodeProof(proof);
|
|
107
|
+
expect(encoded).toMatch(/^0x[a-f0-9]+$/);
|
|
108
|
+
|
|
109
|
+
// Decode
|
|
110
|
+
const decoded = proofGenerator.decodeProof(encoded);
|
|
111
|
+
expect(decoded.txId).toBe(proof.txId);
|
|
112
|
+
expect(decoded.contentHash).toBe(proof.contentHash);
|
|
113
|
+
expect(decoded.timestamp).toBe(proof.timestamp);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe('Message Signing & Verification', () => {
|
|
118
|
+
it('should sign and verify ACTP messages', async () => {
|
|
119
|
+
const message: ACTPMessage = {
|
|
120
|
+
type: 'quote.request',
|
|
121
|
+
version: '1.0',
|
|
122
|
+
from: messageSigner.addressToDID(wallet.address),
|
|
123
|
+
to: messageSigner.addressToDID('0x' + '1'.repeat(40)),
|
|
124
|
+
timestamp: Date.now(),
|
|
125
|
+
nonce: hexlify(randomBytes(32)),
|
|
126
|
+
serviceRequest: {
|
|
127
|
+
capabilityType: 'translation',
|
|
128
|
+
parameters: {}
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// Sign
|
|
133
|
+
const signature = await messageSigner.signMessage(message);
|
|
134
|
+
expect(signature).toMatch(/^0x[a-f0-9]{130}$/);
|
|
135
|
+
|
|
136
|
+
// Verify
|
|
137
|
+
const isValid = await messageSigner.verifySignature(message, signature);
|
|
138
|
+
expect(isValid).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should reject invalid signatures', async () => {
|
|
142
|
+
const message: ACTPMessage = {
|
|
143
|
+
type: 'quote.request',
|
|
144
|
+
version: '1.0',
|
|
145
|
+
from: messageSigner.addressToDID(wallet.address),
|
|
146
|
+
to: messageSigner.addressToDID('0x' + '1'.repeat(40)),
|
|
147
|
+
timestamp: Date.now(),
|
|
148
|
+
nonce: hexlify(randomBytes(32))
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// Sign with this wallet
|
|
152
|
+
const signature = await messageSigner.signMessage(message);
|
|
153
|
+
|
|
154
|
+
// Modify message (tamper)
|
|
155
|
+
message.timestamp = Date.now() + 1000;
|
|
156
|
+
|
|
157
|
+
// Verification should fail
|
|
158
|
+
const isValid = await messageSigner.verifySignature(message, signature);
|
|
159
|
+
expect(isValid).toBe(false);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should convert between DID and address', () => {
|
|
163
|
+
const address = wallet.address;
|
|
164
|
+
const did = messageSigner.addressToDID(address);
|
|
165
|
+
|
|
166
|
+
expect(did).toBe(`did:ethr:${address}`);
|
|
167
|
+
|
|
168
|
+
// DID resolution would happen here in real implementation
|
|
169
|
+
expect(did).toMatch(/^did:ethr:0x[a-fA-F0-9]{40}$/);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('Content Hashing (Keccak256)', () => {
|
|
174
|
+
it('should produce consistent hashes', () => {
|
|
175
|
+
const content = 'Test content for hashing';
|
|
176
|
+
|
|
177
|
+
const hash1 = proofGenerator.hashContent(content);
|
|
178
|
+
const hash2 = proofGenerator.hashContent(content);
|
|
179
|
+
|
|
180
|
+
expect(hash1).toBe(hash2);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should produce different hashes for different content', () => {
|
|
184
|
+
const content1 = 'Content A';
|
|
185
|
+
const content2 = 'Content B';
|
|
186
|
+
|
|
187
|
+
const hash1 = proofGenerator.hashContent(content1);
|
|
188
|
+
const hash2 = proofGenerator.hashContent(content2);
|
|
189
|
+
|
|
190
|
+
expect(hash1).not.toBe(hash2);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should handle binary data', () => {
|
|
194
|
+
const buffer = Buffer.from([1, 2, 3, 4, 5]);
|
|
195
|
+
const hash = proofGenerator.hashContent(buffer);
|
|
196
|
+
|
|
197
|
+
expect(hash).toMatch(/^0x[a-f0-9]{64}$/);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should match ethers.js keccak256', () => {
|
|
201
|
+
const content = 'Hello, ACTP!';
|
|
202
|
+
const contentBytes = toUtf8Bytes(content);
|
|
203
|
+
|
|
204
|
+
const sdkHash = proofGenerator.hashContent(content);
|
|
205
|
+
const ethersHash = keccak256(contentBytes);
|
|
206
|
+
|
|
207
|
+
expect(sdkHash).toBe(ethersHash);
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
describe('Error Scenarios', () => {
|
|
212
|
+
it('should throw on invalid state transitions', () => {
|
|
213
|
+
expect(() => {
|
|
214
|
+
StateMachine.validateTransition(State.INITIATED, State.SETTLED);
|
|
215
|
+
}).toThrow('Invalid state transition');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('should identify terminal states correctly', () => {
|
|
219
|
+
expect(StateMachine.isTerminalState(State.SETTLED)).toBe(true);
|
|
220
|
+
expect(StateMachine.isTerminalState(State.CANCELLED)).toBe(true);
|
|
221
|
+
expect(StateMachine.isTerminalState(State.IN_PROGRESS)).toBe(false);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('should list valid next states', () => {
|
|
225
|
+
const nextStates = StateMachine.getNextValidStates(State.DELIVERED);
|
|
226
|
+
expect(nextStates).toContain(State.SETTLED);
|
|
227
|
+
expect(nextStates).toContain(State.DISPUTED);
|
|
228
|
+
expect(nextStates).toHaveLength(2);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
describe('Full Mock Transaction Flow', () => {
|
|
233
|
+
it('should simulate complete transaction', async () => {
|
|
234
|
+
console.log('\n=== Mock Transaction Flow ===\n');
|
|
235
|
+
|
|
236
|
+
// 1. Create transaction (INITIATED)
|
|
237
|
+
const txId = hexlify(randomBytes(32));
|
|
238
|
+
let state = State.INITIATED;
|
|
239
|
+
console.log(`1. Transaction created: ${txId}`);
|
|
240
|
+
console.log(` State: ${State[state]}`);
|
|
241
|
+
|
|
242
|
+
// 2. Quote provided (QUOTED)
|
|
243
|
+
state = State.QUOTED;
|
|
244
|
+
console.log(`\n2. Quote provided`);
|
|
245
|
+
console.log(` State: ${State[state]}`);
|
|
246
|
+
|
|
247
|
+
// 3. Funds escrowed (COMMITTED)
|
|
248
|
+
state = State.COMMITTED;
|
|
249
|
+
console.log(`\n3. Funds escrowed`);
|
|
250
|
+
console.log(` State: ${State[state]}`);
|
|
251
|
+
|
|
252
|
+
// 4. Work started (IN_PROGRESS)
|
|
253
|
+
state = State.IN_PROGRESS;
|
|
254
|
+
console.log(`\n4. Work started`);
|
|
255
|
+
console.log(` State: ${State[state]}`);
|
|
256
|
+
|
|
257
|
+
// 5. Work delivered (DELIVERED)
|
|
258
|
+
const deliverable = 'Completed translation: Hola, mundo!';
|
|
259
|
+
const proof = proofGenerator.generateDeliveryProof({
|
|
260
|
+
txId,
|
|
261
|
+
deliverable,
|
|
262
|
+
metadata: { language: 'es', wordCount: 3 }
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
state = State.DELIVERED;
|
|
266
|
+
console.log(`\n5. Work delivered`);
|
|
267
|
+
console.log(` State: ${State[state]}`);
|
|
268
|
+
console.log(` Content Hash: ${proof.contentHash}`);
|
|
269
|
+
|
|
270
|
+
// 6. Verify delivery
|
|
271
|
+
const isValid = proofGenerator.verifyDeliverable(deliverable, proof.contentHash);
|
|
272
|
+
console.log(`\n6. Delivery verified: ${isValid}`);
|
|
273
|
+
|
|
274
|
+
// 7. Settle transaction (SETTLED)
|
|
275
|
+
state = State.SETTLED;
|
|
276
|
+
console.log(`\n7. Transaction settled`);
|
|
277
|
+
console.log(` State: ${State[state]}`);
|
|
278
|
+
console.log(` Terminal: ${StateMachine.isTerminalState(state)}`);
|
|
279
|
+
|
|
280
|
+
// Assertions
|
|
281
|
+
expect(state).toBe(State.SETTLED);
|
|
282
|
+
expect(StateMachine.isTerminalState(state)).toBe(true);
|
|
283
|
+
expect(isValid).toBe(true);
|
|
284
|
+
|
|
285
|
+
console.log('\n=== Transaction Complete ===\n');
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|