@bitpay-labs/bitcore-wallet-service 11.11.3 → 11.11.4

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 (109) hide show
  1. package/package.json +4 -4
  2. package/src/config.ts +8 -0
  3. package/src/externalservices/coingecko.ts +6 -1
  4. package/src/externalservices/transak.ts +394 -70
  5. package/src/lib/blockchainexplorer.ts +4 -0
  6. package/src/lib/blockchainexplorers/v8.ts +1 -0
  7. package/src/lib/blockchainmonitor.ts +1 -0
  8. package/src/lib/chain/arc/index.ts +95 -0
  9. package/src/lib/chain/eth/index.ts +41 -23
  10. package/src/lib/chain/index.ts +2 -0
  11. package/src/lib/common/constants.ts +12 -1
  12. package/src/lib/common/defaults.ts +31 -0
  13. package/src/lib/emailservice.ts +3 -1
  14. package/src/lib/errors/errordefinitions.ts +4 -0
  15. package/src/lib/model/preferences.ts +4 -0
  16. package/src/lib/model/wallet.ts +1 -0
  17. package/src/lib/pushnotificationsservice.ts +2 -0
  18. package/src/lib/routes/services.ts +1 -1
  19. package/src/lib/routes/walletdata.ts +2 -0
  20. package/src/lib/server.ts +20 -2
  21. package/test/blockchainexplorer.test.ts +7 -0
  22. package/test/expressapp.test.ts +31 -0
  23. package/test/integration/externalservices/coinGecko.test.ts +42 -2
  24. package/test/integration/externalservices/transak.test.ts +545 -135
  25. package/test/integration/fiatrateservice.test.ts +13 -0
  26. package/test/integration/helpers.ts +1 -0
  27. package/test/integration/server.test.ts +139 -3
  28. package/ts_build/package.json +1 -1
  29. package/ts_build/src/config.d.ts.map +1 -1
  30. package/ts_build/src/config.js +8 -0
  31. package/ts_build/src/config.js.map +1 -1
  32. package/ts_build/src/externalservices/coingecko.d.ts.map +1 -1
  33. package/ts_build/src/externalservices/coingecko.js +6 -1
  34. package/ts_build/src/externalservices/coingecko.js.map +1 -1
  35. package/ts_build/src/externalservices/transak.d.ts +28 -2
  36. package/ts_build/src/externalservices/transak.d.ts.map +1 -1
  37. package/ts_build/src/externalservices/transak.js +274 -57
  38. package/ts_build/src/externalservices/transak.js.map +1 -1
  39. package/ts_build/src/lib/blockchainexplorer.d.ts.map +1 -1
  40. package/ts_build/src/lib/blockchainexplorer.js +4 -0
  41. package/ts_build/src/lib/blockchainexplorer.js.map +1 -1
  42. package/ts_build/src/lib/blockchainexplorers/v8.d.ts.map +1 -1
  43. package/ts_build/src/lib/blockchainexplorers/v8.js +1 -0
  44. package/ts_build/src/lib/blockchainexplorers/v8.js.map +1 -1
  45. package/ts_build/src/lib/blockchainmonitor.d.ts.map +1 -1
  46. package/ts_build/src/lib/blockchainmonitor.js +1 -0
  47. package/ts_build/src/lib/blockchainmonitor.js.map +1 -1
  48. package/ts_build/src/lib/chain/arc/index.d.ts +20 -0
  49. package/ts_build/src/lib/chain/arc/index.d.ts.map +1 -0
  50. package/ts_build/src/lib/chain/arc/index.js +95 -0
  51. package/ts_build/src/lib/chain/arc/index.js.map +1 -0
  52. package/ts_build/src/lib/chain/eth/index.d.ts +1 -0
  53. package/ts_build/src/lib/chain/eth/index.d.ts.map +1 -1
  54. package/ts_build/src/lib/chain/eth/index.js +38 -19
  55. package/ts_build/src/lib/chain/eth/index.js.map +1 -1
  56. package/ts_build/src/lib/chain/index.d.ts.map +1 -1
  57. package/ts_build/src/lib/chain/index.js +2 -0
  58. package/ts_build/src/lib/chain/index.js.map +1 -1
  59. package/ts_build/src/lib/common/constants.d.ts +12 -0
  60. package/ts_build/src/lib/common/constants.d.ts.map +1 -1
  61. package/ts_build/src/lib/common/constants.js +12 -1
  62. package/ts_build/src/lib/common/constants.js.map +1 -1
  63. package/ts_build/src/lib/common/defaults.d.ts +24 -0
  64. package/ts_build/src/lib/common/defaults.d.ts.map +1 -1
  65. package/ts_build/src/lib/common/defaults.js +30 -0
  66. package/ts_build/src/lib/common/defaults.js.map +1 -1
  67. package/ts_build/src/lib/common/index.d.ts +36 -0
  68. package/ts_build/src/lib/common/index.d.ts.map +1 -1
  69. package/ts_build/src/lib/emailservice.d.ts.map +1 -1
  70. package/ts_build/src/lib/emailservice.js +2 -0
  71. package/ts_build/src/lib/emailservice.js.map +1 -1
  72. package/ts_build/src/lib/errors/errordefinitions.d.ts +2 -0
  73. package/ts_build/src/lib/errors/errordefinitions.d.ts.map +1 -1
  74. package/ts_build/src/lib/errors/errordefinitions.js +2 -0
  75. package/ts_build/src/lib/errors/errordefinitions.js.map +1 -1
  76. package/ts_build/src/lib/model/preferences.d.ts +2 -0
  77. package/ts_build/src/lib/model/preferences.d.ts.map +1 -1
  78. package/ts_build/src/lib/model/preferences.js +3 -0
  79. package/ts_build/src/lib/model/preferences.js.map +1 -1
  80. package/ts_build/src/lib/model/wallet.d.ts.map +1 -1
  81. package/ts_build/src/lib/model/wallet.js +1 -0
  82. package/ts_build/src/lib/model/wallet.js.map +1 -1
  83. package/ts_build/src/lib/pushnotificationsservice.d.ts.map +1 -1
  84. package/ts_build/src/lib/pushnotificationsservice.js +2 -0
  85. package/ts_build/src/lib/pushnotificationsservice.js.map +1 -1
  86. package/ts_build/src/lib/routes/services.js +1 -1
  87. package/ts_build/src/lib/routes/services.js.map +1 -1
  88. package/ts_build/src/lib/routes/walletdata.d.ts.map +1 -1
  89. package/ts_build/src/lib/routes/walletdata.js +2 -0
  90. package/ts_build/src/lib/routes/walletdata.js.map +1 -1
  91. package/ts_build/src/lib/server.d.ts.map +1 -1
  92. package/ts_build/src/lib/server.js +17 -2
  93. package/ts_build/src/lib/server.js.map +1 -1
  94. package/ts_build/test/blockchainexplorer.test.js +6 -0
  95. package/ts_build/test/blockchainexplorer.test.js.map +1 -1
  96. package/ts_build/test/expressapp.test.js +30 -0
  97. package/ts_build/test/expressapp.test.js.map +1 -1
  98. package/ts_build/test/integration/externalservices/coinGecko.test.js +38 -2
  99. package/ts_build/test/integration/externalservices/coinGecko.test.js.map +1 -1
  100. package/ts_build/test/integration/externalservices/transak.test.d.ts.map +1 -1
  101. package/ts_build/test/integration/externalservices/transak.test.js +498 -128
  102. package/ts_build/test/integration/externalservices/transak.test.js.map +1 -1
  103. package/ts_build/test/integration/fiatrateservice.test.js +11 -0
  104. package/ts_build/test/integration/fiatrateservice.test.js.map +1 -1
  105. package/ts_build/test/integration/helpers.d.ts.map +1 -1
  106. package/ts_build/test/integration/helpers.js +1 -0
  107. package/ts_build/test/integration/helpers.js.map +1 -1
  108. package/ts_build/test/integration/server.test.js +135 -3
  109. package/ts_build/test/integration/server.test.js.map +1 -1
