@openzeppelin/miden-multisig-client 0.16.2 → 0.17.0-rc.2
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 +144 -7
- 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.map +1 -1
- package/dist/client.js +5 -3
- package/dist/client.js.map +1 -1
- package/dist/client.test.js +68 -15
- package/dist/client.test.js.map +1 -1
- package/dist/index.d.ts +4 -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 +106 -32
- package/dist/multisig.d.ts.map +1 -1
- package/dist/multisig.js +289 -95
- package/dist/multisig.js.map +1 -1
- package/dist/multisig.test.js +581 -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/workflow.d.ts +3 -2
- 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 +6 -4
- package/dist/prover/workflow.test.js.map +1 -1
- 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 +80 -15
- package/src/client.ts +5 -3
- package/src/index.ts +26 -1
- package/src/inspector.test.ts +330 -38
- package/src/inspector.ts +196 -33
- package/src/multisig.test.ts +679 -63
- package/src/multisig.ts +361 -107
- package/src/procedures.ts +6 -7
- package/src/proposal/metadata.test.ts +76 -0
- package/src/proposal/metadata.ts +13 -2
- package/src/prover/workflow.test.ts +9 -4
- package/src/prover/workflow.ts +15 -3
- 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/src/multisig.test.ts
CHANGED
|
@@ -5,16 +5,38 @@ import {
|
|
|
5
5
|
buildUpdateProcedureThresholdTransactionRequest,
|
|
6
6
|
buildUpdateGuardianTransactionRequest,
|
|
7
7
|
buildUpdateSignersTransactionRequest,
|
|
8
|
+
chainAnchorFromBase64,
|
|
8
9
|
executeForSummary,
|
|
10
|
+
executeForSummaryAt,
|
|
9
11
|
} from './transaction.js';
|
|
10
12
|
|
|
11
|
-
const {
|
|
13
|
+
const {
|
|
14
|
+
mockRpcGetAccountDetails,
|
|
15
|
+
mockAccountDeserialize,
|
|
16
|
+
mockDetectConfig,
|
|
17
|
+
mockNoteFileDeserialize,
|
|
18
|
+
mockGetSignerCommitments,
|
|
19
|
+
mockGetGuardianCommitment,
|
|
20
|
+
} = vi.hoisted(() => ({
|
|
12
21
|
mockRpcGetAccountDetails: vi.fn(),
|
|
13
22
|
mockAccountDeserialize: vi.fn(),
|
|
14
23
|
mockDetectConfig: vi.fn(),
|
|
15
24
|
mockNoteFileDeserialize: vi.fn(),
|
|
25
|
+
mockGetSignerCommitments: vi.fn(),
|
|
26
|
+
mockGetGuardianCommitment: vi.fn(),
|
|
16
27
|
}));
|
|
17
28
|
|
|
29
|
+
const { MOCK_CHAIN_ANCHOR_B64, createMockChainAnchor } = vi.hoisted(() => {
|
|
30
|
+
const MOCK_CHAIN_ANCHOR_B64 = 'bW9jay1jaGFpbi1hbmNob3I=';
|
|
31
|
+
const createMockChainAnchor = () =>
|
|
32
|
+
({
|
|
33
|
+
commitment: () => ({ toHex: () => '0x' + 'b'.repeat(64) }),
|
|
34
|
+
free: () => {},
|
|
35
|
+
serialize: () => new Uint8Array([9, 9, 9]),
|
|
36
|
+
}) as never;
|
|
37
|
+
return { MOCK_CHAIN_ANCHOR_B64, createMockChainAnchor };
|
|
38
|
+
});
|
|
39
|
+
|
|
18
40
|
// Mock the Miden SDK
|
|
19
41
|
vi.mock('@miden-sdk/miden-sdk', () => ({
|
|
20
42
|
Account: {
|
|
@@ -40,9 +62,10 @@ vi.mock('@miden-sdk/miden-sdk', () => ({
|
|
|
40
62
|
toCommitment: () => ({
|
|
41
63
|
toHex: () => '0x' + 'c'.repeat(64),
|
|
42
64
|
}),
|
|
43
|
-
|
|
44
|
-
toHex: () => '0x' + '
|
|
65
|
+
blockCommitment: () => ({
|
|
66
|
+
toHex: () => '0x' + 'b'.repeat(64),
|
|
45
67
|
}),
|
|
68
|
+
userParams: () => [0, 0, 0, 1, 2, 3, 4],
|
|
46
69
|
serialize: () => new Uint8Array([1, 2, 3]),
|
|
47
70
|
}),
|
|
48
71
|
},
|
|
@@ -78,6 +101,12 @@ vi.mock('@miden-sdk/miden-sdk', () => ({
|
|
|
78
101
|
// Mock transaction module
|
|
79
102
|
vi.mock('./transaction.js', () => ({
|
|
80
103
|
executeForSummary: vi.fn(),
|
|
104
|
+
executeForSummaryAt: vi.fn(),
|
|
105
|
+
chainAnchorToBase64: vi.fn(() => MOCK_CHAIN_ANCHOR_B64),
|
|
106
|
+
chainAnchorFromBase64: vi.fn(() => createMockChainAnchor()),
|
|
107
|
+
summarySalt: vi.fn(() => ({
|
|
108
|
+
toHex: () => '0x' + 'd'.repeat(64),
|
|
109
|
+
})),
|
|
81
110
|
buildUpdateSignersTransactionRequest: vi.fn().mockResolvedValue({
|
|
82
111
|
request: {},
|
|
83
112
|
salt: { toHex: () => '0x' + 'd'.repeat(64) },
|
|
@@ -122,6 +151,9 @@ vi.mock('./utils/signature.js', async () => {
|
|
|
122
151
|
values: [1, 2, 3],
|
|
123
152
|
})),
|
|
124
153
|
signatureHexToBytes: vi.fn((hex: string) => new Uint8Array([0, 1, 2, 3])),
|
|
154
|
+
// These tests use synthetic signature bytes to exercise advice routing;
|
|
155
|
+
// recoverability is covered by tests/ecdsa-advice-encoding.test.ts.
|
|
156
|
+
assertEcdsaSignatureRecoverable: vi.fn(),
|
|
125
157
|
};
|
|
126
158
|
});
|
|
127
159
|
|
|
@@ -133,11 +165,19 @@ vi.mock('./utils/encoding.js', async () => {
|
|
|
133
165
|
};
|
|
134
166
|
});
|
|
135
167
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
168
|
+
// Keep the real assertCompleteDetectedConfig so refreshConfigFromAccount's
|
|
169
|
+
// fail-closed validation is exercised.
|
|
170
|
+
vi.mock('./inspector.js', async (importOriginal) => {
|
|
171
|
+
const actual = await importOriginal<typeof import('./inspector.js')>();
|
|
172
|
+
return {
|
|
173
|
+
...actual,
|
|
174
|
+
AccountInspector: {
|
|
175
|
+
fromAccount: mockDetectConfig,
|
|
176
|
+
getSignerPublicKeyCommitments: mockGetSignerCommitments,
|
|
177
|
+
getGuardianPublicKeyCommitment: mockGetGuardianCommitment,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
});
|
|
141
181
|
|
|
142
182
|
// Mock fetch for GUARDIAN client
|
|
143
183
|
const mockFetch = vi.fn();
|
|
@@ -186,6 +226,15 @@ describe('Multisig', () => {
|
|
|
186
226
|
beforeEach(() => {
|
|
187
227
|
mockFetch.mockReset();
|
|
188
228
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
229
|
+
summary: {
|
|
230
|
+
toCommitment: () => ({
|
|
231
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
232
|
+
}),
|
|
233
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
234
|
+
},
|
|
235
|
+
anchor: createMockChainAnchor(),
|
|
236
|
+
} as any);
|
|
237
|
+
vi.mocked(executeForSummaryAt).mockResolvedValue({
|
|
189
238
|
toCommitment: () => ({
|
|
190
239
|
toHex: () => '0x' + 'c'.repeat(64),
|
|
191
240
|
}),
|
|
@@ -204,7 +253,6 @@ describe('Multisig', () => {
|
|
|
204
253
|
threshold: 1,
|
|
205
254
|
numSigners: 1,
|
|
206
255
|
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
207
|
-
guardianEnabled: true,
|
|
208
256
|
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
209
257
|
vaultBalances: [],
|
|
210
258
|
procedureThresholds: new Map(),
|
|
@@ -350,6 +398,38 @@ describe('Multisig', () => {
|
|
|
350
398
|
});
|
|
351
399
|
});
|
|
352
400
|
|
|
401
|
+
describe('history (issue #413)', () => {
|
|
402
|
+
it('delegates to the guardian client with the account id and options', async () => {
|
|
403
|
+
const config = {
|
|
404
|
+
threshold: 1,
|
|
405
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
406
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
407
|
+
};
|
|
408
|
+
const multisig = createTestMultisig(config);
|
|
409
|
+
|
|
410
|
+
const page = {
|
|
411
|
+
entries: [
|
|
412
|
+
{
|
|
413
|
+
nonce: 3,
|
|
414
|
+
status: 'canonical' as const,
|
|
415
|
+
timestamp: '2026-08-01T12:00:03Z',
|
|
416
|
+
newCommitment: '0x' + 'b'.repeat(64),
|
|
417
|
+
inputNotes: [],
|
|
418
|
+
outputNotes: [],
|
|
419
|
+
decodeWarnings: [],
|
|
420
|
+
},
|
|
421
|
+
],
|
|
422
|
+
nextCursor: 'cursor-token',
|
|
423
|
+
};
|
|
424
|
+
const spy = vi.spyOn(guardian, 'getDeltaHistory').mockResolvedValue(page);
|
|
425
|
+
|
|
426
|
+
const result = await multisig.deltaHistory({ limit: 5, cursor: 'prev' });
|
|
427
|
+
|
|
428
|
+
expect(result).toBe(page);
|
|
429
|
+
expect(spy).toHaveBeenCalledWith('0x' + 'a'.repeat(30), { limit: 5, cursor: 'prev' });
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
|
|
353
433
|
describe('signerCommitment', () => {
|
|
354
434
|
it('should return signer commitment', () => {
|
|
355
435
|
const config = {
|
|
@@ -363,6 +443,56 @@ describe('Multisig', () => {
|
|
|
363
443
|
});
|
|
364
444
|
});
|
|
365
445
|
|
|
446
|
+
describe('getSignerPublicKeyCommitments (issue #306)', () => {
|
|
447
|
+
const config = {
|
|
448
|
+
threshold: 1,
|
|
449
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
450
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
it('reads commitments from the store-backed account', async () => {
|
|
454
|
+
const storeAccount = mockedAccount('0x' + 'b'.repeat(64), 1);
|
|
455
|
+
mockWebClient.getAccount.mockResolvedValueOnce(storeAccount);
|
|
456
|
+
const expected = ['0x' + '1'.repeat(64), '0x' + '2'.repeat(64)];
|
|
457
|
+
mockGetSignerCommitments.mockReturnValueOnce(expected);
|
|
458
|
+
|
|
459
|
+
const multisig = createTestMultisig(config);
|
|
460
|
+
const commitments = await multisig.getSignerPublicKeyCommitments();
|
|
461
|
+
|
|
462
|
+
expect(commitments).toEqual(expected);
|
|
463
|
+
expect(mockGetSignerCommitments).toHaveBeenCalledWith(storeAccount);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
it('falls back to the account snapshot when the store has no record', async () => {
|
|
467
|
+
mockWebClient.getAccount.mockResolvedValueOnce(null);
|
|
468
|
+
mockGetSignerCommitments.mockReturnValueOnce(['0x' + '3'.repeat(64)]);
|
|
469
|
+
|
|
470
|
+
const multisig = createTestMultisig(config);
|
|
471
|
+
await multisig.getSignerPublicKeyCommitments();
|
|
472
|
+
|
|
473
|
+
expect(mockGetSignerCommitments).toHaveBeenCalledWith(mockAccount);
|
|
474
|
+
});
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
describe('getGuardianPublicKeyCommitment (issue #306)', () => {
|
|
478
|
+
it('reads the guardian commitment from the store-backed account', async () => {
|
|
479
|
+
const storeAccount = mockedAccount('0x' + 'b'.repeat(64), 1);
|
|
480
|
+
mockWebClient.getAccount.mockResolvedValueOnce(storeAccount);
|
|
481
|
+
mockGetGuardianCommitment.mockReturnValueOnce('0x' + '4'.repeat(64));
|
|
482
|
+
|
|
483
|
+
const multisig = createTestMultisig({
|
|
484
|
+
threshold: 1,
|
|
485
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
486
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
const commitment = await multisig.getGuardianPublicKeyCommitment();
|
|
490
|
+
|
|
491
|
+
expect(commitment).toBe('0x' + '4'.repeat(64));
|
|
492
|
+
expect(mockGetGuardianCommitment).toHaveBeenCalledWith(storeAccount);
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
|
|
366
496
|
describe('fetchState', () => {
|
|
367
497
|
it('should fetch account state from GUARDIAN', async () => {
|
|
368
498
|
const config = {
|
|
@@ -499,7 +629,6 @@ describe('Multisig', () => {
|
|
|
499
629
|
threshold: 2,
|
|
500
630
|
numSigners: 2,
|
|
501
631
|
signerCommitments: ['0x' + '1'.repeat(64), '0x' + '2'.repeat(64)],
|
|
502
|
-
guardianEnabled: true,
|
|
503
632
|
guardianCommitment: '0x' + 'd'.repeat(64),
|
|
504
633
|
vaultBalances: [],
|
|
505
634
|
procedureThresholds: new Map(),
|
|
@@ -516,6 +645,44 @@ describe('Multisig', () => {
|
|
|
516
645
|
expect(mockWebClient.newAccount).not.toHaveBeenCalled();
|
|
517
646
|
});
|
|
518
647
|
|
|
648
|
+
it('keeps the previous config when a refresh reads an incomplete signer set (issue #306 review)', async () => {
|
|
649
|
+
const config = {
|
|
650
|
+
threshold: 1,
|
|
651
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
652
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
653
|
+
};
|
|
654
|
+
const multisig = createTestMultisig(config, mockSigner, '0x' + 'a'.repeat(30));
|
|
655
|
+
|
|
656
|
+
mockWebClient.getAccount.mockResolvedValueOnce(mockedAccount('0x' + 'b'.repeat(64), 0));
|
|
657
|
+
mockFetch.mockResolvedValueOnce({
|
|
658
|
+
ok: true,
|
|
659
|
+
json: async () => ({
|
|
660
|
+
account_id: multisig.accountId,
|
|
661
|
+
commitment: '0x' + 'b'.repeat(64),
|
|
662
|
+
state_json: { data: 'AQID' },
|
|
663
|
+
created_at: '2024-01-01T00:00:00Z',
|
|
664
|
+
updated_at: '2024-01-02T00:00:00Z',
|
|
665
|
+
}),
|
|
666
|
+
});
|
|
667
|
+
// Storage reports 3 signers but only 1 entry was readable: adopting
|
|
668
|
+
// this would let membership proposals rewrite the on-chain set without
|
|
669
|
+
// the omitted keys. The refresh must keep the previous config instead.
|
|
670
|
+
mockDetectConfig.mockReturnValueOnce({
|
|
671
|
+
threshold: 2,
|
|
672
|
+
numSigners: 3,
|
|
673
|
+
signerCommitments: ['0x' + '1'.repeat(64)],
|
|
674
|
+
guardianCommitment: '0x' + 'd'.repeat(64),
|
|
675
|
+
vaultBalances: [],
|
|
676
|
+
procedureThresholds: new Map(),
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
await multisig.syncState();
|
|
680
|
+
|
|
681
|
+
expect(multisig.threshold).toBe(1);
|
|
682
|
+
expect(multisig.signerCommitments).toEqual(['0x' + 'a'.repeat(64)]);
|
|
683
|
+
expect(multisig.guardianCommitment).toBe('0x' + 'c'.repeat(64));
|
|
684
|
+
});
|
|
685
|
+
|
|
519
686
|
it('should overwrite local state when account is not found on-chain', async () => {
|
|
520
687
|
const config = {
|
|
521
688
|
threshold: 1,
|
|
@@ -923,6 +1090,7 @@ describe('Multisig', () => {
|
|
|
923
1090
|
signatures: [],
|
|
924
1091
|
metadata: {
|
|
925
1092
|
proposal_type: 'add_signer',
|
|
1093
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
926
1094
|
target_threshold: 1,
|
|
927
1095
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
928
1096
|
description: '',
|
|
@@ -974,6 +1142,7 @@ describe('Multisig', () => {
|
|
|
974
1142
|
signatures: [],
|
|
975
1143
|
metadata: {
|
|
976
1144
|
proposal_type: 'add_signer',
|
|
1145
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
977
1146
|
target_threshold: 1,
|
|
978
1147
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
979
1148
|
description: '',
|
|
@@ -1026,6 +1195,7 @@ describe('Multisig', () => {
|
|
|
1026
1195
|
signatures: [],
|
|
1027
1196
|
metadata: {
|
|
1028
1197
|
proposal_type: 'add_signer',
|
|
1198
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1029
1199
|
target_threshold: 1,
|
|
1030
1200
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
1031
1201
|
description: '',
|
|
@@ -1042,7 +1212,7 @@ describe('Multisig', () => {
|
|
|
1042
1212
|
}),
|
|
1043
1213
|
});
|
|
1044
1214
|
|
|
1045
|
-
vi.mocked(
|
|
1215
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
1046
1216
|
toCommitment: () => ({
|
|
1047
1217
|
toHex: () => '0x' + 'f'.repeat(64),
|
|
1048
1218
|
}),
|
|
@@ -1053,6 +1223,65 @@ describe('Multisig', () => {
|
|
|
1053
1223
|
);
|
|
1054
1224
|
});
|
|
1055
1225
|
|
|
1226
|
+
/// A structurally valid anchor pinned to the wrong block must be rejected
|
|
1227
|
+
/// before anything executes against it: its commitment disagrees with the
|
|
1228
|
+
/// block commitment signed into the tx_summary.
|
|
1229
|
+
it('should reject a proposal whose chain anchor does not match the summary block commitment', async () => {
|
|
1230
|
+
const config = {
|
|
1231
|
+
threshold: 1,
|
|
1232
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1233
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
1234
|
+
};
|
|
1235
|
+
|
|
1236
|
+
const multisig = createTestMultisig(config);
|
|
1237
|
+
|
|
1238
|
+
mockFetch.mockResolvedValueOnce({
|
|
1239
|
+
ok: true,
|
|
1240
|
+
json: async () => ({
|
|
1241
|
+
proposals: [
|
|
1242
|
+
{
|
|
1243
|
+
account_id: '0x' + 'a'.repeat(30),
|
|
1244
|
+
nonce: 1,
|
|
1245
|
+
prev_commitment: '0x' + 'b'.repeat(64),
|
|
1246
|
+
delta_payload: {
|
|
1247
|
+
tx_summary: { data: 'AQID' },
|
|
1248
|
+
signatures: [],
|
|
1249
|
+
metadata: {
|
|
1250
|
+
proposal_type: 'add_signer',
|
|
1251
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1252
|
+
target_threshold: 1,
|
|
1253
|
+
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
1254
|
+
description: '',
|
|
1255
|
+
},
|
|
1256
|
+
},
|
|
1257
|
+
status: {
|
|
1258
|
+
status: 'pending',
|
|
1259
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
1260
|
+
proposer_id: '0x' + 'c'.repeat(64),
|
|
1261
|
+
cosigner_sigs: [],
|
|
1262
|
+
},
|
|
1263
|
+
},
|
|
1264
|
+
],
|
|
1265
|
+
}),
|
|
1266
|
+
});
|
|
1267
|
+
|
|
1268
|
+
// Deserializes fine, but pins a different block than the one bound into
|
|
1269
|
+
// the summary (mock summary blockCommitment is 'b' * 64).
|
|
1270
|
+
const freed = vi.fn();
|
|
1271
|
+
vi.mocked(chainAnchorFromBase64).mockReturnValueOnce({
|
|
1272
|
+
commitment: () => ({ toHex: () => '0x' + 'e'.repeat(64) }),
|
|
1273
|
+
free: freed,
|
|
1274
|
+
serialize: () => new Uint8Array([9, 9, 9]),
|
|
1275
|
+
} as never);
|
|
1276
|
+
|
|
1277
|
+
const reExecutionsBefore = vi.mocked(executeForSummaryAt).mock.calls.length;
|
|
1278
|
+
await expect(multisig.syncProposals()).rejects.toThrow(
|
|
1279
|
+
'chain anchor does not match the block commitment bound into the tx_summary'
|
|
1280
|
+
);
|
|
1281
|
+
expect(vi.mocked(executeForSummaryAt).mock.calls.length).toBe(reExecutionsBefore);
|
|
1282
|
+
expect(freed).toHaveBeenCalledTimes(1);
|
|
1283
|
+
});
|
|
1284
|
+
|
|
1056
1285
|
it('should reject non-32-byte signer IDs from GUARDIAN proposals', async () => {
|
|
1057
1286
|
const config = {
|
|
1058
1287
|
threshold: 1,
|
|
@@ -1072,6 +1301,7 @@ describe('Multisig', () => {
|
|
|
1072
1301
|
signatures: [],
|
|
1073
1302
|
metadata: {
|
|
1074
1303
|
proposal_type: 'add_signer',
|
|
1304
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1075
1305
|
target_threshold: 1,
|
|
1076
1306
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
1077
1307
|
description: '',
|
|
@@ -1119,6 +1349,7 @@ describe('Multisig', () => {
|
|
|
1119
1349
|
signatures: [],
|
|
1120
1350
|
metadata: {
|
|
1121
1351
|
proposal_type: 'add_signer',
|
|
1352
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1122
1353
|
target_threshold: 2,
|
|
1123
1354
|
signer_commitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
1124
1355
|
description: '',
|
|
@@ -1202,6 +1433,7 @@ describe('Multisig', () => {
|
|
|
1202
1433
|
|
|
1203
1434
|
const proposal = await multisig.createProposal(1, 'AQID', {
|
|
1204
1435
|
proposalType: 'add_signer',
|
|
1436
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1205
1437
|
targetThreshold: 1,
|
|
1206
1438
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1207
1439
|
description: '',
|
|
@@ -1247,6 +1479,7 @@ describe('Multisig', () => {
|
|
|
1247
1479
|
await expect(
|
|
1248
1480
|
multisig.createProposal(1, 'AQID', {
|
|
1249
1481
|
proposalType: 'add_signer',
|
|
1482
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1250
1483
|
targetThreshold: 1,
|
|
1251
1484
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1252
1485
|
description: '',
|
|
@@ -1289,7 +1522,7 @@ describe('Multisig', () => {
|
|
|
1289
1522
|
}),
|
|
1290
1523
|
});
|
|
1291
1524
|
|
|
1292
|
-
vi.mocked(
|
|
1525
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
1293
1526
|
toCommitment: () => ({
|
|
1294
1527
|
toHex: () => '0x' + 'f'.repeat(64),
|
|
1295
1528
|
}),
|
|
@@ -1298,6 +1531,7 @@ describe('Multisig', () => {
|
|
|
1298
1531
|
await expect(
|
|
1299
1532
|
multisig.createProposal(1, 'AQID', {
|
|
1300
1533
|
proposalType: 'add_signer',
|
|
1534
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1301
1535
|
targetThreshold: 1,
|
|
1302
1536
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1303
1537
|
description: '',
|
|
@@ -1310,10 +1544,13 @@ describe('Multisig', () => {
|
|
|
1310
1544
|
it('should include the faucet asset in the proposal description', async () => {
|
|
1311
1545
|
const { executeForSummary } = await import('./transaction.js');
|
|
1312
1546
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1547
|
+
summary: {
|
|
1548
|
+
toCommitment: () => ({
|
|
1549
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
1550
|
+
}),
|
|
1551
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1552
|
+
},
|
|
1553
|
+
anchor: createMockChainAnchor(),
|
|
1317
1554
|
} as any);
|
|
1318
1555
|
|
|
1319
1556
|
const config = {
|
|
@@ -1333,6 +1570,7 @@ describe('Multisig', () => {
|
|
|
1333
1570
|
signatures: [],
|
|
1334
1571
|
metadata: {
|
|
1335
1572
|
proposal_type: 'p2id',
|
|
1573
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1336
1574
|
recipient_id: '0xrecipient',
|
|
1337
1575
|
faucet_id: '0xfaucet',
|
|
1338
1576
|
amount: '100',
|
|
@@ -1355,7 +1593,7 @@ describe('Multisig', () => {
|
|
|
1355
1593
|
}),
|
|
1356
1594
|
});
|
|
1357
1595
|
|
|
1358
|
-
const proposal = await multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n, 1);
|
|
1596
|
+
const proposal = await multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n, { nonce: 1 });
|
|
1359
1597
|
|
|
1360
1598
|
expect(proposal.metadata.description).toBe('Send 100 of asset 0xfaucet... to 0xrecipien...');
|
|
1361
1599
|
});
|
|
@@ -1364,10 +1602,13 @@ describe('Multisig', () => {
|
|
|
1364
1602
|
const { executeForSummary, buildP2idTransactionRequest } = await import('./transaction.js');
|
|
1365
1603
|
const { NoteType } = await import('@miden-sdk/miden-sdk');
|
|
1366
1604
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1605
|
+
summary: {
|
|
1606
|
+
toCommitment: () => ({
|
|
1607
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
1608
|
+
}),
|
|
1609
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1610
|
+
},
|
|
1611
|
+
anchor: createMockChainAnchor(),
|
|
1371
1612
|
} as any);
|
|
1372
1613
|
|
|
1373
1614
|
const config = {
|
|
@@ -1387,6 +1628,7 @@ describe('Multisig', () => {
|
|
|
1387
1628
|
signatures: [],
|
|
1388
1629
|
metadata: {
|
|
1389
1630
|
proposal_type: 'p2id',
|
|
1631
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1390
1632
|
recipient_id: '0xrecipient',
|
|
1391
1633
|
faucet_id: '0xfaucet',
|
|
1392
1634
|
amount: '100',
|
|
@@ -1410,7 +1652,8 @@ describe('Multisig', () => {
|
|
|
1410
1652
|
}),
|
|
1411
1653
|
});
|
|
1412
1654
|
|
|
1413
|
-
const proposal = await multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n,
|
|
1655
|
+
const proposal = await multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n, {
|
|
1656
|
+
nonce: 1,
|
|
1414
1657
|
noteType: NoteType.Private,
|
|
1415
1658
|
});
|
|
1416
1659
|
|
|
@@ -1420,12 +1663,11 @@ describe('Multisig', () => {
|
|
|
1420
1663
|
'0xrecipient',
|
|
1421
1664
|
'0xfaucet',
|
|
1422
1665
|
100n,
|
|
1423
|
-
expect.anything(),
|
|
1424
1666
|
{ noteType: NoteType.Private },
|
|
1425
1667
|
);
|
|
1426
1668
|
// ...and the rebuild-from-metadata path parses note_type back to Private.
|
|
1427
1669
|
const lastCall = vi.mocked(buildP2idTransactionRequest).mock.calls.at(-1)!;
|
|
1428
|
-
expect(lastCall[
|
|
1670
|
+
expect(lastCall[4]).toMatchObject({ noteType: NoteType.Private });
|
|
1429
1671
|
|
|
1430
1672
|
// The pushed wire metadata carries note_type so cosigners rebuild the
|
|
1431
1673
|
// same private note at verification/execution.
|
|
@@ -1435,6 +1677,137 @@ describe('Multisig', () => {
|
|
|
1435
1677
|
expect(proposal.metadata.proposalType).toBe('p2id');
|
|
1436
1678
|
expect((proposal.metadata as { noteType?: string }).noteType).toBe('private');
|
|
1437
1679
|
});
|
|
1680
|
+
|
|
1681
|
+
it('threads P2IDE reclaim/timelock heights into the request and wire metadata (issue #366)', async () => {
|
|
1682
|
+
const { executeForSummary, buildP2idTransactionRequest } = await import('./transaction.js');
|
|
1683
|
+
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1684
|
+
summary: {
|
|
1685
|
+
toCommitment: () => ({
|
|
1686
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
1687
|
+
}),
|
|
1688
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1689
|
+
},
|
|
1690
|
+
anchor: createMockChainAnchor(),
|
|
1691
|
+
} as any);
|
|
1692
|
+
|
|
1693
|
+
const config = {
|
|
1694
|
+
threshold: 1,
|
|
1695
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1696
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
1697
|
+
};
|
|
1698
|
+
|
|
1699
|
+
const multisig = createTestMultisig(config);
|
|
1700
|
+
|
|
1701
|
+
const mockDelta = {
|
|
1702
|
+
account_id: '0x' + 'a'.repeat(30),
|
|
1703
|
+
nonce: 1,
|
|
1704
|
+
prev_commitment: '0x' + 'b'.repeat(64),
|
|
1705
|
+
delta_payload: {
|
|
1706
|
+
tx_summary: { data: 'AQID' },
|
|
1707
|
+
signatures: [],
|
|
1708
|
+
metadata: {
|
|
1709
|
+
proposal_type: 'p2id',
|
|
1710
|
+
recipient_id: '0xrecipient',
|
|
1711
|
+
faucet_id: '0xfaucet',
|
|
1712
|
+
amount: '100',
|
|
1713
|
+
reclaim_height: 12345,
|
|
1714
|
+
timelock_height: 700,
|
|
1715
|
+
description: '',
|
|
1716
|
+
},
|
|
1717
|
+
},
|
|
1718
|
+
status: {
|
|
1719
|
+
status: 'pending',
|
|
1720
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
1721
|
+
proposer_id: '0x' + 'c'.repeat(64),
|
|
1722
|
+
cosigner_sigs: [],
|
|
1723
|
+
},
|
|
1724
|
+
};
|
|
1725
|
+
|
|
1726
|
+
mockFetch.mockResolvedValueOnce({
|
|
1727
|
+
ok: true,
|
|
1728
|
+
json: async () => ({
|
|
1729
|
+
delta: mockDelta,
|
|
1730
|
+
commitment: '0x' + 'c'.repeat(64),
|
|
1731
|
+
}),
|
|
1732
|
+
});
|
|
1733
|
+
|
|
1734
|
+
const proposal = await multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n, {
|
|
1735
|
+
nonce: 1,
|
|
1736
|
+
reclaimHeight: 12345,
|
|
1737
|
+
timelockHeight: 700,
|
|
1738
|
+
});
|
|
1739
|
+
|
|
1740
|
+
// Propose path builds the P2IDE note from the heights...
|
|
1741
|
+
const lastCall = vi.mocked(buildP2idTransactionRequest).mock.calls.at(-1)!;
|
|
1742
|
+
expect(lastCall[4]).toMatchObject({ reclaimHeight: 12345, timelockHeight: 700 });
|
|
1743
|
+
|
|
1744
|
+
// ...and the pushed wire metadata carries the heights so cosigners
|
|
1745
|
+
// rebuild the same P2IDE note at verification/execution.
|
|
1746
|
+
const pushBody = JSON.parse(mockFetch.mock.calls.at(-1)![1].body as string);
|
|
1747
|
+
expect(pushBody.delta_payload.metadata.reclaim_height).toBe(12345);
|
|
1748
|
+
expect(pushBody.delta_payload.metadata.timelock_height).toBe(700);
|
|
1749
|
+
|
|
1750
|
+
expect(proposal.metadata.proposalType).toBe('p2id');
|
|
1751
|
+
expect(proposal.metadata).toMatchObject({ reclaimHeight: 12345, timelockHeight: 700 });
|
|
1752
|
+
});
|
|
1753
|
+
|
|
1754
|
+
it('omits the heights from wire metadata for a plain P2ID send (pre-#366 shape)', async () => {
|
|
1755
|
+
const { executeForSummary } = await import('./transaction.js');
|
|
1756
|
+
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1757
|
+
summary: {
|
|
1758
|
+
toCommitment: () => ({
|
|
1759
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
1760
|
+
}),
|
|
1761
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1762
|
+
},
|
|
1763
|
+
anchor: createMockChainAnchor(),
|
|
1764
|
+
} as any);
|
|
1765
|
+
|
|
1766
|
+
const config = {
|
|
1767
|
+
threshold: 1,
|
|
1768
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1769
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
1770
|
+
};
|
|
1771
|
+
|
|
1772
|
+
const multisig = createTestMultisig(config);
|
|
1773
|
+
|
|
1774
|
+
const mockDelta = {
|
|
1775
|
+
account_id: '0x' + 'a'.repeat(30),
|
|
1776
|
+
nonce: 1,
|
|
1777
|
+
prev_commitment: '0x' + 'b'.repeat(64),
|
|
1778
|
+
delta_payload: {
|
|
1779
|
+
tx_summary: { data: 'AQID' },
|
|
1780
|
+
signatures: [],
|
|
1781
|
+
metadata: {
|
|
1782
|
+
proposal_type: 'p2id',
|
|
1783
|
+
recipient_id: '0xrecipient',
|
|
1784
|
+
faucet_id: '0xfaucet',
|
|
1785
|
+
amount: '100',
|
|
1786
|
+
description: '',
|
|
1787
|
+
},
|
|
1788
|
+
},
|
|
1789
|
+
status: {
|
|
1790
|
+
status: 'pending',
|
|
1791
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
1792
|
+
proposer_id: '0x' + 'c'.repeat(64),
|
|
1793
|
+
cosigner_sigs: [],
|
|
1794
|
+
},
|
|
1795
|
+
};
|
|
1796
|
+
|
|
1797
|
+
mockFetch.mockResolvedValueOnce({
|
|
1798
|
+
ok: true,
|
|
1799
|
+
json: async () => ({
|
|
1800
|
+
delta: mockDelta,
|
|
1801
|
+
commitment: '0x' + 'c'.repeat(64),
|
|
1802
|
+
}),
|
|
1803
|
+
});
|
|
1804
|
+
|
|
1805
|
+
await multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n, { nonce: 1 });
|
|
1806
|
+
|
|
1807
|
+
const pushBody = JSON.parse(mockFetch.mock.calls.at(-1)![1].body as string);
|
|
1808
|
+
expect('reclaim_height' in pushBody.delta_payload.metadata).toBe(false);
|
|
1809
|
+
expect('timelock_height' in pushBody.delta_payload.metadata).toBe(false);
|
|
1810
|
+
});
|
|
1438
1811
|
});
|
|
1439
1812
|
|
|
1440
1813
|
describe('exportNoteToBytes / importNoteFromBytes (issue #356)', () => {
|
|
@@ -1561,6 +1934,7 @@ describe('Multisig', () => {
|
|
|
1561
1934
|
const proposal = {
|
|
1562
1935
|
metadata: {
|
|
1563
1936
|
proposalType: 'p2id',
|
|
1937
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1564
1938
|
recipientId: '0x' + 'b'.repeat(30),
|
|
1565
1939
|
faucetId: '0x' + 'c'.repeat(30),
|
|
1566
1940
|
amount: '100',
|
|
@@ -1588,10 +1962,13 @@ describe('Multisig', () => {
|
|
|
1588
1962
|
describe('createChangeThresholdProposal', () => {
|
|
1589
1963
|
it('passes the signer scheme to update-signers requests', async () => {
|
|
1590
1964
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1965
|
+
summary: {
|
|
1966
|
+
toCommitment: () => ({
|
|
1967
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
1968
|
+
}),
|
|
1969
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
1970
|
+
},
|
|
1971
|
+
anchor: createMockChainAnchor(),
|
|
1595
1972
|
} as any);
|
|
1596
1973
|
|
|
1597
1974
|
const ecdsaSigner: Signer = {
|
|
@@ -1616,6 +1993,7 @@ describe('Multisig', () => {
|
|
|
1616
1993
|
signatures: [],
|
|
1617
1994
|
metadata: {
|
|
1618
1995
|
proposal_type: 'change_threshold',
|
|
1996
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1619
1997
|
target_threshold: 2,
|
|
1620
1998
|
description: '',
|
|
1621
1999
|
},
|
|
@@ -1637,7 +2015,7 @@ describe('Multisig', () => {
|
|
|
1637
2015
|
});
|
|
1638
2016
|
|
|
1639
2017
|
const multisig = createTestMultisig(config, ecdsaSigner);
|
|
1640
|
-
await multisig.createChangeThresholdProposal(2, 1);
|
|
2018
|
+
await multisig.createChangeThresholdProposal(2, { nonce: 1 });
|
|
1641
2019
|
|
|
1642
2020
|
expect(buildUpdateSignersTransactionRequest).toHaveBeenCalledWith(
|
|
1643
2021
|
mockWebClient,
|
|
@@ -1648,10 +2026,153 @@ describe('Multisig', () => {
|
|
|
1648
2026
|
});
|
|
1649
2027
|
});
|
|
1650
2028
|
|
|
2029
|
+
describe('createAddSignerProposal / createRemoveSignerProposal', () => {
|
|
2030
|
+
const config = {
|
|
2031
|
+
threshold: 2,
|
|
2032
|
+
signerCommitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64), '0x' + 'd'.repeat(64)],
|
|
2033
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
2034
|
+
};
|
|
2035
|
+
|
|
2036
|
+
const mockPushResponse = (proposalType: string) => {
|
|
2037
|
+
mockFetch.mockResolvedValueOnce({
|
|
2038
|
+
ok: true,
|
|
2039
|
+
json: async () => ({
|
|
2040
|
+
delta: {
|
|
2041
|
+
account_id: '0x' + 'a'.repeat(30),
|
|
2042
|
+
nonce: 1,
|
|
2043
|
+
prev_commitment: '0x' + 'b'.repeat(64),
|
|
2044
|
+
delta_payload: {
|
|
2045
|
+
tx_summary: { data: 'AQID' },
|
|
2046
|
+
signatures: [],
|
|
2047
|
+
metadata: { proposal_type: proposalType, description: '' },
|
|
2048
|
+
},
|
|
2049
|
+
status: {
|
|
2050
|
+
status: 'pending',
|
|
2051
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
2052
|
+
proposer_id: '0x' + 'c'.repeat(64),
|
|
2053
|
+
cosigner_sigs: [],
|
|
2054
|
+
},
|
|
2055
|
+
},
|
|
2056
|
+
commitment: '0x' + 'c'.repeat(64),
|
|
2057
|
+
}),
|
|
2058
|
+
});
|
|
2059
|
+
};
|
|
2060
|
+
|
|
2061
|
+
beforeEach(() => {
|
|
2062
|
+
vi.mocked(executeForSummary).mockResolvedValue({
|
|
2063
|
+
summary: {
|
|
2064
|
+
toCommitment: () => ({ toHex: () => '0x' + 'c'.repeat(64) }),
|
|
2065
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
2066
|
+
},
|
|
2067
|
+
anchor: createMockChainAnchor(),
|
|
2068
|
+
} as any);
|
|
2069
|
+
});
|
|
2070
|
+
|
|
2071
|
+
it('add: passes newThreshold from the options bag and appends the commitment', async () => {
|
|
2072
|
+
mockPushResponse('add_signer');
|
|
2073
|
+
const newCommitment = '0x' + 'e'.repeat(64);
|
|
2074
|
+
|
|
2075
|
+
const multisig = createTestMultisig(config);
|
|
2076
|
+
await multisig.createAddSignerProposal(newCommitment, { nonce: 1, newThreshold: 3 });
|
|
2077
|
+
|
|
2078
|
+
expect(buildUpdateSignersTransactionRequest).toHaveBeenCalledWith(
|
|
2079
|
+
mockWebClient,
|
|
2080
|
+
3,
|
|
2081
|
+
[...config.signerCommitments, newCommitment],
|
|
2082
|
+
{ signatureScheme: mockSigner.scheme },
|
|
2083
|
+
);
|
|
2084
|
+
});
|
|
2085
|
+
|
|
2086
|
+
it('add: defaults to the current threshold when newThreshold is omitted', async () => {
|
|
2087
|
+
mockPushResponse('add_signer');
|
|
2088
|
+
|
|
2089
|
+
const multisig = createTestMultisig(config);
|
|
2090
|
+
await multisig.createAddSignerProposal('0x' + 'e'.repeat(64), { nonce: 1 });
|
|
2091
|
+
|
|
2092
|
+
expect(buildUpdateSignersTransactionRequest).toHaveBeenCalledWith(
|
|
2093
|
+
mockWebClient,
|
|
2094
|
+
config.threshold,
|
|
2095
|
+
expect.any(Array),
|
|
2096
|
+
{ signatureScheme: mockSigner.scheme },
|
|
2097
|
+
);
|
|
2098
|
+
});
|
|
2099
|
+
|
|
2100
|
+
it('remove: passes newThreshold from the options bag and drops the commitment', async () => {
|
|
2101
|
+
mockPushResponse('remove_signer');
|
|
2102
|
+
|
|
2103
|
+
const multisig = createTestMultisig(config);
|
|
2104
|
+
await multisig.createRemoveSignerProposal('0x' + 'd'.repeat(64), { nonce: 1, newThreshold: 1 });
|
|
2105
|
+
|
|
2106
|
+
expect(buildUpdateSignersTransactionRequest).toHaveBeenCalledWith(
|
|
2107
|
+
mockWebClient,
|
|
2108
|
+
1,
|
|
2109
|
+
[config.signerCommitments[0], config.signerCommitments[1]],
|
|
2110
|
+
{ signatureScheme: mockSigner.scheme },
|
|
2111
|
+
);
|
|
2112
|
+
});
|
|
2113
|
+
|
|
2114
|
+
it('remove: defaults to min(current threshold, remaining signers) when newThreshold is omitted', async () => {
|
|
2115
|
+
mockPushResponse('remove_signer');
|
|
2116
|
+
|
|
2117
|
+
const multisig = createTestMultisig(config);
|
|
2118
|
+
await multisig.createRemoveSignerProposal('0x' + 'd'.repeat(64), { nonce: 1 });
|
|
2119
|
+
|
|
2120
|
+
expect(buildUpdateSignersTransactionRequest).toHaveBeenCalledWith(
|
|
2121
|
+
mockWebClient,
|
|
2122
|
+
2,
|
|
2123
|
+
expect.any(Array),
|
|
2124
|
+
{ signatureScheme: mockSigner.scheme },
|
|
2125
|
+
);
|
|
2126
|
+
});
|
|
2127
|
+
});
|
|
2128
|
+
|
|
2129
|
+
describe('legacy positional-caller guard (issue #387)', () => {
|
|
2130
|
+
const config = {
|
|
2131
|
+
threshold: 1,
|
|
2132
|
+
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2133
|
+
guardianCommitment: '0x' + 'c'.repeat(64),
|
|
2134
|
+
};
|
|
2135
|
+
|
|
2136
|
+
it('rejects a legacy positional nonce where the options bag is expected', async () => {
|
|
2137
|
+
const multisig = createTestMultisig(config);
|
|
2138
|
+
|
|
2139
|
+
await expect(
|
|
2140
|
+
multisig.createP2idProposal('0xrecipient', '0xfaucet', 100n, 1 as any),
|
|
2141
|
+
).rejects.toThrow(/issue #387/);
|
|
2142
|
+
await expect(
|
|
2143
|
+
multisig.createConsumeNotesProposal(['0x1'], 1 as any),
|
|
2144
|
+
).rejects.toThrow(/issue #387/);
|
|
2145
|
+
await expect(
|
|
2146
|
+
multisig.createAddSignerProposal('0x' + 'e'.repeat(64), 1 as any),
|
|
2147
|
+
).rejects.toThrow(/issue #387/);
|
|
2148
|
+
await expect(
|
|
2149
|
+
multisig.createCustomProposal(new Uint8Array([1]), 'label', 1 as any),
|
|
2150
|
+
).rejects.toThrow(/issue #387/);
|
|
2151
|
+
});
|
|
2152
|
+
|
|
2153
|
+
it('rejects a legacy trailing argument after the options slot', async () => {
|
|
2154
|
+
const multisig = createTestMultisig(config);
|
|
2155
|
+
|
|
2156
|
+
// Pre-#387 pattern: createP2idProposal(r, f, amount, nonceHole, { noteType })
|
|
2157
|
+
await expect(
|
|
2158
|
+
(multisig.createP2idProposal as any)('0xrecipient', '0xfaucet', 100n, undefined, {
|
|
2159
|
+
noteType: 'private',
|
|
2160
|
+
}),
|
|
2161
|
+
).rejects.toThrow(/issue #387/);
|
|
2162
|
+
// Pre-#387 pattern: createAddSignerProposal(commitment, nonceHole, newThreshold)
|
|
2163
|
+
await expect(
|
|
2164
|
+
(multisig.createAddSignerProposal as any)('0x' + 'e'.repeat(64), undefined, 3),
|
|
2165
|
+
).rejects.toThrow(/issue #387/);
|
|
2166
|
+
});
|
|
2167
|
+
});
|
|
2168
|
+
|
|
1651
2169
|
describe('createSwitchGuardianProposal', () => {
|
|
1652
2170
|
it('should verify new endpoint commitment before creating proposal', async () => {
|
|
1653
2171
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1654
|
-
|
|
2172
|
+
summary: {
|
|
2173
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
2174
|
+
},
|
|
2175
|
+
anchor: createMockChainAnchor(),
|
|
1655
2176
|
} as any);
|
|
1656
2177
|
|
|
1657
2178
|
const config = {
|
|
@@ -1700,7 +2221,10 @@ describe('Multisig', () => {
|
|
|
1700
2221
|
|
|
1701
2222
|
it('should reject switch proposal when endpoint commitment does not match', async () => {
|
|
1702
2223
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1703
|
-
|
|
2224
|
+
summary: {
|
|
2225
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
2226
|
+
},
|
|
2227
|
+
anchor: createMockChainAnchor(),
|
|
1704
2228
|
} as any);
|
|
1705
2229
|
|
|
1706
2230
|
const config = {
|
|
@@ -1723,7 +2247,10 @@ describe('Multisig', () => {
|
|
|
1723
2247
|
|
|
1724
2248
|
it('should use the signer scheme when resolving new GUARDIAN commitments', async () => {
|
|
1725
2249
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1726
|
-
|
|
2250
|
+
summary: {
|
|
2251
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
2252
|
+
},
|
|
2253
|
+
anchor: createMockChainAnchor(),
|
|
1727
2254
|
} as any);
|
|
1728
2255
|
|
|
1729
2256
|
const ecdsaSigner: Signer = {
|
|
@@ -1782,10 +2309,13 @@ describe('Multisig', () => {
|
|
|
1782
2309
|
describe('createUpdateProcedureThresholdProposal', () => {
|
|
1783
2310
|
it('should create procedure-threshold update proposals', async () => {
|
|
1784
2311
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
2312
|
+
summary: {
|
|
2313
|
+
toCommitment: () => ({
|
|
2314
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
2315
|
+
}),
|
|
2316
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
2317
|
+
},
|
|
2318
|
+
anchor: createMockChainAnchor(),
|
|
1789
2319
|
} as any);
|
|
1790
2320
|
|
|
1791
2321
|
const config = {
|
|
@@ -1805,6 +2335,7 @@ describe('Multisig', () => {
|
|
|
1805
2335
|
signatures: [],
|
|
1806
2336
|
metadata: {
|
|
1807
2337
|
proposal_type: 'update_procedure_threshold',
|
|
2338
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1808
2339
|
target_threshold: 1,
|
|
1809
2340
|
target_procedure: 'send_asset',
|
|
1810
2341
|
description: '',
|
|
@@ -1826,7 +2357,7 @@ describe('Multisig', () => {
|
|
|
1826
2357
|
}),
|
|
1827
2358
|
});
|
|
1828
2359
|
|
|
1829
|
-
const proposal = await multisig.createUpdateProcedureThresholdProposal('send_asset', 1, 1);
|
|
2360
|
+
const proposal = await multisig.createUpdateProcedureThresholdProposal('send_asset', 1, { nonce: 1 });
|
|
1830
2361
|
|
|
1831
2362
|
expect(buildUpdateProcedureThresholdTransactionRequest).toHaveBeenCalledWith(
|
|
1832
2363
|
mockWebClient,
|
|
@@ -1843,10 +2374,13 @@ describe('Multisig', () => {
|
|
|
1843
2374
|
|
|
1844
2375
|
it('passes the signer scheme to ECDSA procedure-threshold updates', async () => {
|
|
1845
2376
|
vi.mocked(executeForSummary).mockResolvedValue({
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
2377
|
+
summary: {
|
|
2378
|
+
toCommitment: () => ({
|
|
2379
|
+
toHex: () => '0x' + 'c'.repeat(64),
|
|
2380
|
+
}),
|
|
2381
|
+
serialize: () => new Uint8Array([1, 2, 3]),
|
|
2382
|
+
},
|
|
2383
|
+
anchor: createMockChainAnchor(),
|
|
1850
2384
|
} as any);
|
|
1851
2385
|
|
|
1852
2386
|
const ecdsaSigner: Signer = {
|
|
@@ -1873,6 +2407,7 @@ describe('Multisig', () => {
|
|
|
1873
2407
|
signatures: [],
|
|
1874
2408
|
metadata: {
|
|
1875
2409
|
proposal_type: 'update_procedure_threshold',
|
|
2410
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1876
2411
|
target_threshold: 1,
|
|
1877
2412
|
target_procedure: 'send_asset',
|
|
1878
2413
|
description: '',
|
|
@@ -1894,7 +2429,7 @@ describe('Multisig', () => {
|
|
|
1894
2429
|
}),
|
|
1895
2430
|
});
|
|
1896
2431
|
|
|
1897
|
-
await multisig.createUpdateProcedureThresholdProposal('send_asset', 1, 1);
|
|
2432
|
+
await multisig.createUpdateProcedureThresholdProposal('send_asset', 1, { nonce: 1 });
|
|
1898
2433
|
|
|
1899
2434
|
expect(buildUpdateProcedureThresholdTransactionRequest).toHaveBeenCalledWith(
|
|
1900
2435
|
mockWebClient,
|
|
@@ -1942,6 +2477,7 @@ describe('Multisig', () => {
|
|
|
1942
2477
|
|
|
1943
2478
|
await multisig.createProposal(1, 'AQID', {
|
|
1944
2479
|
proposalType: 'add_signer',
|
|
2480
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1945
2481
|
targetThreshold: 1,
|
|
1946
2482
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
1947
2483
|
description: '',
|
|
@@ -1965,6 +2501,7 @@ describe('Multisig', () => {
|
|
|
1965
2501
|
...mockDelta.delta_payload,
|
|
1966
2502
|
metadata: {
|
|
1967
2503
|
proposal_type: 'add_signer',
|
|
2504
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
1968
2505
|
description: '',
|
|
1969
2506
|
target_threshold: 1,
|
|
1970
2507
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
@@ -2019,12 +2556,13 @@ describe('Multisig', () => {
|
|
|
2019
2556
|
|
|
2020
2557
|
await multisig.createProposal(1, 'AQID', {
|
|
2021
2558
|
proposalType: 'add_signer',
|
|
2559
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2022
2560
|
targetThreshold: 1,
|
|
2023
2561
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2024
2562
|
description: '',
|
|
2025
2563
|
});
|
|
2026
2564
|
|
|
2027
|
-
vi.mocked(
|
|
2565
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
2028
2566
|
toCommitment: () => ({
|
|
2029
2567
|
toHex: () => '0x' + 'f'.repeat(64),
|
|
2030
2568
|
}),
|
|
@@ -2058,6 +2596,7 @@ describe('Multisig', () => {
|
|
|
2058
2596
|
signatures: [],
|
|
2059
2597
|
metadata: {
|
|
2060
2598
|
proposal_type: 'add_signer',
|
|
2599
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2061
2600
|
description: '',
|
|
2062
2601
|
target_threshold: 1,
|
|
2063
2602
|
signer_commitments: [mockSigner.commitment],
|
|
@@ -2091,7 +2630,7 @@ describe('Multisig', () => {
|
|
|
2091
2630
|
|
|
2092
2631
|
const multisig = createTestMultisig(config);
|
|
2093
2632
|
|
|
2094
|
-
vi.mocked(
|
|
2633
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
2095
2634
|
toCommitment: () => ({
|
|
2096
2635
|
toHex: () => '0x' + 'f'.repeat(64),
|
|
2097
2636
|
}),
|
|
@@ -2107,6 +2646,7 @@ describe('Multisig', () => {
|
|
|
2107
2646
|
signatures: [],
|
|
2108
2647
|
metadata: {
|
|
2109
2648
|
proposalType: 'add_signer',
|
|
2649
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2110
2650
|
targetThreshold: 1,
|
|
2111
2651
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2112
2652
|
description: '',
|
|
@@ -2127,7 +2667,7 @@ describe('Multisig', () => {
|
|
|
2127
2667
|
|
|
2128
2668
|
const multisig = createTestMultisig(config);
|
|
2129
2669
|
|
|
2130
|
-
vi.mocked(
|
|
2670
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
2131
2671
|
toCommitment: () => ({
|
|
2132
2672
|
toHex: () => '0x' + 'c'.repeat(64),
|
|
2133
2673
|
}),
|
|
@@ -2142,6 +2682,7 @@ describe('Multisig', () => {
|
|
|
2142
2682
|
signatures: [],
|
|
2143
2683
|
metadata: {
|
|
2144
2684
|
proposalType: 'add_signer',
|
|
2685
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2145
2686
|
targetThreshold: 1,
|
|
2146
2687
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2147
2688
|
description: '',
|
|
@@ -2151,12 +2692,13 @@ describe('Multisig', () => {
|
|
|
2151
2692
|
|
|
2152
2693
|
proposal.metadata = {
|
|
2153
2694
|
proposalType: 'add_signer',
|
|
2695
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2154
2696
|
targetThreshold: 2,
|
|
2155
2697
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2156
2698
|
description: '',
|
|
2157
2699
|
};
|
|
2158
2700
|
|
|
2159
|
-
vi.mocked(
|
|
2701
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
2160
2702
|
toCommitment: () => ({
|
|
2161
2703
|
toHex: () => '0x' + 'f'.repeat(64),
|
|
2162
2704
|
}),
|
|
@@ -2188,6 +2730,7 @@ describe('Multisig', () => {
|
|
|
2188
2730
|
signatures: [],
|
|
2189
2731
|
metadata: {
|
|
2190
2732
|
proposal_type: 'add_signer',
|
|
2733
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2191
2734
|
description: '',
|
|
2192
2735
|
target_threshold: 1,
|
|
2193
2736
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
@@ -2243,6 +2786,7 @@ describe('Multisig', () => {
|
|
|
2243
2786
|
signatures: [],
|
|
2244
2787
|
metadata: {
|
|
2245
2788
|
proposal_type: 'change_threshold',
|
|
2789
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2246
2790
|
description: '',
|
|
2247
2791
|
target_threshold: 2,
|
|
2248
2792
|
signer_commitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
@@ -2298,7 +2842,7 @@ describe('Multisig', () => {
|
|
|
2298
2842
|
// folded into the error message; raw text bodies are dropped.
|
|
2299
2843
|
text: async () =>
|
|
2300
2844
|
JSON.stringify({
|
|
2301
|
-
code: '
|
|
2845
|
+
code: 'proposal_not_found',
|
|
2302
2846
|
message: 'Proposal not found',
|
|
2303
2847
|
meta: { retryable: false },
|
|
2304
2848
|
}),
|
|
@@ -2333,6 +2877,7 @@ describe('Multisig', () => {
|
|
|
2333
2877
|
],
|
|
2334
2878
|
metadata: {
|
|
2335
2879
|
proposalType: 'add_signer' as const,
|
|
2880
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2336
2881
|
targetThreshold: 1,
|
|
2337
2882
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2338
2883
|
description: '',
|
|
@@ -2371,6 +2916,7 @@ describe('Multisig', () => {
|
|
|
2371
2916
|
],
|
|
2372
2917
|
metadata: {
|
|
2373
2918
|
proposalType: 'change_threshold',
|
|
2919
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2374
2920
|
targetThreshold: 1,
|
|
2375
2921
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2376
2922
|
description: '',
|
|
@@ -2416,6 +2962,7 @@ describe('Multisig', () => {
|
|
|
2416
2962
|
],
|
|
2417
2963
|
metadata: {
|
|
2418
2964
|
proposalType: 'change_threshold',
|
|
2965
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2419
2966
|
targetThreshold: 1,
|
|
2420
2967
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2421
2968
|
description: '',
|
|
@@ -2442,6 +2989,7 @@ describe('Multisig', () => {
|
|
|
2442
2989
|
signatures: [],
|
|
2443
2990
|
metadata: {
|
|
2444
2991
|
proposalType: 'add_signer' as const,
|
|
2992
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2445
2993
|
targetThreshold: 2,
|
|
2446
2994
|
targetSignerCommitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
2447
2995
|
description: '',
|
|
@@ -2517,6 +3065,7 @@ describe('Multisig', () => {
|
|
|
2517
3065
|
],
|
|
2518
3066
|
metadata: {
|
|
2519
3067
|
proposalType: 'change_threshold',
|
|
3068
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2520
3069
|
targetThreshold: 1,
|
|
2521
3070
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2522
3071
|
description: '',
|
|
@@ -2534,6 +3083,7 @@ describe('Multisig', () => {
|
|
|
2534
3083
|
signatures: [],
|
|
2535
3084
|
metadata: {
|
|
2536
3085
|
proposal_type: 'change_threshold',
|
|
3086
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2537
3087
|
target_threshold: 1,
|
|
2538
3088
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
2539
3089
|
},
|
|
@@ -2576,17 +3126,19 @@ describe('Multisig', () => {
|
|
|
2576
3126
|
expect.anything(),
|
|
2577
3127
|
expect.anything(),
|
|
2578
3128
|
expect.anything(),
|
|
2579
|
-
cosignerPubkey,
|
|
2580
|
-
cosignerSignature,
|
|
2581
3129
|
);
|
|
2582
3130
|
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(
|
|
2583
3131
|
2,
|
|
2584
3132
|
expect.anything(),
|
|
2585
3133
|
expect.anything(),
|
|
2586
3134
|
expect.anything(),
|
|
2587
|
-
ackPubkey,
|
|
2588
|
-
ackSignature,
|
|
2589
3135
|
);
|
|
3136
|
+
// The advice payload now comes from the SDK, so the routing assertion is
|
|
3137
|
+
// the commitment each entry is keyed on: cosigner first, GUARDIAN ack
|
|
3138
|
+
// second. Swapping the two entries must not pass.
|
|
3139
|
+
const adviceCalls = vi.mocked(buildSignatureAdviceEntry).mock.calls;
|
|
3140
|
+
expect(adviceCalls[0][0].toHex()).toBe(config.signerCommitments[0]);
|
|
3141
|
+
expect(adviceCalls[1][0].toHex()).toBe(config.guardianCommitment);
|
|
2590
3142
|
expect(mockWebClient.executeTransaction).not.toHaveBeenCalled();
|
|
2591
3143
|
expect(mockWebClient.proveTransaction).not.toHaveBeenCalled();
|
|
2592
3144
|
expect(mockWebClient.submitProvenTransaction).not.toHaveBeenCalled();
|
|
@@ -2628,6 +3180,7 @@ describe('Multisig', () => {
|
|
|
2628
3180
|
],
|
|
2629
3181
|
metadata: {
|
|
2630
3182
|
proposalType: 'switch_guardian',
|
|
3183
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2631
3184
|
newGuardianPubkey,
|
|
2632
3185
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
2633
3186
|
description: '',
|
|
@@ -2681,6 +3234,7 @@ describe('Multisig', () => {
|
|
|
2681
3234
|
signatures: [],
|
|
2682
3235
|
metadata: {
|
|
2683
3236
|
proposal_type: 'add_signer',
|
|
3237
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2684
3238
|
description: '',
|
|
2685
3239
|
target_threshold: 2,
|
|
2686
3240
|
signer_commitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
@@ -2723,7 +3277,7 @@ describe('Multisig', () => {
|
|
|
2723
3277
|
const multisig = createTestMultisig(config);
|
|
2724
3278
|
const proposalId = '0x' + 'c'.repeat(64);
|
|
2725
3279
|
|
|
2726
|
-
vi.mocked(
|
|
3280
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
2727
3281
|
toCommitment: () => ({
|
|
2728
3282
|
toHex: () => '0x' + 'd'.repeat(64),
|
|
2729
3283
|
}),
|
|
@@ -2744,6 +3298,7 @@ describe('Multisig', () => {
|
|
|
2744
3298
|
],
|
|
2745
3299
|
metadata: {
|
|
2746
3300
|
proposalType: 'change_threshold',
|
|
3301
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2747
3302
|
targetThreshold: 1,
|
|
2748
3303
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2749
3304
|
description: '',
|
|
@@ -2781,6 +3336,7 @@ describe('Multisig', () => {
|
|
|
2781
3336
|
],
|
|
2782
3337
|
metadata: {
|
|
2783
3338
|
proposalType: 'switch_guardian',
|
|
3339
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2784
3340
|
newGuardianPubkey: '0x' + '1'.repeat(64),
|
|
2785
3341
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
2786
3342
|
description: '',
|
|
@@ -2828,6 +3384,7 @@ describe('Multisig', () => {
|
|
|
2828
3384
|
],
|
|
2829
3385
|
metadata: {
|
|
2830
3386
|
proposalType: 'switch_guardian',
|
|
3387
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2831
3388
|
newGuardianPubkey: '0x' + '1'.repeat(64),
|
|
2832
3389
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
2833
3390
|
description: '',
|
|
@@ -2908,6 +3465,7 @@ describe('Multisig', () => {
|
|
|
2908
3465
|
],
|
|
2909
3466
|
metadata: {
|
|
2910
3467
|
proposalType: 'change_threshold',
|
|
3468
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2911
3469
|
targetThreshold: 1,
|
|
2912
3470
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
2913
3471
|
description: '',
|
|
@@ -2925,6 +3483,7 @@ describe('Multisig', () => {
|
|
|
2925
3483
|
signatures: [],
|
|
2926
3484
|
metadata: {
|
|
2927
3485
|
proposal_type: 'change_threshold',
|
|
3486
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
2928
3487
|
target_threshold: 1,
|
|
2929
3488
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
2930
3489
|
},
|
|
@@ -2999,6 +3558,7 @@ describe('Multisig', () => {
|
|
|
2999
3558
|
],
|
|
3000
3559
|
metadata: {
|
|
3001
3560
|
proposalType: 'switch_guardian',
|
|
3561
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3002
3562
|
newGuardianPubkey: '0x' + '1'.repeat(64),
|
|
3003
3563
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
3004
3564
|
description: '',
|
|
@@ -3046,6 +3606,7 @@ describe('Multisig', () => {
|
|
|
3046
3606
|
signatures: [],
|
|
3047
3607
|
metadata: {
|
|
3048
3608
|
proposal_type: 'add_signer',
|
|
3609
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3049
3610
|
description: '',
|
|
3050
3611
|
target_threshold: 2,
|
|
3051
3612
|
signer_commitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
@@ -3079,7 +3640,7 @@ describe('Multisig', () => {
|
|
|
3079
3640
|
).rejects.toThrow('not ready for execution');
|
|
3080
3641
|
});
|
|
3081
3642
|
|
|
3082
|
-
it('should fail when GUARDIAN ack signature is missing
|
|
3643
|
+
it('should fail when GUARDIAN ack signature is missing', async () => {
|
|
3083
3644
|
const config = {
|
|
3084
3645
|
threshold: 1,
|
|
3085
3646
|
signerCommitments: ['0x' + 'a'.repeat(64)],
|
|
@@ -3097,6 +3658,7 @@ describe('Multisig', () => {
|
|
|
3097
3658
|
signatures: [],
|
|
3098
3659
|
metadata: {
|
|
3099
3660
|
proposal_type: 'add_signer',
|
|
3661
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3100
3662
|
description: '',
|
|
3101
3663
|
target_threshold: 1,
|
|
3102
3664
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
@@ -3189,6 +3751,7 @@ describe('Multisig', () => {
|
|
|
3189
3751
|
],
|
|
3190
3752
|
metadata: {
|
|
3191
3753
|
proposalType: 'change_threshold',
|
|
3754
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3192
3755
|
targetThreshold: 1,
|
|
3193
3756
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
3194
3757
|
description: '',
|
|
@@ -3206,6 +3769,7 @@ describe('Multisig', () => {
|
|
|
3206
3769
|
signatures: [],
|
|
3207
3770
|
metadata: {
|
|
3208
3771
|
proposal_type: 'change_threshold',
|
|
3772
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3209
3773
|
target_threshold: 1,
|
|
3210
3774
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
3211
3775
|
},
|
|
@@ -3259,17 +3823,19 @@ describe('Multisig', () => {
|
|
|
3259
3823
|
expect.anything(),
|
|
3260
3824
|
expect.anything(),
|
|
3261
3825
|
expect.anything(),
|
|
3262
|
-
cosignerPubkey,
|
|
3263
|
-
cosignerSignature,
|
|
3264
3826
|
);
|
|
3265
3827
|
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(
|
|
3266
3828
|
2,
|
|
3267
3829
|
expect.anything(),
|
|
3268
3830
|
expect.anything(),
|
|
3269
3831
|
expect.anything(),
|
|
3270
|
-
ackPubkey,
|
|
3271
|
-
ackSignature,
|
|
3272
3832
|
);
|
|
3833
|
+
// The advice payload now comes from the SDK, so the routing assertion is
|
|
3834
|
+
// the commitment each entry is keyed on: cosigner first, GUARDIAN ack
|
|
3835
|
+
// second. Swapping the two entries must not pass.
|
|
3836
|
+
const adviceCalls = vi.mocked(buildSignatureAdviceEntry).mock.calls;
|
|
3837
|
+
expect(adviceCalls[0][0].toHex()).toBe(config.signerCommitments[0]);
|
|
3838
|
+
expect(adviceCalls[1][0].toHex()).toBe(config.guardianCommitment);
|
|
3273
3839
|
});
|
|
3274
3840
|
|
|
3275
3841
|
it('should execute imported ECDSA proposals with scheme-aware advice', async () => {
|
|
@@ -3314,6 +3880,7 @@ describe('Multisig', () => {
|
|
|
3314
3880
|
],
|
|
3315
3881
|
metadata: {
|
|
3316
3882
|
proposalType: 'change_threshold',
|
|
3883
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3317
3884
|
targetThreshold: 1,
|
|
3318
3885
|
targetSignerCommitments: ['0x' + 'a'.repeat(64)],
|
|
3319
3886
|
description: '',
|
|
@@ -3332,6 +3899,7 @@ describe('Multisig', () => {
|
|
|
3332
3899
|
signatures: [],
|
|
3333
3900
|
metadata: {
|
|
3334
3901
|
proposal_type: 'change_threshold',
|
|
3902
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3335
3903
|
target_threshold: 1,
|
|
3336
3904
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
3337
3905
|
},
|
|
@@ -3375,17 +3943,19 @@ describe('Multisig', () => {
|
|
|
3375
3943
|
expect.anything(),
|
|
3376
3944
|
expect.anything(),
|
|
3377
3945
|
expect.anything(),
|
|
3378
|
-
cosignerPubkey,
|
|
3379
|
-
cosignerSignature,
|
|
3380
3946
|
);
|
|
3381
3947
|
expect(vi.mocked(buildSignatureAdviceEntry)).toHaveBeenNthCalledWith(
|
|
3382
3948
|
2,
|
|
3383
3949
|
expect.anything(),
|
|
3384
3950
|
expect.anything(),
|
|
3385
3951
|
expect.anything(),
|
|
3386
|
-
ackPubkey,
|
|
3387
|
-
ackSignature,
|
|
3388
3952
|
);
|
|
3953
|
+
// The advice payload now comes from the SDK, so the routing assertion is
|
|
3954
|
+
// the commitment each entry is keyed on: cosigner first, GUARDIAN ack
|
|
3955
|
+
// second. Swapping the two entries must not pass.
|
|
3956
|
+
const adviceCalls = vi.mocked(buildSignatureAdviceEntry).mock.calls;
|
|
3957
|
+
expect(adviceCalls[0][0].toHex()).toBe(config.signerCommitments[0]);
|
|
3958
|
+
expect(adviceCalls[1][0].toHex()).toBe(config.guardianCommitment);
|
|
3389
3959
|
});
|
|
3390
3960
|
|
|
3391
3961
|
it('should verify switch_guardian endpoint commitment before execution', async () => {
|
|
@@ -3414,6 +3984,7 @@ describe('Multisig', () => {
|
|
|
3414
3984
|
],
|
|
3415
3985
|
metadata: {
|
|
3416
3986
|
proposalType: 'switch_guardian',
|
|
3987
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3417
3988
|
newGuardianPubkey,
|
|
3418
3989
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
3419
3990
|
description: '',
|
|
@@ -3436,6 +4007,7 @@ describe('Multisig', () => {
|
|
|
3436
4007
|
signatures: [],
|
|
3437
4008
|
metadata: {
|
|
3438
4009
|
proposal_type: 'switch_guardian',
|
|
4010
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3439
4011
|
new_guardian_pubkey: newGuardianPubkey,
|
|
3440
4012
|
new_guardian_endpoint: 'http://new-guardian.com',
|
|
3441
4013
|
},
|
|
@@ -3498,6 +4070,7 @@ describe('Multisig', () => {
|
|
|
3498
4070
|
],
|
|
3499
4071
|
metadata: {
|
|
3500
4072
|
proposalType: 'switch_guardian',
|
|
4073
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3501
4074
|
newGuardianPubkey,
|
|
3502
4075
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
3503
4076
|
description: '',
|
|
@@ -3549,6 +4122,7 @@ describe('Multisig', () => {
|
|
|
3549
4122
|
],
|
|
3550
4123
|
metadata: {
|
|
3551
4124
|
proposalType: 'switch_guardian',
|
|
4125
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3552
4126
|
newGuardianPubkey: '0x' + '1'.repeat(64),
|
|
3553
4127
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
3554
4128
|
description: '',
|
|
@@ -3596,6 +4170,7 @@ describe('Multisig', () => {
|
|
|
3596
4170
|
],
|
|
3597
4171
|
metadata: {
|
|
3598
4172
|
proposalType: 'switch_guardian',
|
|
4173
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3599
4174
|
newGuardianPubkey: '0x' + '1'.repeat(64),
|
|
3600
4175
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
3601
4176
|
description: '',
|
|
@@ -3648,6 +4223,7 @@ describe('Multisig', () => {
|
|
|
3648
4223
|
],
|
|
3649
4224
|
metadata: {
|
|
3650
4225
|
proposalType: 'switch_guardian',
|
|
4226
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3651
4227
|
newGuardianPubkey: '0x' + '1'.repeat(64),
|
|
3652
4228
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
3653
4229
|
description: '',
|
|
@@ -3683,9 +4259,33 @@ describe('Multisig', () => {
|
|
|
3683
4259
|
.mockRejectedValueOnce(transient)
|
|
3684
4260
|
.mockResolvedValueOnce({});
|
|
3685
4261
|
|
|
4262
|
+
mockFetch.mockResolvedValueOnce({
|
|
4263
|
+
ok: true,
|
|
4264
|
+
json: async () => ({
|
|
4265
|
+
account_id: '0x' + 'a'.repeat(30),
|
|
4266
|
+
nonce: 1,
|
|
4267
|
+
prev_commitment: '0x' + 'b'.repeat(64),
|
|
4268
|
+
delta_payload: {
|
|
4269
|
+
tx_summary: { data: 'AQID' },
|
|
4270
|
+
signatures: [],
|
|
4271
|
+
metadata: {
|
|
4272
|
+
proposal_type: 'b2agg',
|
|
4273
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
4274
|
+
description: '',
|
|
4275
|
+
},
|
|
4276
|
+
},
|
|
4277
|
+
status: {
|
|
4278
|
+
status: 'pending',
|
|
4279
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
4280
|
+
proposer_id: '0x' + 'c'.repeat(64),
|
|
4281
|
+
cosigner_sigs: [],
|
|
4282
|
+
},
|
|
4283
|
+
}),
|
|
4284
|
+
});
|
|
4285
|
+
|
|
3686
4286
|
vi.useFakeTimers();
|
|
3687
4287
|
try {
|
|
3688
|
-
const submission = multisig.submitTransaction({} as never);
|
|
4288
|
+
const submission = multisig.submitTransaction('0x' + 'c'.repeat(64), {} as never);
|
|
3689
4289
|
await vi.runAllTimersAsync();
|
|
3690
4290
|
await submission;
|
|
3691
4291
|
} finally {
|
|
@@ -3715,6 +4315,7 @@ describe('Multisig', () => {
|
|
|
3715
4315
|
signatures: [],
|
|
3716
4316
|
metadata: {
|
|
3717
4317
|
proposal_type: proposalType,
|
|
4318
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3718
4319
|
description: '',
|
|
3719
4320
|
},
|
|
3720
4321
|
},
|
|
@@ -3748,6 +4349,7 @@ describe('Multisig', () => {
|
|
|
3748
4349
|
};
|
|
3749
4350
|
builtinDelta.delta_payload.metadata = {
|
|
3750
4351
|
proposal_type: 'change_threshold',
|
|
4352
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3751
4353
|
description: '',
|
|
3752
4354
|
target_threshold: 1,
|
|
3753
4355
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
@@ -3791,7 +4393,7 @@ describe('Multisig', () => {
|
|
|
3791
4393
|
|
|
3792
4394
|
// Signed commitment comes from TransactionSummary.deserialize -> 'c' * 64.
|
|
3793
4395
|
// Make the binding request derive a different commitment so the check fails.
|
|
3794
|
-
vi.mocked(
|
|
4396
|
+
vi.mocked(executeForSummaryAt).mockResolvedValueOnce({
|
|
3795
4397
|
toCommitment: () => ({
|
|
3796
4398
|
toHex: () => '0x' + '9'.repeat(64),
|
|
3797
4399
|
}),
|
|
@@ -3855,6 +4457,7 @@ describe('Multisig', () => {
|
|
|
3855
4457
|
signatures: [],
|
|
3856
4458
|
metadata: {
|
|
3857
4459
|
proposal_type: 'add_signer',
|
|
4460
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3858
4461
|
target_threshold: 2,
|
|
3859
4462
|
signer_commitments: ['0x1', '0x2'],
|
|
3860
4463
|
},
|
|
@@ -3877,6 +4480,7 @@ describe('Multisig', () => {
|
|
|
3877
4480
|
|
|
3878
4481
|
const proposal = await multisig.createProposal(1, 'AQID', {
|
|
3879
4482
|
proposalType: 'add_signer',
|
|
4483
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3880
4484
|
targetThreshold: 2,
|
|
3881
4485
|
targetSignerCommitments: ['0x1', '0x2'],
|
|
3882
4486
|
description: '',
|
|
@@ -3918,6 +4522,7 @@ describe('Multisig', () => {
|
|
|
3918
4522
|
signatures: [],
|
|
3919
4523
|
metadata: {
|
|
3920
4524
|
proposal_type: 'p2id',
|
|
4525
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3921
4526
|
recipient_id: '0xrecipient',
|
|
3922
4527
|
faucet_id: '0xfaucet',
|
|
3923
4528
|
amount: '100',
|
|
@@ -3963,6 +4568,7 @@ describe('Multisig', () => {
|
|
|
3963
4568
|
signatures: [],
|
|
3964
4569
|
metadata: {
|
|
3965
4570
|
proposal_type: 'add_signer',
|
|
4571
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3966
4572
|
target_threshold: 2,
|
|
3967
4573
|
signer_commitments: ['0x1', '0x2'],
|
|
3968
4574
|
description: '',
|
|
@@ -3986,6 +4592,7 @@ describe('Multisig', () => {
|
|
|
3986
4592
|
|
|
3987
4593
|
const proposal = await multisig.createProposal(1, 'AQID', {
|
|
3988
4594
|
proposalType: 'consume_notes',
|
|
4595
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
3989
4596
|
noteIds: ['0xnote1', '0xnote2'],
|
|
3990
4597
|
description: '',
|
|
3991
4598
|
});
|
|
@@ -4011,6 +4618,7 @@ describe('Multisig', () => {
|
|
|
4011
4618
|
signatures: [],
|
|
4012
4619
|
metadata: {
|
|
4013
4620
|
proposal_type: 'add_signer',
|
|
4621
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
4014
4622
|
target_threshold: 1,
|
|
4015
4623
|
signer_commitments: ['0x' + 'a'.repeat(64)],
|
|
4016
4624
|
description: '',
|
|
@@ -4034,6 +4642,7 @@ describe('Multisig', () => {
|
|
|
4034
4642
|
|
|
4035
4643
|
const proposal = await multisig.createProposal(1, 'AQID', {
|
|
4036
4644
|
proposalType: 'p2id',
|
|
4645
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
4037
4646
|
recipientId: '0xrecipient',
|
|
4038
4647
|
faucetId: '0xfaucet',
|
|
4039
4648
|
amount: '100',
|
|
@@ -4061,6 +4670,7 @@ describe('Multisig', () => {
|
|
|
4061
4670
|
signatures: [],
|
|
4062
4671
|
metadata: {
|
|
4063
4672
|
proposalType: 'add_signer',
|
|
4673
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
4064
4674
|
targetThreshold: 2,
|
|
4065
4675
|
targetSignerCommitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
4066
4676
|
description: '',
|
|
@@ -4084,6 +4694,7 @@ describe('Multisig', () => {
|
|
|
4084
4694
|
|
|
4085
4695
|
const proposal = await multisig.createProposal(1, 'AQID', {
|
|
4086
4696
|
proposalType: 'switch_guardian',
|
|
4697
|
+
chainAnchor: MOCK_CHAIN_ANCHOR_B64,
|
|
4087
4698
|
newGuardianPubkey: '0xnewpubkey',
|
|
4088
4699
|
newGuardianEndpoint: 'http://new-guardian.com',
|
|
4089
4700
|
description: '',
|
|
@@ -4114,6 +4725,7 @@ describe('Multisig', () => {
|
|
|
4114
4725
|
signatures: [],
|
|
4115
4726
|
metadata: {
|
|
4116
4727
|
proposal_type: 'add_signer',
|
|
4728
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
4117
4729
|
target_threshold: 2,
|
|
4118
4730
|
signer_commitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
4119
4731
|
description: '',
|
|
@@ -4150,6 +4762,7 @@ describe('Multisig', () => {
|
|
|
4150
4762
|
...mockProposalsPending[0].delta_payload,
|
|
4151
4763
|
metadata: {
|
|
4152
4764
|
proposal_type: 'add_signer',
|
|
4765
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
4153
4766
|
target_threshold: 2,
|
|
4154
4767
|
signer_commitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
|
|
4155
4768
|
description: '',
|
|
@@ -4254,6 +4867,7 @@ describe('Multisig', () => {
|
|
|
4254
4867
|
signatures: [],
|
|
4255
4868
|
metadata: {
|
|
4256
4869
|
proposal_type: 'change_threshold',
|
|
4870
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
4257
4871
|
target_threshold: 3,
|
|
4258
4872
|
signer_commitments: ['0xa', '0xb', '0xc'],
|
|
4259
4873
|
salt: '0xlegacysalt',
|
|
@@ -4304,6 +4918,7 @@ describe('Multisig', () => {
|
|
|
4304
4918
|
signatures: [],
|
|
4305
4919
|
metadata: {
|
|
4306
4920
|
proposal_type: 'p2id',
|
|
4921
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
4307
4922
|
recipient_id: '0xrecipient',
|
|
4308
4923
|
faucet_id: '0xfaucet',
|
|
4309
4924
|
amount: '12345',
|
|
@@ -4360,6 +4975,7 @@ describe('Multisig', () => {
|
|
|
4360
4975
|
signatures: [],
|
|
4361
4976
|
metadata: {
|
|
4362
4977
|
proposal_type: 'switch_guardian',
|
|
4978
|
+
chain_anchor: MOCK_CHAIN_ANCHOR_B64,
|
|
4363
4979
|
new_guardian_pubkey: '0xnewpubkey',
|
|
4364
4980
|
new_guardian_endpoint: 'http://new-guardian.com',
|
|
4365
4981
|
salt: '0xsalt',
|