@bitpay-labs/bitcore-wallet-service 11.11.0 → 11.11.2

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.
Files changed (157) hide show
  1. package/Dockerfile +1 -1
  2. package/package.json +5 -5
  3. package/src/config.ts +0 -20
  4. package/src/externalservices/banxa.ts +51 -10
  5. package/src/externalservices/changelly.ts +54 -6
  6. package/src/externalservices/moonpay.ts +85 -19
  7. package/src/externalservices/oneInch.ts +13 -5
  8. package/src/externalservices/ramp.ts +42 -8
  9. package/src/externalservices/sardine.ts +51 -10
  10. package/src/externalservices/simplex.ts +58 -11
  11. package/src/externalservices/thorswap.ts +46 -11
  12. package/src/externalservices/transak.ts +53 -11
  13. package/src/lib/chain/btc/index.ts +3 -2
  14. package/src/lib/chain/eth/index.ts +134 -117
  15. package/src/lib/chain/sol/index.ts +1 -1
  16. package/src/lib/chain/xrp/index.ts +1 -1
  17. package/src/lib/routes/services.ts +0 -12
  18. package/src/lib/routes/wallets.ts +3 -1
  19. package/src/lib/server.ts +136 -91
  20. package/src/lib/storage.ts +90 -20
  21. package/src/types/externalservices.d.ts +0 -1
  22. package/test/chain/eth.test.ts +70 -0
  23. package/test/chain/sol.test.ts +1 -1
  24. package/test/chain/xrp.test.ts +1 -1
  25. package/test/expressapp.test.ts +144 -0
  26. package/test/integration/addressReads.test.ts +503 -0
  27. package/test/integration/bcmonitor.test.ts +44 -0
  28. package/test/integration/externalservices/banxa.test.ts +95 -5
  29. package/test/integration/externalservices/changelly.test.ts +118 -6
  30. package/test/integration/externalservices/coinGecko.test.ts +4 -0
  31. package/test/integration/externalservices/moonpay.test.ts +178 -9
  32. package/test/integration/externalservices/oneInch.test.ts +28 -1
  33. package/test/integration/externalservices/ramp.test.ts +126 -4
  34. package/test/integration/externalservices/sardine.test.ts +95 -5
  35. package/test/integration/externalservices/simplex.test.ts +95 -5
  36. package/test/integration/externalservices/thorswap.test.ts +81 -5
  37. package/test/integration/externalservices/transak.test.ts +98 -6
  38. package/test/integration/helpers.ts +1 -1
  39. package/test/integration/server.test.ts +254 -136
  40. package/test/integration/walletReads.test.ts +488 -0
  41. package/ts_build/package.json +3 -3
  42. package/ts_build/src/config.d.ts.map +1 -1
  43. package/ts_build/src/config.js +0 -4
  44. package/ts_build/src/config.js.map +1 -1
  45. package/ts_build/src/externalservices/banxa.d.ts.map +1 -1
  46. package/ts_build/src/externalservices/banxa.js +51 -10
  47. package/ts_build/src/externalservices/banxa.js.map +1 -1
  48. package/ts_build/src/externalservices/changelly.d.ts.map +1 -1
  49. package/ts_build/src/externalservices/changelly.js +54 -6
  50. package/ts_build/src/externalservices/changelly.js.map +1 -1
  51. package/ts_build/src/externalservices/moonpay.d.ts.map +1 -1
  52. package/ts_build/src/externalservices/moonpay.js +85 -19
  53. package/ts_build/src/externalservices/moonpay.js.map +1 -1
  54. package/ts_build/src/externalservices/oneInch.d.ts.map +1 -1
  55. package/ts_build/src/externalservices/oneInch.js +13 -5
  56. package/ts_build/src/externalservices/oneInch.js.map +1 -1
  57. package/ts_build/src/externalservices/ramp.d.ts.map +1 -1
  58. package/ts_build/src/externalservices/ramp.js +42 -8
  59. package/ts_build/src/externalservices/ramp.js.map +1 -1
  60. package/ts_build/src/externalservices/sardine.d.ts.map +1 -1
  61. package/ts_build/src/externalservices/sardine.js +51 -10
  62. package/ts_build/src/externalservices/sardine.js.map +1 -1
  63. package/ts_build/src/externalservices/simplex.d.ts.map +1 -1
  64. package/ts_build/src/externalservices/simplex.js +55 -11
  65. package/ts_build/src/externalservices/simplex.js.map +1 -1
  66. package/ts_build/src/externalservices/thorswap.d.ts.map +1 -1
  67. package/ts_build/src/externalservices/thorswap.js +45 -11
  68. package/ts_build/src/externalservices/thorswap.js.map +1 -1
  69. package/ts_build/src/externalservices/transak.d.ts.map +1 -1
  70. package/ts_build/src/externalservices/transak.js +53 -11
  71. package/ts_build/src/externalservices/transak.js.map +1 -1
  72. package/ts_build/src/lib/chain/btc/index.d.ts.map +1 -1
  73. package/ts_build/src/lib/chain/btc/index.js +3 -2
  74. package/ts_build/src/lib/chain/btc/index.js.map +1 -1
  75. package/ts_build/src/lib/chain/eth/index.d.ts +8 -1
  76. package/ts_build/src/lib/chain/eth/index.d.ts.map +1 -1
  77. package/ts_build/src/lib/chain/eth/index.js +114 -102
  78. package/ts_build/src/lib/chain/eth/index.js.map +1 -1
  79. package/ts_build/src/lib/chain/sol/index.js +1 -1
  80. package/ts_build/src/lib/chain/sol/index.js.map +1 -1
  81. package/ts_build/src/lib/chain/xrp/index.js +1 -1
  82. package/ts_build/src/lib/chain/xrp/index.js.map +1 -1
  83. package/ts_build/src/lib/routes/services.d.ts.map +1 -1
  84. package/ts_build/src/lib/routes/services.js +0 -10
  85. package/ts_build/src/lib/routes/services.js.map +1 -1
  86. package/ts_build/src/lib/routes/wallets.d.ts.map +1 -1
  87. package/ts_build/src/lib/routes/wallets.js +2 -1
  88. package/ts_build/src/lib/routes/wallets.js.map +1 -1
  89. package/ts_build/src/lib/server.d.ts +1 -3
  90. package/ts_build/src/lib/server.d.ts.map +1 -1
  91. package/ts_build/src/lib/server.js +128 -96
  92. package/ts_build/src/lib/server.js.map +1 -1
  93. package/ts_build/src/lib/storage.d.ts +17 -10
  94. package/ts_build/src/lib/storage.d.ts.map +1 -1
  95. package/ts_build/src/lib/storage.js +73 -20
  96. package/ts_build/src/lib/storage.js.map +1 -1
  97. package/ts_build/test/chain/eth.test.js +59 -0
  98. package/ts_build/test/chain/eth.test.js.map +1 -1
  99. package/ts_build/test/chain/sol.test.js +1 -1
  100. package/ts_build/test/chain/sol.test.js.map +1 -1
  101. package/ts_build/test/chain/xrp.test.js +1 -1
  102. package/ts_build/test/chain/xrp.test.js.map +1 -1
  103. package/ts_build/test/expressapp.test.js +132 -0
  104. package/ts_build/test/expressapp.test.js.map +1 -1
  105. package/ts_build/test/integration/addressReads.test.d.ts +2 -0
  106. package/ts_build/test/integration/addressReads.test.d.ts.map +1 -0
  107. package/ts_build/test/integration/addressReads.test.js +465 -0
  108. package/ts_build/test/integration/addressReads.test.js.map +1 -0
  109. package/ts_build/test/integration/bcmonitor.test.js +40 -0
  110. package/ts_build/test/integration/bcmonitor.test.js.map +1 -1
  111. package/ts_build/test/integration/externalservices/banxa.test.d.ts.map +1 -1
  112. package/ts_build/test/integration/externalservices/banxa.test.js +93 -5
  113. package/ts_build/test/integration/externalservices/banxa.test.js.map +1 -1
  114. package/ts_build/test/integration/externalservices/changelly.test.d.ts.map +1 -1
  115. package/ts_build/test/integration/externalservices/changelly.test.js +111 -6
  116. package/ts_build/test/integration/externalservices/changelly.test.js.map +1 -1
  117. package/ts_build/test/integration/externalservices/coinGecko.test.js +4 -0
  118. package/ts_build/test/integration/externalservices/coinGecko.test.js.map +1 -1
  119. package/ts_build/test/integration/externalservices/moonpay.test.d.ts.map +1 -1
  120. package/ts_build/test/integration/externalservices/moonpay.test.js +169 -9
  121. package/ts_build/test/integration/externalservices/moonpay.test.js.map +1 -1
  122. package/ts_build/test/integration/externalservices/oneInch.test.d.ts.map +1 -1
  123. package/ts_build/test/integration/externalservices/oneInch.test.js +26 -1
  124. package/ts_build/test/integration/externalservices/oneInch.test.js.map +1 -1
  125. package/ts_build/test/integration/externalservices/ramp.test.d.ts.map +1 -1
  126. package/ts_build/test/integration/externalservices/ramp.test.js +115 -4
  127. package/ts_build/test/integration/externalservices/ramp.test.js.map +1 -1
  128. package/ts_build/test/integration/externalservices/sardine.test.d.ts.map +1 -1
  129. package/ts_build/test/integration/externalservices/sardine.test.js +94 -5
  130. package/ts_build/test/integration/externalservices/sardine.test.js.map +1 -1
  131. package/ts_build/test/integration/externalservices/simplex.test.d.ts.map +1 -1
  132. package/ts_build/test/integration/externalservices/simplex.test.js +89 -5
  133. package/ts_build/test/integration/externalservices/simplex.test.js.map +1 -1
  134. package/ts_build/test/integration/externalservices/thorswap.test.d.ts.map +1 -1
  135. package/ts_build/test/integration/externalservices/thorswap.test.js +76 -5
  136. package/ts_build/test/integration/externalservices/thorswap.test.js.map +1 -1
  137. package/ts_build/test/integration/externalservices/transak.test.d.ts.map +1 -1
  138. package/ts_build/test/integration/externalservices/transak.test.js +93 -6
  139. package/ts_build/test/integration/externalservices/transak.test.js.map +1 -1
  140. package/ts_build/test/integration/helpers.js +1 -1
  141. package/ts_build/test/integration/helpers.js.map +1 -1
  142. package/ts_build/test/integration/server.test.js +225 -124
  143. package/ts_build/test/integration/server.test.js.map +1 -1
  144. package/ts_build/test/integration/walletReads.test.d.ts +2 -0
  145. package/ts_build/test/integration/walletReads.test.d.ts.map +1 -0
  146. package/ts_build/test/integration/walletReads.test.js +436 -0
  147. package/ts_build/test/integration/walletReads.test.js.map +1 -0
  148. package/src/externalservices/wyre.ts +0 -131
  149. package/test/integration/externalservices/wyre.test.ts +0 -270
  150. package/ts_build/src/externalservices/wyre.d.ts +0 -7
  151. package/ts_build/src/externalservices/wyre.d.ts.map +0 -1
  152. package/ts_build/src/externalservices/wyre.js +0 -144
  153. package/ts_build/src/externalservices/wyre.js.map +0 -1
  154. package/ts_build/test/integration/externalservices/wyre.test.d.ts +0 -2
  155. package/ts_build/test/integration/externalservices/wyre.test.d.ts.map +0 -1
  156. package/ts_build/test/integration/externalservices/wyre.test.js +0 -281
  157. package/ts_build/test/integration/externalservices/wyre.test.js.map +0 -1
