PHP WebShell
Текущая директория: /opt/BitGoJS/modules/sdk-coin-cspr/test/unit/lib/transactionBuilder
Просмотр файла: walletInitialization.ts
import assert from 'assert';
import should from 'should';
import { KeyPair, TransactionBuilderFactory } from '../../../../src/lib';
import * as testData from '../../../fixtures/resources';
import { TransactionType } from '@bitgo/sdk-core';
import { Transaction } from '../../../../src/lib/transaction';
import { verifySignature } from '../../../../src/lib/utils';
import { CLString } from 'casper-js-sdk';
import { coins } from '@bitgo/statics';
describe('CSPR Wallet initialization', () => {
const factory = new TransactionBuilderFactory(coins.get('tcspr'));
const owner1Address = new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress();
const owner2Address = new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress();
const owner3Address = new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress();
const owner4Address = new KeyPair({ pub: testData.ACCOUNT_4.publicKey }).getAddress();
const sourceAddress = new KeyPair({ pub: testData.ROOT_ACCOUNT.publicKey }).getAddress();
const initSignedTxBuilder = () => {
const txBuilder = initUnsignedTxBuilder();
txBuilder.sign({ key: testData.ROOT_ACCOUNT.privateKey });
return txBuilder;
};
const initSignedTxBuilderWithExtendedKey = () => {
const txBuilder = initUnsignedTxBuilder();
txBuilder.sign({ key: testData.ROOT_ACCOUNT.xPrivateKey });
return txBuilder;
};
const initUnsignedTxBuilder = () => {
const txBuilder = factory.getWalletInitializationBuilder();
txBuilder.fee(testData.FEE);
txBuilder.owner(owner1Address);
txBuilder.owner(owner2Address);
txBuilder.owner(owner3Address);
txBuilder.source({ address: sourceAddress });
return txBuilder;
};
describe('should build ', () => {
it('an init transaction', async () => {
const txBuilder = initSignedTxBuilder();
const tx = await txBuilder.build();
const txJson = tx.toJson();
should.deepEqual(txJson.fee, testData.FEE);
should.deepEqual(tx.signature.length, 1);
should.doesNotThrow(() => verifySignature(tx.signature[0], txJson.hash, testData.ROOT_ACCOUNT.publicKey));
should.equal(txJson.from, sourceAddress);
tx.type.should.equal(TransactionType.WalletInitialization);
});
it('an init transaction using extended key to sign', async () => {
const txBuilder = initSignedTxBuilderWithExtendedKey();
const tx = await txBuilder.build();
const txJson = tx.toJson();
should.deepEqual(txJson.fee, testData.FEE);
should.deepEqual(tx.signature.length, 1);
should.doesNotThrow(() => verifySignature(tx.signature[0], txJson.hash, testData.ROOT_ACCOUNT.publicKey));
should.equal(txJson.from, sourceAddress);
tx.type.should.equal(TransactionType.WalletInitialization);
});
it('an init transaction with external signature', async () => {
const txBuilder = factory.getWalletInitializationBuilder();
txBuilder.fee(testData.FEE);
txBuilder.owner(owner1Address);
txBuilder.owner(owner2Address);
txBuilder.owner(owner3Address);
txBuilder.source({ address: sourceAddress });
txBuilder.signature(
testData.EXTERNAL_SIGNATURE.signature,
new KeyPair({ pub: testData.EXTERNAL_SIGNATURE.publicKey })
);
const tx = await txBuilder.build();
const txJson = tx.toJson();
should.equal(txJson.from, sourceAddress);
});
it('an init transaction with external signature included twice', async () => {
const txBuilder = factory.getWalletInitializationBuilder();
txBuilder.fee(testData.FEE);
txBuilder.owner(owner1Address);
txBuilder.owner(owner2Address);
txBuilder.owner(owner3Address);
txBuilder.source({ address: sourceAddress });
txBuilder.signature(
testData.EXTERNAL_SIGNATURE.signature,
new KeyPair({ pub: testData.EXTERNAL_SIGNATURE.publicKey })
);
txBuilder.signature(
testData.EXTERNAL_SIGNATURE.signature,
new KeyPair({ pub: testData.EXTERNAL_SIGNATURE.publicKey })
);
const tx = await txBuilder.build();
const txJson = tx.toJson();
should.equal(txJson.from, sourceAddress);
});
});
describe('should fail to build', () => {
const factory = new TransactionBuilderFactory(coins.get('tcspr'));
it('a transaction without fee', async () => {
const txBuilder = factory.getWalletInitializationBuilder();
txBuilder.owner(owner1Address);
txBuilder.owner(owner2Address);
txBuilder.owner(owner3Address);
txBuilder.source({ address: sourceAddress });
await txBuilder.build().should.be.rejectedWith(testData.INVALID_TRANSACTION_MISSING_FEE);
});
it('a wallet initialization the wrong number of owners', async () => {
const txBuilder = factory.getWalletInitializationBuilder();
txBuilder.fee(testData.FEE);
txBuilder.owner(owner1Address);
txBuilder.owner(owner2Address);
txBuilder.source({ address: sourceAddress });
await txBuilder.build().should.be.rejectedWith(testData.INVALID_NUMBER_OF_OWNERS_TWO_OF_THREE);
assert.throws(() => txBuilder.owner(owner1Address), 'Repeated owner address: ' + owner1Address);
should.doesNotThrow(() => txBuilder.owner(owner3Address));
assert.throws(() => txBuilder.owner(owner4Address), /A maximum of 3 owners can be set for a multisig wallet/);
const newTxBuilder = factory.getWalletInitializationBuilder();
newTxBuilder.fee(testData.FEE);
txBuilder.source({ address: sourceAddress });
await newTxBuilder.build().should.be.rejectedWith(testData.INVALID_TRANSACTION_MISSING_OWNERS);
});
it('a transaction with invalid source', async () => {
const factory = new TransactionBuilderFactory(coins.get('thbar'));
const txBuilder = factory.getWalletInitializationBuilder();
txBuilder.fee(testData.FEE);
txBuilder.owner(owner1Address);
txBuilder.owner(owner2Address);
txBuilder.owner(owner3Address);
await txBuilder.build().should.be.rejectedWith(testData.INVALID_TRANSACTION_MISSING_SOURCE);
});
});
describe('should validate', () => {
const factory = new TransactionBuilderFactory(coins.get('tcspr'));
it('an address', async () => {
const txBuilder = factory.getWalletInitializationBuilder();
txBuilder.validateAddress({ address: testData.VALID_ADDRESS });
assert.throws(
() => txBuilder.validateAddress({ address: testData.INVALID_ADDRESS }),
new RegExp('Invalid address ' + testData.INVALID_ADDRESS)
);
});
it('value should be greater than zero', () => {
const txBuilder = factory.getWalletInitializationBuilder();
assert.throws(() => txBuilder.fee({ gasLimit: '-10' }));
should.doesNotThrow(() => txBuilder.fee({ gasLimit: '10' }));
});
it('a private key', () => {
const txBuilder = factory.getWalletInitializationBuilder();
assert.throws(() => txBuilder.validateKey({ key: 'abc' }), /Unsupported private key/);
should.doesNotThrow(() => txBuilder.validateKey({ key: testData.ACCOUNT_1.privateKey }));
});
it('a transaction to build', async () => {
const txBuilder = factory.getWalletInitializationBuilder();
assert.throws(() => txBuilder.validateTransaction(), /Invalid transaction: missing wallet owners/);
txBuilder.fee(testData.FEE);
assert.throws(() => txBuilder.validateTransaction(), /Invalid transaction: missing wallet owners/);
txBuilder.source({ address: testData.VALID_ADDRESS });
assert.throws(() => txBuilder.validateTransaction(), /Invalid transaction: missing wallet owners/);
txBuilder.owner(new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress());
assert.throws(() => txBuilder.validateTransaction(), /wrong number of owners -- required: 3, found: 1/);
txBuilder.owner(new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress());
assert.throws(() => txBuilder.validateTransaction(), /wrong number of owners -- required: 3, found: 2/);
txBuilder.owner(new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress());
should.doesNotThrow(() => txBuilder.validateTransaction());
});
});
describe('should build from', () => {
describe('serialized transactions', () => {
it('a non signed transfer transaction from serialized', async () => {
const builder = initUnsignedTxBuilder();
const tx = (await builder.build()) as Transaction;
const txJson = tx.toJson();
should.equal((tx.casperTx.session.getArgByName('deploy_type') as CLString).value(), 'WalletInitialization');
should.equal(
(tx.casperTx.session.getArgByName('owner_0') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress()
);
should.equal(
(tx.casperTx.session.getArgByName('owner_1') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress()
);
should.equal(
(tx.casperTx.session.getArgByName('owner_2') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress()
);
const builder2 = factory.getWalletInitializationBuilder();
builder2.from(tx.toBroadcastFormat());
const tx2 = (await builder2.build()) as Transaction;
const tx2Json = tx2.toJson();
should.equal((tx2.casperTx.session.getArgByName('deploy_type') as CLString).value(), 'WalletInitialization');
should.equal(
(tx2.casperTx.session.getArgByName('owner_0') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress()
);
should.equal(
(tx2.casperTx.session.getArgByName('owner_1') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress()
);
should.equal(
(tx2.casperTx.session.getArgByName('owner_2') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress()
);
should.deepEqual(tx2Json, txJson, 'from implementation from factory should recreate original transaction');
});
it('a signed transfer transaction from serialized', async () => {
const builder = initUnsignedTxBuilder();
builder.sign({ key: testData.ROOT_ACCOUNT.privateKey });
const tx = (await builder.build()) as Transaction;
const txJson = tx.toJson();
should.equal((tx.casperTx.session.getArgByName('deploy_type') as CLString).value(), 'WalletInitialization');
should.equal(
(tx.casperTx.session.getArgByName('owner_0') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress()
);
should.equal(
(tx.casperTx.session.getArgByName('owner_1') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress()
);
should.equal(
(tx.casperTx.session.getArgByName('owner_2') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress()
);
const builder2 = factory.getWalletInitializationBuilder();
builder2.from(tx.toBroadcastFormat());
const tx2 = (await builder2.build()) as Transaction;
const tx2Json = tx2.toJson();
should.equal((tx2.casperTx.session.getArgByName('deploy_type') as CLString).value(), 'WalletInitialization');
should.equal(
(tx2.casperTx.session.getArgByName('owner_0') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress()
);
should.equal(
(tx2.casperTx.session.getArgByName('owner_1') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress()
);
should.equal(
(tx2.casperTx.session.getArgByName('owner_2') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress()
);
should.deepEqual(tx2Json, txJson, 'from implementation from factory should recreate original transaction');
should.deepEqual(
tx2.casperTx.approvals,
tx.casperTx.approvals,
'from implementation from factory should get approvals correctly'
);
});
it('a signed transfer transaction with extended key from serialized', async () => {
const builder = initUnsignedTxBuilder();
builder.sign({ key: testData.ROOT_ACCOUNT.xPrivateKey });
const tx = (await builder.build()) as Transaction;
const txJson = tx.toJson();
should.equal((tx.casperTx.session.getArgByName('deploy_type') as CLString).value(), 'WalletInitialization');
should.equal(
(tx.casperTx.session.getArgByName('owner_0') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress()
);
should.equal(
(tx.casperTx.session.getArgByName('owner_1') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress()
);
should.equal(
(tx.casperTx.session.getArgByName('owner_2') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress()
);
const builder2 = factory.getWalletInitializationBuilder();
builder2.from(tx.toBroadcastFormat());
const tx2 = (await builder2.build()) as Transaction;
const tx2Json = tx2.toJson();
should.equal((tx2.casperTx.session.getArgByName('deploy_type') as CLString).value(), 'WalletInitialization');
should.equal(
(tx2.casperTx.session.getArgByName('owner_0') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress()
);
should.equal(
(tx2.casperTx.session.getArgByName('owner_1') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress()
);
should.equal(
(tx2.casperTx.session.getArgByName('owner_2') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress()
);
should.deepEqual(tx2Json, txJson, 'from implementation from factory should recreate original transaction');
should.deepEqual(
tx2.casperTx.approvals,
tx.casperTx.approvals,
'from implementation from factory should get approvals correctly'
);
});
it('an offline multisig transfer transaction', async () => {
const builder = initUnsignedTxBuilder();
builder.sign({ key: testData.ROOT_ACCOUNT.privateKey });
builder.sign({ key: testData.ACCOUNT_1.privateKey });
const tx = (await builder.build()) as Transaction;
const txJson = tx.toJson();
should.equal((tx.casperTx.session.getArgByName('deploy_type') as CLString).value(), 'WalletInitialization');
should.equal(
(tx.casperTx.session.getArgByName('owner_0') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress()
);
should.equal(
(tx.casperTx.session.getArgByName('owner_1') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress()
);
should.equal(
(tx.casperTx.session.getArgByName('owner_2') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress()
);
const builder2 = factory.getWalletInitializationBuilder();
builder2.from(tx.toBroadcastFormat());
const tx2 = (await builder2.build()) as Transaction;
const tx2Json = tx2.toJson();
should.equal((tx2.casperTx.session.getArgByName('deploy_type') as CLString).value(), 'WalletInitialization');
should.equal(
(tx2.casperTx.session.getArgByName('owner_0') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress()
);
should.equal(
(tx2.casperTx.session.getArgByName('owner_1') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress()
);
should.equal(
(tx2.casperTx.session.getArgByName('owner_2') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress()
);
should.deepEqual(tx2Json, txJson, 'from implementation from factory should recreate original transaction');
should.deepEqual(
tx2.casperTx.approvals,
tx.casperTx.approvals,
'from implementation from factory should get approvals correctly'
);
});
it('an offline multisig transfer transaction using extended keys', async () => {
const builder = initUnsignedTxBuilder();
builder.sign({ key: testData.ROOT_ACCOUNT.xPrivateKey });
builder.sign({ key: testData.ACCOUNT_1.xPrivateKey });
const tx = (await builder.build()) as Transaction;
const txJson = tx.toJson();
should.equal((tx.casperTx.session.getArgByName('deploy_type') as CLString).value(), 'WalletInitialization');
should.equal(
(tx.casperTx.session.getArgByName('owner_0') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress()
);
should.equal(
(tx.casperTx.session.getArgByName('owner_1') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress()
);
should.equal(
(tx.casperTx.session.getArgByName('owner_2') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress()
);
const builder2 = factory.getWalletInitializationBuilder();
builder2.from(tx.toBroadcastFormat());
const tx2 = (await builder2.build()) as Transaction;
const tx2Json = tx2.toJson();
should.equal((tx2.casperTx.session.getArgByName('deploy_type') as CLString).value(), 'WalletInitialization');
should.equal(
(tx2.casperTx.session.getArgByName('owner_0') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress()
);
should.equal(
(tx2.casperTx.session.getArgByName('owner_1') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress()
);
should.equal(
(tx2.casperTx.session.getArgByName('owner_2') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress()
);
should.deepEqual(tx2Json, txJson, 'from implementation from factory should recreate original transaction');
should.deepEqual(
tx2.casperTx.approvals,
tx.casperTx.approvals,
'from implementation from factory should get approvals correctly'
);
});
it('an offline multisig transfer transaction using one extended key', async () => {
const builder = initUnsignedTxBuilder();
builder.sign({ key: testData.ROOT_ACCOUNT.xPrivateKey });
builder.sign({ key: testData.ACCOUNT_1.privateKey });
const tx = (await builder.build()) as Transaction;
const txJson = tx.toJson();
should.equal((tx.casperTx.session.getArgByName('deploy_type') as CLString).value(), 'WalletInitialization');
should.equal(
(tx.casperTx.session.getArgByName('owner_0') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress()
);
should.equal(
(tx.casperTx.session.getArgByName('owner_1') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress()
);
should.equal(
(tx.casperTx.session.getArgByName('owner_2') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress()
);
const builder2 = factory.getWalletInitializationBuilder();
builder2.from(tx.toBroadcastFormat());
const tx2 = (await builder2.build()) as Transaction;
const tx2Json = tx2.toJson();
should.equal((tx2.casperTx.session.getArgByName('deploy_type') as CLString).value(), 'WalletInitialization');
should.equal(
(tx2.casperTx.session.getArgByName('owner_0') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress()
);
should.equal(
(tx2.casperTx.session.getArgByName('owner_1') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress()
);
should.equal(
(tx2.casperTx.session.getArgByName('owner_2') as CLString).value(),
new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress()
);
should.deepEqual(tx2Json, txJson, 'from implementation from factory should recreate original transaction');
should.deepEqual(
tx2.casperTx.approvals,
tx.casperTx.approvals,
'from implementation from factory should get approvals correctly'
);
});
});
});
describe('txJson validation', () => {
it('contains all required fields for Wallet Initialization', async () => {
const txBuilder = initSignedTxBuilder();
const tx = (await txBuilder.build()) as Transaction;
const txJson = tx.toJson();
should.deepEqual(txJson.fee, testData.FEE);
should.equal(txJson.deployType, 'WalletInitialization');
should.equal(txJson.from, '02' + testData.ROOT_ACCOUNT.publicKey);
should.equal(txJson.hash, Buffer.from(tx.casperTx.hash).toString('hex'));
should.equal(txJson.owner1, new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress());
should.equal(txJson.owner2, new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress());
should.equal(txJson.owner3, new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress());
});
it('contains all required fields for Wallet Initialization using extended key to sign', async () => {
const txBuilder = initSignedTxBuilderWithExtendedKey();
const tx = (await txBuilder.build()) as Transaction;
const txJson = tx.toJson();
should.deepEqual(txJson.fee, testData.FEE);
should.equal(txJson.deployType, 'WalletInitialization');
should.equal(txJson.from, '02' + testData.ROOT_ACCOUNT.publicKey);
should.equal(txJson.hash, Buffer.from(tx.casperTx.hash).toString('hex'));
should.equal(txJson.owner1, new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress());
should.equal(txJson.owner2, new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress());
should.equal(txJson.owner3, new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress());
});
});
});
Выполнить команду
Для локальной разработки. Не используйте в интернете!