@@ -57,6 +57,7 @@ const TestData = __importStar(require("../testdata"));
57
57
  const helpers_1 = __importDefault(require("./helpers"));
58
58
  const clienterror_1 = require("../../src/lib/errors/clienterror");
59
59
  const expressapp_1 = require("../../src/lib/expressapp");
60
+ const abi_erc20_1 = require("../../src/lib/chain/eth/abi-erc20");
60
61
  const should = chai.should();
61
62
  config_1.default.moralis = config_1.default.moralis ?? {
62
63
  apiKey: 'apiKey',
@@ -2499,6 +2500,28 @@ describe('Wallet service', function () {
2499
2500
  beforeEach(async function () {
2500
2501
  ({ server, wallet } = await helpers_1.default.createAndJoinWallet(1, 1, { coin: 'eth' }));
2501
2502
  });
2503
+ it('should save and merge Arc token preferences without linking native USDC', async function () {
2504
+ ({ server } = await helpers_1.default.createAndJoinWallet(1, 1, { coin: 'arc', network: 'livenet' }));
2505
+ await util_1.default.promisify(server.savePreferences).call(server, { arcTokenAddresses: [TOKENS[0]], language: 'es' });
2506
+ await util_1.default.promisify(server.savePreferences).call(server, {
2507
+ arcTokenAddresses: [TOKENS[1], CWC.ethers.getAddress(TOKENS[0])],
2508
+ });
2509
+ let preferences = await util_1.default.promisify(server.getPreferences).call(server, {});
2510
+ preferences.arcTokenAddresses.should.deep.equal(TOKENS);
2511
+ preferences.language.should.equal('es');
2512
+ try {
2513
+ await util_1.default.promisify(server.savePreferences).call(server, {
2514
+ arcTokenAddresses: [TOKENS[0], CWC.Constants.ARC.USDC_CONTRACT_ADDRESS], language: 'en',
2515
+ });
2516
+ should.fail('Expected native USDC token preference rejection');
2517
+ }
2518
+ catch (err) {
2519
+ err.message.toString().should.contain('arcTokenAddresses');
2520
+ }
2521
+ preferences = await util_1.default.promisify(server.getPreferences).call(server, {});
2522
+ preferences.arcTokenAddresses.should.deep.equal(TOKENS);
2523
+ preferences.language.should.equal('es');
2524
+ });
2502
2525
  it('should save & retrieve preferences', function (done) {
2503
2526
  server.savePreferences({
2504
2527
  email: 'dummy@dummy.com',
@@ -2685,7 +2708,8 @@ describe('Wallet service', function () {
2685
2708
  unit: 'xxxxx',
2686
2709
  },
2687
2710
  expected: 'unit'
2688
- },];
2711
+ }, ...['not-an-array', ['invalid']]
2712
+ .map(arcTokenAddresses => ({ preferences: { arcTokenAddresses }, expected: 'arcTokenAddresses' }))];
2689
2713
  for (const item of invalid) {
2690
2714
  try {
2691
2715
  await util_1.default.promisify(server.savePreferences).call(server, item.preferences);
@@ -5737,6 +5761,111 @@ describe('Wallet service', function () {
5737
5761
  });
5738
5762
  });
5739
5763
  });
5764
+ for (const [network, chainId] of [['livenet', 5042n], ['testnet', 5042002n]]) {
5765
+ describe(`#createTX ARC ${network}`, () => {
5766
+ let server;
5767
+ let from;
5768
+ const destination = '0x37d7B3bBD88EFdE6a93cF74D2F5b0385D3E3B08A';
5769
+ const usdc = new CWC.ethers.Interface(abi_erc20_1.ERC20Abi);
5770
+ const contractOpts = (data) => makeOpts({
5771
+ outputs: [{ toAddress: CWC.Constants.ARC.USDC_CONTRACT_ADDRESS, amount: 0, gasLimit: 100000, data }]
5772
+ });
5773
+ const makeOpts = (overrides = {}) => ({
5774
+ outputs: [{ toAddress: destination, amount: 1e18, gasLimit: 21000 }],
5775
+ nonce: 0, feeLevel: 'normal', ...overrides
5776
+ });
5777
+ beforeEach(async () => {
5778
+ ({ server } = await helpers_1.default.createAndJoinWallet(1, 1, { coin: 'arc', network }));
5779
+ from = (await util_1.default.promisify(server.createAddress).call(server, {})).address;
5780
+ blockchainExplorer.getBalance = sinon_1.default.stub().callsArgWith(1, null, { balance: 2e18, confirmed: 2e18, unconfirmed: 0 });
5781
+ helpers_1.default.stubFeeLevels({ 1: 25000000000, 2: 25000000000, 3: 25000000000, 4: 25000000000 }, true, 'arc');
5782
+ });
5783
+ for (const [txType, sendMax] of [[0, false], [2, false], [2, true]]) {
5784
+ it(`should publish, sign and submit a type ${txType} native USDC ${sendMax ? 'send-max ' : ''}proposal`, async () => {
5785
+ const maxGasFee = sendMax ? 31000000000 : 30000000000;
5786
+ sinon_1.default.stub(server, 'estimateFee').resolves(maxGasFee).onFirstCall().resolves(30000000000);
5787
+ sinon_1.default.stub(server, 'estimatePriorityFee').resolves(0);
5788
+ const fee = (txType === 2 ? maxGasFee : 25000000000) * 21000;
5789
+ const amount = sendMax ? 2e18 - fee : 1e18;
5790
+ const txp = await util_1.default.promisify(server.createTx).call(server, makeOpts({ txType, sendMax,
5791
+ outputs: [{ toAddress: destination, amount: sendMax ? null : amount, gasLimit: 21000 }] }));
5792
+ txp.fee.should.equal(fee);
5793
+ txp.amount.should.equal(amount);
5794
+ await util_1.default.promisify(server.publishTx).call(server, helpers_1.default.getProposalSignatureOpts(txp, TestData.copayers[0].privKey_1H_0));
5795
+ await util_1.default.promisify(server.signTx).call(server, { txProposalId: txp.id, signatures: helpers_1.default.clientSign(txp, TestData.copayers[0].xPrivKey_44H_0H_0H) });
5796
+ const accepted = await util_1.default.promisify(server.getTx).call(server, { txProposalId: txp.id });
5797
+ accepted.status.should.equal('accepted');
5798
+ const [raw] = accepted.getRawTx();
5799
+ const signed = CWC.ethers.Transaction.from(raw);
5800
+ signed.chainId.should.equal(chainId);
5801
+ signed.value.should.equal(BigInt(amount));
5802
+ BigInt(txp.fee).should.equal((signed.maxFeePerGas ?? signed.gasPrice) * signed.gasLimit);
5803
+ signed.isSigned().should.equal(true);
5804
+ helpers_1.default.stubBroadcast(accepted.txid);
5805
+ await util_1.default.promisify(server.broadcastTx).call(server, { txProposalId: txp.id });
5806
+ blockchainExplorer.broadcast.firstCall.args[0].should.deep.equal([raw]);
5807
+ (await util_1.default.promisify(server.getTx).call(server, { txProposalId: txp.id })).status.should.equal('broadcasted');
5808
+ });
5809
+ }
5810
+ it('should reserve wallet-owned USDC contract debits and release them when removed', async () => {
5811
+ for (const [method, args, debit, legacyData] of [
5812
+ ['transfer', [destination, 1000000n], 1e18],
5813
+ ['transferFrom', [from, destination, 1000000n], 1e18],
5814
+ ['transferFrom', [destination, from, 1000000n], 0],
5815
+ ['approve', [destination, 1000000n], 0],
5816
+ ['approve', [destination, 1000000n], 1e18, usdc.encodeFunctionData('transfer', [destination, 1000000n])]
5817
+ ]) {
5818
+ const data = usdc.encodeFunctionData(method, args);
5819
+ const txp = await util_1.default.promisify(server.createTx).call(server, { ...contractOpts(data), data: legacyData });
5820
+ txp.amount.should.equal(0);
5821
+ txp.outputs[0].amount.should.equal(0);
5822
+ txp.outputs[0].data.should.equal(data);
5823
+ CWC.ethers.Transaction.from(txp.getRawTx()[0]).data.should.equal(legacyData || data);
5824
+ await util_1.default.promisify(server.publishTx).call(server, helpers_1.default.getProposalSignatureOpts(txp, TestData.copayers[0].privKey_1H_0));
5825
+ const balance = await util_1.default.promisify(server.getBalance).call(server, {});
5826
+ balance.lockedAmount.should.equal(debit + txp.fee);
5827
+ balance.availableAmount.should.equal(2e18 - debit - txp.fee);
5828
+ if (debit) {
5829
+ try {
5830
+ await util_1.default.promisify(server.createTx).call(server, makeOpts({ nonce: 1,
5831
+ outputs: [{ toAddress: destination, amount: 1.5e18, gasLimit: 21000 }] }));
5832
+ should.fail('Expected pending USDC funds to be unavailable');
5833
+ }
5834
+ catch (err) {
5835
+ err.code.should.equal('LOCKED_FUNDS');
5836
+ }
5837
+ }
5838
+ await util_1.default.promisify(server.removePendingTx).call(server, { txProposalId: txp.id });
5839
+ (await util_1.default.promisify(server.getBalance).call(server, {})).lockedAmount.should.equal(0);
5840
+ }
5841
+ });
5842
+ it('should reject underpriced proposals, duplicate USDC token views and zero-address transfers', async () => {
5843
+ try {
5844
+ await util_1.default.promisify(server.getBalance).call(server, { tokenAddress: CWC.Constants.ARC.USDC_CONTRACT_ADDRESS });
5845
+ throw new Error('Expected duplicate token balance rejection');
5846
+ }
5847
+ catch (err) {
5848
+ err.message.should.contain('omit tokenAddress');
5849
+ }
5850
+ for (const [opts, message] of [
5851
+ [makeOpts({ feeLevel: undefined, feePerKb: 10000000000 }), 'at least 20 gwei'],
5852
+ [makeOpts({ tokenAddress: CWC.Constants.ARC.USDC_CONTRACT_ADDRESS }), 'omit tokenAddress'],
5853
+ [contractOpts(usdc.encodeFunctionData('transfer', [destination, 3000000n])), 'Insufficient funds'],
5854
+ [contractOpts(usdc.encodeFunctionData('transfer', [destination, 2000000n])), 'Insufficient funds for fee'],
5855
+ [contractOpts(usdc.getFunction('transfer').selector), 'Invalid Arc USDC contract call data'],
5856
+ [makeOpts({ outputs: [{ toAddress: '0x0000000000000000000000000000000000000000', amount: 1e18 }] }), 'zero address']
5857
+ ]) {
5858
+ try {
5859
+ await util_1.default.promisify(server.createTx).call(server, opts);
5860
+ throw new Error('Expected proposal rejection');
5861
+ }
5862
+ catch (err) {
5863
+ err.message.should.contain(message);
5864
+ }
5865
+ }
5866
+ });
5867
+ });
5868
+ }
5740
5869
  describe('#createTX ETH Only tests', () => {
5741
5870
  let server;
5742
5871
  let wallet;
@@ -5919,8 +6048,8 @@ describe('Wallet service', function () {
5919
6048
  sinon_1.default.stub(server, 'estimatePriorityFee').resolves(1000000000);
5920
6049
  const txp = await util_1.default.promisify(server.createTx).call(server, makeOpts({ txType: 2 }));
5921
6050
  txp.feeLevel.should.equal('normal');
5922
- txp.gasPrice.should.equal(1000000000);
5923
- txp.fee.should.equal(100000000000000);
6051
+ txp.gasPrice.should.equal(4500000000);
6052
+ txp.fee.should.equal(450000000000000);
5924
6053
  txp.maxGasFee.should.equal(4500000000);
5925
6054
  txp.priorityGasFee.should.equal(1000000000);
5926
6055
  const [raw] = txp.getRawTx();
@@ -5973,6 +6102,9 @@ describe('Wallet service', function () {
5973
6102
  await helpers_1.default.stubUtxos(server, wallet, [0.0002]);
5974
6103
  const defaultTxp = await util_1.default.promisify(server.createTx).call(server, makeOpts({ tokenAddress }));
5975
6104
  defaultTxp.fee.should.equal(100000000000000);
6105
+ sinon_1.default.stub(server, 'estimateFee').resolves(3000000000);
6106
+ sinon_1.default.stub(server, 'estimatePriorityFee').resolves(1000000000);
6107
+ await assert_1.default.rejects(util_1.default.promisify(server.createTx).call(server, makeOpts({ txType: 2, tokenAddress })), { code: tokenAddress ? 'INSUFFICIENT_ETH_FEE' : 'INSUFFICIENT_FUNDS_FOR_FEE' });
5976
6108
  await assert_1.default.rejects(util_1.default.promisify(server.createTx).call(server, makeOpts({
5977
6109
  txType: 2, maxGasFee: 3000000000, priorityGasFee: 1000000000, tokenAddress
5978
6110
  })), { code: tokenAddress ? 'INSUFFICIENT_ETH_FEE' : 'INSUFFICIENT_FUNDS_FOR_FEE' });