@@ -3,6 +3,7 @@
3
3
  import * as chai from 'chai';
4
4
  import 'chai/register-should';
5
5
  import util from 'util';
6
+ import assert from 'assert';
6
7
  import sinon from 'sinon';
7
8
  import http from 'http';
8
9
  import request from 'request';
@@ -2930,30 +2931,23 @@ describe('Wallet service', function() {
2930
2931
  should.exist(address);
2931
2932
  utxo.path.should.equal(address.path);
2932
2933
  utxo.publicKeys.should.deep.equal(address.publicKeys);
2934
+ utxo.isChange.should.equal(false);
2933
2935
  done();
2934
2936
  });
2935
2937
  });
2936
2938
  });
2937
2939
  });
2938
2940
 
2941
+ it('should identify UTXOs for change addresses', async function() {
2942
+ const address = await util.promisify(server.createAddress).call(server, { isChange: true });
2943
+ await helpers.stubUtxos(server, wallet, [1], { addresses: [address] });
2939
2944
 
2940
- it('should get UTXOs for wallet addresses', function(done) {
2941
- helpers.stubUtxos(server, wallet, [1, 2]).then(function() {
2942
- server.getUtxos({}, function(err, utxos) {
2943
- should.not.exist(err);
2944
- should.exist(utxos);
2945
- utxos.length.should.equal(2);
2946
- utxos.reduce((sum, u) => sum += u.satoshis, 0).should.equal(3 * 1e8);
2947
- server.getAddresses({ noChange: true }, function(err, addresses) {
2948
- const utxo = utxos[0];
2949
- const address = addresses.find(a => a.address === utxo.address);
2950
- should.exist(address);
2951
- utxo.path.should.equal(address.path);
2952
- utxo.publicKeys.should.deep.equal(address.publicKeys);
2953
- done();
2954
- });
2955
- });
2956
- });
2945
+ const utxos = await util.promisify(server.getUtxos).call(server, {});
2946
+ utxos.length.should.equal(1);
2947
+ utxos[0].address.should.equal(address.address);
2948
+ utxos[0].path.should.equal(address.path);
2949
+ utxos[0].publicKeys.should.deep.equal(address.publicKeys);
2950
+ utxos[0].isChange.should.equal(true);
2957
2951
  });
2958
2952
 
2959
2953
  it('should return empty UTXOs for specific addresses if network mismatch', function(done) {
@@ -4951,7 +4945,6 @@ describe('Wallet service', function() {
4951
4945
  toAddress: addressStr,
4952
4946
  amount: ts,
4953
4947
  }],
4954
- gasPrice: 1,
4955
4948
  feeLevel: level,
4956
4949
  from: fromAddr,
4957
4950
  }, flags);
@@ -6186,36 +6179,36 @@ describe('Wallet service', function() {
6186
6179
  }));
6187
6180
  });
