@bitpay-labs/bitcore-wallet-service 11.11.2 → 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 (152) 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 +13 -2
  12. package/src/lib/common/defaults.ts +31 -0
  13. package/src/lib/common/utils.ts +18 -1
  14. package/src/lib/emailservice.ts +3 -1
  15. package/src/lib/errors/errordefinitions.ts +4 -0
  16. package/src/lib/model/preferences.ts +4 -0
  17. package/src/lib/model/tsskeygen.ts +16 -0
  18. package/src/lib/model/wallet.ts +1 -0
  19. package/src/lib/pushnotificationsservice.ts +2 -0
  20. package/src/lib/routes/maintenance.ts +11 -2
  21. package/src/lib/routes/middleware/authTssRequest.ts +28 -16
  22. package/src/lib/routes/middleware/verifyTssMessage.ts +4 -1
  23. package/src/lib/routes/services.ts +8 -2
  24. package/src/lib/routes/tss.ts +33 -30
  25. package/src/lib/routes/walletdata.ts +2 -0
  26. package/src/lib/server.ts +82 -19
  27. package/src/lib/storage.ts +39 -0
  28. package/src/lib/tss.ts +111 -7
  29. package/test/blockchainexplorer.test.ts +7 -0
  30. package/test/expressapp.test.ts +130 -0
  31. package/test/integration/externalservices/coinGecko.test.ts +42 -2
  32. package/test/integration/externalservices/transak.test.ts +545 -135
  33. package/test/integration/fiatrateservice.test.ts +13 -0
  34. package/test/integration/helpers.ts +1 -0
  35. package/test/integration/server.test.ts +192 -4
  36. package/test/integration/tss.test.ts +428 -0
  37. package/ts_build/package.json +4 -4
  38. package/ts_build/src/config.d.ts.map +1 -1
  39. package/ts_build/src/config.js +8 -0
  40. package/ts_build/src/config.js.map +1 -1
  41. package/ts_build/src/externalservices/coingecko.d.ts.map +1 -1
  42. package/ts_build/src/externalservices/coingecko.js +6 -1
  43. package/ts_build/src/externalservices/coingecko.js.map +1 -1
  44. package/ts_build/src/externalservices/transak.d.ts +28 -2
  45. package/ts_build/src/externalservices/transak.d.ts.map +1 -1
  46. package/ts_build/src/externalservices/transak.js +274 -57
  47. package/ts_build/src/externalservices/transak.js.map +1 -1
  48. package/ts_build/src/lib/blockchainexplorer.d.ts.map +1 -1
  49. package/ts_build/src/lib/blockchainexplorer.js +4 -0
  50. package/ts_build/src/lib/blockchainexplorer.js.map +1 -1
  51. package/ts_build/src/lib/blockchainexplorers/v8.d.ts.map +1 -1
  52. package/ts_build/src/lib/blockchainexplorers/v8.js +1 -0
  53. package/ts_build/src/lib/blockchainexplorers/v8.js.map +1 -1
  54. package/ts_build/src/lib/blockchainmonitor.d.ts.map +1 -1
  55. package/ts_build/src/lib/blockchainmonitor.js +1 -0
  56. package/ts_build/src/lib/blockchainmonitor.js.map +1 -1
  57. package/ts_build/src/lib/chain/arc/index.d.ts +20 -0
  58. package/ts_build/src/lib/chain/arc/index.d.ts.map +1 -0
  59. package/ts_build/src/lib/chain/arc/index.js +95 -0
  60. package/ts_build/src/lib/chain/arc/index.js.map +1 -0
  61. package/ts_build/src/lib/chain/eth/index.d.ts +1 -0
  62. package/ts_build/src/lib/chain/eth/index.d.ts.map +1 -1
  63. package/ts_build/src/lib/chain/eth/index.js +38 -19
  64. package/ts_build/src/lib/chain/eth/index.js.map +1 -1
  65. package/ts_build/src/lib/chain/index.d.ts.map +1 -1
  66. package/ts_build/src/lib/chain/index.js +2 -0
  67. package/ts_build/src/lib/chain/index.js.map +1 -1
  68. package/ts_build/src/lib/common/constants.d.ts +13 -1
  69. package/ts_build/src/lib/common/constants.d.ts.map +1 -1
  70. package/ts_build/src/lib/common/constants.js +13 -2
  71. package/ts_build/src/lib/common/constants.js.map +1 -1
  72. package/ts_build/src/lib/common/defaults.d.ts +24 -0
  73. package/ts_build/src/lib/common/defaults.d.ts.map +1 -1
  74. package/ts_build/src/lib/common/defaults.js +30 -0
  75. package/ts_build/src/lib/common/defaults.js.map +1 -1
  76. package/ts_build/src/lib/common/index.d.ts +38 -1
  77. package/ts_build/src/lib/common/index.d.ts.map +1 -1
  78. package/ts_build/src/lib/common/utils.d.ts +1 -0
  79. package/ts_build/src/lib/common/utils.d.ts.map +1 -1
  80. package/ts_build/src/lib/common/utils.js +16 -1
  81. package/ts_build/src/lib/common/utils.js.map +1 -1
  82. package/ts_build/src/lib/emailservice.d.ts.map +1 -1
  83. package/ts_build/src/lib/emailservice.js +2 -0
  84. package/ts_build/src/lib/emailservice.js.map +1 -1
  85. package/ts_build/src/lib/errors/errordefinitions.d.ts +2 -0
  86. package/ts_build/src/lib/errors/errordefinitions.d.ts.map +1 -1
  87. package/ts_build/src/lib/errors/errordefinitions.js +2 -0
  88. package/ts_build/src/lib/errors/errordefinitions.js.map +1 -1
  89. package/ts_build/src/lib/model/preferences.d.ts +2 -0
  90. package/ts_build/src/lib/model/preferences.d.ts.map +1 -1
  91. package/ts_build/src/lib/model/preferences.js +3 -0
  92. package/ts_build/src/lib/model/preferences.js.map +1 -1
  93. package/ts_build/src/lib/model/tsskeygen.d.ts +10 -0
  94. package/ts_build/src/lib/model/tsskeygen.d.ts.map +1 -1
  95. package/ts_build/src/lib/model/tsskeygen.js +3 -0
  96. package/ts_build/src/lib/model/tsskeygen.js.map +1 -1
  97. package/ts_build/src/lib/model/wallet.d.ts.map +1 -1
  98. package/ts_build/src/lib/model/wallet.js +1 -0
  99. package/ts_build/src/lib/model/wallet.js.map +1 -1
  100. package/ts_build/src/lib/pushnotificationsservice.d.ts.map +1 -1
  101. package/ts_build/src/lib/pushnotificationsservice.js +2 -0
  102. package/ts_build/src/lib/pushnotificationsservice.js.map +1 -1
  103. package/ts_build/src/lib/routes/maintenance.d.ts.map +1 -1
  104. package/ts_build/src/lib/routes/maintenance.js +12 -4
  105. package/ts_build/src/lib/routes/maintenance.js.map +1 -1
  106. package/ts_build/src/lib/routes/middleware/authTssRequest.d.ts +6 -2
  107. package/ts_build/src/lib/routes/middleware/authTssRequest.d.ts.map +1 -1
  108. package/ts_build/src/lib/routes/middleware/authTssRequest.js +21 -14
  109. package/ts_build/src/lib/routes/middleware/authTssRequest.js.map +1 -1
  110. package/ts_build/src/lib/routes/middleware/verifyTssMessage.d.ts.map +1 -1
  111. package/ts_build/src/lib/routes/middleware/verifyTssMessage.js +2 -1
  112. package/ts_build/src/lib/routes/middleware/verifyTssMessage.js.map +1 -1
  113. package/ts_build/src/lib/routes/services.d.ts.map +1 -1
  114. package/ts_build/src/lib/routes/services.js +7 -2
  115. package/ts_build/src/lib/routes/services.js.map +1 -1
  116. package/ts_build/src/lib/routes/tss.d.ts.map +1 -1
  117. package/ts_build/src/lib/routes/tss.js +32 -30
  118. package/ts_build/src/lib/routes/tss.js.map +1 -1
  119. package/ts_build/src/lib/routes/walletdata.d.ts.map +1 -1
  120. package/ts_build/src/lib/routes/walletdata.js +2 -0
  121. package/ts_build/src/lib/routes/walletdata.js.map +1 -1
  122. package/ts_build/src/lib/server.d.ts +23 -2
  123. package/ts_build/src/lib/server.d.ts.map +1 -1
  124. package/ts_build/src/lib/server.js +37 -5
  125. package/ts_build/src/lib/server.js.map +1 -1
  126. package/ts_build/src/lib/storage.d.ts +9 -0
  127. package/ts_build/src/lib/storage.d.ts.map +1 -1
  128. package/ts_build/src/lib/storage.js +26 -0
  129. package/ts_build/src/lib/storage.js.map +1 -1
  130. package/ts_build/src/lib/tss.d.ts +12 -0
  131. package/ts_build/src/lib/tss.d.ts.map +1 -1
  132. package/ts_build/src/lib/tss.js +64 -5
  133. package/ts_build/src/lib/tss.js.map +1 -1
  134. package/ts_build/test/blockchainexplorer.test.js +6 -0
  135. package/ts_build/test/blockchainexplorer.test.js.map +1 -1
  136. package/ts_build/test/expressapp.test.js +120 -0
  137. package/ts_build/test/expressapp.test.js.map +1 -1
  138. package/ts_build/test/integration/externalservices/coinGecko.test.js +38 -2
  139. package/ts_build/test/integration/externalservices/coinGecko.test.js.map +1 -1
  140. package/ts_build/test/integration/externalservices/transak.test.d.ts.map +1 -1
  141. package/ts_build/test/integration/externalservices/transak.test.js +498 -128
  142. package/ts_build/test/integration/externalservices/transak.test.js.map +1 -1
  143. package/ts_build/test/integration/fiatrateservice.test.js +11 -0
  144. package/ts_build/test/integration/fiatrateservice.test.js.map +1 -1
  145. package/ts_build/test/integration/helpers.d.ts.map +1 -1
  146. package/ts_build/test/integration/helpers.js +1 -0
  147. package/ts_build/test/integration/helpers.js.map +1 -1
  148. package/ts_build/test/integration/server.test.js +182 -3
  149. package/ts_build/test/integration/server.test.js.map +1 -1
  150. package/ts_build/test/integration/tss.test.d.ts.map +1 -1
  151. package/ts_build/test/integration/tss.test.js +344 -0
  152. package/ts_build/test/integration/tss.test.js.map +1 -1
