@bitpay-labs/bitcore-wallet-service 11.6.6 → 11.7.0
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/package.json +22 -11
- package/src/externalservices/moonpay.ts +3 -0
- package/src/lib/blockchainexplorers/v8.ts +42 -0
- package/src/lib/chain/eth/index.ts +3 -2
- package/src/lib/expressapp.ts +25 -0
- package/src/lib/model/txproposal.ts +8 -0
- package/src/lib/routes/aave.ts +48 -0
- package/src/lib/routes/tss.ts +2 -2
- package/src/lib/server.ts +183 -6
- package/src/lib/tss.ts +9 -4
- package/test/expressapp.test.ts +170 -0
- package/test/integration/server.test.ts +333 -0
- package/test/v8.test.ts +103 -0
- package/ts_build/package.json +21 -10
- package/ts_build/src/externalservices/changelly.d.ts +2 -2
- package/ts_build/src/externalservices/moonpay.d.ts.map +1 -1
- package/ts_build/src/externalservices/moonpay.js +6 -0
- package/ts_build/src/externalservices/moonpay.js.map +1 -1
- package/ts_build/src/lib/blockchainexplorers/v8.d.ts +12 -0
- package/ts_build/src/lib/blockchainexplorers/v8.d.ts.map +1 -1
- package/ts_build/src/lib/blockchainexplorers/v8.js +39 -0
- package/ts_build/src/lib/blockchainexplorers/v8.js.map +1 -1
- package/ts_build/src/lib/chain/eth/index.d.ts.map +1 -1
- package/ts_build/src/lib/chain/eth/index.js +3 -2
- package/ts_build/src/lib/chain/eth/index.js.map +1 -1
- package/ts_build/src/lib/expressapp.d.ts.map +1 -1
- package/ts_build/src/lib/expressapp.js +23 -0
- package/ts_build/src/lib/expressapp.js.map +1 -1
- package/ts_build/src/lib/model/txproposal.d.ts +3 -0
- package/ts_build/src/lib/model/txproposal.d.ts.map +1 -1
- package/ts_build/src/lib/model/txproposal.js +6 -0
- package/ts_build/src/lib/model/txproposal.js.map +1 -1
- package/ts_build/src/lib/routes/aave.d.ts +12 -0
- package/ts_build/src/lib/routes/aave.d.ts.map +1 -0
- package/ts_build/src/lib/routes/aave.js +47 -0
- package/ts_build/src/lib/routes/aave.js.map +1 -0
- package/ts_build/src/lib/routes/tss.js +2 -2
- package/ts_build/src/lib/routes/tss.js.map +1 -1
- package/ts_build/src/lib/server.d.ts +5 -0
- package/ts_build/src/lib/server.d.ts.map +1 -1
- package/ts_build/src/lib/server.js +131 -6
- package/ts_build/src/lib/server.js.map +1 -1
- package/ts_build/src/lib/tss.d.ts +1 -0
- package/ts_build/src/lib/tss.d.ts.map +1 -1
- package/ts_build/src/lib/tss.js +6 -2
- package/ts_build/src/lib/tss.js.map +1 -1
- package/ts_build/test/expressapp.test.js +162 -0
- package/ts_build/test/expressapp.test.js.map +1 -1
- package/ts_build/test/integration/server.test.js +281 -0
- package/ts_build/test/integration/server.test.js.map +1 -1
- package/ts_build/test/v8.test.js +89 -0
- package/ts_build/test/v8.test.js.map +1 -1
|
@@ -7274,6 +7274,287 @@ describe('Wallet service', function () {
|
|
|
7274
7274
|
});
|
|
7275
7275
|
});
|
|
7276
7276
|
});
|
|
7277
|
+
describe('#prepareTx (deferred nonce)', function () {
|
|
7278
|
+
const ETH_ADDR = '0x37d7B3bBD88EFdE6a93cF74D2F5b0385D3E3B08A';
|
|
7279
|
+
let server, wallet, fromAddr;
|
|
7280
|
+
beforeEach(async function () {
|
|
7281
|
+
({ server, wallet } = await helpers_1.default.createAndJoinWallet(1, 1, { coin: 'eth' }));
|
|
7282
|
+
const address = await util_1.default.promisify(server.createAddress).call(server, {});
|
|
7283
|
+
fromAddr = address.address;
|
|
7284
|
+
await helpers_1.default.stubUtxos(server, wallet, [1, 2], { coin: 'eth' });
|
|
7285
|
+
blockchainExplorer.getTransactionCount = sinon_1.default.stub().callsArgWith(1, null, '5');
|
|
7286
|
+
});
|
|
7287
|
+
it('should create txp with nonce=null when deferNonce is true', async function () {
|
|
7288
|
+
const txOpts = {
|
|
7289
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 8000 }],
|
|
7290
|
+
feePerKb: 123e2,
|
|
7291
|
+
from: fromAddr,
|
|
7292
|
+
deferNonce: true
|
|
7293
|
+
};
|
|
7294
|
+
const txp = await util_1.default.promisify(server.createTx).call(server, txOpts);
|
|
7295
|
+
should.exist(txp);
|
|
7296
|
+
txp.deferNonce.should.be.true;
|
|
7297
|
+
should.not.exist(txp.nonce);
|
|
7298
|
+
});
|
|
7299
|
+
it('should create txp with nonce when deferNonce is absent', async function () {
|
|
7300
|
+
const txOpts = {
|
|
7301
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 8000 }],
|
|
7302
|
+
feePerKb: 123e2,
|
|
7303
|
+
from: fromAddr
|
|
7304
|
+
};
|
|
7305
|
+
const txp = await util_1.default.promisify(server.createTx).call(server, txOpts);
|
|
7306
|
+
should.exist(txp);
|
|
7307
|
+
should.not.exist(txp.deferNonce);
|
|
7308
|
+
txp.nonce.should.equal('5');
|
|
7309
|
+
});
|
|
7310
|
+
it('should publish a deferred-nonce txp and save prePublishRaw', async function () {
|
|
7311
|
+
const txOpts = {
|
|
7312
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 8000 }],
|
|
7313
|
+
feePerKb: 123e2,
|
|
7314
|
+
from: fromAddr,
|
|
7315
|
+
deferNonce: true
|
|
7316
|
+
};
|
|
7317
|
+
const txp = await util_1.default.promisify(server.createTx).call(server, txOpts);
|
|
7318
|
+
should.not.exist(txp.nonce);
|
|
7319
|
+
const publishOpts = helpers_1.default.getProposalSignatureOpts(txp, TestData.copayers[0].privKey_1H_0);
|
|
7320
|
+
const published = await util_1.default.promisify(server.publishTx).call(server, publishOpts);
|
|
7321
|
+
should.exist(published);
|
|
7322
|
+
published.status.should.equal('pending');
|
|
7323
|
+
published.deferNonce.should.be.true;
|
|
7324
|
+
should.exist(published.prePublishRaw);
|
|
7325
|
+
});
|
|
7326
|
+
it('should assign nonce to a deferred-nonce txp', async function () {
|
|
7327
|
+
blockchainExplorer.getTransactionCount = sinon_1.default.stub().callsArgWith(1, null, '10');
|
|
7328
|
+
const txp = await helpers_1.default.createAndPublishTx(server, {
|
|
7329
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 8000 }],
|
|
7330
|
+
feePerKb: 123e2,
|
|
7331
|
+
from: fromAddr,
|
|
7332
|
+
deferNonce: true
|
|
7333
|
+
}, TestData.copayers[0].privKey_1H_0);
|
|
7334
|
+
should.not.exist(txp.nonce);
|
|
7335
|
+
const result = await util_1.default.promisify(server.prepareTx).call(server, {
|
|
7336
|
+
txProposalId: txp.id
|
|
7337
|
+
});
|
|
7338
|
+
should.exist(result);
|
|
7339
|
+
result.nonce.should.equal(10);
|
|
7340
|
+
});
|
|
7341
|
+
it('should return txp as-is if deferNonce is not set', async function () {
|
|
7342
|
+
const txp = await helpers_1.default.createAndPublishTx(server, {
|
|
7343
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 8000 }],
|
|
7344
|
+
feePerKb: 123e2,
|
|
7345
|
+
from: fromAddr
|
|
7346
|
+
}, TestData.copayers[0].privKey_1H_0);
|
|
7347
|
+
txp.nonce.should.equal('5');
|
|
7348
|
+
const result = await util_1.default.promisify(server.prepareTx).call(server, {
|
|
7349
|
+
txProposalId: txp.id
|
|
7350
|
+
});
|
|
7351
|
+
result.nonce.should.equal('5');
|
|
7352
|
+
});
|
|
7353
|
+
it('should fail for non-existent txp', function (done) {
|
|
7354
|
+
server.prepareTx({ txProposalId: 'nonexistent' }, function (err) {
|
|
7355
|
+
should.exist(err);
|
|
7356
|
+
err.message.should.contain('not found');
|
|
7357
|
+
done();
|
|
7358
|
+
});
|
|
7359
|
+
});
|
|
7360
|
+
it('should calculate gap-free nonce skipping pending txp nonces', async function () {
|
|
7361
|
+
blockchainExplorer.getTransactionCount = sinon_1.default.stub().callsArgWith(1, null, '5');
|
|
7362
|
+
const txp1 = await helpers_1.default.createAndPublishTx(server, {
|
|
7363
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 1000 }],
|
|
7364
|
+
feePerKb: 123e2,
|
|
7365
|
+
from: fromAddr
|
|
7366
|
+
}, TestData.copayers[0].privKey_1H_0);
|
|
7367
|
+
txp1.nonce.should.equal('5');
|
|
7368
|
+
const txp2 = await helpers_1.default.createAndPublishTx(server, {
|
|
7369
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 2000 }],
|
|
7370
|
+
feePerKb: 123e2,
|
|
7371
|
+
from: fromAddr,
|
|
7372
|
+
deferNonce: true
|
|
7373
|
+
}, TestData.copayers[0].privKey_1H_0);
|
|
7374
|
+
should.not.exist(txp2.nonce);
|
|
7375
|
+
const result = await util_1.default.promisify(server.prepareTx).call(server, {
|
|
7376
|
+
txProposalId: txp2.id
|
|
7377
|
+
});
|
|
7378
|
+
result.nonce.should.equal(6);
|
|
7379
|
+
});
|
|
7380
|
+
it('should assign sequential nonces for multiple deferred txps', async function () {
|
|
7381
|
+
blockchainExplorer.getTransactionCount = sinon_1.default.stub().callsArgWith(1, null, '0');
|
|
7382
|
+
const txps = [];
|
|
7383
|
+
for (let i = 0; i < 3; i++) {
|
|
7384
|
+
const txp = await helpers_1.default.createAndPublishTx(server, {
|
|
7385
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 1000 * (i + 1) }],
|
|
7386
|
+
feePerKb: 123e2,
|
|
7387
|
+
from: fromAddr,
|
|
7388
|
+
deferNonce: true
|
|
7389
|
+
}, TestData.copayers[0].privKey_1H_0);
|
|
7390
|
+
txps.push(txp);
|
|
7391
|
+
}
|
|
7392
|
+
const results = [];
|
|
7393
|
+
for (const txp of txps) {
|
|
7394
|
+
const result = await util_1.default.promisify(server.prepareTx).call(server, {
|
|
7395
|
+
txProposalId: txp.id
|
|
7396
|
+
});
|
|
7397
|
+
results.push(result);
|
|
7398
|
+
}
|
|
7399
|
+
results[0].nonce.should.equal(0);
|
|
7400
|
+
results[1].nonce.should.equal(1);
|
|
7401
|
+
results[2].nonce.should.equal(2);
|
|
7402
|
+
});
|
|
7403
|
+
it('should handle mix of normal and deferred-nonce txps', async function () {
|
|
7404
|
+
blockchainExplorer.getTransactionCount = sinon_1.default.stub().callsArgWith(1, null, '3');
|
|
7405
|
+
const normalTxp = await helpers_1.default.createAndPublishTx(server, {
|
|
7406
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 1000 }],
|
|
7407
|
+
feePerKb: 123e2,
|
|
7408
|
+
from: fromAddr
|
|
7409
|
+
}, TestData.copayers[0].privKey_1H_0);
|
|
7410
|
+
normalTxp.nonce.should.equal('3');
|
|
7411
|
+
const deferred1 = await helpers_1.default.createAndPublishTx(server, {
|
|
7412
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 2000 }],
|
|
7413
|
+
feePerKb: 123e2,
|
|
7414
|
+
from: fromAddr,
|
|
7415
|
+
deferNonce: true
|
|
7416
|
+
}, TestData.copayers[0].privKey_1H_0);
|
|
7417
|
+
const deferred2 = await helpers_1.default.createAndPublishTx(server, {
|
|
7418
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 3000 }],
|
|
7419
|
+
feePerKb: 123e2,
|
|
7420
|
+
from: fromAddr,
|
|
7421
|
+
deferNonce: true
|
|
7422
|
+
}, TestData.copayers[0].privKey_1H_0);
|
|
7423
|
+
const result1 = await util_1.default.promisify(server.prepareTx).call(server, {
|
|
7424
|
+
txProposalId: deferred1.id
|
|
7425
|
+
});
|
|
7426
|
+
result1.nonce.should.equal(4);
|
|
7427
|
+
const result2 = await util_1.default.promisify(server.prepareTx).call(server, {
|
|
7428
|
+
txProposalId: deferred2.id
|
|
7429
|
+
});
|
|
7430
|
+
result2.nonce.should.equal(5);
|
|
7431
|
+
});
|
|
7432
|
+
it('should sign a deferred-nonce txp after assignNonce', async function () {
|
|
7433
|
+
blockchainExplorer.getTransactionCount = sinon_1.default.stub().callsArgWith(1, null, '7');
|
|
7434
|
+
helpers_1.default.stubBroadcast('txid123');
|
|
7435
|
+
const txp = await helpers_1.default.createAndPublishTx(server, {
|
|
7436
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 8000 }],
|
|
7437
|
+
feePerKb: 123e2,
|
|
7438
|
+
from: fromAddr,
|
|
7439
|
+
deferNonce: true
|
|
7440
|
+
}, TestData.copayers[0].privKey_1H_0);
|
|
7441
|
+
const withNonce = await util_1.default.promisify(server.prepareTx).call(server, {
|
|
7442
|
+
txProposalId: txp.id
|
|
7443
|
+
});
|
|
7444
|
+
withNonce.nonce.should.equal(7);
|
|
7445
|
+
const fetched = await util_1.default.promisify(server.getTx).call(server, { txProposalId: txp.id });
|
|
7446
|
+
const signatures = helpers_1.default.clientSign(fetched, TestData.copayers[0].xPrivKey_44H_0H_0H);
|
|
7447
|
+
const signed = await util_1.default.promisify(server.signTx).call(server, {
|
|
7448
|
+
txProposalId: txp.id,
|
|
7449
|
+
signatures
|
|
7450
|
+
});
|
|
7451
|
+
signed.status.should.equal('accepted');
|
|
7452
|
+
});
|
|
7453
|
+
it('should not trigger nonce conflict for deferred txps with null nonce', async function () {
|
|
7454
|
+
blockchainExplorer.getTransactionCount = sinon_1.default.stub().callsArgWith(1, null, '5');
|
|
7455
|
+
const normalTxp = await helpers_1.default.createAndPublishTx(server, {
|
|
7456
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 1000 }],
|
|
7457
|
+
feePerKb: 123e2,
|
|
7458
|
+
from: fromAddr
|
|
7459
|
+
}, TestData.copayers[0].privKey_1H_0);
|
|
7460
|
+
normalTxp.nonce.should.equal('5');
|
|
7461
|
+
const deferredTxp = await helpers_1.default.createAndPublishTx(server, {
|
|
7462
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 2000 }],
|
|
7463
|
+
feePerKb: 123e2,
|
|
7464
|
+
from: fromAddr,
|
|
7465
|
+
deferNonce: true
|
|
7466
|
+
}, TestData.copayers[0].privKey_1H_0);
|
|
7467
|
+
const withNonce = await util_1.default.promisify(server.prepareTx).call(server, {
|
|
7468
|
+
txProposalId: deferredTxp.id
|
|
7469
|
+
});
|
|
7470
|
+
withNonce.nonce.should.equal(6);
|
|
7471
|
+
const sigs1 = helpers_1.default.clientSign(normalTxp, TestData.copayers[0].xPrivKey_44H_0H_0H);
|
|
7472
|
+
const signed1 = await util_1.default.promisify(server.signTx).call(server, {
|
|
7473
|
+
txProposalId: normalTxp.id,
|
|
7474
|
+
signatures: sigs1
|
|
7475
|
+
});
|
|
7476
|
+
signed1.status.should.equal('accepted');
|
|
7477
|
+
helpers_1.default.stubBroadcast(signed1.txid);
|
|
7478
|
+
await util_1.default.promisify(server.broadcastTx).call(server, { txProposalId: normalTxp.id });
|
|
7479
|
+
const fetchedDeferred = await util_1.default.promisify(server.getTx).call(server, { txProposalId: deferredTxp.id });
|
|
7480
|
+
const sigs2 = helpers_1.default.clientSign(fetchedDeferred, TestData.copayers[0].xPrivKey_44H_0H_0H);
|
|
7481
|
+
const signed2 = await util_1.default.promisify(server.signTx).call(server, {
|
|
7482
|
+
txProposalId: deferredTxp.id,
|
|
7483
|
+
signatures: sigs2
|
|
7484
|
+
});
|
|
7485
|
+
signed2.status.should.equal('accepted');
|
|
7486
|
+
});
|
|
7487
|
+
it('should complete full lifecycle for a deferred-nonce txp', async function () {
|
|
7488
|
+
blockchainExplorer.getTransactionCount = sinon_1.default.stub().callsArgWith(1, null, '42');
|
|
7489
|
+
const txOpts = {
|
|
7490
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 8000 }],
|
|
7491
|
+
feePerKb: 123e2,
|
|
7492
|
+
from: fromAddr,
|
|
7493
|
+
deferNonce: true
|
|
7494
|
+
};
|
|
7495
|
+
const created = await util_1.default.promisify(server.createTx).call(server, txOpts);
|
|
7496
|
+
created.isTemporary().should.be.true;
|
|
7497
|
+
created.deferNonce.should.be.true;
|
|
7498
|
+
should.not.exist(created.nonce);
|
|
7499
|
+
const publishOpts = helpers_1.default.getProposalSignatureOpts(created, TestData.copayers[0].privKey_1H_0);
|
|
7500
|
+
const published = await util_1.default.promisify(server.publishTx).call(server, publishOpts);
|
|
7501
|
+
published.status.should.equal('pending');
|
|
7502
|
+
should.exist(published.prePublishRaw);
|
|
7503
|
+
const withNonce = await util_1.default.promisify(server.prepareTx).call(server, {
|
|
7504
|
+
txProposalId: created.id
|
|
7505
|
+
});
|
|
7506
|
+
withNonce.nonce.should.equal(42);
|
|
7507
|
+
const fetched = await util_1.default.promisify(server.getTx).call(server, { txProposalId: created.id });
|
|
7508
|
+
const signatures = helpers_1.default.clientSign(fetched, TestData.copayers[0].xPrivKey_44H_0H_0H);
|
|
7509
|
+
const signed = await util_1.default.promisify(server.signTx).call(server, {
|
|
7510
|
+
txProposalId: created.id,
|
|
7511
|
+
signatures
|
|
7512
|
+
});
|
|
7513
|
+
signed.status.should.equal('accepted');
|
|
7514
|
+
helpers_1.default.stubBroadcast(signed.txid);
|
|
7515
|
+
const broadcasted = await util_1.default.promisify(server.broadcastTx).call(server, {
|
|
7516
|
+
txProposalId: created.id
|
|
7517
|
+
});
|
|
7518
|
+
broadcasted.status.should.equal('broadcasted');
|
|
7519
|
+
should.exist(broadcasted.txid);
|
|
7520
|
+
});
|
|
7521
|
+
it('should handle bulk sign scenario (3 deferred txps signed sequentially)', async function () {
|
|
7522
|
+
blockchainExplorer.getTransactionCount = sinon_1.default.stub().callsArgWith(1, null, '10');
|
|
7523
|
+
const txps = [];
|
|
7524
|
+
for (let i = 0; i < 3; i++) {
|
|
7525
|
+
const txp = await helpers_1.default.createAndPublishTx(server, {
|
|
7526
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 1000 * (i + 1) }],
|
|
7527
|
+
feePerKb: 123e2,
|
|
7528
|
+
from: fromAddr,
|
|
7529
|
+
deferNonce: true
|
|
7530
|
+
}, TestData.copayers[0].privKey_1H_0);
|
|
7531
|
+
txps.push(txp);
|
|
7532
|
+
}
|
|
7533
|
+
const assignedNonces = [];
|
|
7534
|
+
for (let i = 0; i < txps.length; i++) {
|
|
7535
|
+
const withNonce = await util_1.default.promisify(server.prepareTx).call(server, {
|
|
7536
|
+
txProposalId: txps[i].id
|
|
7537
|
+
});
|
|
7538
|
+
withNonce.nonce.should.equal(10 + i);
|
|
7539
|
+
assignedNonces.push(withNonce.nonce);
|
|
7540
|
+
}
|
|
7541
|
+
assignedNonces.should.deep.equal([10, 11, 12]);
|
|
7542
|
+
});
|
|
7543
|
+
it('should return txp with nonce set (extensibility baseline)', async function () {
|
|
7544
|
+
const txp = await helpers_1.default.createAndPublishTx(server, {
|
|
7545
|
+
outputs: [{ toAddress: ETH_ADDR, amount: 8000 }],
|
|
7546
|
+
feePerKb: 123e2,
|
|
7547
|
+
from: fromAddr,
|
|
7548
|
+
deferNonce: true
|
|
7549
|
+
}, TestData.copayers[0].privKey_1H_0);
|
|
7550
|
+
should.not.exist(txp.nonce);
|
|
7551
|
+
const result = await util_1.default.promisify(server.prepareTx).call(server, {
|
|
7552
|
+
txProposalId: txp.id
|
|
7553
|
+
});
|
|
7554
|
+
result.nonce.should.be.a('number');
|
|
7555
|
+
result.nonce.should.equal(5);
|
|
7556
|
+
});
|
|
7557
|
+
});
|
|
7277
7558
|
describe('#broadcastTx & #broadcastRawTx', function () {
|
|
7278
7559
|
let server;
|
|
7279
7560
|
let wallet;
|