Skip to content

Commit

Permalink
remove addKey, add tests for key rotations, addKey (app key), sendMoney
Browse files Browse the repository at this point in the history
  • Loading branch information
mattlockyer committed Nov 8, 2020
1 parent 000c833 commit f96252f
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 49 deletions.
2 changes: 0 additions & 2 deletions lib/account_multisig.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 1 addition & 7 deletions lib/account_multisig.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 1 addition & 8 deletions src/account_multisig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,6 @@ export class AccountMultisig extends Account {
this.contract = <MultisigContract>getContract(this);
}

async addKey(publicKey: string | PublicKey, contractId?: string, methodName?: string, amount?: BN): Promise<FinalExecutionOutcome> {
if (contractId) {
return super.addKey(publicKey, contractId, MULTISIG_CHANGE_METHODS.join(), MULTISIG_ALLOWANCE)
}
return super.addKey(publicKey)
}

async signAndSendTransaction(receiverId: string, actions: Action[]): Promise<FinalExecutionOutcome> {
const { accountId } = this;

Expand All @@ -112,7 +105,7 @@ export class AccountMultisig extends Account {

const result = await this.promptAndVerify();
if (this.onResult) {
this.onResult(result);
await this.onResult(result);
}
return result
}
Expand Down
129 changes: 97 additions & 32 deletions test/account_multisig.test.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,65 @@

const nearApi = require('../lib/index');
const fs = require('fs');
const BN = require('bn.js');
const testUtils = require('./test-utils');
const semver = require('semver');

let nearjs;
let workingAccount;
let startFromVersion;


const { KeyPair } = nearApi;

const {
KeyPair,
transactions: { functionCall },
InMemorySigner,
keyStores: { InMemoryKeyStore },
multisig: { AccountMultisig, MULTISIG_GAS, MULTISIG_DEPOSIT },
utils: { format: { parseNearAmount } }
} = nearApi;

jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000;

const AccountMultisigInstance = async (account, keyMapping = ({ public_key: publicKey }) => ({ publicKey, kind: 'phone' })) => {
// modifiers to functions replaces contract helper (CH)
const { accountId } = account
const keys = await account.getAccessKeys()
const accountMultisig = new AccountMultisig(nearjs.connection, accountId, {
// skip this (not using CH)
getCode: () => {},
sendCode: () => {},
// auto accept "code"
verifyCode: () => ({ success: true, res: '' }),
onResult: async () => {
const { requestId } = accountMultisig.getRequest()
console.log('requestId', requestId)
// set confirmKey as signer
const originalSigner = nearjs.connection.signer
const tempKeyStore = new InMemoryKeyStore()
await tempKeyStore.setKey(nearjs.connection.networkId, accountId, accountMultisig.confirmKey)
nearjs.connection.signer = new InMemorySigner(tempKeyStore)
// 2nd confirmation signing with confirmKey from Account instance
await account.signAndSendTransaction(accountId, [
functionCall('confirm', { request_id: requestId }, MULTISIG_GAS, MULTISIG_DEPOSIT)
]);
nearjs.connection.signer = originalSigner
}
});
accountMultisig.confirmKey = KeyPair.fromRandom('ed25519')
accountMultisig.postSignedJson = () => ({ publicKey: accountMultisig.confirmKey.getPublicKey() });
accountMultisig.getRecoveryMethods = () => ({
data: keys.map(keyMapping)
});
try {
await accountMultisig.deployMultisig([...fs.readFileSync('./test/data/multisig.wasm')]);
} catch (e) {
console.log(e)
if (e.message.indexOf('Contract method is not found') === -1) {
throw(e);
}
}
return accountMultisig;
};

beforeAll(async () => {
nearjs = await testUtils.setUpTestConnection();
workingAccount = await testUtils.createAccountMultisig(nearjs, {
Expand All @@ -24,41 +70,60 @@ beforeAll(async () => {
console.log(startFromVersion);
});

test('view pre-defined account works and returns correct name', async () => {
let status = await workingAccount.state();
console.log(status);
expect(status.code_hash).toEqual('11111111111111111111111111111111');
});

describe('deployMultisig key rotations', () => {

test('skip access key if recovery method is "ledger"', async () => {
test('full access key if recovery method is "ledger" or "phrase"', async () => {
const account = await testUtils.createAccount(nearjs);
await account.addKey(KeyPair.fromRandom('ed25519').getPublicKey());
const originalKeys = await account.getAccessKeys();
const { multisig: { AccountMultisig } } = nearApi;
const accountMultisig = new AccountMultisig(nearjs.connection, account.accountId, {});
// modifiers to return the key material we want to test against
accountMultisig.getRecoveryMethods = () => ({
data: originalKeys.map(({ public_key: publicKey }, i) => ({ publicKey, kind: i > 0 ? 'ledger' : 'phrase' }))
});
accountMultisig.postSignedJson = () => ({
publicKey: KeyPair.fromRandom('ed25519').getPublicKey()
});
try {
await accountMultisig.deployMultisig([...fs.readFileSync('./test/data/main.wasm')]);
} catch (e) {
if (e.message.indexOf('Contract method is not found') === -1) {
throw(e);
}
}
const keys = await account.getAccessKeys()
const accountMultisig = await AccountMultisigInstance(
account,
({ public_key: publicKey }, i) => ({ publicKey, kind: i > 0 ? 'ledger' : 'phrase' })
);
const currentKeys = await accountMultisig.getAccessKeys();
expect(currentKeys.find(({ public_key }) => keys[0].public_key === public_key).access_key.permission).toEqual('FullAccess');
expect(currentKeys.find(({ public_key }) => keys[1].public_key === public_key).access_key.permission).toEqual('FullAccess');
});

test('access key if method is "phone"', async () => {
const account = await testUtils.createAccount(nearjs);
const keys = await account.getAccessKeys()
const accountMultisig = await AccountMultisigInstance(account);
const currentKeys = await accountMultisig.getAccessKeys();
expect(currentKeys.find(({ public_key }) => keys[0].public_key === public_key).access_key.permission).not.toEqual('FullAccess');
});

});

console.log(await accountMultisig.state());
describe('accountMultisig transactions', () => {

test('add app key', async() => {
let account = await testUtils.createAccount(nearjs);
account = await AccountMultisigInstance(account);
const appPublicKey = KeyPair.fromRandom('ed25519').getPublicKey()
const appMethodNames = ['some_app_stuff', 'some_more_app_stuff']
await account.addKey(appPublicKey, 'foobar', appMethodNames.join(), new BN(parseNearAmount('0.25')));
const keys = await account.getAccessKeys()
// console.log(keys.map((k) => ({
// publicKey: k.public_key,
// permission: k.access_key.permission,
// method_names: k.access_key.permission.FunctionCall.method_names
// })))
// console.log('appPublicKey', appPublicKey.toString())
expect(keys.find(({ public_key }) => appPublicKey.toString() === public_key)
.access_key.permission.FunctionCall.method_names).toEqual(appMethodNames);
});

const currentKeys = await accountMultisig.getAccessKeys();
expect(currentKeys[0].access_key.permission).toEqual('FullAccess');
expect(currentKeys[1].access_key.permission).toEqual('FullAccess');
test('send money', async() => {
let sender = await testUtils.createAccount(nearjs);
let receiver = await testUtils.createAccount(nearjs);
sender = await AccountMultisigInstance(sender);
receiver = await AccountMultisigInstance(receiver);
const { amount: receiverAmount } = await receiver.state();
await sender.sendMoney(receiver.accountId, new BN(parseNearAmount('1')));
await receiver.fetchState();
const state = await receiver.state();
expect(BigInt(state.amount)).toBeGreaterThanOrEqual(BigInt(new BN(receiverAmount).add(new BN(parseNearAmount('0.9'))).toString()));
});

});
Binary file added test/data/multisig.wasm
Binary file not shown.

0 comments on commit f96252f

Please sign in to comment.