PHP WebShell
Текущая директория: /opt/BitGoJS/modules/bitgo/test/v2/integration
Просмотр файла: wallet.ts
//
// Tests for Wallets
//
import * as should from 'should';
import * as _ from 'lodash';
import * as nock from 'nock';
import { TestBitGo } from '../../lib/test_bitgo';
describe('V2 Wallet:', function () {
let bitgo;
let wallets;
let basecoin;
let wallet;
let sequenceId;
let walletAddress;
let walletAddressId;
// TODO: automate keeping test wallet full with bitcoin
// If failures are occurring, make sure that the wallet at test.bitgo.com contains bitcoin.
// The wallet is named Test Wallet, and its information is sometimes cleared from the test environment, causing
// many of these tests to fail. If that is the case, send it some bitcoin with at least 2 transactions
// to make sure the tests will pass.
before(async function () {
nock.restore();
bitgo = new TestBitGo({ env: 'test' });
bitgo.initializeTestVars();
basecoin = bitgo.coin('tbtc');
wallets = basecoin.wallets();
basecoin.keychains();
await bitgo.authenticateTestUser(bitgo.testUserOTP());
wallet = await wallets.getWallet({ id: TestBitGo.V2.TEST_WALLET1_ID });
const fundingVerificationBitgo = new TestBitGo({ env: 'test' });
fundingVerificationBitgo.initializeTestVars();
await fundingVerificationBitgo.checkFunded();
});
describe('Create Address', function () {
it('should create a new address', function () {
return wallet.createAddress({ label: 'test run address' }).then(function (newAddress) {
newAddress.should.have.property('address');
newAddress.should.have.property('coin');
newAddress.should.have.property('wallet');
newAddress.label.should.equal('test run address');
newAddress.wallet.should.equal(wallet._wallet.id);
newAddress.coin.should.equal(wallet._wallet.coin);
});
});
it('should create a new address from a listed wallet', async function () {
const { wallets: walletsListing } = await wallets.list();
// there is one known bad wallet with missing keychains. This will break this test, so filter it out
const wallet = _(walletsListing)
.filter((w) => w.id() !== '585cc6eb16efb0a50675fe4e3054662b')
.sample();
const { address } = await wallet.createAddress('listed wallet address');
basecoin.isValidAddress(address).should.be.True();
});
it('should create new addresses in bulk', async function () {
const result = await wallet.createAddress({ count: 3 });
result.should.have.property('addresses');
result.addresses.should.have.length(3);
_.forEach(result.addresses, (addr) => {
addr.should.have.property('id');
addr.should.have.property('address');
addr.should.have.property('chain');
addr.should.have.property('index');
addr.should.have.property('coin', wallet.coin());
addr.should.have.property('wallet', wallet.id());
addr.should.have.property('keychains');
});
});
it('should label a new address', async function () {
const originalAddress = await wallet.createAddress({ label: 'old_label' });
const postParams = { address: originalAddress.id, label: 'label_01' };
let updatedAddress = await wallet.updateAddress(postParams);
updatedAddress.label.should.equal('label_01');
postParams.address = originalAddress.address;
postParams.label = 'label_02';
updatedAddress = await wallet.updateAddress(postParams);
updatedAddress.label.should.equal('label_02');
});
it('should set gas price for a new address', async function () {
const address1 = await wallet.createAddress({ gasPrice: '12345' });
address1.chain.should.equal(10);
const address2 = await wallet.createAddress({ gasPrice: '123456789111315171921' });
address2.chain.should.equal(10);
const address3 = await wallet.createAddress({ gasPrice: 1234567 });
address3.chain.should.equal(10);
});
});
describe('List Unspents', function () {
it('unspents', function () {
return wallet.unspents().then(function (unspents) {
unspents.should.have.property('coin');
unspents.should.have.property('unspents');
unspents.unspents.length.should.be.greaterThan(2);
});
});
});
describe('List Addresses', function () {
it('addresses', function () {
return wallet.addresses().then(function (addresses) {
addresses.should.have.property('coin');
addresses.should.have.property('count');
addresses.should.have.property('addresses');
addresses.addresses.length.should.be.greaterThan(2);
walletAddress = (_.head(addresses.addresses) as any).address;
walletAddressId = (_.head(addresses.addresses) as any).id;
});
});
it('should get single address', function () {
return wallet.getAddress({ address: walletAddress }).then(function (address) {
address.should.have.property('coin');
address.should.have.property('wallet');
address.address.should.equal(walletAddress);
address.wallet.should.equal(wallet.id());
});
});
it('should get single address by id', function () {
return wallet.getAddress({ id: walletAddressId }).then(function (address) {
address.should.have.property('coin');
address.should.have.property('wallet');
address.address.should.equal(walletAddress);
address.id.should.equal(walletAddressId);
address.wallet.should.equal(wallet.id());
});
});
it('getbalances', function () {
// TODO server currently doesn't use this param
});
it('prevId', function () {
// TODO server currently doesn't use this param
});
});
describe('List Transactions', function () {
it('transactions', function () {
return wallet.transactions().then(function (transactions) {
transactions.should.have.property('coin');
transactions.should.have.property('transactions');
transactions.transactions.length.should.be.greaterThan(2);
const firstTransaction = transactions.transactions[0];
firstTransaction.should.have.property('date');
firstTransaction.should.have.property('entries');
firstTransaction.should.have.property('fee');
firstTransaction.should.have.property('hex');
firstTransaction.should.have.property('id');
firstTransaction.should.have.property('inputIds');
firstTransaction.should.have.property('inputs');
firstTransaction.should.have.property('outputs');
firstTransaction.should.have.property('size');
});
});
it('transactions with limit', function () {
return wallet.transactions({ limit: 2 }).then(function (transactions) {
transactions.should.have.property('coin');
transactions.should.have.property('transactions');
transactions.transactions.length.should.eql(2);
const firstTransaction = transactions.transactions[0];
firstTransaction.should.have.property('date');
firstTransaction.should.have.property('entries');
firstTransaction.should.have.property('fee');
firstTransaction.should.have.property('hex');
firstTransaction.should.have.property('id');
firstTransaction.should.have.property('inputIds');
firstTransaction.should.have.property('inputs');
firstTransaction.should.have.property('outputs');
firstTransaction.should.have.property('size');
});
});
it('should fetch transaction by id', function () {
return wallet
.getTransaction({ txHash: '96b2376fb0ccfdbcc9472489ca3ec75df1487b08a0ea8d9d82c55da19d8cceea' })
.then(function (transaction) {
transaction.should.have.property('id');
transaction.should.have.property('normalizedTxHash');
transaction.should.have.property('date');
transaction.should.have.property('blockHash');
transaction.should.have.property('blockHeight');
transaction.should.have.property('blockPosition');
transaction.should.have.property('confirmations');
transaction.should.have.property('fee');
transaction.should.have.property('feeString');
transaction.should.have.property('size');
transaction.should.have.property('inputIds');
transaction.should.have.property('inputs');
transaction.should.have.property('size');
});
});
it('should fail if not given a txHash', async function () {
try {
await wallet.getTransaction();
throw '';
} catch (error) {
error.message.should.equal('Missing parameter: txHash');
}
});
it('should fail if limit is negative', async function () {
try {
await wallet.getTransaction({
txHash: '96b2376fb0ccfdbcc9472489ca3ec75df1487b08a0ea8d9d82c55da19d8cceea',
limit: -1,
});
throw '';
} catch (error) {
error.message.should.equal('invalid limit argument, expecting positive integer');
}
});
});
describe('List Transfers', function () {
let lookupTransfer;
let wallet;
let thirdTransfer;
before(async function () {
wallet = await wallets.getWallet({ id: TestBitGo.V2.TEST_WALLET2_UNSPENTS_ID });
const transfers = await wallet.transfers();
transfers.should.have.property('transfers');
transfers.transfers.length.should.be.greaterThan(2);
thirdTransfer = transfers.transfers[2];
// need a confirmed transaction to ensure lookup works correctly
lookupTransfer = _(transfers.transfers)
.filter((t) => t.state === 'confirmed')
.sample();
});
it('transfers with limit and nextBatchPrevId', async function () {
const transfers = await wallet.transfers({ limit: 2 });
transfers.should.have.property('transfers');
transfers.transfers.length.should.eql(2);
const nextBatch = await wallet.transfers({ prevId: transfers.nextBatchPrevId });
nextBatch.should.have.property('transfers');
nextBatch.transfers.length.should.be.greaterThan(0);
nextBatch.transfers[0].id.should.eql(thirdTransfer.id);
});
// test is currently broken/flaky (BG-6378)
xit('transfers with a searchLabel', async function () {
const transfers = await wallet.transfers({ limit: 2, searchLabel: 'test' });
transfers.should.have.property('transfers');
transfers.transfers.length.should.eql(2);
});
it('get a transfer by id', async function () {
const transfer = await wallet.getTransfer({ id: lookupTransfer.id });
transfer.should.have.property('coin');
transfer.should.have.property('height');
transfer.should.have.property('txid');
transfer.id.should.eql(lookupTransfer.id);
});
it('update comment', async function () {
const result = await wallet.transfers();
const params = {
id: result.transfers[0].id,
comment: 'testComment',
};
const transfer = await wallet.transferComment(params);
transfer.should.have.property('comment');
transfer.comment.should.eql('testComment');
});
it('remove comment', async function () {
const result = await wallet.transfers();
const params = {
id: result.transfers[0].id,
comment: null,
};
const transfer = await wallet.transferComment(params);
transfer.should.have.property('comment');
transfer.comment.should.eql('');
});
});
describe('Prebuild Transactions', () => {
it('should retrieve offline verification data for transaction prebuilds, if requested', async function () {
const recipientAddress = await wallet.createAddress();
const params = {
recipients: [
{
amount: 0.01 * 1e8, // 0.01 tBTC
address: recipientAddress.address,
},
],
offlineVerification: true,
};
const prebuild = await wallet.prebuildTransaction(params);
prebuild.should.have.property('txInfo');
prebuild.txInfo.should.have.property('unspents');
prebuild.txInfo.should.have.property('txHexes');
const txIds = Object.keys(prebuild.txInfo.txHexes);
for (const unspent of prebuild.txInfo.unspents) {
txIds.some((txId) => unspent.id.split(':')[0] === txId).should.be.true();
}
});
});
describe('Send Transactions', function () {
// some of the tests will return the error "Error: transaction attempted to double spend",
// that occurs when the same unspent is selected different transactions, this is unlikely when
// first running the function, but if you need to run it multiple times, all unspents will
// be selected and used for pending transactions, and the tests will fail until there are available unspents.
before(async function () {
// TODO temporarily unlocking session to fix tests. Address unlock concept in BG-322.
await bitgo.unlock({ otp: bitgo.testUserOTP() });
});
it('should send transaction to the wallet itself with send', function () {
return wallet
.createAddress()
.delay(3000) // wait three seconds before sending
.then(function (recipientAddress) {
const params = {
amount: 0.01 * 1e8, // 0.01 tBTC
address: recipientAddress.address,
walletPassphrase: TestBitGo.V2.TEST_WALLET1_PASSCODE,
};
return wallet.send(params);
})
.then(function (transaction) {
transaction.should.have.property('status');
transaction.should.have.property('txid');
transaction.status.should.equal('signed');
});
});
it('should send transaction with sequence Id', async function () {
// Wait five seconds to send a new tx
await new Promise((resolve) => setTimeout(resolve, 5000));
sequenceId = Math.random().toString(36).slice(-10);
const recipientAddress = await wallet.createAddress();
const params = {
amount: 0.01 * 1e8, // 0.01 tBTC
address: recipientAddress.address,
walletPassphrase: TestBitGo.V2.TEST_WALLET1_PASSCODE,
sequenceId: sequenceId,
};
const transaction = await wallet.send(params);
transaction.should.have.property('status');
transaction.should.have.property('txid');
transaction.status.should.equal('signed');
});
it('should fetch a transfer by its sequence Id', async function () {
// Wait for worker to do its work
await new Promise((resolve) => setTimeout(resolve, 10000));
const transfer = await wallet.transferBySequenceId({ sequenceId: sequenceId });
transfer.should.have.property('sequenceId');
transfer.sequenceId.should.equal(sequenceId);
});
it('sendMany should error when given a non-array of recipients', async function () {
const recipientAddress = await wallet.createAddress();
const params = {
recipients: {
amount: 0.01 * 1e8, // 0.01 tBTC
address: recipientAddress.address,
},
walletPassphrase: TestBitGo.V2.TEST_WALLET1_PASSCODE,
};
await wallet.sendMany(params).should.be.rejected();
});
it('should send a transaction to the wallet itself with sendMany', function () {
return wallet
.createAddress()
.then(function (recipientAddress) {
const params = {
recipients: [
{
amount: 0.01 * 1e8, // 0.01 tBTC
address: recipientAddress.address,
},
],
walletPassphrase: TestBitGo.V2.TEST_WALLET1_PASSCODE,
};
return wallet.sendMany(params);
})
.then(function (transaction) {
transaction.should.have.property('status');
transaction.should.have.property('txid');
transaction.status.should.equal('signed');
});
});
it('should prebuild a transaction to the wallet', async function () {
const recipientAddress = await wallet.createAddress();
const params = {
recipients: [
{
amount: 0.01 * 1e8, // 0.01 tBTC
address: recipientAddress.address,
},
],
};
const prebuild = await wallet.prebuildTransaction(params);
const explanation = await basecoin.explainTransaction(prebuild);
explanation.displayOrder.length.should.equal(7);
explanation.outputs.length.should.equal(1);
// sometimes the change output is below the dust threshold and gets dumped to fees, so it may be missing
explanation.changeOutputs.length.should.be.within(0, 1);
explanation.outputAmount.should.equal(0.01 * 1e8);
explanation.outputs[0].amount.should.equal(0.01 * 1e8);
const chainhead = await bitgo.get(basecoin.url('/public/block/latest')).result();
explanation.locktime.should.equal(chainhead.height);
explanation.should.have.property('fee');
const transaction = await wallet.sendMany({
prebuildTx: prebuild,
walletPassphrase: TestBitGo.V2.TEST_WALLET1_PASSCODE,
comment: 'Hello World!',
txHex: 'should be overwritten',
});
transaction.should.have.property('status');
transaction.should.have.property('txid');
transaction.status.should.equal('signed');
});
it('should prebuild a transaction to the wallet and manually sign and submit it', function () {
let keychain;
return basecoin
.keychains()
.get({ id: wallet._wallet.keys[0] })
.then(function (key) {
keychain = key;
return wallet.createAddress();
})
.then(function (recipientAddress) {
const params = {
recipients: [
{
amount: 0.01 * 1e8, // 0.01 tBTC
address: recipientAddress.address,
},
],
};
return wallet.prebuildTransaction(params);
})
.then(function (prebuild) {
return wallet.signTransaction({
txPrebuild: prebuild,
key: keychain,
walletPassphrase: TestBitGo.V2.TEST_WALLET1_PASSCODE,
comment: 'Hello World!',
txHex: 'should be overwritten',
});
})
.then(function (signedTransaction) {
return wallet.submitTransaction(signedTransaction);
})
.then(function (transaction) {
transaction.should.have.property('status');
transaction.should.have.property('txid');
transaction.status.should.equal('signed');
});
});
});
// FIXME(BG-20416): test is failing
xdescribe('Sharing & Pending Approvals', function () {
let sharingUserBitgo;
let sharingUserBasecoin;
before(async function () {
sharingUserBitgo = new TestBitGo({ env: 'test' });
sharingUserBitgo.initializeTestVars();
sharingUserBasecoin = sharingUserBitgo.coin('tbtc');
await sharingUserBitgo.authenticateSharingTestUser(sharingUserBitgo.testUserOTP());
// clean up all incoming wallet shares for the sharing (shared-to) user
const activeShares = await sharingUserBasecoin.wallets().listShares({});
const cancelShare = (share) => sharingUserBasecoin.wallets().cancelShare({ walletShareId: share.id });
return Promise.all(_.map(activeShares.incoming, cancelShare));
});
it('should extend invitation from main user to sharing user', function () {
// take the main user wallet and invite this user
let share;
return wallet
.shareWallet({
email: TestBitGo.TEST_SHARED_KEY_USER,
permissions: 'view,spend,admin',
walletPassphrase: TestBitGo.V2.TEST_WALLET1_PASSCODE,
})
.then(function (shareDetails) {
share = shareDetails;
return sharingUserBitgo.unlock({ otp: sharingUserBitgo.testUserOTP() });
})
.then(function () {
return sharingUserBasecoin.wallets().acceptShare({
walletShareId: share.id,
userPassword: TestBitGo.TEST_SHARED_KEY_PASSWORD,
});
})
.then(function (acceptanceDetails) {
acceptanceDetails.should.have.property('changed');
acceptanceDetails.should.have.property('state');
acceptanceDetails.changed.should.equal(true);
acceptanceDetails.state.should.equal('accepted');
});
});
it('should have sharing user self-remove from accepted wallet and reject it', function () {
const receivedWalletId = wallet.id();
return sharingUserBasecoin
.wallets()
.list()
.then(function (sharedWallets) {
const receivedWallet = _.find(sharedWallets.wallets, function (w) {
return w.id() === receivedWalletId;
});
receivedWallet.should.have.property('_permissions');
receivedWallet._permissions.length.should.equal(3);
receivedWallet._permissions.should.containEql('admin');
receivedWallet._permissions.should.containEql('view');
receivedWallet._permissions.should.containEql('spend');
return receivedWallet.removeUser({ userId: sharingUserBitgo._user.id });
})
.then(function (removal) {
// this should require a pending approval
return basecoin.wallets().get({ id: receivedWalletId });
})
.then(function (updatedWallet) {
return updatedWallet.pendingApprovals();
})
.then(function (pendingApprovals) {
const pendingApproval = _.find(pendingApprovals, function (pa) {
return pa.wallet.id() === receivedWalletId;
});
pendingApproval.ownerType().should.equal('wallet');
should.exist(pendingApproval.walletId());
should.exist(pendingApproval.state());
should.exist(pendingApproval.creator());
should.exist(pendingApproval.info());
should.exist(pendingApproval.type());
should.exist(pendingApproval.approvalsRequired());
pendingApproval.approvalsRequired().should.equal(1);
return pendingApproval.reject();
})
.then(function (approval) {
approval.wallet.should.equal(receivedWalletId);
approval.state.should.equal('rejected');
});
});
it('should have sharing user self-remove from accepted wallet and approve it', function () {
const receivedWalletId = wallet.id();
return sharingUserBasecoin
.wallets()
.list()
.then(function (sharedWallets) {
const receivedWallet = _.find(sharedWallets.wallets, function (w) {
return w.id() === receivedWalletId;
});
return receivedWallet.removeUser({ userId: sharingUserBitgo._user.id });
})
.then(function (removal) {
// this should require a pending approval
return basecoin.wallets().get({ id: receivedWalletId });
})
.then(function (updatedWallet) {
return updatedWallet.pendingApprovals();
})
.then(function (pendingApprovals) {
const pendingApproval = _.find(pendingApprovals, function (pa) {
return pa.wallet.id() === receivedWalletId;
});
return pendingApproval.approve({ otp: bitgo.testUserOTP() });
})
.then(function (approval) {
approval.should.have.property('approvalsRequired');
approval.should.have.property('coin');
approval.should.have.property('creator');
approval.should.have.property('id');
approval.should.have.property('state');
approval.should.have.property('userIds');
approval.should.have.property('wallet');
approval.state.should.equal('approved');
approval.wallet.should.equal(receivedWalletId);
});
});
it('should share a wallet and then resend the wallet invite', async function () {
// share this wallet
const share = await wallet.shareWallet({
email: TestBitGo.TEST_SHARED_KEY_USER,
permissions: 'view',
walletPassphrase: TestBitGo.V2.TEST_WALLET1_PASSCODE,
});
// resend the wallet share invitation
const resendDetails = await basecoin.wallets().resendShareInvite({
walletShareId: share.id,
});
// should get back an object like this: { resent: true }
resendDetails.should.have.property('resent', true);
});
});
describe('Policies', function () {
let policyWallet;
before(async function () {
// create a throwaway wallet
const newWallet = await bitgo.coin('tltc').wallets().generateWallet({
label: 'Policy Testing Wallet',
passphrase: TestBitGo.V2.TEST_WALLET1_PASSCODE,
});
policyWallet = newWallet.wallet;
});
it('should create a velocity limit policy and then remove it', async function () {
const policyRuleWallet = await policyWallet.createPolicyRule({
action: {
type: 'getApproval',
},
condition: {
amountString: 100000,
groupTags: [':tag'],
timeWindow: 86400,
},
id: 'abcdef',
default: true,
type: 'velocityLimit',
});
const policyRules = policyRuleWallet.admin.policy.rules;
policyRules.length.should.equal(1);
const policyRule = policyRules[0];
policyRule.type.should.equal('velocityLimit');
policyRule.id.should.equal('abcdef');
policyRule.coin.should.equal('tltc');
policyRule.condition.amountString.should.equal('100000');
const updatedRuleWallet = await policyWallet.setPolicyRule({
action: {
type: 'getApproval',
},
condition: {
amountString: 50000,
groupTags: [':tag'],
timeWindow: 86400,
},
id: 'abcdef',
default: true,
type: 'velocityLimit',
});
const updatedRules = updatedRuleWallet.admin.policy.rules;
updatedRules.length.should.equal(1);
const updatedRule = updatedRules[0];
updatedRule.type.should.equal('velocityLimit');
updatedRule.id.should.equal('abcdef');
updatedRule.coin.should.equal('tltc');
updatedRule.condition.amountString.should.equal('50000');
const removalWallet = await policyWallet.removePolicyRule({
action: {
type: 'getApproval',
},
condition: {
amountString: 100000,
groupTags: [':tag'],
timeWindow: 86400,
},
id: 'abcdef',
default: true,
type: 'velocityLimit',
});
const newPolicyRules = removalWallet.admin.policy.rules;
newPolicyRules.length.should.equal(0);
});
after(async function () {
return policyWallet.remove();
});
});
describe('Unspent Manipulation', function () {
xit('should consolidate the number of unspents to 2, and fanout the number of unspents to 200', async function () {
const unspentWallet = await wallets.getWallet({ id: TestBitGo.V2.TEST_WALLET2_UNSPENTS_ID });
await bitgo.unlock({ otp: bitgo.testUserOTP() });
await new Promise((resolve) => setTimeout(resolve, 3000));
const params1 = {
limit: 250,
numUnspentsToMake: 2,
minValue: 1000,
numBlocks: 12,
walletPassphrase: TestBitGo.V2.TEST_WALLET2_UNSPENTS_PASSCODE,
};
const transaction1 = await unspentWallet.consolidateUnspents(params1);
transaction1.should.have.property('status');
transaction1.should.have.property('txid');
transaction1.status.should.equal('signed');
await new Promise((resolve) => setTimeout(resolve, 8000));
const unspentsResult1 = await unspentWallet.unspents({ limit: 1000 });
const numUnspents1 = unspentsResult1.unspents.length;
numUnspents1.should.equal(2);
await new Promise((resolve) => setTimeout(resolve, 6000));
const params2 = {
minHeight: 1,
maxNumInputsToUse: 80, // should be 2, but if a test were to fail and need to be rerun we want to use more of them
numUnspentsToMake: 20,
numBlocks: 12,
walletPassphrase: TestBitGo.V2.TEST_WALLET2_UNSPENTS_PASSCODE,
};
const transaction2 = await unspentWallet.fanoutUnspents(params2);
transaction2.should.have.property('status');
transaction2.should.have.property('txid');
transaction2.status.should.equal('signed');
await new Promise((resolve) => setTimeout(resolve, 8000));
const unspentsResult2 = await unspentWallet.unspents({ limit: 1000 });
const numUnspents2 = unspentsResult2.unspents.length;
numUnspents2.should.equal(20);
});
// TODO: change xit to it once the sweepWallet route is running on test, to run this integration test
xit('should sweep funds between two wallets', async function () {
const unspentWallet = await wallets.getWallet({ id: TestBitGo.V2.TEST_WALLET2_UNSPENTS_ID });
const sweep1Wallet = await wallets.getWallet({ id: TestBitGo.V2.TEST_SWEEP1_ID });
const sweep2Wallet = await wallets.getWallet({ id: TestBitGo.V2.TEST_SWEEP2_ID });
await bitgo.unlock({ otp: bitgo.testUserOTP() });
await new Promise((resolve) => setTimeout(resolve, 3000));
const params1 = {
address: TestBitGo.V2.TEST_SWEEP2_ADDRESS,
walletPassphrase: TestBitGo.V2.TEST_SWEEP1_PASSCODE,
};
const transaction1 = await sweep1Wallet.sweep(params1);
transaction1.should.have.property('status');
transaction1.should.have.property('txid');
transaction1.status.should.equal('signed');
await new Promise((resolve) => setTimeout(resolve, 8000));
const unspentsResult1 = await sweep1Wallet.unspents();
const numUnspents1 = unspentsResult1.unspents.length;
numUnspents1.should.equal(0);
const unspentsResult2 = await sweep2Wallet.unspents();
const numUnspents2 = unspentsResult2.unspents.length;
numUnspents2.should.equal(1);
// sweep funds back to starting wallet
const params2 = {
address: TestBitGo.V2.TEST_SWEEP1_ADDRESS,
walletPassphrase: TestBitGo.V2.TEST_SWEEP2_PASSCODE,
};
const transaction2 = await unspentWallet.sweep(params2);
transaction2.should.have.property('status');
transaction2.should.have.property('txid');
transaction2.status.should.equal('signed');
await new Promise((resolve) => setTimeout(resolve, 8000));
const unspentsResult3 = await sweep2Wallet.unspents();
const numUnspents3 = unspentsResult3.unspents.length;
numUnspents3.should.equal(0);
const unspentsResult4 = await sweep1Wallet.unspents();
const numUnspents4 = unspentsResult4.unspents.length;
numUnspents4.should.equal(1);
});
});
});
Выполнить команду
Для локальной разработки. Не используйте в интернете!