@@ -931,6 +931,19 @@ describe('Fiat rate service', function() {
931
931
  });
932
932
  });
933
933
  });
934
+ it('should fetch and store USD-pegged rates for native USDC on Arc', async function() {
935
+ await util.promisify(service.storage.storeFiatRate).call(service.storage, 'btc', btcRates);
936
+ request.get.yields(null, null, btcRates.map(({ code, value }) => ({ code, rate: value })));
937
+
938
+ await util.promisify(service._fetch).call(service);
939
+
940
+ const storedRate = await util.promisify(service.getRate).call(service, { coin: 'arc', code: 'USD' });
941
+ storedRate.rate.should.equal(1);
942
+ const rates = await util.promisify(service.getRatesByCoin).call(service, { coin: 'arc' });
943
+ rates.find(rate => rate.code === 'USD').rate.should.equal(1);
944
+ rates.find(rate => rate.code === 'EUR').rate.should.equal(0.87);
945
+ request.get.calledWith(sinon.match({ url: sinon.match(/\/rates\/ARC\?/) })).should.equal(false);
946
+ });
934
947
  it('should get rate for specific ts', function(done) {
935
948
  const clock = sinon.useFakeTimers({ toFake: ['Date'] });
936
949
  clock.tick(20);
@@ -555,6 +555,7 @@ class Helpers {
555
555
 
556
556
  switch (txp.coin) {
557
557
  case 'eth':
558
+ case 'arc':
558
559
  case 'xrp':
559
560
  // For eth => account, 0, change = 0
560
561
  const priv = xpriv.derive('m/0/0').privateKey;
@@ -21,6 +21,8 @@ import * as TestData from '../testdata';
21
21
  import helpers from './helpers';
22
22
  import { ClientError } from '../../src/lib/errors/clienterror';
23
23
  import { ExpressApp } from '../../src/lib/expressapp';
24
+ import { ERC20Abi } from '../../src/lib/chain/eth/abi-erc20';
25
+ import { type JoinWalletOpts } from '../../src/lib/server';
24
26
 
25
27
  const should = chai.should();
26
28
  config.moralis = config.moralis ?? {
@@ -1120,7 +1122,7 @@ describe('Wallet service', function() {
1120
1122
  xPubKey: TestData.copayers[0].xPubKey_44H_0H_0H,
1121
1123
  requestPubKey: TestData.copayers[0].pubKey_1H_0,
1122
1124
  };
1123
- server.joinWallet(copayerOpts, function(err) {
1125
+ server.joinWallet(copayerOpts as JoinWalletOpts, function(err) {
1124
1126
  should.exist(err);
1125
1127
  err.message.should.contain('argument: copayerSignature missing');
1126
1128
  done();
@@ -1774,6 +1776,57 @@ describe('Wallet service', function() {
1774
1776
  wallet.copayers.length.should.equal(0);
1775
1777
  });
1776
1778
  });
1779
+
1780
+ describe('TSS wallets (concurrent join)', function() {
1781
+ it('should keep a copayer that joins while the wallet is being registered', async function() {
1782
+ const server = new WalletService();
1783
+ const copayerIds = [0, 1].map(i => Model.Copayer.xPubToCopayerId('btc', TestData.copayers[i].xPubKey_44H_0H_0H));
1784
+
1785
+ const session = TssKeyGenModel.create({
1786
+ id: 'tss-join-during-register-test-session',
1787
+ message: { partyId: 0, broadcastMessages: [], p2pMessages: [], publicKey: 'dummy', round: 0 },
1788
+ n: 2,
1789
+ copayerId: copayerIds[0],
1790
+ version: Defaults.TSS_KEYGEN_SCHEME_VERSION
1791
+ });
1792
+ session.participants[1] = copayerIds[1];
1793
+ session.sharedPublicKey = 'dummy-shared-public-key';
1794
+ await server.storage.db.collection('tss_keygen').deleteMany({ id: session.id });
1795
+ await server.storage.storeTssKeyGenSession({ doc: session });
1796
+
1797
+ const walletId = await util.promisify(server.createWallet).call(server, {
1798
+ name: 'tss wallet',
1799
+ m: 1,
1800
+ n: 1,
1801
+ pubKey: TestData.keyPair.pub,
1802
+ coin: 'btc',
1803
+ tssKeyId: session.id,
1804
+ });
1805
+ const [creatorOpts, joinerOpts] = [0, 1].map(i => helpers.getSignedCopayerOpts({
1806
+ walletId,
1807
+ name: 'copayer ' + (i + 1),
1808
+ xPubKey: TestData.copayers[i].xPubKey_44H_0H_0H,
1809
+ requestPubKey: TestData.copayers[i].pubKey_1H_0,
1810
+ }));
1811
+ const { copayerId } = await util.promisify(server.joinWallet).call(server, creatorOpts);
1812
+ const creatorServer = await helpers.getAuthServer(copayerId);
1813
+ creatorServer.checkWalletSync = function(a, b, simple, cb) {
1814
+ if (simple) return cb(null, false);
1815
+ return cb(null, true);
1816
+ };
1817
+
1818
+ blockchainExplorer.register = sinon.stub().callsFake((wallet, cb) => server.joinWallet(joinerOpts, cb));
1819
+ await util.promisify(creatorServer.getStatus).call(creatorServer, { includeExtendedInfo: true });
1820
+
1821
+ blockchainExplorer.register.calledOnce.should.equal(true);
1822
+ const registeredWallet = blockchainExplorer.register.firstCall.args[0];
1823
+ const wallet = await util.promisify(server.storage.fetchWallet).call(server.storage, walletId);
1824
+ wallet.copayers.length.should.equal(2);
1825
+ wallet.beRegistered.should.equal(true);
1826
+ wallet.beAuthPrivateKey2.should.equal(registeredWallet.beAuthPrivateKey2);
1827
+ wallet.beAuthPublicKey2.should.equal(registeredWallet.beAuthPublicKey2);
1828
+ });
1829
+ });
1777
1830
  });
1778
1831
 
1779
1832
  describe('#removeWallet', function() {
@@ -2697,6 +2750,29 @@ describe('Wallet service', function() {
2697
2750
  ({ server, wallet } = await helpers.createAndJoinWallet(1, 1, { coin: 'eth' }));
2698
2751
  });
2699
2752
 
2753
+ it('should save and merge Arc token preferences without linking native USDC', async function() {
2754
+ ({ server } = await helpers.createAndJoinWallet(1, 1, { coin: 'arc', network: 'livenet' }));
2755
+ await util.promisify(server.savePreferences).call(server, { arcTokenAddresses: [TOKENS[0]], language: 'es' });
2756
+ await util.promisify(server.savePreferences).call(server, {
2757
+ arcTokenAddresses: [TOKENS[1], CWC.ethers.getAddress(TOKENS[0])],
2758
+ });
2759
+ let preferences = await util.promisify(server.getPreferences).call(server, {});
2760
+ preferences.arcTokenAddresses.should.deep.equal(TOKENS);
2761
+ preferences.language.should.equal('es');
2762
+
2763
+ try {
2764
+ await util.promisify(server.savePreferences).call(server, {
2765
+ arcTokenAddresses: [TOKENS[0], CWC.Constants.ARC.USDC_CONTRACT_ADDRESS], language: 'en',
2766
+ });
2767
+ should.fail('Expected native USDC token preference rejection');
2768
+ } catch (err) {
2769
+ err.message.toString().should.contain('arcTokenAddresses');
2770
+ }
2771
+ preferences = await util.promisify(server.getPreferences).call(server, {});
2772
+ preferences.arcTokenAddresses.should.deep.equal(TOKENS);
2773
+ preferences.language.should.equal('es');
2774
+ });
2775
+
2700
2776
  it('should save & retrieve preferences', function(done) {
2701
2777
  server.savePreferences({
2702
2778
  email: 'dummy@dummy.com',
@@ -2896,7 +2972,8 @@ describe('Wallet service', function() {
2896
2972
  unit: 'xxxxx',
2897
2973
  },
2898
2974
  expected: 'unit'
2899
- },];
2975
+ }, ...['not-an-array', ['invalid']]
2976
+ .map(arcTokenAddresses => ({ preferences: { arcTokenAddresses }, expected: 'arcTokenAddresses' }))];
2900
2977
 
2901
2978
  for (const item of invalid) {
2902
2979
  try {
@@ -6169,6 +6246,113 @@ describe('Wallet service', function() {
6169
6246
  });
6170
6247
  });
6171
6248
 
6249
+ for (const [network, chainId] of [['livenet', 5042n], ['testnet', 5042002n]] as const) {
6250
+ describe(`#createTX ARC ${network}`, () => {
6251
+ let server: WalletService;
6252
+ let from: string;
6253
+ const destination = '0x37d7B3bBD88EFdE6a93cF74D2F5b0385D3E3B08A';
6254
+ const usdc = new CWC.ethers.Interface(ERC20Abi);
6255
+ const contractOpts = (data: string) => makeOpts({
6256
+ outputs: [{ toAddress: CWC.Constants.ARC.USDC_CONTRACT_ADDRESS, amount: 0, gasLimit: 100000, data }]
6257
+ });
6258
+ const makeOpts = (overrides = {}) => ({
6259
+ outputs: [{ toAddress: destination, amount: 1e18, gasLimit: 21000 }],
6260
+ nonce: 0, feeLevel: 'normal', ...overrides
6261
+ });
6262
+
6263
+ beforeEach(async () => {
6264
+ ({ server } = await helpers.createAndJoinWallet(1, 1, { coin: 'arc', network }));
6265
+ from = (await util.promisify(server.createAddress).call(server, {})).address;
6266
+ blockchainExplorer.getBalance = sinon.stub().callsArgWith(1, null, { balance: 2e18, confirmed: 2e18, unconfirmed: 0 });
6267
+ helpers.stubFeeLevels({ 1: 25000000000, 2: 25000000000, 3: 25000000000, 4: 25000000000 }, true, 'arc');
6268
+ });
6269
+
6270
+ for (const [txType, sendMax] of [[0, false], [2, false], [2, true]] as const) {
6271
+ it(`should publish, sign and submit a type ${txType} native USDC ${sendMax ? 'send-max ' : ''}proposal`, async () => {
6272
+ const maxGasFee = sendMax ? 31000000000 : 30000000000;
6273
+ sinon.stub(server, 'estimateFee').resolves(maxGasFee).onFirstCall().resolves(30000000000);
6274
+ sinon.stub(server, 'estimatePriorityFee').resolves(0);
6275
+ const fee = (txType === 2 ? maxGasFee : 25000000000) * 21000;
6276
+ const amount = sendMax ? 2e18 - fee : 1e18;
6277
+ const txp = await util.promisify(server.createTx).call(server, makeOpts({ txType, sendMax,
6278
+ outputs: [{ toAddress: destination, amount: sendMax ? null : amount, gasLimit: 21000 }] }));
6279
+ txp.fee.should.equal(fee);
6280
+ txp.amount.should.equal(amount);
6281
+ await util.promisify(server.publishTx).call(server, helpers.getProposalSignatureOpts(txp, TestData.copayers[0].privKey_1H_0));
6282
+ await util.promisify(server.signTx).call(server, { txProposalId: txp.id, signatures: helpers.clientSign(txp, TestData.copayers[0].xPrivKey_44H_0H_0H) });
6283
+ const accepted = await util.promisify(server.getTx).call(server, { txProposalId: txp.id });
6284
+ accepted.status.should.equal('accepted');
6285
+ const [raw] = accepted.getRawTx();
6286
+ const signed = CWC.ethers.Transaction.from(raw);
6287
+ signed.chainId.should.equal(chainId);
6288
+ signed.value.should.equal(BigInt(amount));
6289
+ BigInt(txp.fee).should.equal((signed.maxFeePerGas ?? signed.gasPrice) * signed.gasLimit);
6290
+ signed.isSigned().should.equal(true);
6291
+ helpers.stubBroadcast(accepted.txid);
6292
+ await util.promisify(server.broadcastTx).call(server, { txProposalId: txp.id });
6293
+ blockchainExplorer.broadcast.firstCall.args[0].should.deep.equal([raw]);
6294
+ (await util.promisify(server.getTx).call(server, { txProposalId: txp.id })).status.should.equal('broadcasted');
6295
+ });
6296
+ }
6297
+
6298
+ it('should reserve wallet-owned USDC contract debits and release them when removed', async () => {
6299
+ for (const [method, args, debit, legacyData] of [
6300
+ ['transfer', [destination, 1000000n], 1e18],
6301
+ ['transferFrom', [from, destination, 1000000n], 1e18],
6302
+ ['transferFrom', [destination, from, 1000000n], 0],
6303
+ ['approve', [destination, 1000000n], 0],
6304
+ ['approve', [destination, 1000000n], 1e18, usdc.encodeFunctionData('transfer', [destination, 1000000n])]
6305
+ ] as Array<[string, any[], number, string?]>) {
6306
+ const data = usdc.encodeFunctionData(method, args);
6307
+ const txp = await util.promisify(server.createTx).call(server, { ...contractOpts(data), data: legacyData });
6308
+ txp.amount.should.equal(0);
6309
+ txp.outputs[0].amount.should.equal(0);
6310
+ txp.outputs[0].data.should.equal(data);
6311
+ CWC.ethers.Transaction.from(txp.getRawTx()[0]).data.should.equal(legacyData || data);
6312
+ await util.promisify(server.publishTx).call(server, helpers.getProposalSignatureOpts(txp, TestData.copayers[0].privKey_1H_0));
6313
+ const balance = await util.promisify(server.getBalance).call(server, {});
6314
+ balance.lockedAmount.should.equal(debit + txp.fee);
6315
+ balance.availableAmount.should.equal(2e18 - debit - txp.fee);
6316
+ if (debit) {
6317
+ try {
6318
+ await util.promisify(server.createTx).call(server, makeOpts({ nonce: 1,
6319
+ outputs: [{ toAddress: destination, amount: 1.5e18, gasLimit: 21000 }] }));
6320
+ should.fail('Expected pending USDC funds to be unavailable');
6321
+ } catch (err) {
6322
+ err.code.should.equal('LOCKED_FUNDS');
6323
+ }
6324
+ }
6325
+ await util.promisify(server.removePendingTx).call(server, { txProposalId: txp.id });
6326
+ (await util.promisify(server.getBalance).call(server, {})).lockedAmount.should.equal(0);
6327
+ }
6328
+ });
6329
+
6330
+ it('should reject underpriced proposals, duplicate USDC token views and zero-address transfers', async () => {
6331
+ try {
6332
+ await util.promisify(server.getBalance).call(server, { tokenAddress: CWC.Constants.ARC.USDC_CONTRACT_ADDRESS });
6333
+ throw new Error('Expected duplicate token balance rejection');
6334
+ } catch (err) {
6335
+ err.message.should.contain('omit tokenAddress');
6336
+ }
6337
+ for (const [opts, message] of [
6338
+ [makeOpts({ feeLevel: undefined, feePerKb: 10000000000 }), 'at least 20 gwei'],
6339
+ [makeOpts({ tokenAddress: CWC.Constants.ARC.USDC_CONTRACT_ADDRESS }), 'omit tokenAddress'],
6340
+ [contractOpts(usdc.encodeFunctionData('transfer', [destination, 3000000n])), 'Insufficient funds'],
6341
+ [contractOpts(usdc.encodeFunctionData('transfer', [destination, 2000000n])), 'Insufficient funds for fee'],
6342
+ [contractOpts(usdc.getFunction('transfer').selector), 'Invalid Arc USDC contract call data'],
6343
+ [makeOpts({ outputs: [{ toAddress: '0x0000000000000000000000000000000000000000', amount: 1e18 }] }), 'zero address']
6344
+ ] as Array<[any, string]>) {
6345
+ try {
6346
+ await util.promisify(server.createTx).call(server, opts);
6347
+ throw new Error('Expected proposal rejection');
6348
+ } catch (err) {
6349
+ err.message.should.contain(message);
6350
+ }
6351
+ }
6352
+ });
6353
+ });
6354
+ }
6355
+
6172
6356
  describe('#createTX ETH Only tests', () => {
6173
6357
  let server: WalletService;
6174
6358
  let wallet: Model.Wallet;
@@ -6362,8 +6546,8 @@ describe('Wallet service', function() {
6362
6546
  sinon.stub(server, 'estimatePriorityFee').resolves(1000000000);
6363
6547
  const txp = await util.promisify(server.createTx).call(server, makeOpts({ txType: 2 }));
6364
6548
  txp.feeLevel.should.equal('normal');
6365
- txp.gasPrice.should.equal(1000000000);
6366
- txp.fee.should.equal(100000000000000);
6549
+ txp.gasPrice.should.equal(4500000000);
6550
+ txp.fee.should.equal(450000000000000);
6367
6551
  txp.maxGasFee.should.equal(4500000000);
6368
6552
  txp.priorityGasFee.should.equal(1000000000);
6369
6553
  const [raw] = txp.getRawTx();
@@ -6425,6 +6609,10 @@ describe('Wallet service', function() {
6425
6609
  await helpers.stubUtxos(server, wallet, [0.0002]);
6426
6610
  const defaultTxp = await util.promisify(server.createTx).call(server, makeOpts({ tokenAddress }));
6427
6611
  defaultTxp.fee.should.equal(100000000000000);
6612
+ sinon.stub(server, 'estimateFee').resolves(3000000000);
6613
+ sinon.stub(server, 'estimatePriorityFee').resolves(1000000000);
6614
+ await assert.rejects(util.promisify(server.createTx).call(server, makeOpts({ txType: 2, tokenAddress })),
6615
+ { code: tokenAddress ? 'INSUFFICIENT_ETH_FEE' : 'INSUFFICIENT_FUNDS_FOR_FEE' });
6428
6616
  await assert.rejects(util.promisify(server.createTx).call(server, makeOpts({
6429
6617
  txType: 2, maxGasFee: 3000000000, priorityGasFee: 1000000000, tokenAddress
6430
6618
  })), { code: tokenAddress ? 'INSUFFICIENT_ETH_FEE' : 'INSUFFICIENT_FUNDS_FOR_FEE' });