6188
6181
 
6189
- it('should allow to create a TX with fee and no inputs', function(done) {
6190
- helpers.stubFeeLevels({});
6191
- server.createAddress({}, from => {
6192
- helpers.stubUtxos(server, wallet, [1, 2]).then(function() {
6193
- const amount = 0.8 * 1e8;
6194
- const txOpts = {
6195
- outputs: [{
6196
- toAddress: '0x37d7B3bBD88EFdE6a93cF74D2F5b0385D3E3B08A',
6197
- amount: amount,
6198
- }],
6199
- from,
6200
- message: 'some message',
6201
- customData: 'some custom data',
6202
- fee: 252000000000000,
6203
- };
6204
- server.createTx(txOpts, function(err, tx) {
6205
- should.not.exist(err);
6206
- should.exist(tx);
6207
- tx.outputs.should.deep.equal([{
6208
- toAddress: '0x37d7B3bBD88EFdE6a93cF74D2F5b0385D3E3B08A',
6209
- gasLimit: 21000,
6210
- amount: amount,
6211
- }]);
6212
- tx.gasPrice.should.equal(12000000000);
6213
- tx.outputs[0].gasLimit.should.equal(21000);
6214
- (tx.gasPrice * tx.outputs[0].gasLimit).should.equal(txOpts.fee);
6215
- done();
6216
- });
6217
- });
6218
- });
6182
+ it('should allow to create a TX with fee and no inputs', async function() {
6183
+ const feeLevels = sinon.stub(server, 'getFeeLevels').callsArgWith(1, new Error('Unexpected fee estimation'));
6184
+ await util.promisify(server.createAddress).call(server, {});
6185
+ await helpers.stubUtxos(server, wallet, [1, 2]);
6186
+ const amount = 0.8 * 1e8;
6187
+
6188
+ for (const fee of [252000000000000, '252000000000000']) {
6189
+ const txOpts = {
6190
+ outputs: [{
6191
+ toAddress: '0x37d7B3bBD88EFdE6a93cF74D2F5b0385D3E3B08A',
6192
+ amount: amount,
6193
+ }],
6194
+ message: 'some message',
6195
+ customData: 'some custom data',
6196
+ fee,
6197
+ };
6198
+ const tx = await util.promisify(server.createTx).call(server, txOpts);
6199
+ should.exist(tx);
6200
+ tx.outputs.should.deep.equal([{
6201
+ toAddress: '0x37d7B3bBD88EFdE6a93cF74D2F5b0385D3E3B08A',
6202
+ gasLimit: 21000,
6203
+ amount: amount,
6204
+ }]);
6205
+ tx.fee.should.equal(Number(fee));
6206
+ tx.gasPrice.should.equal(12000000000);
6207
+ (tx.gasPrice * tx.outputs[0].gasLimit).should.equal(Number(fee));
6208
+ const [raw] = tx.getRawTx();
6209
+ CWC.ethers.Transaction.from(raw).gasPrice.should.equal(12000000000n);
6210
+ }
6211
+ feeLevels.called.should.be.false;
6219
6212
  });
6220
6213
 
6221
6214
  it('should allow to create a TX with multiple outputs and set the correct fee', function(done) {
@@ -6283,6 +6276,163 @@ describe('Wallet service', function() {
6283
6276
  });
6284
6277
  });
6285
6278
 
6279
+ describe('#createTX EVM gas overrides', function() {
6280
+ let server: WalletService;
6281
+ let wallet: Model.Wallet;
6282
+ const destination = '0x37d7B3bBD88EFdE6a93cF74D2F5b0385D3E3B08A';
6283
+ const makeOpts = (overrides = {}) => ({
6284
+ outputs: [{ toAddress: destination, amount: 1000000, gasLimit: 100000 }],
6285
+ nonce: 1,
6286
+ ...overrides
6287
+ });
6288
+
6289
+ beforeEach(async function() {
6290
+ ({ server, wallet } = await helpers.createAndJoinWallet(1, 1, { coin: 'eth' }));
6291
+ await util.promisify(server.createAddress).call(server, {});
6292
+ await helpers.stubUtxos(server, wallet, [1]);
6293
+ });
6294
+
6295
+ for (const scenario of [
6296
+ { name: 'type 0', fees: { gasPrice: 3000000000 }, tokenAddress: undefined },
6297
+ { name: 'type 0 token', fees: { gasPrice: 3000000000 }, tokenAddress: TOKENS[0] },
6298
+ { name: 'type 2 native', fees: { txType: 2, maxGasFee: 3000000000, priorityGasFee: 1000000000 }, tokenAddress: undefined },
6299
+ { name: 'type 2 token', fees: { txType: 2, maxGasFee: 3000000000, priorityGasFee: 1000000000 }, tokenAddress: TOKENS[0] }
6300
+ ]) {
6301
+ it(`should preserve ${scenario.name} overrides through publication, signing and broadcast`, async function() {
6302
+ const feeLevels = sinon.stub(server, 'getFeeLevels').callsArgWith(1, new Error('Unexpected fee estimation'));
6303
+ const maxFee = sinon.stub(server, 'estimateFee').rejects(new Error('Unexpected fee estimation'));
6304
+ const priorityFee = sinon.stub(server, 'estimatePriorityFee').rejects(new Error('Unexpected fee estimation'));
6305
+ const txp = await util.promisify(server.createTx).call(server, makeOpts({
6306
+ ...scenario.fees, tokenAddress: scenario.tokenAddress, feeLevel: 'economy'
6307
+ }));
6308
+ await util.promisify(server.publishTx).call(server,
6309
+ helpers.getProposalSignatureOpts(txp, TestData.copayers[0].privKey_1H_0));
6310
+ await util.promisify(server.signTx).call(server, {
6311
+ txProposalId: txp.id,
6312
+ signatures: helpers.clientSign(txp, TestData.copayers[0].xPrivKey_44H_0H_0H)
6313
+ });
6314
+ const accepted = await util.promisify(server.getTx).call(server, { txProposalId: txp.id });
6315
+ accepted.status.should.equal('accepted');
6316
+ const signedRaw = accepted.getRawTx();
6317
+ helpers.stubBroadcast(accepted.txid);
6318
+ await util.promisify(server.broadcastTx).call(server, { txProposalId: txp.id });
6319
+ blockchainExplorer.broadcast.calledOnce.should.be.true;
6320
+ blockchainExplorer.broadcast.firstCall.args[0].should.deep.equal(signedRaw);
6321
+ const stored = await util.promisify(server.getTx).call(server, { txProposalId: txp.id });
6322
+ stored.status.should.equal('broadcasted');
6323
+ stored.txid.should.equal(accepted.txid);
6324
+ should.not.exist(stored.feeLevel);
6325
+ stored.fee.should.equal(300000000000000);
6326
+ for (const [key, value] of Object.entries(scenario.fees)) {
6327
+ stored[key].should.equal(value);
6328
+ }
6329
+ const [raw] = stored.getRawTx();
6330
+ const tx = CWC.ethers.Transaction.from(raw);
6331
+ tx.isSigned().should.be.true;
6332
+ tx.type.should.equal(scenario.fees.txType || 0);
6333
+ if (scenario.fees.txType === 2) {
6334
+ tx.maxFeePerGas.should.equal(3000000000n);
6335
+ tx.maxPriorityFeePerGas.should.equal(1000000000n);
6336
+ } else {
6337
+ tx.gasPrice.should.equal(3000000000n);
6338
+ }
6339
+ feeLevels.called.should.be.false;
6340
+ maxFee.called.should.be.false;
6341
+ priorityFee.called.should.be.false;
6342
+ });
6343
+ }
6344
+
6345
+ it('should preserve a zero priority fee estimated for ARB', async function() {
6346
+ ({ server, wallet } = await helpers.createAndJoinWallet(1, 1, { coin: 'arb' }));
6347
+ await util.promisify(server.createAddress).call(server, {});
6348
+ sinon.replace(blockchainExplorer, 'getBalance',
6349
+ sinon.stub().callsArgWith(1, null, { confirmed: 1e18, unconfirmed: 0, balance: 1e18 }));
6350
+ helpers.stubFeeLevels({});
6351
+ sinon.stub(server, 'estimateFee').resolves(3000000000);
6352
+ sinon.stub(server, 'estimatePriorityFee').resolves(0);
6353
+ const txp = await util.promisify(server.createTx).call(server, makeOpts({ txType: 2 }));
6354
+ txp.priorityGasFee.should.equal(0);
6355
+ const [raw] = txp.getRawTx();
6356
+ CWC.ethers.Transaction.from(raw).maxPriorityFeePerGas.should.equal(0n);
6357
+ });
6358
+
6359
+ it('should preserve automatic type 2 fee estimation without overrides', async function() {
6360
+ helpers.stubFeeLevels({});
6361
+ sinon.stub(server, 'estimateFee').resolves(4500000000);
6362
+ sinon.stub(server, 'estimatePriorityFee').resolves(1000000000);
6363
+ const txp = await util.promisify(server.createTx).call(server, makeOpts({ txType: 2 }));
6364
+ txp.feeLevel.should.equal('normal');
6365
+ txp.gasPrice.should.equal(1000000000);
6366
+ txp.fee.should.equal(100000000000000);
6367
+ txp.maxGasFee.should.equal(4500000000);
6368
+ txp.priorityGasFee.should.equal(1000000000);
6369
+ const [raw] = txp.getRawTx();
6370
+ const tx = CWC.ethers.Transaction.from(raw);
6371
+ tx.maxFeePerGas.should.equal(4500000000n);
6372
+ tx.maxPriorityFeePerGas.should.equal(1000000000n);
6373
+ });
6374
+
6375
+ it('should enforce the existing MATIC minimum for explicit priority fees', async function() {
6376
+ ({ server, wallet } = await helpers.createAndJoinWallet(1, 1, { coin: 'matic' }));
6377
+ await util.promisify(server.createAddress).call(server, {});
6378
+ sinon.replace(blockchainExplorer, 'getBalance',
6379
+ sinon.stub().callsArgWith(1, null, { confirmed: 1e18, unconfirmed: 0, balance: 1e18 }));
6380
+ const fees = { txType: 2, maxGasFee: 40000000000, priorityGasFee: 30000000000 };
6381
+ await assert.rejects(util.promisify(server.createTx).call(server,
6382
+ makeOpts({ ...fees, priorityGasFee: fees.priorityGasFee - 1 })), {
6383
+ message: 'priorityGasFee must be at least 30000000000 wei for matic'
6384
+ });
6385
+ const txp = await util.promisify(server.createTx).call(server, makeOpts(fees));
6386
+ const [raw] = txp.getRawTx();
6387
+ CWC.ethers.Transaction.from(raw).maxPriorityFeePerGas.should.equal(30000000000n);
6388
+ txp.fee.should.equal(fees.maxGasFee * 100000);
6389
+ });
6390
+
6391
+ it('should reject invalid or conflicting gas overrides', async function() {
6392
+ const requests = [
6393
+ ...[
6394
+ { key: 'gasPrice', values: [0, 1.5, '1000', Number.MAX_SAFE_INTEGER + 1] },
6395
+ { key: 'maxGasFee', values: [0] },
6396
+ { key: 'priorityGasFee', values: [0] }
6397
+ ].flatMap(({ key, values }) =>
6398
+ values.map(value => ({
6399
+ params: { [key]: value }, message: `${key} must be a positive safe integer in wei`
6400
+ }))
6401
+ ),
6402
+ { params: { gasPrice: 1000, txType: 2 }, message: 'gasPrice requires a type 0 transaction' },
6403
+ { params: { maxGasFee: 1000 }, message: 'maxGasFee and priorityGasFee require a type 2 transaction' },
6404
+ { params: { priorityGasFee: 1000, txType: 0 }, message: 'maxGasFee and priorityGasFee require a type 2 transaction' },
6405
+ { params: { maxGasFee: 1000, txType: 2 }, message: 'maxGasFee and priorityGasFee must be supplied together' },
6406
+ { params: { priorityGasFee: 1000, txType: 2 }, message: 'maxGasFee and priorityGasFee must be supplied together' },
6407
+ { params: { gasPrice: 1000, feePerKb: 1000 }, message: 'Gas fee overrides cannot be combined with feePerKb or fee' },
6408
+ { params: { gasPrice: 1000, fee: 1000 }, message: 'Gas fee overrides cannot be combined with feePerKb or fee' },
6409
+ { params: { gasPrice: 1000, sendMax: true }, message: 'Gas fee overrides are not supported with sendMax' },
6410
+ { params: { txType: 2, maxGasFee: 1000, priorityGasFee: 2000 }, message: 'priorityGasFee must not exceed maxGasFee' }
6411
+ ];
6412
+ for (const { params, message } of requests) {
6413
+ await assert.rejects(util.promisify(server.createTx).call(server, makeOpts(params)), { message });
6414
+ }
6415
+ await assert.rejects(util.promisify(server._validateAndSanitizeTxOpts).call(server,
6416
+ { ...wallet, chain: 'btc' }, makeOpts({ gasPrice: 1000 })), {
6417
+ message: 'Gas fee overrides are only supported for EVM chains'
6418
+ });
6419
+ });
6420
+
6421
+ for (const tokenAddress of [undefined, TOKENS[0]]) {
6422
+ it(`should reserve the overridden fee for ${tokenAddress ? 'token' : 'native'} proposals`, async function() {
6423
+ helpers.stubFeeLevels({});
6424
+ // Enough for the default fee, but not the overridden fee.
6425
+ await helpers.stubUtxos(server, wallet, [0.0002]);
6426
+ const defaultTxp = await util.promisify(server.createTx).call(server, makeOpts({ tokenAddress }));
6427
+ defaultTxp.fee.should.equal(100000000000000);
6428
+ await assert.rejects(util.promisify(server.createTx).call(server, makeOpts({
6429
+ txType: 2, maxGasFee: 3000000000, priorityGasFee: 1000000000, tokenAddress
6430
+ })), { code: tokenAddress ? 'INSUFFICIENT_ETH_FEE' : 'INSUFFICIENT_FUNDS_FOR_FEE' });
6431
+ });
6432
+ }
6433
+
6434
+ });
6435
+
6286
6436
  describe('cashAddr backwards compat', function() {
6287
6437
  // LEGACY MODE
6288
6438
  it('should create a BCH tx proposal with cashaddr outputs (w/o prefix) and return Copay addr', function(done) {
@@ -7712,43 +7862,31 @@ describe('Wallet service', function() {
7712
7862
  },
7713
7863
  ];
7714
7864
 
7715
- function checkTx(txOpts, x, cb) {
7716
- function sign(copayerM, tx, cb) {
7717
- helpers.getAuthServer(wallet.copayers[copayerM].id).then(function(server) {
7718
- const signatures = helpers.clientSign(tx, TestData.copayers[copayerM].xPrivKey_44H_0H_0H);
7719
- server.signTx({
7720
- txProposalId: tx.id,
7721
- signatures: signatures,
7722
- }, function(err, txp) {
7723
- should.not.exist(err, err);
7724
-
7725
- if (++copayerM == x.m) {
7726
- return cb(txp);
7727
- } else {
7728
- return sign(copayerM, tx, cb);
7729
- }
7730
- });
7865
+ async function checkTx(txOpts, x): Promise<number> {
7866
+ const tx = await helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0);
7867
+ let txp;
7868
+ for (let copayerM = 0; copayerM < x.m; copayerM++) {
7869
+ const authServer = await helpers.getAuthServer(wallet.copayers[copayerM].id);
7870
+ const signatures = helpers.clientSign(tx, TestData.copayers[copayerM].xPrivKey_44H_0H_0H);
7871
+ txp = await util.promisify(authServer.signTx).call(authServer, {
7872
+ txProposalId: tx.id,
7873
+ signatures: signatures,
7731
7874
  });
7732
7875
  }
7733
-
7734
- helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0).then(function(tx) {
7735
- sign(0, tx, (txp) => {
7736
- should.exist(txp.raw);
7737
- txp.status.should.equal('accepted');
7738
- const t = ChainService.getBitcoreTx(txp);
7739
-
7740
- // Check size and fee rate
7741
- (txp.raw.length / 2).should.equal(t.size);
7742
- const feeRate = t.getFee() / (x.fromSegwit ? t.vsize : t.size) * 1000;
7743
- console.log(`Wire Size: ${t.size} vSize: ${t.vsize} (Segwit: ${x.fromSegwit}, SegwitVersion: ${x.segwitVersion || 0}) Fee:${t.getFee()} ActualRate:${Math.round(feeRate)} RequiredRate:${x.requiredFeeRate}`);
7744
-
7745
- // size should be above (or equal) the required FeeRate
7746
- feeRate.should.not.be.below(x.requiredFeeRate);
7747
- feeRate.should.be.below(x.requiredFeeRate * 1.5); // no more that 50% extra
7748
- return cb(feeRate);
7749
- });
7750
- });
7751
- };
7876
+ should.exist(txp.raw);
7877
+ txp.status.should.equal('accepted');
7878
+ const t = ChainService.getBitcoreTx(txp);
7879
+
7880
+ // Check size and fee rate
7881
+ (txp.raw.length / 2).should.equal(t.size);
7882
+ const feeRate = t.getFee() / (x.fromSegwit ? t.vsize : t.size) * 1000;
7883
+ console.log(`Wire Size: ${t.size} vSize: ${t.vsize} (Segwit: ${x.fromSegwit}, SegwitVersion: ${x.segwitVersion || 0}) Fee:${t.getFee()} ActualRate:${Math.round(feeRate)} RequiredRate:${x.requiredFeeRate}`);
7884
+
7885
+ // size should be above (or equal) the required FeeRate
7886
+ feeRate.should.not.be.below(x.requiredFeeRate);
7887
+ feeRate.should.be.below(x.requiredFeeRate * 1.5); // no more that 50% extra
7888
+ return feeRate;
7889
+ }
7752
7890
 
7753
7891
  for (let i = 0; i < cases.length; i++) {
7754
7892
  const x = cases[i];
@@ -7780,7 +7918,7 @@ describe('Wallet service', function() {
7780
7918
  Object.assign(txOpts, { feePerKb: x.requiredFeeRate });
7781
7919
  }
7782
7920
 
7783
- const fee1 = await new Promise<number>(r => checkTx(txOpts, x, r));
7921
+ const fee1 = await checkTx(txOpts, x);
7784
7922
  should.exist(fee1);
7785
7923
 
7786
7924
  // CASE 8
@@ -7791,7 +7929,7 @@ describe('Wallet service', function() {
7791
7929
  ({ server, wallet } = await helpers.createAndJoinWallet(x.m, x.n, { useNativeSegwit: x.fromSegwit }));
7792
7930
  await helpers.stubUtxos(server, wallet, x.utxos);
7793
7931
  txOpts.payProUrl = null;
7794
- const fee2 = await new Promise<number>(r => checkTx(txOpts, x, r));
7932
+ const fee2 = await checkTx(txOpts, x);
7795
7933
  console.log(`## Fee PayPro: ${fee1} vs ${fee2}`);
7796
7934
  fee1.should.be.above(fee2);
7797
7935
  }
@@ -7880,49 +8018,37 @@ describe('Wallet service', function() {
7880
8018
  },
7881
8019
  ];
7882
8020
 
7883
- function checkTx(txOpts, x, cb) {
7884
- function sign(copayerM, tx, cb) {
7885
- helpers.getAuthServer(wallet.copayers[copayerM].id).then(function(server) {
7886
- const signatures = helpers.clientSign(tx, TestData.copayers[copayerM].xPrivKey_44H_0H_0H);
7887
- server.signTx({
7888
- txProposalId: tx.id,
7889
- signatures: signatures,
7890
- }, function(err, txp) {
7891
- should.not.exist(err, err);
7892
-
7893
- if (++copayerM == x.m) {
7894
- return cb(txp);
7895
- } else {
7896
- return sign(copayerM, tx, cb);
7897
- }
7898
- });
8021
+ async function checkTx(txOpts, x): Promise<number> {
8022
+ const tx = await helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0);
8023
+ let txp;
8024
+ for (let copayerM = 0; copayerM < x.m; copayerM++) {
8025
+ const authServer = await helpers.getAuthServer(wallet.copayers[copayerM].id);
8026
+ const signatures = helpers.clientSign(tx, TestData.copayers[copayerM].xPrivKey_44H_0H_0H);
8027
+ txp = await util.promisify(authServer.signTx).call(authServer, {
8028
+ txProposalId: tx.id,
8029
+ signatures: signatures,
7899
8030
  });
7900
8031
  }
7901
-
7902
- helpers.createAndPublishTx(server, txOpts, TestData.copayers[0].privKey_1H_0).then(function(tx) {
7903
- sign(0, tx, (txp) => {
7904
- should.exist(txp.raw);
7905
- txp.status.should.equal('accepted');
7906
-
7907
- const t = ChainService.getBitcoreTx(txp);
7908
- const vSize = x.vSize || t._estimateSize(); // use given vSize if available
7909
- // Check size and fee rate
7910
- const actualSize = txp.raw.length / 2;
7911
- const actualFeeRate = t.getFee() / (x.fromSegwit ? vSize : actualSize) * 1000;
7912
- console.log(`Wire Size:${actualSize} vSize: ${vSize} (Segwit: ${x.fromSegwit}) Fee: ${t.getFee()} ActualRate:${Math.round(actualFeeRate)} RequiredRate:${x.requiredFeeRate}`);
7913
-
7914
- // Fee should be more than min relay fee
7915
- t.getFee().should.be.gte(CWC.BitcoreLibDoge.Transaction.DUST_AMOUNT);
7916
-
7917
- if (t.getFee() > CWC.BitcoreLibDoge.Transaction.DUST_AMOUNT) {
7918
- // size should be above (or equal) the required FeeRate
7919
- actualFeeRate.should.not.be.below(x.requiredFeeRate);
7920
- actualFeeRate.should.be.below(x.requiredFeeRate * 1.5); // no more that 50% extra
7921
- }
7922
- return cb(actualFeeRate);
7923
- });
7924
- });
7925
- };
8032
+ should.exist(txp.raw);
8033
+ txp.status.should.equal('accepted');
8034
+
8035
+ const t = ChainService.getBitcoreTx(txp);
8036
+ const vSize = x.vSize || t._estimateSize(); // use given vSize if available
8037
+ // Check size and fee rate
8038
+ const actualSize = txp.raw.length / 2;
8039
+ const actualFeeRate = t.getFee() / (x.fromSegwit ? vSize : actualSize) * 1000;
8040
+ console.log(`Wire Size:${actualSize} vSize: ${vSize} (Segwit: ${x.fromSegwit}) Fee: ${t.getFee()} ActualRate:${Math.round(actualFeeRate)} RequiredRate:${x.requiredFeeRate}`);
8041
+
8042
+ // Fee should be more than min relay fee
8043
+ t.getFee().should.be.gte(CWC.BitcoreLibDoge.Transaction.DUST_AMOUNT);
8044
+
8045
+ if (t.getFee() > CWC.BitcoreLibDoge.Transaction.DUST_AMOUNT) {
8046
+ // size should be above (or equal) the required FeeRate
8047
+ actualFeeRate.should.not.be.below(x.requiredFeeRate);
8048
+ actualFeeRate.should.be.below(x.requiredFeeRate * 1.5); // no more that 50% extra
8049
+ }
8050
+ return actualFeeRate;
8051
+ }
7926
8052
 
7927
8053
  for (let i = 0; i < cases.length; i++) {
7928
8054
  const x = cases[i];
@@ -7954,7 +8080,7 @@ describe('Wallet service', function() {
7954
8080
  Object.assign(txOpts, { feePerKb: x.requiredFeeRate });
7955
8081
  }
7956
8082
 
7957
- const fee1 = await new Promise<number>(r => checkTx(txOpts, x, r));
8083
+ const fee1 = await checkTx(txOpts, x);
7958
8084
  should.exist(fee1);
7959
8085
 
7960
8086
  // CASE 8
@@ -7965,7 +8091,7 @@ describe('Wallet service', function() {
7965
8091
  ({ server, wallet } = await helpers.createAndJoinWallet(x.m, x.n, { useNativeSegwit: x.fromSegwit }));
7966
8092
  await helpers.stubUtxos(server, wallet, x.utxos);
7967
8093
  txOpts.payProUrl = null;
7968
- const fee2 = await new Promise<number>(r => checkTx(txOpts, x, r));
8094
+ const fee2 = await checkTx(txOpts, x);
7969
8095
  console.log(`## Fee PayPro: ${fee1} vs ${fee2}`);
7970
8096
  fee1.should.be.above(fee2);
7971
8097
  }
@@ -11637,10 +11763,6 @@ describe('Wallet service', function() {
11637
11763
  simplex: {
11638
11764
  disabled: false,
11639
11765
  removed: false
11640
- },
11641
- wyre: {
11642
- disabled: false,
11643
- removed: false
11644
11766
  }
11645
11767
  },
11646
11768
  sellCrypto: {
@@ -11730,10 +11852,6 @@ describe('Wallet service', function() {
11730
11852
  transak: {
11731
11853
  disabled: false,
11732
11854
  removed: false
11733
- },
11734
- wyre: {
11735
- disabled: false,
11736
- removed: false
11737
11855
  }
11738
11856
  },
11739
11857
  sellCrypto: {