@openzeppelin/miden-multisig-client 0.16.1 → 0.17.0-rc.1
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 +192 -11
- package/dist/account/builder.d.ts.map +1 -1
- package/dist/account/builder.js +32 -25
- package/dist/account/builder.js.map +1 -1
- package/dist/account/builder.test.js +73 -21
- package/dist/account/builder.test.js.map +1 -1
- package/dist/account/layout.d.ts +31 -0
- package/dist/account/layout.d.ts.map +1 -0
- package/dist/account/layout.js +31 -0
- package/dist/account/layout.js.map +1 -0
- package/dist/account/masm/account-components/auth.d.ts +1 -4
- package/dist/account/masm/account-components/auth.d.ts.map +1 -1
- package/dist/account/masm/account-components/auth.js +36 -53
- package/dist/account/masm/account-components/auth.js.map +1 -1
- package/dist/account/masm/index.d.ts +0 -1
- package/dist/account/masm/index.d.ts.map +1 -1
- package/dist/account/masm/index.js +0 -1
- package/dist/account/masm/index.js.map +1 -1
- package/dist/account/storage.d.ts +4 -0
- package/dist/account/storage.d.ts.map +1 -1
- package/dist/account/storage.js +9 -20
- package/dist/account/storage.js.map +1 -1
- package/dist/client.d.ts +4 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +10 -5
- package/dist/client.js.map +1 -1
- package/dist/client.test.js +74 -16
- package/dist/client.test.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/inspector.d.ts +59 -1
- package/dist/inspector.d.ts.map +1 -1
- package/dist/inspector.js +157 -29
- package/dist/inspector.js.map +1 -1
- package/dist/inspector.test.js +246 -37
- package/dist/inspector.test.js.map +1 -1
- package/dist/multisig.d.ts +109 -33
- package/dist/multisig.d.ts.map +1 -1
- package/dist/multisig.js +307 -104
- package/dist/multisig.js.map +1 -1
- package/dist/multisig.test.js +582 -58
- package/dist/multisig.test.js.map +1 -1
- package/dist/procedures.d.ts +6 -7
- package/dist/procedures.d.ts.map +1 -1
- package/dist/procedures.js +6 -7
- package/dist/procedures.js.map +1 -1
- package/dist/proposal/metadata.d.ts.map +1 -1
- package/dist/proposal/metadata.js +13 -2
- package/dist/proposal/metadata.js.map +1 -1
- package/dist/proposal/metadata.test.js +57 -0
- package/dist/proposal/metadata.test.js.map +1 -1
- package/dist/prover/errors.d.ts +5 -0
- package/dist/prover/errors.d.ts.map +1 -1
- package/dist/prover/errors.js +7 -155
- package/dist/prover/errors.js.map +1 -1
- package/dist/prover/errors.test.js +5 -0
- package/dist/prover/errors.test.js.map +1 -1
- package/dist/prover/retry.d.ts +1 -6
- package/dist/prover/retry.d.ts.map +1 -1
- package/dist/prover/retry.js +5 -28
- package/dist/prover/retry.js.map +1 -1
- package/dist/prover/retry.test.js +1 -1
- package/dist/prover/retry.test.js.map +1 -1
- package/dist/prover/workflow.d.ts +4 -3
- package/dist/prover/workflow.d.ts.map +1 -1
- package/dist/prover/workflow.js +5 -2
- package/dist/prover/workflow.js.map +1 -1
- package/dist/prover/workflow.test.js +28 -3
- package/dist/prover/workflow.test.js.map +1 -1
- package/dist/retry/classify.d.ts +16 -0
- package/dist/retry/classify.d.ts.map +1 -0
- package/dist/retry/classify.js +187 -0
- package/dist/retry/classify.js.map +1 -0
- package/dist/retry/runtime.d.ts +13 -0
- package/dist/retry/runtime.d.ts.map +1 -0
- package/dist/retry/runtime.js +33 -0
- package/dist/retry/runtime.js.map +1 -0
- package/dist/rpc/config.d.ts +11 -0
- package/dist/rpc/config.d.ts.map +1 -0
- package/dist/rpc/config.js +17 -0
- package/dist/rpc/config.js.map +1 -0
- package/dist/rpc/config.test.d.ts +2 -0
- package/dist/rpc/config.test.d.ts.map +1 -0
- package/dist/rpc/config.test.js +24 -0
- package/dist/rpc/config.test.js.map +1 -0
- package/dist/rpc/errors.d.ts +2 -0
- package/dist/rpc/errors.d.ts.map +1 -0
- package/dist/rpc/errors.js +11 -0
- package/dist/rpc/errors.js.map +1 -0
- package/dist/rpc/errors.test.d.ts +2 -0
- package/dist/rpc/errors.test.d.ts.map +1 -0
- package/dist/rpc/errors.test.js +34 -0
- package/dist/rpc/errors.test.js.map +1 -0
- package/dist/rpc/retry.d.ts +4 -0
- package/dist/rpc/retry.d.ts.map +1 -0
- package/dist/rpc/retry.js +6 -0
- package/dist/rpc/retry.js.map +1 -0
- package/dist/rpc/retry.test.d.ts +2 -0
- package/dist/rpc/retry.test.d.ts.map +1 -0
- package/dist/rpc/retry.test.js +98 -0
- package/dist/rpc/retry.test.js.map +1 -0
- package/dist/transaction/index.d.ts +1 -1
- package/dist/transaction/index.d.ts.map +1 -1
- package/dist/transaction/index.js +1 -1
- package/dist/transaction/index.js.map +1 -1
- package/dist/transaction/p2id.d.ts +17 -6
- package/dist/transaction/p2id.d.ts.map +1 -1
- package/dist/transaction/p2id.js +22 -31
- package/dist/transaction/p2id.js.map +1 -1
- package/dist/transaction/p2id.test.js +62 -24
- package/dist/transaction/p2id.test.js.map +1 -1
- package/dist/transaction/summary.d.ts +45 -2
- package/dist/transaction/summary.d.ts.map +1 -1
- package/dist/transaction/summary.js +42 -2
- package/dist/transaction/summary.js.map +1 -1
- package/dist/transaction/summary.test.d.ts +2 -0
- package/dist/transaction/summary.test.d.ts.map +1 -0
- package/dist/transaction/summary.test.js +26 -0
- package/dist/transaction/summary.test.js.map +1 -0
- package/dist/transaction/updateGuardian.d.ts.map +1 -1
- package/dist/transaction/updateGuardian.js +16 -18
- package/dist/transaction/updateGuardian.js.map +1 -1
- package/dist/transaction/updateProcedureThreshold.d.ts.map +1 -1
- package/dist/transaction/updateProcedureThreshold.js +15 -17
- package/dist/transaction/updateProcedureThreshold.js.map +1 -1
- package/dist/transaction/updateSigners.d.ts +6 -1
- package/dist/transaction/updateSigners.d.ts.map +1 -1
- package/dist/transaction/updateSigners.js +20 -17
- package/dist/transaction/updateSigners.js.map +1 -1
- package/dist/transaction.d.ts +2 -2
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +1 -1
- package/dist/transaction.js.map +1 -1
- package/dist/types/proposal.d.ts +28 -4
- package/dist/types/proposal.d.ts.map +1 -1
- package/dist/types/proposal.js +18 -0
- package/dist/types/proposal.js.map +1 -1
- package/dist/types.d.ts +0 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/signature.d.ts +11 -7
- package/dist/utils/signature.d.ts.map +1 -1
- package/dist/utils/signature.js +24 -58
- package/dist/utils/signature.js.map +1 -1
- package/dist/utils/word.d.ts +7 -0
- package/dist/utils/word.d.ts.map +1 -1
- package/dist/utils/word.js +15 -0
- package/dist/utils/word.js.map +1 -1
- package/masm/account_components/auth/guarded_multisig.masm +42 -0
- package/package.json +7 -4
- package/src/account/builder.test.ts +111 -45
- package/src/account/builder.ts +45 -33
- package/src/account/layout.ts +33 -0
- package/src/account/masm/account-components/auth.ts +36 -56
- package/src/account/masm/index.ts +0 -1
- package/src/account/storage.ts +9 -22
- package/src/client.test.ts +87 -16
- package/src/client.ts +16 -3
- package/src/index.ts +27 -1
- package/src/inspector.test.ts +330 -38
- package/src/inspector.ts +196 -33
- package/src/multisig.test.ts +680 -63
- package/src/multisig.ts +400 -115
- package/src/procedures.ts +6 -7
- package/src/proposal/metadata.test.ts +76 -0
- package/src/proposal/metadata.ts +13 -2
- package/src/prover/errors.test.ts +8 -0
- package/src/prover/errors.ts +7 -175
- package/src/prover/retry.test.ts +1 -1
- package/src/prover/retry.ts +10 -35
- package/src/prover/workflow.test.ts +40 -4
- package/src/prover/workflow.ts +16 -4
- package/src/retry/classify.ts +220 -0
- package/src/retry/runtime.ts +45 -0
- package/src/rpc/config.test.ts +45 -0
- package/src/rpc/config.ts +30 -0
- package/src/rpc/errors.test.ts +69 -0
- package/src/rpc/errors.ts +12 -0
- package/src/rpc/retry.test.ts +144 -0
- package/src/rpc/retry.ts +12 -0
- package/src/transaction/index.ts +7 -1
- package/src/transaction/p2id.test.ts +112 -31
- package/src/transaction/p2id.ts +39 -38
- package/src/transaction/summary.test.ts +32 -0
- package/src/transaction/summary.ts +83 -4
- package/src/transaction/updateGuardian.ts +15 -25
- package/src/transaction/updateProcedureThreshold.ts +13 -29
- package/src/transaction/updateSigners.ts +38 -30
- package/src/transaction.ts +8 -1
- package/src/types/proposal.ts +43 -4
- package/src/types.ts +0 -1
- package/src/utils/signature.ts +32 -65
- package/src/utils/word.ts +17 -0
- package/dist/account/masm/auth.d.ts +0 -5
- package/dist/account/masm/auth.d.ts.map +0 -1
- package/dist/account/masm/auth.js +0 -1509
- package/dist/account/masm/auth.js.map +0 -1
- package/masm/account_components/auth/multisig.masm +0 -12
- package/masm/account_components/auth/multisig_ecdsa.masm +0 -12
- package/masm/account_components/auth/multisig_guardian.masm +0 -16
- package/masm/account_components/auth/multisig_guardian_ecdsa.masm +0 -16
- package/masm/auth/guardian.masm +0 -199
- package/masm/auth/guardian_ecdsa.masm +0 -195
- package/masm/auth/multisig.masm +0 -554
- package/masm/auth/multisig_ecdsa.masm +0 -554
- package/src/account/masm/auth.ts +0 -1512
package/dist/multisig.test.js
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { Multisig } from './multisig.js';
|
|
3
3
|
import { GuardianHttpClient } from '@openzeppelin/guardian-client';
|
|
4
|
-
import { buildUpdateProcedureThresholdTransactionRequest, buildUpdateGuardianTransactionRequest, buildUpdateSignersTransactionRequest, executeForSummary, } from './transaction.js';
|
|
5
|
-
const { mockRpcGetAccountDetails, mockAccountDeserialize, mockDetectConfig, mockNoteFileDeserialize } = vi.hoisted(() => ({
|
|
4
|
+
import { buildUpdateProcedureThresholdTransactionRequest, buildUpdateGuardianTransactionRequest, buildUpdateSignersTransactionRequest, chainAnchorFromBase64, executeForSummary, executeForSummaryAt, } from './transaction.js';
|
|
5
|
+
const { mockRpcGetAccountDetails, mockAccountDeserialize, mockDetectConfig, mockNoteFileDeserialize, mockGetSignerCommitments, mockGetGuardianCommitment, } = vi.hoisted(() => ({
|
|
6
6
|
mockRpcGetAccountDetails: vi.fn(),
|
|
7
7
|
mockAccountDeserialize: vi.fn(),
|
|
8
8
|
mockDetectConfig: vi.fn(),
|
|
9
9
|
mockNoteFileDeserialize: vi.fn(),
|
|
10
|
+
mockGetSignerCommitments: vi.fn(),
|
|
11
|
+
mockGetGuardianCommitment: vi.fn(),
|
|
10
12
|
}));
|
|
13
|
+
const { MOCK_CHAIN_ANCHOR_B64, createMockChainAnchor } = vi.hoisted(() => {
|
|
14
|
+
const MOCK_CHAIN_ANCHOR_B64 = 'bW9jay1jaGFpbi1hbmNob3I=';
|
|
15
|
+
const createMockChainAnchor = () => ({
|
|
16
|
+
commitment: () => ({ toHex: () => '0x' + 'b'.repeat(64) }),
|
|
17
|
+
free: () => { },
|
|
18
|
+
serialize: () => new Uint8Array([9, 9, 9]),
|
|
19
|
+
});
|
|
20
|
+
return { MOCK_CHAIN_ANCHOR_B64, createMockChainAnchor };
|
|
21
|
+
});
|
|
11
22
|
// Mock the Miden SDK
|
|
12
23
|
vi.mock('@miden-sdk/miden-sdk', () => ({
|
|
13
24
|
Account: {
|
|
@@ -33,9 +44,10 @@ vi.mock('@miden-sdk/miden-sdk', () => ({
|
|
|
33
44
|
toCommitment: () => ({
|
|
34
45
|
toHex: () => '0x' + 'c'.repeat(64),
|
|
35
46
|
}),
|
|
36
|
-
|
|
37
|
-
toHex: () => '0x' + '
|
|
47
|
+
blockCommitment: () => ({
|
|
48
|
+
toHex: () => '0x' + 'b'.repeat(64),
|
|
38
49
|
}),
|
|
50
|
+
userParams: () => [0, 0, 0, 1, 2, 3, 4],
|
|
39
51
|
serialize: () => new Uint8Array([1, 2, 3]),
|
|
40
52
|
}),
|
|
41
53
|
},
|
|
@@ -70,6 +82,12 @@ vi.mock('@miden-sdk/miden-sdk', () => ({
|
|
|
70
82
|
// Mock transaction module
|
|
71
83
|
vi.mock('./transaction.js', () => ({
|
|
72
84
|
executeForSummary: vi.fn(),
|
|
85
|
+
executeForSummaryAt: vi.fn(),
|
|
86
|
+
chainAnchorToBase64: vi.fn(() => MOCK_CHAIN_ANCHOR_B64),
|
|
87
|
+
chainAnchorFromBase64: vi.fn(() => createMockChainAnchor()),
|
|
88
|
+
summarySalt: vi.fn(() => ({
|
|
89
|
+
toHex: () => '0x' + 'd'.repeat(64),
|
|
90
|
+
})),
|
|
73
91
|
buildUpdateSignersTransactionRequest: vi.fn().mockResolvedValue({
|
|
74
92
|
request: {},
|
|
75
93
|
salt: { toHex: () => '0x' + 'd'.repeat(64) },
|
|
@@ -115,6 +133,9 @@ vi.mock('./utils/signature.js', async () => {
|
|
|
115
133
|
values: [1, 2, 3],
|
|
116
134
|
})),
|
|
117
135
|
signatureHexToBytes: vi.fn((hex) => new Uint8Array([0, 1, 2, 3])),
|
|
136
|
+
// These tests use synthetic signature bytes to exercise advice routing;
|
|
137
|
+
// recoverability is covered by tests/ecdsa-advice-encoding.test.ts.
|
|
138
|
+
assertEcdsaSignatureRecoverable: vi.fn(),
|
|
118
139
|
};
|
|
119
140
|
});
|
|
120
141
|
vi.mock('./utils/encoding.js', async () => {
|
|
@@ -124,11 +145,19 @@ vi.mock('./utils/encoding.js', async () => {
|
|
|
124
145
|
normalizeHexWord: vi.fn((hex) => '0x' + hex.replace(/^0x/i, '').toLowerCase().padStart(64, '0')),
|
|
125
146
|
};
|
|
126
147
|
});
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
148
|
+
// Keep the real assertCompleteDetectedConfig so refreshConfigFromAccount's
|
|
149
|
+
// fail-closed validation is exercised.
|
|
150
|
+
vi.mock('./inspector.js', async (importOriginal) => {
|
|
151
|
+
const actual = await importOriginal();
|
|
152
|
+
return {
|
|
153
|
+
...actual,
|
|
154
|
+
AccountInspector: {
|
|
155
|
+
fromAccount: mockDetectConfig,
|
|
156
|
+
getSignerPublicKeyCommitments: mockGetSignerCommitments,
|
|
157
|
+
getGuardianPublicKeyCommitment: mockGetGuardianCommitment,
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
});
|
|
132
161
|
// Mock fetch for GUARDIAN client
|
|
133
162
|
const mockFetch = vi.fn();
|
|
134
163
|
vi.stubGlobal('fetch', mockFetch);
|
|
@@ -157,6 +186,15 @@ describe('Multisig', () => {
|
|
|
157
186
|
beforeEach(() => {
|
|
158
187
|
mockFetch.mockReset();
|
|
159
188
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
189
|
+
summary: {
|
|
190
|
+
toCommitment: () => ({
|
|
191
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
192
|
+
}),
|
|
193
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
194
|
+
},
|
|
195
|
+
anchor: createMockChainAnchor(),
|
|
196
|
+
});
|
|
197
|
+
vi.mocked(executeForSummaryAt).mockResolvedValue({
|
|
160
198
|
toCommitment: () => ({
|
|
161
199
|
toHex: () => '0x' + 'c'.repeat(64),
|
|
162
200
|
}),
|
|
@@ -175,7 +213,6 @@ describe('Multisig', () => {
|
|
|
175
213
|
threshold: 1,
|
|
176
214
|
numSigners: 1,
|
|
177
215
|
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
178
|
-
guardianEnabled: true,
|
|
179
216
|
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
180
217
|
vaultBalances: [],
|
|
181
218
|
procedureThresholds: new Map(),
|
|
@@ -291,6 +328,34 @@ describe('Multisig', () => {
|
|
|
291
328
|
expect(multisig.accountId).toBe(accountId);
|
|
292
329
|
});
|
|
293
330
|
});
|
|
331
|
+
describe('history (issue #413)', () => {
|
|
332
|
+
it('delegates to the guardian client with the account id and options', async () => {
|
|
333
|
+
const config = {
|
|
334
|
+
threshold: 1,
|
|
335
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
336
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
337
|
+
};
|
|
338
|
+
const multisig = createTestMultisig(config);
|
|
339
|
+
const page = {
|
|
340
|
+
entries: [
|
|
341
|
+
{
|
|
342
|
+
nonce: 3,
|
|
343
|
+
status: 'canonical',
|
|
344
|
+
timestamp: '2026-08-01T12:00:03Z',
|
|
345
|
+
newCommitment: '0x' + 'b'.repeat(64),
|
|
346
|
+
inputNotes: [],
|
|
347
|
+
outputNotes: [],
|
|
348
|
+
decodeWarnings: [],
|
|
349
|
+
},
|
|
350
|
+
],
|
|
351
|
+
nextCursor: 'cursor-token',
|
|
352
|
+
};
|
|
353
|
+
const spy = vi.spyOn(guardian, 'getDeltaHistory').mockResolvedValue(page);
|
|
354
|
+
const result = await multisig.deltaHistory({ limit: 5, cursor: 'prev' });
|
|
355
|
+
expect(result).toBe(page);
|
|
356
|
+
expect(spy).toHaveBeenCalledWith('0x' + 'a'.repeat(30), { limit: 5, cursor: 'prev' });
|
|
357
|
+
});
|
|
358
|
+
});
|
|
294
359
|
describe('signerCommitment', () => {
|
|
295
360
|
it('should return signer commitment', () => {
|
|
296
361
|
const config = {
|
|
@@ -302,6 +367,45 @@ describe('Multisig', () => {
|
|
|
302
367
|
expect(multisig.signerCommitment).toBe(mockSigner.commitment);
|
|
303
368
|
});
|
|
304
369
|
});
|
|
370
|
+
describe('getSignerPublicKeyCommitments (issue #306)', () => {
|
|
371
|
+
const config = {
|
|
372
|
+
threshold: 1,
|
|
373
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
374
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
375
|
+
};
|
|
376
|
+
it('reads commitments from the store-backed account', async () => {
|
|
377
|
+
const storeAccount = mockedAccount('0x' + 'b'.repeat(64), 1);
|
|
378
|
+
mockWebClient.getAccount.mockResolvedValueOnce(storeAccount);
|
|
379
|
+
const expected = ['0x' + '1'.repeat(64), '0x' + '2'.repeat(64)];
|
|
380
|
+
mockGetSignerCommitments.mockReturnValueOnce(expected);
|
|
381
|
+
const multisig = createTestMultisig(config);
|
|
382
|
+
const commitments = await multisig.getSignerPublicKeyCommitments();
|
|
383
|
+
expect(commitments).toEqual(expected);
|
|
384
|
+
expect(mockGetSignerCommitments).toHaveBeenCalledWith(storeAccount);
|
|
385
|
+
});
|
|
386
|
+
it('falls back to the account snapshot when the store has no record', async () => {
|
|
387
|
+
mockWebClient.getAccount.mockResolvedValueOnce(null);
|
|
388
|
+
mockGetSignerCommitments.mockReturnValueOnce(['0x' + '3'.repeat(64)]);
|
|
389
|
+
const multisig = createTestMultisig(config);
|
|
390
|
+
await multisig.getSignerPublicKeyCommitments();
|
|
391
|
+
expect(mockGetSignerCommitments).toHaveBeenCalledWith(mockAccount);
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
describe('getGuardianPublicKeyCommitment (issue #306)', () => {
|
|
395
|
+
it('reads the guardian commitment from the store-backed account', async () => {
|
|
396
|
+
const storeAccount = mockedAccount('0x' + 'b'.repeat(64), 1);
|
|
397
|
+
mockWebClient.getAccount.mockResolvedValueOnce(storeAccount);
|
|
398
|
+
mockGetGuardianCommitment.mockReturnValueOnce('0x' + '4'.repeat(64));
|
|
399
|
+
const multisig = createTestMultisig({
|
|
400
|
+
threshold: 1,
|
|
401
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
402
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
403
|
+
});
|
|
404
|
+
const commitment = await multisig.getGuardianPublicKeyCommitment();
|
|
405
|
+
expect(commitment).toBe('0x' + '4'.repeat(64));
|
|
406
|
+
expect(mockGetGuardianCommitment).toHaveBeenCalledWith(storeAccount);
|
|
407
|
+
});
|
|
408
|
+
});
|
|
305
409
|
describe('fetchState', () => {
|
|
306
410
|
it('should fetch account state from GUARDIAN', async () => {
|
|
307
411
|
const config = {
|
|
@@ -397,7 +501,6 @@ describe('Multisig', () => {
|
|
|
397
501
|
threshold: 2,
|
|
398
502
|
numSigners: 2,
|
|
399
503
|
signerCommitments: ['0x' + '1'.repeat(64), '0x' + '2'.repeat(64)],
|
|
400
|
-
guardianEnabled: true,
|
|
401
504
|
guardianCommitment: '0x' + 'd'.repeat(64),
|
|
402
505
|
vaultBalances: [],
|
|
403
506
|
procedureThresholds: new Map(),
|
|
@@ -411,6 +514,40 @@ describe('Multisig', () => {
|
|
|
411
514
|
expect(multisig.guardianCommitment).toBe('0x' + 'd'.repeat(64));
|
|
412
515
|
expect(mockWebClient.newAccount).not.toHaveBeenCalled();
|
|
413
516
|
});
|
|
517
|
+
it('keeps the previous config when a refresh reads an incomplete signer set (issue #306 review)', async () => {
|
|
518
|
+
const config = {
|
|
519
|
+
threshold: 1,
|
|
520
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
521
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
522
|
+
};
|
|
523
|
+
const multisig = createTestMultisig(config, mockSigner, '0x' + 'a'.repeat(30));
|
|
524
|
+
mockWebClient.getAccount.mockResolvedValueOnce(mockedAccount('0x' + 'b'.repeat(64), 0));
|
|
525
|
+
mockFetch.mockResolvedValueOnce({
|
|
526
|
+
ok: true,
|
|
527
|
+
json: async () => ({
|
|
528
|
+
account_id: multisig.accountId,
|
|
529
|
+
commitment: '0x' + 'b'.repeat(64),
|
|
530
|
+
state_json: { data: 'AQID' },
|
|
531
|
+
created_at: '2024-01-01T00:00:00Z',
|
|
532
|
+
updated_at: '2024-01-02T00:00:00Z',
|
|
533
|
+
}),
|
|
534
|
+
});
|
|
535
|
+
// Storage reports 3 signers but only 1 entry was readable: adopting
|
|
536
|
+
// this would let membership proposals rewrite the on-chain set without
|
|
537
|
+
// the omitted keys. The refresh must keep the previous config instead.
|
|
538
|
+
mockDetectConfig.mockReturnValueOnce({
|
|
539
|
+
threshold: 2,
|
|
540
|
+
numSigners: 3,
|
|
541
|
+
signerCommitments: ['0x' + '1'.repeat(64)],
|
|
542
|
+
guardianCommitment: '0x' + 'd'.repeat(64),
|
|
543
|
+
vaultBalances: [],
|
|
544
|
+
procedureThresholds: new Map(),
|
|
545
|
+
});
|
|
546
|
+
await multisig.syncState();
|
|
547
|
+
expect(multisig.threshold).toBe(1);
|
|
548
|
+
expect(multisig.signerCommitments).toEqual(['0x' + 'a'.repeat(64)]);
|
|
549
|
+
expect(multisig.guardianCommitment).toBe('0x' + 'c'.repeat(64));
|
|
550
|
+
});
|
|
414
551
|
it('should overwrite local state when account is not found on-chain', async () => {
|
|
415
552
|
const config = {
|
|
416
553
|
threshold: 1,
|
|
@@ -686,6 +823,7 @@ describe('Multisig', () => {
|
|
|
686
823
|
signatures: [],
|
|
687
824
|
metadata: {
|
|
688
825
|
proposal_type: 'add_signer',
|
|
826
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
689
827
|
target_threshold: 1,
|
|
690
828
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
691
829
|
description: '',
|
|
@@ -731,6 +869,7 @@ describe('Multisig', () => {
|
|
|
731
869
|
signatures: [],
|
|
732
870
|
metadata: {
|
|
733
871
|
proposal_type: 'add_signer',
|
|
872
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
734
873
|
target_threshold: 1,
|
|
735
874
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
736
875
|
description: '',
|
|
@@ -777,6 +916,7 @@ describe('Multisig', () => {
|
|
|
777
916
|
signatures: [],
|
|
778
917
|
metadata: {
|
|
779
918
|
proposal_type: 'add_signer',
|
|
919
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
780
920
|
target_threshold: 1,
|
|
781
921
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
782
922
|
description: '',
|
|
@@ -792,13 +932,65 @@ describe('Multisig', () => {
|
|
|
792
932
|
],
|
|
793
933
|
}),
|
|
794
934
|
});
|
|
795
|
-
vi.mocked(
|
|
935
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
796
936
|
toCommitment: () => ({
|
|
797
937
|
toHex: () => '0x' + 'f'.repeat(64),
|
|
798
938
|
}),
|
|
799
939
|
});
|
|
800
940
|
await expect(multisig.syncProposals()).rejects.toThrow('Invalid proposal: metadata does not match tx_summary');
|
|
801
941
|
});
|
|
942
|
+
/// A structurally valid anchor pinned to the wrong block must be rejected
|
|
943
|
+
/// before anything executes against it: its commitment disagrees with the
|
|
944
|
+
/// block commitment signed into the tx_summary.
|
|
945
|
+
it('should reject a proposal whose chain anchor does not match the summary block commitment', async () => {
|
|
946
|
+
const config = {
|
|
947
|
+
threshold: 1,
|
|
948
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
949
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
950
|
+
};
|
|
951
|
+
const multisig = createTestMultisig(config);
|
|
952
|
+
mockFetch.mockResolvedValueOnce({
|
|
953
|
+
ok: true,
|
|
954
|
+
json: async () => ({
|
|
955
|
+
proposals: [
|
|
956
|
+
{
|
|
957
|
+
account_id: '0x' + 'a'.repeat(30),
|
|
958
|
+
nonce: 1,
|
|
959
|
+
prev_commitment: '0x' + 'b'.repeat(64),
|
|
960
|
+
delta_payload: {
|
|
961
|
+
tx_summary: { data: 'AQID' },
|
|
962
|
+
signatures: [],
|
|
963
|
+
metadata: {
|
|
964
|
+
proposal_type: 'add_signer',
|
|
965
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
966
|
+
target_threshold: 1,
|
|
967
|
+
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
968
|
+
description: '',
|
|
969
|
+
},
|
|
970
|
+
},
|
|
971
|
+
status: {
|
|
972
|
+
status: 'pending',
|
|
973
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
974
|
+
proposer_id: '0x' + 'c'.repeat(64),
|
|
975
|
+
cosigner_sigs: [],
|
|
976
|
+
},
|
|
977
|
+
},
|
|
978
|
+
],
|
|
979
|
+
}),
|
|
980
|
+
});
|
|
981
|
+
// Deserializes fine, but pins a different block than the one bound into
|
|
982
|
+
// the summary (mock summary blockCommitment is 'b' * 64).
|
|
983
|
+
const freed = vi.fn();
|
|
984
|
+
vi.mocked(chainAnchorFromBase64).mockReturnValueOnce({
|
|
985
|
+
commitment: () => ({ toHex: () => '0x' + 'e'.repeat(64) }),
|
|
986
|
+
free: freed,
|
|
987
|
+
serialize: () => new Uint8Array([9, 9, 9]),
|
|
988
|
+
});
|
|
989
|
+
const reExecutionsBefore = vi.mocked(executeForSummaryAt).mock.calls.length;
|
|
990
|
+
await expect(multisig.syncProposals()).rejects.toThrow('chain anchor does not match the block commitment bound into the tx_summary');
|
|
991
|
+
expect(vi.mocked(executeForSummaryAt).mock.calls.length).toBe(reExecutionsBefore);
|
|
992
|
+
expect(freed).toHaveBeenCalledTimes(1);
|
|
993
|
+
});
|
|
802
994
|
it('should reject non-32-byte signer IDs from GUARDIAN proposals', async () => {
|
|
803
995
|
const config = {
|
|
804
996
|
threshold: 1,
|
|
@@ -816,6 +1008,7 @@ describe('Multisig', () => {
|
|
|
816
1008
|
signatures: [],
|
|
817
1009
|
metadata: {
|
|
818
1010
|
proposal_type: 'add_signer',
|
|
1011
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
819
1012
|
target_threshold: 1,
|
|
820
1013
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
821
1014
|
description: '',
|
|
@@ -858,6 +1051,7 @@ describe('Multisig', () => {
|
|
|
858
1051
|
signatures: [],
|
|
859
1052
|
metadata: {
|
|
860
1053
|
proposal_type: 'add_signer',
|
|
1054
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
861
1055
|
target_threshold: 2,
|
|
862
1056
|
signer_commitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
863
1057
|
description: '',
|
|
@@ -932,6 +1126,7 @@ describe('Multisig', () => {
|
|
|
932
1126
|
});
|
|
933
1127
|
const proposal = await multisig.createProposal(1, 'AQID', {
|
|
934
1128
|
proposalType: 'add_signer',
|
|
1129
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
935
1130
|
targetThreshold: 1,
|
|
936
1131
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
937
1132
|
description: '',
|
|
@@ -970,6 +1165,7 @@ describe('Multisig', () => {
|
|
|
970
1165
|
});
|
|
971
1166
|
await expect(multisig.createProposal(1, 'AQID', {
|
|
972
1167
|
proposalType: 'add_signer',
|
|
1168
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
973
1169
|
targetThreshold: 1,
|
|
974
1170
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
975
1171
|
description: '',
|
|
@@ -1004,13 +1200,14 @@ describe('Multisig', () => {
|
|
|
1004
1200
|
commitment: '0x' + 'c'.repeat(64),
|
|
1005
1201
|
}),
|
|
1006
1202
|
});
|
|
1007
|
-
vi.mocked(
|
|
1203
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
1008
1204
|
toCommitment: () => ({
|
|
1009
1205
|
toHex: () => '0x' + 'f'.repeat(64),
|
|
1010
1206
|
}),
|
|
1011
1207
|
});
|
|
1012
1208
|
await expect(multisig.createProposal(1, 'AQID', {
|
|
1013
1209
|
proposalType: 'add_signer',
|
|
1210
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1014
1211
|
targetThreshold: 1,
|
|
1015
1212
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1016
1213
|
description: '',
|
|
@@ -1021,10 +1218,13 @@ describe('Multisig', () => {
|
|
|
1021
1218
|
it('should include the faucet asset in the proposal description', async () => {
|
|
1022
1219
|
const { executeForSummary } = await import('./transaction.js');
|
|
1023
1220
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1221
|
+
summary: {
|
|
1222
|
+
toCommitment: () => ({
|
|
1223
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
1224
|
+
}),
|
|
1225
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1226
|
+
},
|
|
1227
|
+
anchor: createMockChainAnchor(),
|
|
1028
1228
|
});
|
|
1029
1229
|
const config = {
|
|
1030
1230
|
threshold: 1,
|
|
@@ -1041,6 +1241,7 @@ describe('Multisig', () => {
|
|
|
1041
1241
|
signatures: [],
|
|
1042
1242
|
metadata: {
|
|
1043
1243
|
proposal_type: 'p2id',
|
|
1244
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1044
1245
|
recipient_id: '0xrecipient',
|
|
1045
1246
|
faucet_id: '0xfaucet',
|
|
1046
1247
|
amount: '100',
|
|
@@ -1061,17 +1262,20 @@ describe('Multisig', () => {
|
|
|
1061
1262
|
commitment: '0x' + 'c'.repeat(64),
|
|
1062
1263
|
}),
|
|
1063
1264
|
});
|
|
1064
|
-
const proposal = await multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n, 1);
|
|
1265
|
+
const proposal = await multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n, { nonce: 1 });
|
|
1065
1266
|
expect(proposal.metadata.description).toBe('Send 100 of asset 0xfaucet... to 0xrecipien...');
|
|
1066
1267
|
});
|
|
1067
1268
|
it('threads a private noteType into the request and wire metadata (issue #322)', async () => {
|
|
1068
1269
|
const { executeForSummary, buildP2idTransactionRequest } = await import('./transaction.js');
|
|
1069
1270
|
const { NoteType } = await import('@miden-sdk/miden-sdk');
|
|
1070
1271
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1272
|
+
summary: {
|
|
1273
|
+
toCommitment: () => ({
|
|
1274
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
1275
|
+
}),
|
|
1276
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1277
|
+
},
|
|
1278
|
+
anchor: createMockChainAnchor(),
|
|
1075
1279
|
});
|
|
1076
1280
|
const config = {
|
|
1077
1281
|
threshold: 1,
|
|
@@ -1088,6 +1292,7 @@ describe('Multisig', () => {
|
|
|
1088
1292
|
signatures: [],
|
|
1089
1293
|
metadata: {
|
|
1090
1294
|
proposal_type: 'p2id',
|
|
1295
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1091
1296
|
recipient_id: '0xrecipient',
|
|
1092
1297
|
faucet_id: '0xfaucet',
|
|
1093
1298
|
amount: '100',
|
|
@@ -1109,14 +1314,15 @@ describe('Multisig', () => {
|
|
|
1109
1314
|
commitment: '0x' + 'c'.repeat(64),
|
|
1110
1315
|
}),
|
|
1111
1316
|
});
|
|
1112
|
-
const proposal = await multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n,
|
|
1317
|
+
const proposal = await multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n, {
|
|
1318
|
+
nonce: 1,
|
|
1113
1319
|
noteType: NoteType.Private,
|
|
1114
1320
|
});
|
|
1115
1321
|
// Propose path builds the private note...
|
|
1116
|
-
expect(vi.mocked(buildP2idTransactionRequest)).toHaveBeenCalledWith(expect.any(String), '0xrecipient', '0xfaucet', 100n,
|
|
1322
|
+
expect(vi.mocked(buildP2idTransactionRequest)).toHaveBeenCalledWith(expect.any(String), '0xrecipient', '0xfaucet', 100n, { noteType: NoteType.Private });
|
|
1117
1323
|
// ...and the rebuild-from-metadata path parses note_type back to Private.
|
|
1118
1324
|
const lastCall = vi.mocked(buildP2idTransactionRequest).mock.calls.at(-1);
|
|
1119
|
-
expect(lastCall[
|
|
1325
|
+
expect(lastCall[4]).toMatchObject({ noteType: NoteType.Private });
|
|
1120
1326
|
// The pushed wire metadata carries note_type so cosigners rebuild the
|
|
1121
1327
|
// same private note at verification/execution.
|
|
1122
1328
|
const pushBody = JSON.parse(mockFetch.mock.calls.at(-1)[1].body);
|
|
@@ -1124,6 +1330,121 @@ describe('Multisig', () => {
|
|
|
1124
1330
|
expect(proposal.metadata.proposalType).toBe('p2id');
|
|
1125
1331
|
expect(proposal.metadata.noteType).toBe('private');
|
|
1126
1332
|
});
|
|
1333
|
+
it('threads P2IDE reclaim/timelock heights into the request and wire metadata (issue #366)', async () => {
|
|
1334
|
+
const { executeForSummary, buildP2idTransactionRequest } = await import('./transaction.js');
|
|
1335
|
+
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1336
|
+
summary: {
|
|
1337
|
+
toCommitment: () => ({
|
|
1338
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
1339
|
+
}),
|
|
1340
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1341
|
+
},
|
|
1342
|
+
anchor: createMockChainAnchor(),
|
|
1343
|
+
});
|
|
1344
|
+
const config = {
|
|
1345
|
+
threshold: 1,
|
|
1346
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1347
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
1348
|
+
};
|
|
1349
|
+
const multisig = createTestMultisig(config);
|
|
1350
|
+
const mockDelta = {
|
|
1351
|
+
account_id: '0x' + 'a'.repeat(30),
|
|
1352
|
+
nonce: 1,
|
|
1353
|
+
prev_commitment: '0x' + 'b'.repeat(64),
|
|
1354
|
+
delta_payload: {
|
|
1355
|
+
tx_summary: { data: 'AQID' },
|
|
1356
|
+
signatures: [],
|
|
1357
|
+
metadata: {
|
|
1358
|
+
proposal_type: 'p2id',
|
|
1359
|
+
recipient_id: '0xrecipient',
|
|
1360
|
+
faucet_id: '0xfaucet',
|
|
1361
|
+
amount: '100',
|
|
1362
|
+
reclaim_height: 12345,
|
|
1363
|
+
timelock_height: 700,
|
|
1364
|
+
description: '',
|
|
1365
|
+
},
|
|
1366
|
+
},
|
|
1367
|
+
status: {
|
|
1368
|
+
status: 'pending',
|
|
1369
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
1370
|
+
proposer_id: '0x' + 'c'.repeat(64),
|
|
1371
|
+
cosigner_sigs: [],
|
|
1372
|
+
},
|
|
1373
|
+
};
|
|
1374
|
+
mockFetch.mockResolvedValueOnce({
|
|
1375
|
+
ok: true,
|
|
1376
|
+
json: async () => ({
|
|
1377
|
+
delta: mockDelta,
|
|
1378
|
+
commitment: '0x' + 'c'.repeat(64),
|
|
1379
|
+
}),
|
|
1380
|
+
});
|
|
1381
|
+
const proposal = await multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n, {
|
|
1382
|
+
nonce: 1,
|
|
1383
|
+
reclaimHeight: 12345,
|
|
1384
|
+
timelockHeight: 700,
|
|
1385
|
+
});
|
|
1386
|
+
// Propose path builds the P2IDE note from the heights...
|
|
1387
|
+
const lastCall = vi.mocked(buildP2idTransactionRequest).mock.calls.at(-1);
|
|
1388
|
+
expect(lastCall[4]).toMatchObject({ reclaimHeight: 12345, timelockHeight: 700 });
|
|
1389
|
+
// ...and the pushed wire metadata carries the heights so cosigners
|
|
1390
|
+
// rebuild the same P2IDE note at verification/execution.
|
|
1391
|
+
const pushBody = JSON.parse(mockFetch.mock.calls.at(-1)[1].body);
|
|
1392
|
+
expect(pushBody.delta_payload.metadata.reclaim_height).toBe(12345);
|
|
1393
|
+
expect(pushBody.delta_payload.metadata.timelock_height).toBe(700);
|
|
1394
|
+
expect(proposal.metadata.proposalType).toBe('p2id');
|
|
1395
|
+
expect(proposal.metadata).toMatchObject({ reclaimHeight: 12345, timelockHeight: 700 });
|
|
1396
|
+
});
|
|
1397
|
+
it('omits the heights from wire metadata for a plain P2ID send (pre-#366 shape)', async () => {
|
|
1398
|
+
const { executeForSummary } = await import('./transaction.js');
|
|
1399
|
+
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1400
|
+
summary: {
|
|
1401
|
+
toCommitment: () => ({
|
|
1402
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
1403
|
+
}),
|
|
1404
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1405
|
+
},
|
|
1406
|
+
anchor: createMockChainAnchor(),
|
|
1407
|
+
});
|
|
1408
|
+
const config = {
|
|
1409
|
+
threshold: 1,
|
|
1410
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1411
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
1412
|
+
};
|
|
1413
|
+
const multisig = createTestMultisig(config);
|
|
1414
|
+
const mockDelta = {
|
|
1415
|
+
account_id: '0x' + 'a'.repeat(30),
|
|
1416
|
+
nonce: 1,
|
|
1417
|
+
prev_commitment: '0x' + 'b'.repeat(64),
|
|
1418
|
+
delta_payload: {
|
|
1419
|
+
tx_summary: { data: 'AQID' },
|
|
1420
|
+
signatures: [],
|
|
1421
|
+
metadata: {
|
|
1422
|
+
proposal_type: 'p2id',
|
|
1423
|
+
recipient_id: '0xrecipient',
|
|
1424
|
+
faucet_id: '0xfaucet',
|
|
1425
|
+
amount: '100',
|
|
1426
|
+
description: '',
|
|
1427
|
+
},
|
|
1428
|
+
},
|
|
1429
|
+
status: {
|
|
1430
|
+
status: 'pending',
|
|
1431
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
1432
|
+
proposer_id: '0x' + 'c'.repeat(64),
|
|
1433
|
+
cosigner_sigs: [],
|
|
1434
|
+
},
|
|
1435
|
+
};
|
|
1436
|
+
mockFetch.mockResolvedValueOnce({
|
|
1437
|
+
ok: true,
|
|
1438
|
+
json: async () => ({
|
|
1439
|
+
delta: mockDelta,
|
|
1440
|
+
commitment: '0x' + 'c'.repeat(64),
|
|
1441
|
+
}),
|
|
1442
|
+
});
|
|
1443
|
+
await multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n, { nonce: 1 });
|
|
1444
|
+
const pushBody = JSON.parse(mockFetch.mock.calls.at(-1)[1].body);
|
|
1445
|
+
expect('reclaim_height' in pushBody.delta_payload.metadata).toBe(false);
|
|
1446
|
+
expect('timelock_height' in pushBody.delta_payload.metadata).toBe(false);
|
|
1447
|
+
});
|
|
1127
1448
|
});
|
|
1128
1449
|
describe('exportNoteToBytes / importNoteFromBytes (issue #356)', () => {
|
|
1129
1450
|
const config = {
|
|
@@ -1219,6 +1540,7 @@ describe('Multisig', () => {
|
|
|
1219
1540
|
const proposal = {
|
|
1220
1541
|
metadata: {
|
|
1221
1542
|
proposalType: 'p2id',
|
|
1543
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1222
1544
|
recipientId: '0x' + 'b'.repeat(30),
|
|
1223
1545
|
faucetId: '0x' + 'c'.repeat(30),
|
|
1224
1546
|
amount: '100',
|
|
@@ -1240,10 +1562,13 @@ describe('Multisig', () => {
|
|
|
1240
1562
|
describe('createChangeThresholdProposal', () => {
|
|
1241
1563
|
it('passes the signer scheme to update-signers requests', async () => {
|
|
1242
1564
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1565
|
+
summary: {
|
|
1566
|
+
toCommitment: () => ({
|
|
1567
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
1568
|
+
}),
|
|
1569
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1570
|
+
},
|
|
1571
|
+
anchor: createMockChainAnchor(),
|
|
1247
1572
|
});
|
|
1248
1573
|
const ecdsaSigner = {
|
|
1249
1574
|
...mockSigner,
|
|
@@ -1265,6 +1590,7 @@ describe('Multisig', () => {
|
|
|
1265
1590
|
signatures: [],
|
|
1266
1591
|
metadata: {
|
|
1267
1592
|
proposal_type: 'change_threshold',
|
|
1593
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1268
1594
|
target_threshold: 2,
|
|
1269
1595
|
description: '',
|
|
1270
1596
|
},
|
|
@@ -1284,14 +1610,105 @@ describe('Multisig', () => {
|
|
|
1284
1610
|
}),
|
|
1285
1611
|
});
|
|
1286
1612
|
const multisig = createTestMultisig(config, ecdsaSigner);
|
|
1287
|
-
await multisig.createChangeThresholdProposal(2, 1);
|
|
1613
|
+
await multisig.createChangeThresholdProposal(2, { nonce: 1 });
|
|
1288
1614
|
expect(buildUpdateSignersTransactionRequest).toHaveBeenCalledWith(mockWebClient, 2, config.signerCommitments, { signatureScheme: 'ecdsa' });
|
|
1289
1615
|
});
|
|
1290
1616
|
});
|
|
1617
|
+
describe('createAddSignerProposal / createRemoveSignerProposal', () => {
|
|
1618
|
+
const config = {
|
|
1619
|
+
threshold: 2,
|
|
1620
|
+
signerCommitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64), '0x' + 'd'.repeat(64)],
|
|
1621
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
1622
|
+
};
|
|
1623
|
+
const mockPushResponse = (proposalType) => {
|
|
1624
|
+
mockFetch.mockResolvedValueOnce({
|
|
1625
|
+
ok: true,
|
|
1626
|
+
json: async () => ({
|
|
1627
|
+
delta: {
|
|
1628
|
+
account_id: '0x' + 'a'.repeat(30),
|
|
1629
|
+
nonce: 1,
|
|
1630
|
+
prev_commitment: '0x' + 'b'.repeat(64),
|
|
1631
|
+
delta_payload: {
|
|
1632
|
+
tx_summary: { data: 'AQID' },
|
|
1633
|
+
signatures: [],
|
|
1634
|
+
metadata: { proposal_type: proposalType, description: '' },
|
|
1635
|
+
},
|
|
1636
|
+
status: {
|
|
1637
|
+
status: 'pending',
|
|
1638
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
1639
|
+
proposer_id: '0x' + 'c'.repeat(64),
|
|
1640
|
+
cosigner_sigs: [],
|
|
1641
|
+
},
|
|
1642
|
+
},
|
|
1643
|
+
commitment: '0x' + 'c'.repeat(64),
|
|
1644
|
+
}),
|
|
1645
|
+
});
|
|
1646
|
+
};
|
|
1647
|
+
beforeEach(() => {
|
|
1648
|
+
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1649
|
+
summary: {
|
|
1650
|
+
toCommitment: () => ({ toHex: () => '0x' + 'c'.repeat(64) }),
|
|
1651
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1652
|
+
},
|
|
1653
|
+
anchor: createMockChainAnchor(),
|
|
1654
|
+
});
|
|
1655
|
+
});
|
|
1656
|
+
it('add: passes newThreshold from the options bag and appends the commitment', async () => {
|
|
1657
|
+
mockPushResponse('add_signer');
|
|
1658
|
+
const newCommitment = '0x' + 'e'.repeat(64);
|
|
1659
|
+
const multisig = createTestMultisig(config);
|
|
1660
|
+
await multisig.createAddSignerProposal(newCommitment, { nonce: 1, newThreshold: 3 });
|
|
1661
|
+
expect(buildUpdateSignersTransactionRequest).toHaveBeenCalledWith(mockWebClient, 3, [...config.signerCommitments, newCommitment], { signatureScheme: mockSigner.scheme });
|
|
1662
|
+
});
|
|
1663
|
+
it('add: defaults to the current threshold when newThreshold is omitted', async () => {
|
|
1664
|
+
mockPushResponse('add_signer');
|
|
1665
|
+
const multisig = createTestMultisig(config);
|
|
1666
|
+
await multisig.createAddSignerProposal('0x' + 'e'.repeat(64), { nonce: 1 });
|
|
1667
|
+
expect(buildUpdateSignersTransactionRequest).toHaveBeenCalledWith(mockWebClient, config.threshold, expect.any(Array), { signatureScheme: mockSigner.scheme });
|
|
1668
|
+
});
|
|
1669
|
+
it('remove: passes newThreshold from the options bag and drops the commitment', async () => {
|
|
1670
|
+
mockPushResponse('remove_signer');
|
|
1671
|
+
const multisig = createTestMultisig(config);
|
|
1672
|
+
await multisig.createRemoveSignerProposal('0x' + 'd'.repeat(64), { nonce: 1, newThreshold: 1 });
|
|
1673
|
+
expect(buildUpdateSignersTransactionRequest).toHaveBeenCalledWith(mockWebClient, 1, [config.signerCommitments[0], config.signerCommitments[1]], { signatureScheme: mockSigner.scheme });
|
|
1674
|
+
});
|
|
1675
|
+
it('remove: defaults to min(current threshold, remaining signers) when newThreshold is omitted', async () => {
|
|
1676
|
+
mockPushResponse('remove_signer');
|
|
1677
|
+
const multisig = createTestMultisig(config);
|
|
1678
|
+
await multisig.createRemoveSignerProposal('0x' + 'd'.repeat(64), { nonce: 1 });
|
|
1679
|
+
expect(buildUpdateSignersTransactionRequest).toHaveBeenCalledWith(mockWebClient, 2, expect.any(Array), { signatureScheme: mockSigner.scheme });
|
|
1680
|
+
});
|
|
1681
|
+
});
|
|
1682
|
+
describe('legacy positional-caller guard (issue #387)', () => {
|
|
1683
|
+
const config = {
|
|
1684
|
+
threshold: 1,
|
|
1685
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1686
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
1687
|
+
};
|
|
1688
|
+
it('rejects a legacy positional nonce where the options bag is expected', async () => {
|
|
1689
|
+
const multisig = createTestMultisig(config);
|
|
1690
|
+
await expect(multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n, 1)).rejects.toThrow(/issue #387/);
|
|
1691
|
+
await expect(multisig.createConsumeNotesProposal(['0x1'], 1)).rejects.toThrow(/issue #387/);
|
|
1692
|
+
await expect(multisig.createAddSignerProposal('0x' + 'e'.repeat(64), 1)).rejects.toThrow(/issue #387/);
|
|
1693
|
+
await expect(multisig.createCustomProposal(new Uint8Array([1]), 'label', 1)).rejects.toThrow(/issue #387/);
|
|
1694
|
+
});
|
|
1695
|
+
it('rejects a legacy trailing argument after the options slot', async () => {
|
|
1696
|
+
const multisig = createTestMultisig(config);
|
|
1697
|
+
// Pre-#387 pattern: createP2idProposal(r, f, amount, nonceHole, { noteType })
|
|
1698
|
+
await expect(multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n, undefined, {
|
|
1699
|
+
noteType: 'private',
|
|
1700
|
+
})).rejects.toThrow(/issue #387/);
|
|
1701
|
+
// Pre-#387 pattern: createAddSignerProposal(commitment, nonceHole, newThreshold)
|
|
1702
|
+
await expect(multisig.createAddSignerProposal('0x' + 'e'.repeat(64), undefined, 3)).rejects.toThrow(/issue #387/);
|
|
1703
|
+
});
|
|
1704
|
+
});
|
|
1291
1705
|
describe('createSwitchGuardianProposal', () => {
|
|
1292
1706
|
it('should verify new endpoint commitment before creating proposal', async () => {
|
|
1293
1707
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1294
|
-
|
|
1708
|
+
summary: {
|
|
1709
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1710
|
+
},
|
|
1711
|
+
anchor: createMockChainAnchor(),
|
|
1295
1712
|
});
|
|
1296
1713
|
const config = {
|
|
1297
1714
|
threshold: 1,
|
|
@@ -1331,7 +1748,10 @@ describe('Multisig', () => {
|
|
|
1331
1748
|
});
|
|
1332
1749
|
it('should reject switch proposal when endpoint commitment does not match', async () => {
|
|
1333
1750
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1334
|
-
|
|
1751
|
+
summary: {
|
|
1752
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1753
|
+
},
|
|
1754
|
+
anchor: createMockChainAnchor(),
|
|
1335
1755
|
});
|
|
1336
1756
|
const config = {
|
|
1337
1757
|
threshold: 1,
|
|
@@ -1347,7 +1767,10 @@ describe('Multisig', () => {
|
|
|
1347
1767
|
});
|
|
1348
1768
|
it('should use the signer scheme when resolving new GUARDIAN commitments', async () => {
|
|
1349
1769
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1350
|
-
|
|
1770
|
+
summary: {
|
|
1771
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1772
|
+
},
|
|
1773
|
+
anchor: createMockChainAnchor(),
|
|
1351
1774
|
});
|
|
1352
1775
|
const ecdsaSigner = {
|
|
1353
1776
|
...mockSigner,
|
|
@@ -1392,10 +1815,13 @@ describe('Multisig', () => {
|
|
|
1392
1815
|
describe('createUpdateProcedureThresholdProposal', () => {
|
|
1393
1816
|
it('should create procedure-threshold update proposals', async () => {
|
|
1394
1817
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1818
|
+
summary: {
|
|
1819
|
+
toCommitment: () => ({
|
|
1820
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
1821
|
+
}),
|
|
1822
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1823
|
+
},
|
|
1824
|
+
anchor: createMockChainAnchor(),
|
|
1399
1825
|
});
|
|
1400
1826
|
const config = {
|
|
1401
1827
|
threshold: 2,
|
|
@@ -1412,6 +1838,7 @@ describe('Multisig', () => {
|
|
|
1412
1838
|
signatures: [],
|
|
1413
1839
|
metadata: {
|
|
1414
1840
|
proposal_type: 'update_procedure_threshold',
|
|
1841
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1415
1842
|
target_threshold: 1,
|
|
1416
1843
|
target_procedure: 'send_asset',
|
|
1417
1844
|
description: '',
|
|
@@ -1431,7 +1858,7 @@ describe('Multisig', () => {
|
|
|
1431
1858
|
commitment: '0x' + 'c'.repeat(64),
|
|
1432
1859
|
}),
|
|
1433
1860
|
});
|
|
1434
|
-
const proposal = await multisig.createUpdateProcedureThresholdProposal('send_asset', 1, 1);
|
|
1861
|
+
const proposal = await multisig.createUpdateProcedureThresholdProposal('send_asset', 1, { nonce: 1 });
|
|
1435
1862
|
expect(buildUpdateProcedureThresholdTransactionRequest).toHaveBeenCalledWith(mockWebClient, 'send_asset', 1, { signatureScheme: 'falcon' });
|
|
1436
1863
|
expect(proposal.metadata.proposalType).toBe('update_procedure_threshold');
|
|
1437
1864
|
if (proposal.metadata.proposalType === 'update_procedure_threshold') {
|
|
@@ -1441,10 +1868,13 @@ describe('Multisig', () => {
|
|
|
1441
1868
|
});
|
|
1442
1869
|
it('passes the signer scheme to ECDSA procedure-threshold updates', async () => {
|
|
1443
1870
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1871
|
+
summary: {
|
|
1872
|
+
toCommitment: () => ({
|
|
1873
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
1874
|
+
}),
|
|
1875
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1876
|
+
},
|
|
1877
|
+
anchor: createMockChainAnchor(),
|
|
1448
1878
|
});
|
|
1449
1879
|
const ecdsaSigner = {
|
|
1450
1880
|
...mockSigner,
|
|
@@ -1467,6 +1897,7 @@ describe('Multisig', () => {
|
|
|
1467
1897
|
signatures: [],
|
|
1468
1898
|
metadata: {
|
|
1469
1899
|
proposal_type: 'update_procedure_threshold',
|
|
1900
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1470
1901
|
target_threshold: 1,
|
|
1471
1902
|
target_procedure: 'send_asset',
|
|
1472
1903
|
description: '',
|
|
@@ -1486,7 +1917,7 @@ describe('Multisig', () => {
|
|
|
1486
1917
|
commitment: '0x' + 'c'.repeat(64),
|
|
1487
1918
|
}),
|
|
1488
1919
|
});
|
|
1489
|
-
await multisig.createUpdateProcedureThresholdProposal('send_asset', 1, 1);
|
|
1920
|
+
await multisig.createUpdateProcedureThresholdProposal('send_asset', 1, { nonce: 1 });
|
|
1490
1921
|
expect(buildUpdateProcedureThresholdTransactionRequest).toHaveBeenCalledWith(mockWebClient, 'send_asset', 1, { signatureScheme: 'ecdsa' });
|
|
1491
1922
|
});
|
|
1492
1923
|
});
|
|
@@ -1523,6 +1954,7 @@ describe('Multisig', () => {
|
|
|
1523
1954
|
});
|
|
1524
1955
|
await multisig.createProposal(1, 'AQID', {
|
|
1525
1956
|
proposalType: 'add_signer',
|
|
1957
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1526
1958
|
targetThreshold: 1,
|
|
1527
1959
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1528
1960
|
description: '',
|
|
@@ -1545,6 +1977,7 @@ describe('Multisig', () => {
|
|
|
1545
1977
|
...mockDelta.delta_payload,
|
|
1546
1978
|
metadata: {
|
|
1547
1979
|
proposal_type: 'add_signer',
|
|
1980
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1548
1981
|
description: '',
|
|
1549
1982
|
target_threshold: 1,
|
|
1550
1983
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
@@ -1591,11 +2024,12 @@ describe('Multisig', () => {
|
|
|
1591
2024
|
});
|
|
1592
2025
|
await multisig.createProposal(1, 'AQID', {
|
|
1593
2026
|
proposalType: 'add_signer',
|
|
2027
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1594
2028
|
targetThreshold: 1,
|
|
1595
2029
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1596
2030
|
description: '',
|
|
1597
2031
|
});
|
|
1598
|
-
vi.mocked(
|
|
2032
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
1599
2033
|
toCommitment: () => ({
|
|
1600
2034
|
toHex: () => '0x' + 'f'.repeat(64),
|
|
1601
2035
|
}),
|
|
@@ -1623,6 +2057,7 @@ describe('Multisig', () => {
|
|
|
1623
2057
|
signatures: [],
|
|
1624
2058
|
metadata: {
|
|
1625
2059
|
proposal_type: 'add_signer',
|
|
2060
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1626
2061
|
description: '',
|
|
1627
2062
|
target_threshold: 1,
|
|
1628
2063
|
signer_commitments: [mockSigner.commitment],
|
|
@@ -1650,7 +2085,7 @@ describe('Multisig', () => {
|
|
|
1650
2085
|
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
1651
2086
|
};
|
|
1652
2087
|
const multisig = createTestMultisig(config);
|
|
1653
|
-
vi.mocked(
|
|
2088
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
1654
2089
|
toCommitment: () => ({
|
|
1655
2090
|
toHex: () => '0x' + 'f'.repeat(64),
|
|
1656
2091
|
}),
|
|
@@ -1663,6 +2098,7 @@ describe('Multisig', () => {
|
|
|
1663
2098
|
signatures: [],
|
|
1664
2099
|
metadata: {
|
|
1665
2100
|
proposalType: 'add_signer',
|
|
2101
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1666
2102
|
targetThreshold: 1,
|
|
1667
2103
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1668
2104
|
description: '',
|
|
@@ -1678,7 +2114,7 @@ describe('Multisig', () => {
|
|
|
1678
2114
|
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
1679
2115
|
};
|
|
1680
2116
|
const multisig = createTestMultisig(config);
|
|
1681
|
-
vi.mocked(
|
|
2117
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
1682
2118
|
toCommitment: () => ({
|
|
1683
2119
|
toHex: () => '0x' + 'c'.repeat(64),
|
|
1684
2120
|
}),
|
|
@@ -1691,6 +2127,7 @@ describe('Multisig', () => {
|
|
|
1691
2127
|
signatures: [],
|
|
1692
2128
|
metadata: {
|
|
1693
2129
|
proposalType: 'add_signer',
|
|
2130
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1694
2131
|
targetThreshold: 1,
|
|
1695
2132
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1696
2133
|
description: '',
|
|
@@ -1698,11 +2135,12 @@ describe('Multisig', () => {
|
|
|
1698
2135
|
}));
|
|
1699
2136
|
proposal.metadata = {
|
|
1700
2137
|
proposalType: 'add_signer',
|
|
2138
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1701
2139
|
targetThreshold: 2,
|
|
1702
2140
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1703
2141
|
description: '',
|
|
1704
2142
|
};
|
|
1705
|
-
vi.mocked(
|
|
2143
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
1706
2144
|
toCommitment: () => ({
|
|
1707
2145
|
toHex: () => '0x' + 'f'.repeat(64),
|
|
1708
2146
|
}),
|
|
@@ -1728,6 +2166,7 @@ describe('Multisig', () => {
|
|
|
1728
2166
|
signatures: [],
|
|
1729
2167
|
metadata: {
|
|
1730
2168
|
proposal_type: 'add_signer',
|
|
2169
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1731
2170
|
description: '',
|
|
1732
2171
|
target_threshold: 1,
|
|
1733
2172
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
@@ -1777,6 +2216,7 @@ describe('Multisig', () => {
|
|
|
1777
2216
|
signatures: [],
|
|
1778
2217
|
metadata: {
|
|
1779
2218
|
proposal_type: 'change_threshold',
|
|
2219
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1780
2220
|
description: '',
|
|
1781
2221
|
target_threshold: 2,
|
|
1782
2222
|
signer_commitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
@@ -1822,10 +2262,11 @@ describe('Multisig', () => {
|
|
|
1822
2262
|
ok: false,
|
|
1823
2263
|
status: 404,
|
|
1824
2264
|
statusText: 'Not Found',
|
|
2265
|
+
headers: new Headers(),
|
|
1825
2266
|
// Feature 009: only a conforming { code, message, meta } envelope is
|
|
1826
2267
|
// folded into the error message; raw text bodies are dropped.
|
|
1827
2268
|
text: async () => JSON.stringify({
|
|
1828
|
-
code: '
|
|
2269
|
+
code: 'proposal_not_found',
|
|
1829
2270
|
message: 'Proposal not found',
|
|
1830
2271
|
meta: { retryable: false },
|
|
1831
2272
|
}),
|
|
@@ -1854,6 +2295,7 @@ describe('Multisig', () => {
|
|
|
1854
2295
|
],
|
|
1855
2296
|
metadata: {
|
|
1856
2297
|
proposalType: 'add_signer',
|
|
2298
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1857
2299
|
targetThreshold: 1,
|
|
1858
2300
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1859
2301
|
description: '',
|
|
@@ -1885,6 +2327,7 @@ describe('Multisig', () => {
|
|
|
1885
2327
|
],
|
|
1886
2328
|
metadata: {
|
|
1887
2329
|
proposalType: 'change_threshold',
|
|
2330
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1888
2331
|
targetThreshold: 1,
|
|
1889
2332
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1890
2333
|
description: '',
|
|
@@ -1923,6 +2366,7 @@ describe('Multisig', () => {
|
|
|
1923
2366
|
],
|
|
1924
2367
|
metadata: {
|
|
1925
2368
|
proposalType: 'change_threshold',
|
|
2369
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1926
2370
|
targetThreshold: 1,
|
|
1927
2371
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1928
2372
|
description: '',
|
|
@@ -1944,6 +2388,7 @@ describe('Multisig', () => {
|
|
|
1944
2388
|
signatures: [],
|
|
1945
2389
|
metadata: {
|
|
1946
2390
|
proposalType: 'add_signer',
|
|
2391
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1947
2392
|
targetThreshold: 2,
|
|
1948
2393
|
targetSignerCommitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
1949
2394
|
description: '',
|
|
@@ -2009,6 +2454,7 @@ describe('Multisig', () => {
|
|
|
2009
2454
|
],
|
|
2010
2455
|
metadata: {
|
|
2011
2456
|
proposalType: 'change_threshold',
|
|
2457
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2012
2458
|
targetThreshold: 1,
|
|
2013
2459
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2014
2460
|
description: '',
|
|
@@ -2025,6 +2471,7 @@ describe('Multisig', () => {
|
|
|
2025
2471
|
signatures: [],
|
|
2026
2472
|
metadata: {
|
|
2027
2473
|
proposal_type: 'change_threshold',
|
|
2474
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2028
2475
|
target_threshold: 1,
|
|
2029
2476
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
2030
2477
|
},
|
|
@@ -2050,8 +2497,14 @@ describe('Multisig', () => {
|
|
|
2050
2497
|
await expect(multisig.createTransactionProposalRequest(requestedProposalId)).resolves.toBe(finalRequest);
|
|
2051
2498
|
expect(vi.mocked(signatureHexToBytes)).toHaveBeenNthCalledWith(1, cosignerSignature, 'ecdsa');
|
|
2052
2499
|
expect(vi.mocked(signatureHexToBytes)).toHaveBeenNthCalledWith(2, ackSignature, 'ecdsa');
|
|
2053
|
-
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(1, expect.anything(), expect.anything(), expect.anything()
|
|
2054
|
-
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(2, expect.anything(), expect.anything(), expect.anything()
|
|
2500
|
+
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(1, expect.anything(), expect.anything(), expect.anything());
|
|
2501
|
+
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(2, expect.anything(), expect.anything(), expect.anything());
|
|
2502
|
+
// The advice payload now comes from the SDK, so the routing assertion is
|
|
2503
|
+
// the commitment each entry is keyed on: cosigner first, GUARDIAN ack
|
|
2504
|
+
// second. Swapping the two entries must not pass.
|
|
2505
|
+
const adviceCalls = vi.mocked(buildSignatureAdviceEntry).mock.calls;
|
|
2506
|
+
expect(adviceCalls[0][0].toHex()).toBe(config.signerCommitments[0]);
|
|
2507
|
+
expect(adviceCalls[1][0].toHex()).toBe(config.guardianCommitment);
|
|
2055
2508
|
expect(mockWebClient.executeTransaction).not.toHaveBeenCalled();
|
|
2056
2509
|
expect(mockWebClient.proveTransaction).not.toHaveBeenCalled();
|
|
2057
2510
|
expect(mockWebClient.submitProvenTransaction).not.toHaveBeenCalled();
|
|
@@ -2089,6 +2542,7 @@ describe('Multisig', () => {
|
|
|
2089
2542
|
],
|
|
2090
2543
|
metadata: {
|
|
2091
2544
|
proposalType: 'switch_guardian',
|
|
2545
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2092
2546
|
newGuardianPubkey,
|
|
2093
2547
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
2094
2548
|
description: '',
|
|
@@ -2131,6 +2585,7 @@ describe('Multisig', () => {
|
|
|
2131
2585
|
signatures: [],
|
|
2132
2586
|
metadata: {
|
|
2133
2587
|
proposal_type: 'add_signer',
|
|
2588
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2134
2589
|
description: '',
|
|
2135
2590
|
target_threshold: 2,
|
|
2136
2591
|
signer_commitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
@@ -2165,7 +2620,7 @@ describe('Multisig', () => {
|
|
|
2165
2620
|
};
|
|
2166
2621
|
const multisig = createTestMultisig(config);
|
|
2167
2622
|
const proposalId = '0x' + 'c'.repeat(64);
|
|
2168
|
-
vi.mocked(
|
|
2623
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
2169
2624
|
toCommitment: () => ({
|
|
2170
2625
|
toHex: () => '0x' + 'd'.repeat(64),
|
|
2171
2626
|
}),
|
|
@@ -2185,6 +2640,7 @@ describe('Multisig', () => {
|
|
|
2185
2640
|
],
|
|
2186
2641
|
metadata: {
|
|
2187
2642
|
proposalType: 'change_threshold',
|
|
2643
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2188
2644
|
targetThreshold: 1,
|
|
2189
2645
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2190
2646
|
description: '',
|
|
@@ -2216,6 +2672,7 @@ describe('Multisig', () => {
|
|
|
2216
2672
|
],
|
|
2217
2673
|
metadata: {
|
|
2218
2674
|
proposalType: 'switch_guardian',
|
|
2675
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2219
2676
|
newGuardianPubkey: '0x' + '1'.repeat(64),
|
|
2220
2677
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
2221
2678
|
description: '',
|
|
@@ -2256,6 +2713,7 @@ describe('Multisig', () => {
|
|
|
2256
2713
|
],
|
|
2257
2714
|
metadata: {
|
|
2258
2715
|
proposalType: 'switch_guardian',
|
|
2716
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2259
2717
|
newGuardianPubkey: '0x' + '1'.repeat(64),
|
|
2260
2718
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
2261
2719
|
description: '',
|
|
@@ -2323,6 +2781,7 @@ describe('Multisig', () => {
|
|
|
2323
2781
|
],
|
|
2324
2782
|
metadata: {
|
|
2325
2783
|
proposalType: 'change_threshold',
|
|
2784
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2326
2785
|
targetThreshold: 1,
|
|
2327
2786
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2328
2787
|
description: '',
|
|
@@ -2339,6 +2798,7 @@ describe('Multisig', () => {
|
|
|
2339
2798
|
signatures: [],
|
|
2340
2799
|
metadata: {
|
|
2341
2800
|
proposal_type: 'change_threshold',
|
|
2801
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2342
2802
|
target_threshold: 1,
|
|
2343
2803
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
2344
2804
|
},
|
|
@@ -2409,6 +2869,7 @@ describe('Multisig', () => {
|
|
|
2409
2869
|
],
|
|
2410
2870
|
metadata: {
|
|
2411
2871
|
proposalType: 'switch_guardian',
|
|
2872
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2412
2873
|
newGuardianPubkey: '0x' + '1'.repeat(64),
|
|
2413
2874
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
2414
2875
|
description: '',
|
|
@@ -2445,6 +2906,7 @@ describe('Multisig', () => {
|
|
|
2445
2906
|
signatures: [],
|
|
2446
2907
|
metadata: {
|
|
2447
2908
|
proposal_type: 'add_signer',
|
|
2909
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2448
2910
|
description: '',
|
|
2449
2911
|
target_threshold: 2,
|
|
2450
2912
|
signer_commitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
@@ -2472,7 +2934,7 @@ describe('Multisig', () => {
|
|
|
2472
2934
|
// Proposal ID is mocked to return 'c'.repeat(64)
|
|
2473
2935
|
await expect(multisig.executeProposal('0x' + 'c'.repeat(64))).rejects.toThrow('not ready for execution');
|
|
2474
2936
|
});
|
|
2475
|
-
it('should fail when GUARDIAN ack signature is missing
|
|
2937
|
+
it('should fail when GUARDIAN ack signature is missing', async () => {
|
|
2476
2938
|
const config = {
|
|
2477
2939
|
threshold: 1,
|
|
2478
2940
|
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
@@ -2488,6 +2950,7 @@ describe('Multisig', () => {
|
|
|
2488
2950
|
signatures: [],
|
|
2489
2951
|
metadata: {
|
|
2490
2952
|
proposal_type: 'add_signer',
|
|
2953
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2491
2954
|
description: '',
|
|
2492
2955
|
target_threshold: 1,
|
|
2493
2956
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
@@ -2569,6 +3032,7 @@ describe('Multisig', () => {
|
|
|
2569
3032
|
],
|
|
2570
3033
|
metadata: {
|
|
2571
3034
|
proposalType: 'change_threshold',
|
|
3035
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2572
3036
|
targetThreshold: 1,
|
|
2573
3037
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2574
3038
|
description: '',
|
|
@@ -2585,6 +3049,7 @@ describe('Multisig', () => {
|
|
|
2585
3049
|
signatures: [],
|
|
2586
3050
|
metadata: {
|
|
2587
3051
|
proposal_type: 'change_threshold',
|
|
3052
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2588
3053
|
target_threshold: 1,
|
|
2589
3054
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
2590
3055
|
},
|
|
@@ -2625,8 +3090,14 @@ describe('Multisig', () => {
|
|
|
2625
3090
|
expect(mockWebClient.applyTransaction).toHaveBeenCalledTimes(1);
|
|
2626
3091
|
expect(vi.mocked(signatureHexToBytes)).toHaveBeenNthCalledWith(1, cosignerSignature, 'ecdsa');
|
|
2627
3092
|
expect(vi.mocked(signatureHexToBytes)).toHaveBeenNthCalledWith(2, ackSignature, 'ecdsa');
|
|
2628
|
-
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(1, expect.anything(), expect.anything(), expect.anything()
|
|
2629
|
-
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(2, expect.anything(), expect.anything(), expect.anything()
|
|
3093
|
+
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(1, expect.anything(), expect.anything(), expect.anything());
|
|
3094
|
+
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(2, expect.anything(), expect.anything(), expect.anything());
|
|
3095
|
+
// The advice payload now comes from the SDK, so the routing assertion is
|
|
3096
|
+
// the commitment each entry is keyed on: cosigner first, GUARDIAN ack
|
|
3097
|
+
// second. Swapping the two entries must not pass.
|
|
3098
|
+
const adviceCalls = vi.mocked(buildSignatureAdviceEntry).mock.calls;
|
|
3099
|
+
expect(adviceCalls[0][0].toHex()).toBe(config.signerCommitments[0]);
|
|
3100
|
+
expect(adviceCalls[1][0].toHex()).toBe(config.guardianCommitment);
|
|
2630
3101
|
});
|
|
2631
3102
|
it('should execute imported ECDSA proposals with scheme-aware advice', async () => {
|
|
2632
3103
|
const { buildSignatureAdviceEntry, signatureHexToBytes } = await import('./utils/signature.js');
|
|
@@ -2665,6 +3136,7 @@ describe('Multisig', () => {
|
|
|
2665
3136
|
],
|
|
2666
3137
|
metadata: {
|
|
2667
3138
|
proposalType: 'change_threshold',
|
|
3139
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2668
3140
|
targetThreshold: 1,
|
|
2669
3141
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2670
3142
|
description: '',
|
|
@@ -2681,6 +3153,7 @@ describe('Multisig', () => {
|
|
|
2681
3153
|
signatures: [],
|
|
2682
3154
|
metadata: {
|
|
2683
3155
|
proposal_type: 'change_threshold',
|
|
3156
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2684
3157
|
target_threshold: 1,
|
|
2685
3158
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
2686
3159
|
},
|
|
@@ -2710,8 +3183,14 @@ describe('Multisig', () => {
|
|
|
2710
3183
|
expect(mockWebClient.applyTransaction).toHaveBeenCalledTimes(1);
|
|
2711
3184
|
expect(vi.mocked(signatureHexToBytes)).toHaveBeenNthCalledWith(1, cosignerSignature, 'ecdsa');
|
|
2712
3185
|
expect(vi.mocked(signatureHexToBytes)).toHaveBeenNthCalledWith(2, ackSignature, 'ecdsa');
|
|
2713
|
-
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(1, expect.anything(), expect.anything(), expect.anything()
|
|
2714
|
-
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(2, expect.anything(), expect.anything(), expect.anything()
|
|
3186
|
+
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(1, expect.anything(), expect.anything(), expect.anything());
|
|
3187
|
+
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(2, expect.anything(), expect.anything(), expect.anything());
|
|
3188
|
+
// The advice payload now comes from the SDK, so the routing assertion is
|
|
3189
|
+
// the commitment each entry is keyed on: cosigner first, GUARDIAN ack
|
|
3190
|
+
// second. Swapping the two entries must not pass.
|
|
3191
|
+
const adviceCalls = vi.mocked(buildSignatureAdviceEntry).mock.calls;
|
|
3192
|
+
expect(adviceCalls[0][0].toHex()).toBe(config.signerCommitments[0]);
|
|
3193
|
+
expect(adviceCalls[1][0].toHex()).toBe(config.guardianCommitment);
|
|
2715
3194
|
});
|
|
2716
3195
|
it('should verify switch_guardian endpoint commitment before execution', async () => {
|
|
2717
3196
|
const config = {
|
|
@@ -2737,6 +3216,7 @@ describe('Multisig', () => {
|
|
|
2737
3216
|
],
|
|
2738
3217
|
metadata: {
|
|
2739
3218
|
proposalType: 'switch_guardian',
|
|
3219
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2740
3220
|
newGuardianPubkey,
|
|
2741
3221
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
2742
3222
|
description: '',
|
|
@@ -2758,6 +3238,7 @@ describe('Multisig', () => {
|
|
|
2758
3238
|
signatures: [],
|
|
2759
3239
|
metadata: {
|
|
2760
3240
|
proposal_type: 'switch_guardian',
|
|
3241
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2761
3242
|
new_guardian_pubkey: newGuardianPubkey,
|
|
2762
3243
|
new_guardian_endpoint: 'http://new-guardian.com',
|
|
2763
3244
|
},
|
|
@@ -2817,6 +3298,7 @@ describe('Multisig', () => {
|
|
|
2817
3298
|
],
|
|
2818
3299
|
metadata: {
|
|
2819
3300
|
proposalType: 'switch_guardian',
|
|
3301
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2820
3302
|
newGuardianPubkey,
|
|
2821
3303
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
2822
3304
|
description: '',
|
|
@@ -2864,6 +3346,7 @@ describe('Multisig', () => {
|
|
|
2864
3346
|
],
|
|
2865
3347
|
metadata: {
|
|
2866
3348
|
proposalType: 'switch_guardian',
|
|
3349
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2867
3350
|
newGuardianPubkey: '0x' + '1'.repeat(64),
|
|
2868
3351
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
2869
3352
|
description: '',
|
|
@@ -2904,6 +3387,7 @@ describe('Multisig', () => {
|
|
|
2904
3387
|
],
|
|
2905
3388
|
metadata: {
|
|
2906
3389
|
proposalType: 'switch_guardian',
|
|
3390
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2907
3391
|
newGuardianPubkey: '0x' + '1'.repeat(64),
|
|
2908
3392
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
2909
3393
|
description: '',
|
|
@@ -2949,6 +3433,7 @@ describe('Multisig', () => {
|
|
|
2949
3433
|
],
|
|
2950
3434
|
metadata: {
|
|
2951
3435
|
proposalType: 'switch_guardian',
|
|
3436
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2952
3437
|
newGuardianPubkey: '0x' + '1'.repeat(64),
|
|
2953
3438
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
2954
3439
|
description: '',
|
|
@@ -2974,9 +3459,32 @@ describe('Multisig', () => {
|
|
|
2974
3459
|
.mockRejectedValueOnce(transient)
|
|
2975
3460
|
.mockRejectedValueOnce(transient)
|
|
2976
3461
|
.mockResolvedValueOnce({});
|
|
3462
|
+
mockFetch.mockResolvedValueOnce({
|
|
3463
|
+
ok: true,
|
|
3464
|
+
json: async () => ({
|
|
3465
|
+
account_id: '0x' + 'a'.repeat(30),
|
|
3466
|
+
nonce: 1,
|
|
3467
|
+
prev_commitment: '0x' + 'b'.repeat(64),
|
|
3468
|
+
delta_payload: {
|
|
3469
|
+
tx_summary: { data: 'AQID' },
|
|
3470
|
+
signatures: [],
|
|
3471
|
+
metadata: {
|
|
3472
|
+
proposal_type: 'b2agg',
|
|
3473
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3474
|
+
description: '',
|
|
3475
|
+
},
|
|
3476
|
+
},
|
|
3477
|
+
status: {
|
|
3478
|
+
status: 'pending',
|
|
3479
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
3480
|
+
proposer_id: '0x' + 'c'.repeat(64),
|
|
3481
|
+
cosigner_sigs: [],
|
|
3482
|
+
},
|
|
3483
|
+
}),
|
|
3484
|
+
});
|
|
2977
3485
|
vi.useFakeTimers();
|
|
2978
3486
|
try {
|
|
2979
|
-
const submission = multisig.submitTransaction({});
|
|
3487
|
+
const submission = multisig.submitTransaction('0x' + 'c'.repeat(64), {});
|
|
2980
3488
|
await vi.runAllTimersAsync();
|
|
2981
3489
|
await submission;
|
|
2982
3490
|
}
|
|
@@ -3001,6 +3509,7 @@ describe('Multisig', () => {
|
|
|
3001
3509
|
signatures: [],
|
|
3002
3510
|
metadata: {
|
|
3003
3511
|
proposal_type: proposalType,
|
|
3512
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3004
3513
|
description: '',
|
|
3005
3514
|
},
|
|
3006
3515
|
},
|
|
@@ -3031,6 +3540,7 @@ describe('Multisig', () => {
|
|
|
3031
3540
|
};
|
|
3032
3541
|
builtinDelta.delta_payload.metadata = {
|
|
3033
3542
|
proposal_type: 'change_threshold',
|
|
3543
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3034
3544
|
description: '',
|
|
3035
3545
|
target_threshold: 1,
|
|
3036
3546
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
@@ -3063,7 +3573,7 @@ describe('Multisig', () => {
|
|
|
3063
3573
|
const multisig = createTestMultisig(config);
|
|
3064
3574
|
// Signed commitment comes from TransactionSummary.deserialize -> 'c' * 64.
|
|
3065
3575
|
// Make the binding request derive a different commitment so the check fails.
|
|
3066
|
-
vi.mocked(
|
|
3576
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
3067
3577
|
toCommitment: () => ({
|
|
3068
3578
|
toHex: () => '0x' + '9'.repeat(64),
|
|
3069
3579
|
}),
|
|
@@ -3114,6 +3624,7 @@ describe('Multisig', () => {
|
|
|
3114
3624
|
signatures: [],
|
|
3115
3625
|
metadata: {
|
|
3116
3626
|
proposal_type: 'add_signer',
|
|
3627
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3117
3628
|
target_threshold: 2,
|
|
3118
3629
|
signer_commitments: ['0x1', '0x2'],
|
|
3119
3630
|
},
|
|
@@ -3134,6 +3645,7 @@ describe('Multisig', () => {
|
|
|
3134
3645
|
});
|
|
3135
3646
|
const proposal = await multisig.createProposal(1, 'AQID', {
|
|
3136
3647
|
proposalType: 'add_signer',
|
|
3648
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3137
3649
|
targetThreshold: 2,
|
|
3138
3650
|
targetSignerCommitments: ['0x1', '0x2'],
|
|
3139
3651
|
description: '',
|
|
@@ -3168,6 +3680,7 @@ describe('Multisig', () => {
|
|
|
3168
3680
|
signatures: [],
|
|
3169
3681
|
metadata: {
|
|
3170
3682
|
proposal_type: 'p2id',
|
|
3683
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3171
3684
|
recipient_id: '0xrecipient',
|
|
3172
3685
|
faucet_id: '0xfaucet',
|
|
3173
3686
|
amount: '100',
|
|
@@ -3207,6 +3720,7 @@ describe('Multisig', () => {
|
|
|
3207
3720
|
signatures: [],
|
|
3208
3721
|
metadata: {
|
|
3209
3722
|
proposal_type: 'add_signer',
|
|
3723
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3210
3724
|
target_threshold: 2,
|
|
3211
3725
|
signer_commitments: ['0x1', '0x2'],
|
|
3212
3726
|
description: '',
|
|
@@ -3228,6 +3742,7 @@ describe('Multisig', () => {
|
|
|
3228
3742
|
});
|
|
3229
3743
|
const proposal = await multisig.createProposal(1, 'AQID', {
|
|
3230
3744
|
proposalType: 'consume_notes',
|
|
3745
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3231
3746
|
noteIds: ['0xnote1', '0xnote2'],
|
|
3232
3747
|
description: '',
|
|
3233
3748
|
});
|
|
@@ -3249,6 +3764,7 @@ describe('Multisig', () => {
|
|
|
3249
3764
|
signatures: [],
|
|
3250
3765
|
metadata: {
|
|
3251
3766
|
proposal_type: 'add_signer',
|
|
3767
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3252
3768
|
target_threshold: 1,
|
|
3253
3769
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
3254
3770
|
description: '',
|
|
@@ -3270,6 +3786,7 @@ describe('Multisig', () => {
|
|
|
3270
3786
|
});
|
|
3271
3787
|
const proposal = await multisig.createProposal(1, 'AQID', {
|
|
3272
3788
|
proposalType: 'p2id',
|
|
3789
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3273
3790
|
recipientId: '0xrecipient',
|
|
3274
3791
|
faucetId: '0xfaucet',
|
|
3275
3792
|
amount: '100',
|
|
@@ -3293,6 +3810,7 @@ describe('Multisig', () => {
|
|
|
3293
3810
|
signatures: [],
|
|
3294
3811
|
metadata: {
|
|
3295
3812
|
proposalType: 'add_signer',
|
|
3813
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3296
3814
|
targetThreshold: 2,
|
|
3297
3815
|
targetSignerCommitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
3298
3816
|
description: '',
|
|
@@ -3314,6 +3832,7 @@ describe('Multisig', () => {
|
|
|
3314
3832
|
});
|
|
3315
3833
|
const proposal = await multisig.createProposal(1, 'AQID', {
|
|
3316
3834
|
proposalType: 'switch_guardian',
|
|
3835
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3317
3836
|
newGuardianPubkey: '0xnewpubkey',
|
|
3318
3837
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
3319
3838
|
description: '',
|
|
@@ -3340,6 +3859,7 @@ describe('Multisig', () => {
|
|
|
3340
3859
|
signatures: [],
|
|
3341
3860
|
metadata: {
|
|
3342
3861
|
proposal_type: 'add_signer',
|
|
3862
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3343
3863
|
target_threshold: 2,
|
|
3344
3864
|
signer_commitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
3345
3865
|
description: '',
|
|
@@ -3373,6 +3893,7 @@ describe('Multisig', () => {
|
|
|
3373
3893
|
...mockProposalsPending[0].delta_payload,
|
|
3374
3894
|
metadata: {
|
|
3375
3895
|
proposal_type: 'add_signer',
|
|
3896
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3376
3897
|
target_threshold: 2,
|
|
3377
3898
|
signer_commitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
3378
3899
|
description: '',
|
|
@@ -3464,6 +3985,7 @@ describe('Multisig', () => {
|
|
|
3464
3985
|
signatures: [],
|
|
3465
3986
|
metadata: {
|
|
3466
3987
|
proposal_type: 'change_threshold',
|
|
3988
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3467
3989
|
target_threshold: 3,
|
|
3468
3990
|
signer_commitments: ['0xa', '0xb', '0xc'],
|
|
3469
3991
|
salt: '0xlegacysalt',
|
|
@@ -3508,6 +4030,7 @@ describe('Multisig', () => {
|
|
|
3508
4030
|
signatures: [],
|
|
3509
4031
|
metadata: {
|
|
3510
4032
|
proposal_type: 'p2id',
|
|
4033
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3511
4034
|
recipient_id: '0xrecipient',
|
|
3512
4035
|
faucet_id: '0xfaucet',
|
|
3513
4036
|
amount: '12345',
|
|
@@ -3558,6 +4081,7 @@ describe('Multisig', () => {
|
|
|
3558
4081
|
signatures: [],
|
|
3559
4082
|
metadata: {
|
|
3560
4083
|
proposal_type: 'switch_guardian',
|
|
4084
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3561
4085
|
new_guardian_pubkey: '0xnewpubkey',
|
|
3562
4086
|
new_guardian_endpoint: 'http://new-guardian.com',
|
|
3563
4087
|
salt: '0xsalt',
|