PHP WebShell
Текущая директория: /opt/BitGoJS/modules/sdk-coin-near/test/unit
Просмотр файла: near.ts
import should = require('should');
import { TestBitGo, TestBitGoAPI } from '@bitgo/sdk-test';
import { BitGoAPI } from '@bitgo/sdk-api';
import { randomBytes } from 'crypto';
import {
rawTx,
accounts,
validatorContractAddress,
blockHash,
NearResponses,
keys,
accountInfo,
nonce,
ovcResponse,
} from '../fixtures/near';
import * as _ from 'lodash';
import * as sinon from 'sinon';
import { KeyPair, Near, TNear, Transaction } from '../../src';
import { getBuilderFactory } from './getBuilderFactory';
import { coins } from '@bitgo/statics';
describe('NEAR:', function () {
let bitgo: TestBitGoAPI;
let basecoin;
let newTxPrebuild;
let newTxParams;
const factory = getBuilderFactory('tnear');
const txPrebuild = {
txHex: rawTx.transfer.unsigned,
txInfo: {},
};
const txParams = {
recipients: [
{
address: '9f7b0675db59d19b4bd9c8c72eaabba75a9863d02b30115b8b3c3ca5c20f0254',
amount: '1000000000000000000000000',
},
],
};
before(function () {
bitgo = TestBitGo.decorate(BitGoAPI, { env: 'mock' });
bitgo.initializeTestVars();
bitgo.safeRegister('tnear', Near.createInstance);
bitgo.safeRegister('near', TNear.createInstance);
basecoin = bitgo.coin('tnear');
newTxPrebuild = () => {
return _.cloneDeep(txPrebuild);
};
newTxParams = () => {
return _.cloneDeep(txParams);
};
});
it('should retun the right info', function () {
const near = bitgo.coin('near');
const tnear = bitgo.coin('tnear');
near.getChain().should.equal('near');
near.getFamily().should.equal('near');
near.getFullName().should.equal('Near');
near.getBaseFactor().should.equal(1e24);
tnear.getChain().should.equal('tnear');
tnear.getFamily().should.equal('near');
tnear.getFullName().should.equal('Testnet Near');
tnear.getBaseFactor().should.equal(1e24);
});
describe('Sign Message', () => {
it('should be performed', async () => {
const keyPair = new KeyPair();
const messageToSign = Buffer.from(randomBytes(32)).toString('hex');
const signature = await basecoin.signMessage(keyPair.getKeys(), messageToSign);
keyPair.verifySignature(messageToSign, Uint8Array.from(signature)).should.equals(true);
});
it('should fail with missing private key', async () => {
const keyPair = new KeyPair({
pub: '7788327c695dca4b3e649a0db45bc3e703a2c67428fce360e61800cc4248f4f7',
}).getKeys();
const messageToSign = Buffer.from(randomBytes(32)).toString('hex');
await basecoin.signMessage(keyPair, messageToSign).should.be.rejectedWith('Invalid key pair options');
});
});
describe('Sign transaction', () => {
it('should sign transaction', async function () {
const signed = await basecoin.signTransaction({
txPrebuild: {
txHex: rawTx.transfer.unsigned,
},
pubs: [accounts.account1.publicKey],
prv: accounts.account1.secretKey,
});
signed.txHex.should.equal(rawTx.transfer.signed);
});
it('should fail to sign transaction with an invalid key', async function () {
try {
await basecoin.signTransaction({
txPrebuild: {
txHex: rawTx.transfer.unsigned,
},
pubs: [accounts.account2.publicKey],
prv: accounts.account1.secretKey,
});
} catch (e) {
should.equal(e.message, 'Private key cannot sign the transaction');
}
});
it('should fail to build transaction with missing params', async function () {
try {
await basecoin.signTransaction({
txPrebuild: {
txHex: rawTx.transfer.unsigned,
key: accounts.account1.publicKey,
},
prv: accounts.account1.secretKey,
});
} catch (e) {
should.notEqual(e, null);
}
});
});
describe('Generate wallet key pair: ', () => {
it('should generate key pair', () => {
const kp = basecoin.generateKeyPair();
basecoin.isValidPub(kp.pub).should.equal(true);
basecoin.isValidPrv(kp.prv).should.equal(true);
});
it('should generate key pair from seed', () => {
const seed = Buffer.from('9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60', 'hex');
const kp = basecoin.generateKeyPair(seed);
basecoin.isValidPub(kp.pub).should.equal(true);
basecoin.isValidPrv(kp.prv).should.equal(true);
});
});
describe('Verify transaction: ', () => {
const amount = '1000000';
const gas = '125000000000000';
it('should succeed to verify unsigned transaction in base64 encoding', async () => {
const txPrebuild = newTxPrebuild();
const txParams = newTxParams();
const verification = {};
const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild, verification });
isTransactionVerified.should.equal(true);
});
it('should succeed to verify signed transaction in base64 encoding', async () => {
const txPrebuild = {
txHex: rawTx.transfer.signed,
txInfo: {},
};
const txParams = newTxParams();
const verification = {};
const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild, verification });
isTransactionVerified.should.equal(true);
});
it('should fail verify transactions when have different recipients', async () => {
const txPrebuild = newTxPrebuild();
const txParams = {
recipients: [
{
address: '9f7b0675db59d19b4bd9c8c72eaabba75a9863d02b30115b8b3c3ca5c20f0254',
amount: '1000000000000000000000000',
},
{
address: '9f7b0675db59d19b4bd9c8c72eaabba75a9863d02b30115b8b3c3ca5c20f0254',
amount: '2000000000000000000000000',
},
],
};
const verification = {};
await basecoin
.verifyTransaction({ txParams, txPrebuild, verification })
.should.be.rejectedWith('Tx outputs does not match with expected txParams recipients');
});
it('should fail verify transactions when total amount does not match with expected total amount field', async () => {
const explainedTx = {
id: '5jTEPuDcMCeEgp1iyEbNBKsnhYz4F4c1EPDtRmxm3wCw',
displayOrder: ['outputAmount', 'changeAmount', 'outputs', 'changeOutputs', 'fee', 'type'],
outputAmount: '90000',
changeAmount: '0',
changeOutputs: [],
outputs: [
{
address: '9f7b0675db59d19b4bd9c8c72eaabba75a9863d02b30115b8b3c3ca5c20f0254',
amount: '1000000000000000000000000',
},
],
fee: {
fee: '',
},
type: 0,
};
const stub = sinon.stub(Transaction.prototype, 'explainTransaction');
const txPrebuild = newTxPrebuild();
const txParams = newTxParams();
const verification = {};
stub.returns(explainedTx);
await basecoin
.verifyTransaction({ txParams, txPrebuild, verification })
.should.be.rejectedWith('Tx total amount does not match with expected total amount field');
stub.restore();
});
it('should succeed to verify transaction in hex encoding', async () => {
const txParams = newTxParams();
const txPrebuild = newTxPrebuild();
const verification = {};
const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild, verification });
isTransactionVerified.should.equal(true);
});
it('should convert serialized hex string to base64', async function () {
const txParams = newTxParams();
const txPrebuild = newTxPrebuild();
const verification = {};
txPrebuild.txHex = Buffer.from(txPrebuild.txHex, 'base64').toString('hex');
const validTransaction = await basecoin.verifyTransaction({ txParams, txPrebuild, verification });
validTransaction.should.equal(true);
});
it('should verify when input `recipients` is absent', async function () {
const txParams = newTxParams();
txParams.recipients = undefined;
const txPrebuild = newTxPrebuild();
const validTransaction = await basecoin.verifyTransaction({ txParams, txPrebuild });
validTransaction.should.equal(true);
});
it('should fail verify when txHex is invalid', async function () {
const txParams = newTxParams();
txParams.recipients = undefined;
const txPrebuild = {};
await basecoin
.verifyTransaction({ txParams, txPrebuild })
.should.rejectedWith('missing required tx prebuild property txHex');
});
it('should succeed to verify transactions when recipients has extra data', async function () {
const txPrebuild = newTxPrebuild();
const txParams = newTxParams();
txParams.data = 'data';
const validTransaction = await basecoin.verifyTransaction({ txParams, txPrebuild });
validTransaction.should.equal(true);
});
it('should verify activate staking transaction', async function () {
const txBuilder = factory.getStakingActivateBuilder();
txBuilder
.amount(amount)
.gas(gas)
.sender(accounts.account1.address, accounts.account1.publicKey)
.receiverId(validatorContractAddress)
.recentBlockHash(blockHash.block1)
.nonce(1);
txBuilder.sign({ key: accounts.account1.secretKey });
const tx = await txBuilder.build();
const txToBroadcastFormat = tx.toBroadcastFormat();
const txPrebuild = {
txHex: txToBroadcastFormat,
};
const txParams = {
recipients: [
{
address: 'lavenderfive.pool.f863973.m0',
amount: '1000000',
},
],
};
const validTransaction = await basecoin.verifyTransaction({ txParams, txPrebuild });
validTransaction.should.equal(true);
});
it('should verify deactivate staking transaction', async function () {
const txBuilder = factory.getStakingDeactivateBuilder();
txBuilder
.amount(amount)
.gas(gas)
.sender(accounts.account1.address, accounts.account1.publicKey)
.receiverId(validatorContractAddress)
.recentBlockHash(blockHash.block1)
.nonce(1);
txBuilder.sign({ key: accounts.account1.secretKey });
const tx = await txBuilder.build();
const txToBroadcastFormat = tx.toBroadcastFormat();
const txPrebuild = {
txHex: txToBroadcastFormat,
};
const txParams = {
recipients: [],
};
const validTransaction = await basecoin.verifyTransaction({ txParams, txPrebuild });
validTransaction.should.equal(true);
});
it('should verify withdraw staking transaction', async function () {
const txBuilder = factory.getStakingWithdrawBuilder();
txBuilder
.amount(amount)
.gas(gas)
.sender(accounts.account1.address, accounts.account1.publicKey)
.receiverId(validatorContractAddress)
.recentBlockHash(blockHash.block1)
.nonce(1);
txBuilder.sign({ key: accounts.account1.secretKey });
const tx = await txBuilder.build();
const txToBroadcastFormat = tx.toBroadcastFormat();
const txPrebuild = {
txHex: txToBroadcastFormat,
};
const txParams = {
recipients: [
{
address: '61b18c6dc02ddcabdeac56cb4f21a971cc41cc97640f6f85b073480008c53a0d',
amount: '1000000',
},
],
};
const validTransaction = await basecoin.verifyTransaction({ txParams, txPrebuild });
validTransaction.should.equal(true);
});
});
describe('Explain Transactions:', () => {
const amount = '1000000';
const gas = '125000000000000';
it('should explain an unsigned transfer transaction', async function () {
const explainedTransaction = await basecoin.explainTransaction({
txPrebuild: {
txHex: rawTx.transfer.signed,
},
});
explainedTransaction.should.deepEqual({
displayOrder: ['outputAmount', 'changeAmount', 'outputs', 'changeOutputs', 'fee', 'type'],
id: '5jTEPuDcMCeEgp1iyEbNBKsnhYz4F4c1EPDtRmxm3wCw',
type: 0,
changeOutputs: [],
changeAmount: '0',
outputAmount: '1000000000000000000000000',
outputs: [
{
address: '9f7b0675db59d19b4bd9c8c72eaabba75a9863d02b30115b8b3c3ca5c20f0254',
amount: '1000000000000000000000000',
},
],
fee: {
fee: '',
},
});
});
it('should explain a signed transfer transaction', async function () {
const explainedTransaction = await basecoin.explainTransaction({
txPrebuild: {
txHex: rawTx.transfer.signed,
},
});
explainedTransaction.should.deepEqual({
displayOrder: ['outputAmount', 'changeAmount', 'outputs', 'changeOutputs', 'fee', 'type'],
id: '5jTEPuDcMCeEgp1iyEbNBKsnhYz4F4c1EPDtRmxm3wCw',
type: 0,
changeOutputs: [],
changeAmount: '0',
outputAmount: '1000000000000000000000000',
outputs: [
{
address: '9f7b0675db59d19b4bd9c8c72eaabba75a9863d02b30115b8b3c3ca5c20f0254',
amount: '1000000000000000000000000',
},
],
fee: {
fee: '',
},
});
});
it('should explain activate staking transaction', async function () {
const txBuilder = factory.getStakingActivateBuilder();
txBuilder
.amount(amount)
.gas(gas)
.sender(accounts.account1.address, accounts.account1.publicKey)
.receiverId(validatorContractAddress)
.recentBlockHash(blockHash.block1)
.nonce(1);
txBuilder.sign({ key: accounts.account1.secretKey });
const tx = await txBuilder.build();
const txToBroadcastFormat = tx.toBroadcastFormat();
const explainedTransaction = await basecoin.explainTransaction({
txPrebuild: {
txHex: txToBroadcastFormat,
},
});
explainedTransaction.should.deepEqual({
displayOrder: ['outputAmount', 'changeAmount', 'outputs', 'changeOutputs', 'fee', 'type'],
id: 'GpiLLaGs2Fk2bd7SQvhkJaZjj74UnPPdF7cUa9pw15je',
type: 13,
changeOutputs: [],
changeAmount: '0',
outputAmount: '1000000',
outputs: [
{
address: 'lavenderfive.pool.f863973.m0',
amount: '1000000',
},
],
fee: {
fee: '',
},
});
});
it('should explain deactivate staking transaction', async function () {
const txBuilder = factory.getStakingDeactivateBuilder();
txBuilder
.amount(amount)
.gas(gas)
.sender(accounts.account1.address, accounts.account1.publicKey)
.receiverId(validatorContractAddress)
.recentBlockHash(blockHash.block1)
.nonce(1);
txBuilder.sign({ key: accounts.account1.secretKey });
const tx = await txBuilder.build();
const txToBroadcastFormat = tx.toBroadcastFormat();
const explainedTransaction = await basecoin.explainTransaction({
txPrebuild: {
txHex: txToBroadcastFormat,
},
});
explainedTransaction.should.deepEqual({
displayOrder: ['outputAmount', 'changeAmount', 'outputs', 'changeOutputs', 'fee', 'type'],
id: 'CDxPRP3DgHN8gYmRDagk5TRuX7fsCRYHcuqoNULyQPUW',
type: 17,
changeOutputs: [],
changeAmount: '0',
outputAmount: '0',
outputs: [],
fee: {
fee: '',
},
});
});
it('should explain withdraw staking transaction', async function () {
const txBuilder = factory.getStakingWithdrawBuilder();
txBuilder
.amount(amount)
.gas(gas)
.sender(accounts.account1.address, accounts.account1.publicKey)
.receiverId(validatorContractAddress)
.recentBlockHash(blockHash.block1)
.nonce(1);
txBuilder.sign({ key: accounts.account1.secretKey });
const tx = await txBuilder.build();
const txToBroadcastFormat = tx.toBroadcastFormat();
const explainedTransaction = await basecoin.explainTransaction({
txPrebuild: {
txHex: txToBroadcastFormat,
},
});
explainedTransaction.should.deepEqual({
displayOrder: ['outputAmount', 'changeAmount', 'outputs', 'changeOutputs', 'fee', 'type'],
id: '52ZX8MUwmYc6WQ67riUBpmntkcSxxT5aKkJYt5CtCZub',
type: 15,
changeOutputs: [],
changeAmount: '0',
outputAmount: '1000000',
outputs: [
{
address: '61b18c6dc02ddcabdeac56cb4f21a971cc41cc97640f6f85b073480008c53a0d',
amount: '1000000',
},
],
fee: {
fee: '',
},
});
});
it('should fail to explain transaction with missing params', async function () {
try {
await basecoin.explainTransaction({
txPrebuild: {},
});
} catch (error) {
should.equal(error.message, 'Invalid transaction');
}
});
it('should fail to explain transaction with wrong params', async function () {
try {
await basecoin.explainTransaction({
txPrebuild: {
txHex: 'invalidTxHex',
},
});
} catch (error) {
should.equal(error.message, 'Invalid transaction');
}
});
});
describe('Parse Transactions:', () => {
const TEN_MILLION_NEAR = '10000000000000000000000000000000';
const ONE_MILLION_NEAR = '1000000000000000000000000';
const amount = TEN_MILLION_NEAR;
const gas = '125000000000000';
const response1 = {
address: '9f7b0675db59d19b4bd9c8c72eaabba75a9863d02b30115b8b3c3ca5c20f0254',
amount: ONE_MILLION_NEAR,
};
const response2 = {
address: 'lavenderfive.pool.f863973.m0',
amount: TEN_MILLION_NEAR,
};
const response3 = {
address: '61b18c6dc02ddcabdeac56cb4f21a971cc41cc97640f6f85b073480008c53a0d',
amount: TEN_MILLION_NEAR,
};
it('should parse an unsigned transfer transaction', async function () {
const parsedTransaction = await basecoin.parseTransaction({
txPrebuild: {
txHex: rawTx.transfer.unsigned,
},
feeInfo: {
fee: '5000',
},
});
parsedTransaction.should.deepEqual({
inputs: [response1],
outputs: [response1],
});
});
it('should parse a signed transfer transaction', async function () {
const parsedTransaction = await basecoin.parseTransaction({
txPrebuild: {
txHex: rawTx.transfer.signed,
},
feeInfo: {
fee: '',
},
});
parsedTransaction.should.deepEqual({
inputs: [response1],
outputs: [response1],
});
});
it('should fail parse a signed transfer transaction when explainTransaction response is undefined', async function () {
const stub = sinon.stub(Near.prototype, 'explainTransaction');
stub.resolves(undefined);
await basecoin
.parseTransaction({
txPrebuild: {
txHex: rawTx.transfer.signed,
},
feeInfo: {
fee: '',
},
})
.should.be.rejectedWith('Invalid transaction');
stub.restore();
});
it('should parse activate staking transaction', async function () {
const txBuilder = factory.getStakingActivateBuilder();
txBuilder
.amount(amount)
.gas(gas)
.sender(accounts.account1.address, accounts.account1.publicKey)
.receiverId(validatorContractAddress)
.recentBlockHash(blockHash.block1)
.nonce(1);
txBuilder.sign({ key: accounts.account1.secretKey });
const tx = await txBuilder.build();
const txToBroadcastFormat = tx.toBroadcastFormat();
const parsedTransaction = await basecoin.parseTransaction({
txPrebuild: {
txHex: txToBroadcastFormat,
},
});
parsedTransaction.should.deepEqual({
inputs: [response2],
outputs: [response2],
});
});
it('should parse deactivate staking transaction', async function () {
const txBuilder = factory.getStakingDeactivateBuilder();
txBuilder
.amount(amount)
.gas(gas)
.sender(accounts.account1.address, accounts.account1.publicKey)
.receiverId(validatorContractAddress)
.recentBlockHash(blockHash.block1)
.nonce(1);
txBuilder.sign({ key: accounts.account1.secretKey });
const tx = await txBuilder.build();
const txToBroadcastFormat = tx.toBroadcastFormat();
const parsedTransaction = await basecoin.parseTransaction({
txPrebuild: {
txHex: txToBroadcastFormat,
},
});
parsedTransaction.should.deepEqual({
inputs: [],
outputs: [],
});
});
it('should parse withdraw staking transaction', async function () {
const txBuilder = factory.getStakingWithdrawBuilder();
txBuilder
.amount(amount)
.gas(gas)
.sender(accounts.account1.address, accounts.account1.publicKey)
.receiverId(validatorContractAddress)
.recentBlockHash(blockHash.block1)
.nonce(1);
txBuilder.sign({ key: accounts.account1.secretKey });
const tx = await txBuilder.build();
const txToBroadcastFormat = tx.toBroadcastFormat();
const parsedTransaction = await basecoin.parseTransaction({
txPrebuild: {
txHex: txToBroadcastFormat,
},
});
parsedTransaction.should.deepEqual({
inputs: [response3],
outputs: [response3],
});
});
});
describe('Recover Transactions:', () => {
const sandBox = sinon.createSandbox();
const coin = coins.get('tnear');
beforeEach(() => {
const callBack = sandBox.stub(Near.prototype, 'getDataFromNode' as keyof Near);
callBack
.withArgs({
payload: {
jsonrpc: '2.0',
id: 'dontcare',
method: 'query',
params: {
request_type: 'view_access_key',
finality: 'final',
account_id: accountInfo.accountId,
public_key: accountInfo.bs58EncodedPublicKey,
},
},
})
.resolves(NearResponses.getAccessKeyResponse);
callBack
.withArgs({
payload: {
jsonrpc: '2.0',
id: 'dontcare',
method: 'query',
params: {
request_type: 'view_account',
finality: 'final',
account_id: accountInfo.accountId,
},
},
})
.resolves(NearResponses.getAccountResponse);
callBack.withArgs().resolves(NearResponses.getProtocolConfigResp);
callBack
.withArgs({
payload: {
jsonrpc: '2.0',
id: 'dontcare',
method: 'gas_price',
params: [accountInfo.blockHash],
},
})
.resolves(NearResponses.getGasPriceResponse);
});
afterEach(() => {
sandBox.restore();
});
it('should recover a txn for non-bitgo recoveries', async function () {
const res = await basecoin.recover({
userKey: keys.userKey,
backupKey: keys.backupKey,
bitgoKey: keys.bitgoKey,
recoveryDestination: 'abhay-near.testnet',
walletPassphrase: 'Ghghjkg!455544llll',
});
res.should.not.be.empty();
res.should.hasOwnProperty('serializedTx');
const NonBitGoTxnDeserialize = new Transaction(coin);
NonBitGoTxnDeserialize.fromRawTransaction(res.serializedTx);
const NonBitGoTxnJson = NonBitGoTxnDeserialize.toJson();
should.equal(NonBitGoTxnJson.nonce, nonce);
should.equal(NonBitGoTxnJson.signerId, accountInfo.accountId);
should.equal(NonBitGoTxnJson.publicKey, 'ed25519:' + accountInfo.bs58EncodedPublicKey);
sandBox.assert.callCount(basecoin.getDataFromNode, 4);
});
it('should recover a txn for unsigned sweep recoveries', async function () {
const res = await basecoin.recover({
bitgoKey: keys.bitgoKey,
recoveryDestination: 'abhay-near.testnet',
});
// Assertions for the structure of the result
should.exist(res);
res.should.have.property('txRequests').which.is.an.Array();
res.txRequests[0].should.have.property('transactions').which.is.an.Array();
res.txRequests[0].transactions[0].should.have.property('unsignedTx');
// Assertions for the unsigned transaction
const unsignedTx = res.txRequests[0].transactions[0].unsignedTx;
unsignedTx.should.have.property('serializedTx').which.is.a.String();
unsignedTx.should.have.property('scanIndex', 0);
unsignedTx.should.have.property('coin', 'tnear');
unsignedTx.should.have.property(
'signableHex',
'c27d684b6f09c4b603d9bf8a08baedf12b8bb951f314acd747b16bb75cfbf687'
);
unsignedTx.should.have.property('derivationPath', 'm/0');
// Assertions for parsed transaction
const parsedTx = unsignedTx.parsedTx;
parsedTx.should.have.property('inputs').which.is.an.Array();
parsedTx.inputs[0].should.have.property(
'address',
'f256196dae617aa348149c1e61e997272492668d517506d7a6e2392e06ea532c'
);
parsedTx.inputs[0].should.have.property('valueString', '1.97885506094866269650000001e+26');
parsedTx.inputs[0].should.have.property('value', 1.9788550609486627e26);
parsedTx.should.have.property('outputs').which.is.an.Array();
parsedTx.outputs[0].should.have.property('address', 'abhay-near.testnet');
parsedTx.outputs[0].should.have.property('valueString', '1.97885506094866269650000001e+26');
parsedTx.outputs[0].should.have.property('coinName', 'tnear');
parsedTx.should.have.property('spendAmount', '1.97885506094866269650000001e+26');
parsedTx.should.have.property('type', '');
// Assertions for fee info
unsignedTx.should.have.property('feeInfo');
unsignedTx.feeInfo.should.have.property('fee', 68628637968750000000);
unsignedTx.feeInfo.should.have.property('feeString', '68628637968750000000');
// Assertions for coin-specific data
unsignedTx.should.have.property('coinSpecific');
unsignedTx.coinSpecific.should.have.property(
'commonKeychain',
'8699d2e05d60a3f7ab733a74ccf707f3407494b60f4253616187f5262e20737519a1763de0bcc4d165a7fa0e4dde67a1426ec4cc9fcd0820d749e6589dcfa08e'
);
});
it('should take OVC output and generate a signed sweep transaction for NEAR', async function () {
const params = ovcResponse; // NEAR-specific response fixture
const recoveryTxn = await basecoin.createBroadcastableSweepTransaction(params);
// Validate the serialized transaction
recoveryTxn.transactions[0].serializedTx.should.equal(
'QAAAAGIzODNjYWM2ZjNjZDY0OTViZDZhYjg3NzMwMGE4NzliN2RiYzRhMTZhYjBlZjE5NzlkZTZmNzNkYjAyNDlmYWEAs4PKxvPNZJW9arh3MAqHm328SharDvGXneb3PbAkn6oBuZUj6a0AAEAAAABlYWRiMzIwOGZiOWU5MWY2MGQ3NmUzYzUxNzEzZDA1Y2I0YTU5NDFlNWYzNTVlMWZmOThlMTQwYTcxMjNlODRl2hbJtC4rwLyWAbMzTgTcRmr5xpWlrXOXbzxMWcP7wwcBAAAAA9A1oVfvpz3o4hcAAAAAAAAAvAIWOj2c1QhqbWcClZ8dW7KQcfG9gYFkimbRDyI8t8L4TUiUyRXMYv5U8jaEsNFWteBcUGolFcLQSbbD5MCpDw=='
);
// Validate the scan index
recoveryTxn.transactions[0].scanIndex.should.equal(0);
recoveryTxn.lastScanIndex.should.equal(0);
});
});
describe('Recover Transactions for wallet with multiple addresses:', () => {
const destAddr = 'abhay-near.testnet';
const sandBox = sinon.createSandbox();
const coin = coins.get('tnear');
const address1Info = {
accountId: 'f6842bf4a8e980704fbd9fb799bfbe0a116fd5d8d06f6774e792c68c907d9b20',
bs58EncodedPublicKey: 'HbJBqyagBqtSNUR74fLMQSjQ8HyQVs66fyMySPhZLXz7',
blockHash: '844N9aWefd4TvJwdiBgXDVPz4W9z436kohTiXnp5y4fq',
};
beforeEach(function () {
const callBack = sandBox.stub(Near.prototype, 'getDataFromNode' as keyof Near);
callBack
.withArgs({
payload: {
jsonrpc: '2.0',
id: 'dontcare',
method: 'query',
params: {
request_type: 'view_access_key',
finality: 'final',
account_id: address1Info.accountId,
public_key: address1Info.bs58EncodedPublicKey,
},
},
})
.resolves(NearResponses.getAccessKeyResponse);
callBack
.withArgs({
payload: {
jsonrpc: '2.0',
id: 'dontcare',
method: 'query',
params: {
request_type: 'view_account',
finality: 'final',
account_id: accountInfo.accountId,
},
},
})
.resolves(NearResponses.getZeroBalanceAccountResponse);
callBack
.withArgs({
payload: {
jsonrpc: '2.0',
id: 'dontcare',
method: 'query',
params: {
request_type: 'view_account',
finality: 'final',
account_id: address1Info.accountId,
},
},
})
.resolves(NearResponses.getAccountResponse);
callBack.withArgs().resolves(NearResponses.getProtocolConfigResp);
callBack
.withArgs({
payload: {
jsonrpc: '2.0',
id: 'dontcare',
method: 'gas_price',
params: [address1Info.blockHash],
},
})
.resolves(NearResponses.getGasPriceResponse);
});
afterEach(function () {
sandBox.restore();
});
it('should recover a txn for non-bitgo recoveries at address 1 but search from address 0', async function () {
const res = await basecoin.recover({
userKey: keys.userKey,
backupKey: keys.backupKey,
bitgoKey: keys.bitgoKey,
recoveryDestination: destAddr,
walletPassphrase: 'Ghghjkg!455544llll',
});
res.should.not.be.empty();
res.should.hasOwnProperty('serializedTx');
res.should.hasOwnProperty('scanIndex');
res.scanIndex.should.equal(1);
sandBox.assert.callCount(basecoin.getDataFromNode, 5);
const tx = new Transaction(coin);
tx.fromRawTransaction(res.serializedTx);
const txJson = tx.toJson();
should.equal(txJson.nonce, nonce);
should.equal(txJson.signerId, address1Info.accountId);
should.equal(txJson.publicKey, 'ed25519:' + address1Info.bs58EncodedPublicKey);
});
it('should recover a txn for non-bitgo recoveries at address 1 but search from address 1', async function () {
const res = await basecoin.recover({
userKey: keys.userKey,
backupKey: keys.backupKey,
bitgoKey: keys.bitgoKey,
recoveryDestination: destAddr,
walletPassphrase: 'Ghghjkg!455544llll',
startingScanIndex: 1,
});
res.should.not.be.empty();
res.should.hasOwnProperty('serializedTx');
res.should.hasOwnProperty('scanIndex');
res.scanIndex.should.equal(1);
sandBox.assert.callCount(basecoin.getDataFromNode, 4);
const tx = new Transaction(coin);
tx.fromRawTransaction(res.serializedTx);
const txJson = tx.toJson();
should.equal(txJson.nonce, nonce);
should.equal(txJson.signerId, address1Info.accountId);
should.equal(txJson.publicKey, 'ed25519:' + address1Info.bs58EncodedPublicKey);
});
});
describe('Recover Transaction Failures:', () => {
const sandBox = sinon.createSandbox();
const destAddr = 'abhay-near.testnet';
const numIteration = 10;
beforeEach(function () {
const callBack = sandBox.stub(Near.prototype, 'getDataFromNode' as keyof Near);
callBack
.withArgs(sinon.match.hasNested('payload.method', 'EXPERIMENTAL_protocol_config'))
.resolves(NearResponses.getProtocolConfigResp);
callBack.resolves(NearResponses.getZeroBalanceAccountResponse);
});
afterEach(function () {
sandBox.restore();
});
it('should fail to recover due to not finding an address with funds', async function () {
await basecoin
.recover({
userKey: keys.userKey,
backupKey: keys.backupKey,
bitgoKey: keys.bitgoKey,
walletPassphrase: 'Ghghjkg!455544llll',
recoveryDestination: destAddr,
scan: numIteration,
})
.should.rejectedWith('Did not find an address with funds to recover');
// getDataFromNode should be called numIteration + 1 times since we initially
// call getProtocolConfig
sandBox.assert.callCount(basecoin.getDataFromNode, numIteration + 1);
});
});
});
Выполнить команду
Для локальной разработки. Не используйте в интернете!