@msafe/sui3-sdk 0.0.2-pre-9f39791.0 → 0.0.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/dist/index.cjs +1812 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +454 -0
- package/dist/index.d.ts +454 -0
- package/dist/index.js +1750 -0
- package/dist/index.js.map +1 -0
- package/package.json +6 -1
- package/.eslintignore +0 -3
- package/.eslintrc +0 -87
- package/.idea/inspectionProfiles/Project_Default.xml +0 -6
- package/.idea/jsLinters/eslint.xml +0 -6
- package/.idea/misc.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/msafe-sui3-sdk.iml +0 -9
- package/.idea/vcs.xml +0 -6
- package/.prettierrc +0 -22
- package/jest.config.ts +0 -63
- package/scripts/prerelease.sh +0 -5
- package/temp_package.json +0 -54
- package/test/lib/TestHelper.ts +0 -94
- package/test/lib/account.ts +0 -87
- package/test/lib/config.ts +0 -9
- package/test/lib/faucet.ts +0 -49
- package/test/unit/backend/backend.test.ts +0 -367
- package/test/unit/core/CreateHelper.test.ts +0 -121
- package/test/unit/core/MessageHelper.test.ts +0 -32
- package/test/unit/core/PublicKeyHelper.test.ts +0 -80
- package/test/unit/core/msafe.test.ts +0 -298
- package/test/unit/utils/buffer.test.ts +0 -17
- package/test/unit/utils/crypto.test.ts +0 -32
- package/test/unit/utils/multi-sig.test.ts +0 -47
- package/test/unit/utils/sui.test.ts +0 -25
- package/tsup.config.ts +0 -9
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { PseudoBackend } from '@/backend/PseudoBackend';
|
|
2
|
-
import { CreateHelper } from '@/core/CreateHelper';
|
|
3
|
-
import { PublicKeyHelper } from '@/core/PublicKeyHelper';
|
|
4
|
-
import { MSafeEnv } from '@/globals/const';
|
|
5
|
-
import { MSafeGlobals } from '@/globals/MSafeGlobals';
|
|
6
|
-
import { CreateMSafeAccountInfo } from '@/types/creation';
|
|
7
|
-
|
|
8
|
-
import { LocalWallet } from '../../lib/account';
|
|
9
|
-
import { TESTNET_SUI_CLIENT } from '../../lib/config';
|
|
10
|
-
import { TestHelper } from '../../lib/TestHelper';
|
|
11
|
-
|
|
12
|
-
describe('MSafeCreationHelper', () => {
|
|
13
|
-
let createHelper: CreateHelper;
|
|
14
|
-
let testHelper: TestHelper;
|
|
15
|
-
|
|
16
|
-
const localWallet = new LocalWallet(TESTNET_SUI_CLIENT);
|
|
17
|
-
const coManagerAddress = '0x6e78327c80f18968c5227af0dc1a7637822f2f76cb78adbdc0454e8abe66b235';
|
|
18
|
-
|
|
19
|
-
beforeAll(async () => {
|
|
20
|
-
const globals = await MSafeGlobals.New(MSafeEnv.unit);
|
|
21
|
-
testHelper = new TestHelper(globals);
|
|
22
|
-
await testHelper.init(localWallet);
|
|
23
|
-
|
|
24
|
-
const pkHelper = new PublicKeyHelper(globals);
|
|
25
|
-
createHelper = new CreateHelper(globals, pkHelper);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
afterAll(async () => {
|
|
29
|
-
await testHelper.close();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('validate success', async () => {
|
|
33
|
-
const info: CreateMSafeAccountInfo = {
|
|
34
|
-
ownerWithWeight: [
|
|
35
|
-
{ address: await localWallet.address(), weight: 2 },
|
|
36
|
-
{ address: coManagerAddress, weight: 1 },
|
|
37
|
-
],
|
|
38
|
-
threshold: 2,
|
|
39
|
-
name: 'test wallet',
|
|
40
|
-
creationNonce: 1,
|
|
41
|
-
};
|
|
42
|
-
await createHelper.validateCreateInfo(info);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('unknown public key', async () => {
|
|
46
|
-
const info: CreateMSafeAccountInfo = {
|
|
47
|
-
ownerWithWeight: [{ address: '0x123123123', weight: 1 }],
|
|
48
|
-
threshold: 1,
|
|
49
|
-
name: 'test wallet',
|
|
50
|
-
creationNonce: 1,
|
|
51
|
-
};
|
|
52
|
-
await expect(createHelper.validateCreateInfo(info)).rejects.toThrow('Unknown public key for address');
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('duplicate address', async () => {
|
|
56
|
-
const info: CreateMSafeAccountInfo = {
|
|
57
|
-
ownerWithWeight: [
|
|
58
|
-
{ address: await localWallet.address(), weight: 1 },
|
|
59
|
-
{ address: await localWallet.address(), weight: 3 },
|
|
60
|
-
],
|
|
61
|
-
threshold: 1,
|
|
62
|
-
name: 'test wallet',
|
|
63
|
-
creationNonce: 1,
|
|
64
|
-
};
|
|
65
|
-
await expect(createHelper.validateCreateInfo(info)).rejects.toThrow('Duplicate address detected');
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('invalid weight', async () => {
|
|
69
|
-
const info: CreateMSafeAccountInfo = {
|
|
70
|
-
ownerWithWeight: [
|
|
71
|
-
{ address: await localWallet.address(), weight: 256 },
|
|
72
|
-
{ address: coManagerAddress, weight: 1 },
|
|
73
|
-
],
|
|
74
|
-
threshold: 2,
|
|
75
|
-
name: 'test wallet',
|
|
76
|
-
creationNonce: 1,
|
|
77
|
-
};
|
|
78
|
-
await expect(createHelper.validateCreateInfo(info)).rejects.toThrow('Invalid multi-sig weight: 256 (1-255)');
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('invalid threshold', async () => {
|
|
82
|
-
const info: CreateMSafeAccountInfo = {
|
|
83
|
-
ownerWithWeight: [
|
|
84
|
-
{ address: await localWallet.address(), weight: 2 },
|
|
85
|
-
{ address: coManagerAddress, weight: 1 },
|
|
86
|
-
],
|
|
87
|
-
threshold: 5,
|
|
88
|
-
name: 'test wallet',
|
|
89
|
-
creationNonce: 1,
|
|
90
|
-
};
|
|
91
|
-
await expect(createHelper.validateCreateInfo(info)).rejects.toThrow('Threshold is larger than total weight');
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('submit creation', async () => {
|
|
95
|
-
const info: CreateMSafeAccountInfo = {
|
|
96
|
-
ownerWithWeight: [
|
|
97
|
-
{ address: await localWallet.address(), weight: 2 },
|
|
98
|
-
{ address: coManagerAddress, weight: 1 },
|
|
99
|
-
],
|
|
100
|
-
threshold: 2,
|
|
101
|
-
name: 'test wallet',
|
|
102
|
-
creationNonce: 0,
|
|
103
|
-
};
|
|
104
|
-
await createHelper.submitMSafeCreation(info);
|
|
105
|
-
|
|
106
|
-
const msafeAddress = await createHelper.calculateMSafeAddress(info);
|
|
107
|
-
const db = createHelper.globals.backend as PseudoBackend;
|
|
108
|
-
const msafeAccountInfo = await db.getMSafeAccountInfo(msafeAddress);
|
|
109
|
-
expect(msafeAccountInfo).toBeDefined();
|
|
110
|
-
expect(msafeAccountInfo?.name).toBe(info.name);
|
|
111
|
-
expect(msafeAccountInfo?.threshold).toBe(info.threshold);
|
|
112
|
-
expect(msafeAccountInfo?.ownersWithWeightPK.length).toBe(info.ownerWithWeight.length);
|
|
113
|
-
expect(msafeAccountInfo?.ownersWithWeightPK[0].address).toBe(await localWallet.address());
|
|
114
|
-
expect(msafeAccountInfo?.ownersWithWeightPK[0].weight).toBe(2);
|
|
115
|
-
expect(msafeAccountInfo?.ownersWithWeightPK[1].address).toBe(coManagerAddress);
|
|
116
|
-
expect(msafeAccountInfo?.ownersWithWeightPK[1].weight).toBe(1);
|
|
117
|
-
|
|
118
|
-
const res = await db.getUserInfo(await localWallet.address());
|
|
119
|
-
expect(res.creationNonce).toBe(1);
|
|
120
|
-
});
|
|
121
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { MessageHelper, ProposeIntentionData } from '@/core/MessageHelper';
|
|
2
|
-
|
|
3
|
-
describe('MessageHelper', () => {
|
|
4
|
-
it('create message', () => {
|
|
5
|
-
const addr = '0x123123';
|
|
6
|
-
const msg = MessageHelper.createMSafeMessage(addr);
|
|
7
|
-
const got = MessageHelper.deCreateMSafeMessage(msg);
|
|
8
|
-
expect(addr).toEqual(got);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('welcome message', () => {
|
|
12
|
-
const timeStr = new Date().toDateString();
|
|
13
|
-
const msg = MessageHelper.welcomeMessage(timeStr);
|
|
14
|
-
const got = MessageHelper.deWelcomeMessage(msg);
|
|
15
|
-
expect(timeStr).toEqual(got);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('proposeIntentMessage', async () => {
|
|
19
|
-
const proposeData: ProposeIntentionData = {
|
|
20
|
-
intention: {
|
|
21
|
-
txType: 'CoinTransfer',
|
|
22
|
-
recipient: '0x123',
|
|
23
|
-
coinType: '0x2::sui::Sui',
|
|
24
|
-
amount: '100',
|
|
25
|
-
},
|
|
26
|
-
sn: 100,
|
|
27
|
-
};
|
|
28
|
-
const msg = MessageHelper.proposeIntentionMessage(proposeData);
|
|
29
|
-
const got = MessageHelper.deProposeIntentionMessage(msg);
|
|
30
|
-
expect(proposeData).toEqual(got);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { PublicKeyHelper } from '@/core/PublicKeyHelper';
|
|
2
|
-
import { MSafeEnv } from '@/globals/const';
|
|
3
|
-
import { MSafeGlobals } from '@/globals/MSafeGlobals';
|
|
4
|
-
import { Formatter } from '@/utils/format';
|
|
5
|
-
|
|
6
|
-
import { LocalWallet } from '../../lib/account';
|
|
7
|
-
import { TESTNET_SUI_CLIENT } from '../../lib/config';
|
|
8
|
-
import { TestHelper } from '../../lib/TestHelper';
|
|
9
|
-
|
|
10
|
-
describe('PublicKeyHelper', () => {
|
|
11
|
-
let globals: MSafeGlobals;
|
|
12
|
-
let pkHelper: PublicKeyHelper;
|
|
13
|
-
let testHelper: TestHelper;
|
|
14
|
-
|
|
15
|
-
const localWallet = new LocalWallet(TESTNET_SUI_CLIENT);
|
|
16
|
-
const chainAddress = '0x6e78327c80f18968c5227af0dc1a7637822f2f76cb78adbdc0454e8abe66b235';
|
|
17
|
-
|
|
18
|
-
beforeAll(async () => {
|
|
19
|
-
globals = await MSafeGlobals.New(MSafeEnv.unit);
|
|
20
|
-
testHelper = new TestHelper(globals);
|
|
21
|
-
await testHelper.init(localWallet);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
afterAll(async () => {
|
|
25
|
-
await testHelper.close();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
pkHelper = new PublicKeyHelper(globals);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('getPublicKey from blockchain', async () => {
|
|
33
|
-
const publicKey = await pkHelper.getPublicKey(chainAddress);
|
|
34
|
-
expect(publicKey).toBeDefined();
|
|
35
|
-
expect(Formatter.isSuiAddressEqual(publicKey!.toSuiAddress(), chainAddress)).toBeTruthy();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('getPublicKey with wallet', async () => {
|
|
39
|
-
const publicKey = await pkHelper.getPublicKey(await localWallet.address());
|
|
40
|
-
expect(publicKey).toBeDefined();
|
|
41
|
-
expect(Formatter.isSuiAddressEqual(publicKey!.toSuiAddress(), await localWallet.address())).toBeTruthy();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('getPublicKeyBatch', async () => {
|
|
45
|
-
const pks = await pkHelper.getPublicKeyBatch([await localWallet.address(), chainAddress]);
|
|
46
|
-
expect(pks.length).toBe(2);
|
|
47
|
-
for (let i = 0; i < pks.length; i++) {
|
|
48
|
-
expect(pks[i]).toBeDefined();
|
|
49
|
-
expect(Formatter.isSuiAddressEqual(pks[i]!.toSuiAddress(), await localWallet.address()));
|
|
50
|
-
}
|
|
51
|
-
expect((pkHelper as any).knownPublicKeys.size).toBe(2);
|
|
52
|
-
|
|
53
|
-
const pks2 = await pkHelper.getPublicKeyBatch([await localWallet.address(), chainAddress]);
|
|
54
|
-
expect(pks2.length).toBe(2);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('getPublicKeyBatch with uncached backend values', async () => {
|
|
58
|
-
await pkHelper.getPublicKey(chainAddress);
|
|
59
|
-
expect((pkHelper as any).knownPublicKeys.size).toBe(1);
|
|
60
|
-
|
|
61
|
-
const pks = await pkHelper.getPublicKeyBatch([await localWallet.address(), chainAddress]);
|
|
62
|
-
expect(pks.length).toBe(2);
|
|
63
|
-
expect((pkHelper as any).knownPublicKeys.size).toBe(2);
|
|
64
|
-
|
|
65
|
-
expect(Formatter.isSuiAddressEqual(pks[0]?.toSuiAddress() as string, await localWallet.address())).toBeTruthy();
|
|
66
|
-
expect(Formatter.isSuiAddressEqual(pks[1]?.toSuiAddress() as string, chainAddress)).toBeTruthy();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('getPublicKeyBatch with uncached chain values', async () => {
|
|
70
|
-
await pkHelper.getPublicKey(await localWallet.address());
|
|
71
|
-
expect((pkHelper as any).knownPublicKeys.size).toBe(1);
|
|
72
|
-
|
|
73
|
-
const pks = await pkHelper.getPublicKeyBatch([chainAddress, await localWallet.address()]);
|
|
74
|
-
expect(pks.length).toBe(2);
|
|
75
|
-
expect((pkHelper as any).knownPublicKeys.size).toBe(2);
|
|
76
|
-
|
|
77
|
-
expect(Formatter.isSuiAddressEqual(pks[0]?.toSuiAddress() as string, chainAddress)).toBeTruthy();
|
|
78
|
-
expect(Formatter.isSuiAddressEqual(pks[1]?.toSuiAddress() as string, await localWallet.address())).toBeTruthy();
|
|
79
|
-
});
|
|
80
|
-
});
|
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
import { SuiClient } from '@mysten/sui.js/client';
|
|
2
|
-
|
|
3
|
-
import { PseudoBackend } from '@/backend/PseudoBackend';
|
|
4
|
-
import { MSafeAccount } from '@/core/MSafeAccount';
|
|
5
|
-
import { MSafeClient } from '@/core/MSafeClient';
|
|
6
|
-
import { MSafeEnv } from '@/globals/const';
|
|
7
|
-
import { MSafeGlobals } from '@/globals/MSafeGlobals';
|
|
8
|
-
import { IntentionCoinTransfer } from '@/transactions/coin-transfer';
|
|
9
|
-
import { IWallet } from '@/types/wallet';
|
|
10
|
-
import { SUI_COIN } from '@/utils/sui';
|
|
11
|
-
|
|
12
|
-
import { LocalWallet } from '../../lib/account';
|
|
13
|
-
import { TestHelper } from '../../lib/TestHelper';
|
|
14
|
-
|
|
15
|
-
describe('MSafe integration', () => {
|
|
16
|
-
let testHelper: TestHelper;
|
|
17
|
-
let suiClient: SuiClient;
|
|
18
|
-
const wallets: IWallet[] = [];
|
|
19
|
-
const clients: MSafeClient[] = [];
|
|
20
|
-
let backend: PseudoBackend;
|
|
21
|
-
const userAddresses: string[] = [];
|
|
22
|
-
|
|
23
|
-
beforeAll(async () => {
|
|
24
|
-
const globals = await MSafeGlobals.New(MSafeEnv.unit);
|
|
25
|
-
suiClient = globals.suiClient;
|
|
26
|
-
testHelper = new TestHelper(globals);
|
|
27
|
-
await testHelper.init();
|
|
28
|
-
for (let i = 0; i !== 3; i++) {
|
|
29
|
-
const userGlobals = await MSafeGlobals.New(MSafeEnv.unit);
|
|
30
|
-
const wallet = new LocalWallet(userGlobals.suiClient);
|
|
31
|
-
const client = new MSafeClient(userGlobals);
|
|
32
|
-
await client.connectWallet({ wallet });
|
|
33
|
-
clients.push(client);
|
|
34
|
-
wallets.push(wallet);
|
|
35
|
-
userAddresses.push(await wallet.address());
|
|
36
|
-
}
|
|
37
|
-
backend = globals.backend as PseudoBackend;
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
afterAll(async () => {
|
|
41
|
-
(testHelper.globals.backend as PseudoBackend).db.coreModel.close();
|
|
42
|
-
for (let i = 0; i < clients.length; i++) {
|
|
43
|
-
await (clients[i].globals.backend as PseudoBackend).db.coreModel.close();
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
async function createMSafe() {
|
|
48
|
-
return clients[0].creationHelper.submitMSafeCreation({
|
|
49
|
-
ownerWithWeight: userAddresses.map((addr) => ({
|
|
50
|
-
address: addr,
|
|
51
|
-
weight: 1,
|
|
52
|
-
})),
|
|
53
|
-
threshold: wallets.length,
|
|
54
|
-
name: 'Test MSafe',
|
|
55
|
-
description: 'Some description',
|
|
56
|
-
creationNonce: 0,
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async function getMSafeAccountForTest() {
|
|
61
|
-
const userInfo = await clients[0].userInfo();
|
|
62
|
-
let msafe: MSafeAccount;
|
|
63
|
-
if (userInfo.ownedMSafe.length > 0) {
|
|
64
|
-
msafe = clients[0].getMSafeAccount(userInfo.ownedMSafe[0]);
|
|
65
|
-
} else {
|
|
66
|
-
const msafeAddress = await createMSafe();
|
|
67
|
-
msafe = await clients[0].getMSafeAccountFromAddress(msafeAddress);
|
|
68
|
-
}
|
|
69
|
-
await faucetAccount(msafe.info.address);
|
|
70
|
-
return msafe;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async function faucetAccount(addr: string) {
|
|
74
|
-
const bal = await suiClient.getBalance({ owner: addr });
|
|
75
|
-
if (bal.totalBalance === '0') {
|
|
76
|
-
await testHelper.faucetWallet(addr, 40000000n);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
it('create MSafe', async () => {
|
|
81
|
-
await createMSafe();
|
|
82
|
-
|
|
83
|
-
for (let i = 0; i !== clients.length; i++) {
|
|
84
|
-
const userInfo = await clients[i].userInfo();
|
|
85
|
-
expect(userInfo.creationNonce).toBe(i === 0 ? 1 : 0);
|
|
86
|
-
expect(userInfo.ownedMSafe.length).toBe(1);
|
|
87
|
-
expect(userInfo.address).toBe(userAddresses[i]);
|
|
88
|
-
expect(userInfo.ownedMSafe.length).toBe(1);
|
|
89
|
-
expect(userInfo.ownedMSafe[0].threshold).toBe(userAddresses.length);
|
|
90
|
-
expect(userInfo.ownedMSafe[0].creationNonce).toBe(0);
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('Propose and execute one transaction', async () => {
|
|
95
|
-
const msafeAccount = await getMSafeAccountForTest();
|
|
96
|
-
|
|
97
|
-
const initBal = await suiClient.getBalance({ owner: userAddresses[0] });
|
|
98
|
-
|
|
99
|
-
const intention: IntentionCoinTransfer = {
|
|
100
|
-
txType: 'CoinTransfer',
|
|
101
|
-
recipient: userAddresses[0],
|
|
102
|
-
amount: '100',
|
|
103
|
-
coinType: SUI_COIN,
|
|
104
|
-
};
|
|
105
|
-
const sn = await msafeAccount.currentSequenceNumber();
|
|
106
|
-
await msafeAccount.proposeIntention(intention, sn);
|
|
107
|
-
|
|
108
|
-
const futureIntentions = await msafeAccount.futureIntentions();
|
|
109
|
-
expect(futureIntentions.length).toBe(1);
|
|
110
|
-
expect(futureIntentions[0].sequenceNumber).toBe(0);
|
|
111
|
-
expect(futureIntentions[0].txType).toBe('CoinTransfer');
|
|
112
|
-
expect(futureIntentions[0].creator).toBe(userAddresses[0]);
|
|
113
|
-
|
|
114
|
-
const pendings0 = await msafeAccount.pendingTransactions();
|
|
115
|
-
expect(pendings0.length).toBe(0);
|
|
116
|
-
|
|
117
|
-
await msafeAccount.buildNextIntentionAndAddToPending();
|
|
118
|
-
const pendings = await msafeAccount.pendingTransactions();
|
|
119
|
-
expect(pendings.length).toBe(1);
|
|
120
|
-
|
|
121
|
-
for (let i = 0; i < userAddresses.length; i++) {
|
|
122
|
-
const msafe = clients[i].getMSafeAccount(msafeAccount.info);
|
|
123
|
-
await msafe.voteForTransaction(pendings[0].digest, pendings[0].payload);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const votedPendings = await msafeAccount.pendingTransactions();
|
|
127
|
-
expect(votedPendings.length).toBe(1);
|
|
128
|
-
expect(votedPendings[0].votes.length).toBe(userAddresses.length);
|
|
129
|
-
|
|
130
|
-
const res = await msafeAccount.executePendingTx(votedPendings[0]);
|
|
131
|
-
expect(res.effects?.status.status).toBe('success');
|
|
132
|
-
|
|
133
|
-
await backend.processExecutedTransaction(pendings[0].digest);
|
|
134
|
-
const pendingsExecuted = await msafeAccount.pendingTransactions();
|
|
135
|
-
expect(pendingsExecuted.length).toBe(0);
|
|
136
|
-
|
|
137
|
-
const history = await msafeAccount.historyTransaction();
|
|
138
|
-
const relatedHistory = history.find(
|
|
139
|
-
(tx) => tx.msafeAddress === msafeAccount.info.address && tx.digest === votedPendings[0].digest,
|
|
140
|
-
);
|
|
141
|
-
expect(relatedHistory).toBeDefined();
|
|
142
|
-
expect(relatedHistory?.status).toBe('success');
|
|
143
|
-
|
|
144
|
-
// Check execution result
|
|
145
|
-
const bal = await suiClient.getBalance({ owner: userAddresses[0] });
|
|
146
|
-
expect(bal.totalBalance).not.toBe(initBal.totalBalance);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('proposePendingTransaction and reject transaction', async () => {
|
|
150
|
-
const msafeAccount = await getMSafeAccountForTest();
|
|
151
|
-
|
|
152
|
-
const initBal = await suiClient.getBalance({ owner: userAddresses[0] });
|
|
153
|
-
|
|
154
|
-
const intention: IntentionCoinTransfer = {
|
|
155
|
-
txType: 'CoinTransfer',
|
|
156
|
-
recipient: userAddresses[0],
|
|
157
|
-
amount: '200',
|
|
158
|
-
coinType: SUI_COIN,
|
|
159
|
-
};
|
|
160
|
-
await msafeAccount.proposePendingTransaction(intention);
|
|
161
|
-
|
|
162
|
-
let pendings = await msafeAccount.pendingTransactions();
|
|
163
|
-
expect(pendings.length).toBe(1);
|
|
164
|
-
expect(pendings[0].creator).toBe(userAddresses[0]);
|
|
165
|
-
expect(pendings[0].votes.length).toBe(1);
|
|
166
|
-
expect(pendings[0].votes[0].userAddress).toBe(userAddresses[0]);
|
|
167
|
-
|
|
168
|
-
// Reject the transaction
|
|
169
|
-
await msafeAccount.rejectCurrentTx();
|
|
170
|
-
|
|
171
|
-
pendings = await msafeAccount.pendingTransactions();
|
|
172
|
-
expect(pendings.length).toBe(2);
|
|
173
|
-
const approvePending = pendings.find((pending) => !pending.isRejectTx);
|
|
174
|
-
const rejectPending = pendings.find((pending) => pending.isRejectTx);
|
|
175
|
-
expect(approvePending).toBeDefined();
|
|
176
|
-
expect(approvePending?.intention?.txType).toBe('CoinTransfer');
|
|
177
|
-
expect(approvePending?.votes.length).toBe(0);
|
|
178
|
-
|
|
179
|
-
expect(rejectPending).toBeDefined();
|
|
180
|
-
expect(rejectPending?.intention).toBeUndefined();
|
|
181
|
-
expect(rejectPending?.votes.length).toBe(1);
|
|
182
|
-
|
|
183
|
-
for (let i = 1; i < clients.length; i++) {
|
|
184
|
-
const msafe = clients[i].getMSafeAccount(msafeAccount.info);
|
|
185
|
-
await msafe.voteForTransaction(rejectPending!.digest, rejectPending!.payload!);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
pendings = await msafeAccount.pendingTransactions();
|
|
189
|
-
expect(pendings.length).toBe(2);
|
|
190
|
-
const rejectPending2 = pendings.find((pending) => pending.isRejectTx);
|
|
191
|
-
|
|
192
|
-
expect(rejectPending2).toBeDefined();
|
|
193
|
-
expect(rejectPending2?.intention).toBeUndefined();
|
|
194
|
-
expect(rejectPending2?.votes.length).toBe(clients.length);
|
|
195
|
-
|
|
196
|
-
const res = await msafeAccount.executePendingTx(rejectPending2!);
|
|
197
|
-
expect(res.effects?.status.status).toBe('success');
|
|
198
|
-
|
|
199
|
-
await backend.processExecutedTransaction(rejectPending2!.digest);
|
|
200
|
-
pendings = await msafeAccount.pendingTransactions();
|
|
201
|
-
expect(pendings.length).toBe(0);
|
|
202
|
-
|
|
203
|
-
const history = await msafeAccount.historyTransaction();
|
|
204
|
-
const approveHistory = history.find((hs) => hs.digest === approvePending?.digest);
|
|
205
|
-
expect(approveHistory).toBeDefined();
|
|
206
|
-
expect(approveHistory?.status).toBe('rejected');
|
|
207
|
-
|
|
208
|
-
const rejectHistory = history.find((hs) => hs.digest === rejectPending?.digest);
|
|
209
|
-
expect(rejectHistory).toBeDefined();
|
|
210
|
-
expect(rejectHistory?.status).toBe('success');
|
|
211
|
-
|
|
212
|
-
const bal = await suiClient.getBalance({ owner: userAddresses[0] });
|
|
213
|
-
expect(bal.totalBalance).toBe(initBal.totalBalance);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('Propose multiple intentions, and the second intention fails', async () => {
|
|
217
|
-
const msafeAccount = await getMSafeAccountForTest();
|
|
218
|
-
|
|
219
|
-
const intention: IntentionCoinTransfer = {
|
|
220
|
-
txType: 'CoinTransfer',
|
|
221
|
-
recipient: userAddresses[0],
|
|
222
|
-
amount: '300',
|
|
223
|
-
coinType: SUI_COIN,
|
|
224
|
-
};
|
|
225
|
-
const invalidIntention: IntentionCoinTransfer = {
|
|
226
|
-
txType: 'CoinTransfer',
|
|
227
|
-
recipient: userAddresses[0],
|
|
228
|
-
amount: '18446744073709551614',
|
|
229
|
-
coinType: SUI_COIN,
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
let pendings = await msafeAccount.pendingTransactions();
|
|
233
|
-
expect(pendings.length).toBe(0);
|
|
234
|
-
let futures = await msafeAccount.futureIntentions();
|
|
235
|
-
expect(futures.length).toBe(0);
|
|
236
|
-
|
|
237
|
-
let nextSN = await msafeAccount.nextSequenceNumber();
|
|
238
|
-
await msafeAccount.proposeIntention(intention, nextSN);
|
|
239
|
-
pendings = await msafeAccount.pendingTransactions();
|
|
240
|
-
expect(pendings.length).toBe(0);
|
|
241
|
-
futures = await msafeAccount.futureIntentions();
|
|
242
|
-
expect(futures.length).toBe(1);
|
|
243
|
-
|
|
244
|
-
// Propose multiple intentions
|
|
245
|
-
nextSN = await msafeAccount.nextSequenceNumber();
|
|
246
|
-
await msafeAccount.proposeIntention(invalidIntention, nextSN);
|
|
247
|
-
pendings = await msafeAccount.pendingTransactions();
|
|
248
|
-
expect(pendings.length).toBe(0);
|
|
249
|
-
futures = await msafeAccount.futureIntentions();
|
|
250
|
-
expect(futures.length).toBe(2);
|
|
251
|
-
|
|
252
|
-
// Add the first intention to pendings
|
|
253
|
-
await msafeAccount.buildNextIntentionAndAddToPending();
|
|
254
|
-
pendings = await msafeAccount.pendingTransactions();
|
|
255
|
-
expect(pendings.length).toBe(1);
|
|
256
|
-
|
|
257
|
-
for (let i = 0; i < clients.length; i++) {
|
|
258
|
-
const msafe = clients[i].getMSafeAccount(msafeAccount.info);
|
|
259
|
-
await msafe.voteForTransaction(pendings[0].digest, pendings[0].payload);
|
|
260
|
-
}
|
|
261
|
-
pendings = await msafeAccount.pendingTransactions();
|
|
262
|
-
expect(pendings.length).toBe(1);
|
|
263
|
-
|
|
264
|
-
const res1 = await msafeAccount.executePendingTx(pendings[0]);
|
|
265
|
-
expect(res1.effects?.status.status).toBe('success');
|
|
266
|
-
|
|
267
|
-
// Process the transaction in the backend
|
|
268
|
-
const tx1Digest = pendings[0].digest;
|
|
269
|
-
await backend.processExecutedTransaction(pendings[0].digest);
|
|
270
|
-
pendings = await msafeAccount.pendingTransactions();
|
|
271
|
-
expect(pendings.length).toBe(0);
|
|
272
|
-
futures = await msafeAccount.futureIntentions();
|
|
273
|
-
expect(futures.length).toBe(1);
|
|
274
|
-
let history = await msafeAccount.historyTransaction();
|
|
275
|
-
const tx1History = history.find((hs) => hs.digest === tx1Digest);
|
|
276
|
-
expect(tx1History).toBeDefined();
|
|
277
|
-
expect(tx1History?.status).toBe('success');
|
|
278
|
-
|
|
279
|
-
// Build the next intention will fail. Then user can trigger the skip logic
|
|
280
|
-
await expect(msafeAccount.buildNextIntentionAndAddToPending()).rejects.toThrow();
|
|
281
|
-
futures = await msafeAccount.futureIntentions();
|
|
282
|
-
expect(futures.length).toBe(1);
|
|
283
|
-
expect(futures[0].status).toBe('failed');
|
|
284
|
-
expect(futures[0].statusRemark).toBeDefined();
|
|
285
|
-
|
|
286
|
-
// Skip the build failed transaction
|
|
287
|
-
await msafeAccount.skipNextFailedIntention();
|
|
288
|
-
futures = await msafeAccount.futureIntentions();
|
|
289
|
-
expect(futures.length).toBe(0);
|
|
290
|
-
history = await msafeAccount.historyTransaction();
|
|
291
|
-
const skipped = history.find((hs) => hs.sequenceNumber === nextSN);
|
|
292
|
-
expect(skipped).toBeDefined();
|
|
293
|
-
expect(skipped?.status).toBe('build-failed');
|
|
294
|
-
|
|
295
|
-
const nextSNAfter = await msafeAccount.nextSequenceNumber();
|
|
296
|
-
expect(nextSNAfter).toBe(nextSN + 1);
|
|
297
|
-
});
|
|
298
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { Uint8ArrayToHex, HexToUint8Array } from '@/utils/buffer';
|
|
2
|
-
|
|
3
|
-
describe('Hex Buffer conversion', () => {
|
|
4
|
-
it('should convert forth and back', () => {
|
|
5
|
-
const hex = '0x01020304050607080910aaff';
|
|
6
|
-
const buf = HexToUint8Array(hex);
|
|
7
|
-
const got = Uint8ArrayToHex(buf);
|
|
8
|
-
expect(hex).toEqual(got);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('should convert back and forth', () => {
|
|
12
|
-
const buf = new Uint8Array([0x12, 0x34, 0x56]);
|
|
13
|
-
const hexValue = Uint8ArrayToHex(buf);
|
|
14
|
-
const got = new Uint8Array(HexToUint8Array(hexValue));
|
|
15
|
-
expect(got).toEqual(buf);
|
|
16
|
-
});
|
|
17
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519';
|
|
2
|
-
|
|
3
|
-
import { PublicKeySerde, SignatureVerifier } from '@/utils/crypto';
|
|
4
|
-
|
|
5
|
-
import { LocalWallet } from '../../lib/account';
|
|
6
|
-
import { TESTNET_SUI_CLIENT } from '../../lib/config';
|
|
7
|
-
|
|
8
|
-
describe('verify', () => {
|
|
9
|
-
it('message', async () => {
|
|
10
|
-
const wallet = new LocalWallet(TESTNET_SUI_CLIENT);
|
|
11
|
-
const message = 'User login';
|
|
12
|
-
const sig = await wallet.signPersonalMessage({
|
|
13
|
-
messageStr: message,
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
const result = await SignatureVerifier.verifyPersonalSignature({
|
|
17
|
-
messageStr: message,
|
|
18
|
-
signature: sig.signature,
|
|
19
|
-
targetAddress: await wallet.address(),
|
|
20
|
-
});
|
|
21
|
-
expect(result).toBeTruthy();
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe('public key', () => {
|
|
26
|
-
it('ed25519', () => {
|
|
27
|
-
const publicKey = new Ed25519Keypair().getPublicKey();
|
|
28
|
-
const ser = PublicKeySerde.ser(publicKey);
|
|
29
|
-
const de = PublicKeySerde.de(ser);
|
|
30
|
-
expect(de.toSuiAddress()).toEqual(publicKey.toSuiAddress());
|
|
31
|
-
});
|
|
32
|
-
});
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { SignatureWithBytes } from '@mysten/sui.js/cryptography';
|
|
2
|
-
|
|
3
|
-
import { RawMultiSig } from '@/utils/multi-sig';
|
|
4
|
-
|
|
5
|
-
import { LocalWallet } from '../../lib/account';
|
|
6
|
-
import { TESTNET_SUI_CLIENT } from '../../lib/config';
|
|
7
|
-
|
|
8
|
-
describe('RawMultiSig', () => {
|
|
9
|
-
it('9/9 wallet', async () => {
|
|
10
|
-
const wallets = LocalWallet.createBatch(TESTNET_SUI_CLIENT, 9);
|
|
11
|
-
const ms = await createTestMultiSig(wallets, 9);
|
|
12
|
-
|
|
13
|
-
const message = 'Hello world';
|
|
14
|
-
const signatures = await Promise.all(wallets.map((wallet) => wallet.signPersonalMessage({ messageStr: message })));
|
|
15
|
-
const combinedSig = ms.combinePartialSignatures(signatures.map((sig) => sig.signature));
|
|
16
|
-
const result = await ms.verifyPersonalMessage(message, combinedSig);
|
|
17
|
-
expect(result).toBeTruthy();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('4/9 wallet', async () => {
|
|
21
|
-
const wallets = LocalWallet.createBatch(TESTNET_SUI_CLIENT, 9);
|
|
22
|
-
const ms = await createTestMultiSig(wallets, 4);
|
|
23
|
-
|
|
24
|
-
const message = 'Hello world';
|
|
25
|
-
const signatures: SignatureWithBytes[] = await Promise.all(
|
|
26
|
-
[wallets[1], wallets[3], wallets[5], wallets[7]].map((wallet) =>
|
|
27
|
-
wallet.signPersonalMessage({ messageStr: message }),
|
|
28
|
-
),
|
|
29
|
-
);
|
|
30
|
-
const combinedSig = ms.combinePartialSignatures(signatures.map((sig) => sig.signature));
|
|
31
|
-
const result = await ms.verifyPersonalMessage(message, combinedSig);
|
|
32
|
-
expect(result).toBeTruthy();
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
export async function createTestMultiSig(wallets: LocalWallet[], threshold: number) {
|
|
37
|
-
const publicKeys = await Promise.all(wallets.map((wallet) => wallet.publicKey()));
|
|
38
|
-
const msConfig = {
|
|
39
|
-
threshold,
|
|
40
|
-
ownerWithWeight: publicKeys.map((pk) => ({
|
|
41
|
-
publicKey: pk,
|
|
42
|
-
weight: 1,
|
|
43
|
-
})),
|
|
44
|
-
creationNonce: 0,
|
|
45
|
-
};
|
|
46
|
-
return new RawMultiSig(msConfig);
|
|
47
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { getPublicKeyFromChain } from '@/utils/sui';
|
|
2
|
-
|
|
3
|
-
import { TESTNET_SUI_CLIENT } from '../../lib/config';
|
|
4
|
-
|
|
5
|
-
describe('getPublicKeyFromChain', () => {
|
|
6
|
-
it('single signer', async () => {
|
|
7
|
-
const address = '0x25404f7631419c291644218c198af7e2599a8dbbeee248c82781db889534141b';
|
|
8
|
-
const pk = await getPublicKeyFromChain(TESTNET_SUI_CLIENT, address);
|
|
9
|
-
expect(pk).toBeDefined();
|
|
10
|
-
expect(pk?.toSuiAddress()).toBe(address);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('not found', async () => {
|
|
14
|
-
const address = '0x123123123';
|
|
15
|
-
const pk = await getPublicKeyFromChain(TESTNET_SUI_CLIENT, address);
|
|
16
|
-
expect(pk).toBeUndefined();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('multi-sig', async () => {
|
|
20
|
-
const address = '0xeabab6aa83af760fec754acbab0f10cf878651ac8705c295c88171b7a4260e36';
|
|
21
|
-
await expect(getPublicKeyFromChain(TESTNET_SUI_CLIENT, address)).rejects.toThrow(
|
|
22
|
-
'multi-sig wallet cannot be owner',
|
|
23
|
-
);
|
|
24
|
-
});
|
|
25
|
-
});
|