Skip to content

Commit a412a7c

Browse files
committed
feat: enable erc20 sendmany
Ticket: COIN-3422
1 parent 96b060f commit a412a7c

File tree

3 files changed

+117
-8
lines changed

3 files changed

+117
-8
lines changed

modules/abstract-eth/src/abstractEthLikeNewCoins.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ interface EthTransactionParams extends TransactionParams {
319319
hopParams?: HopParams;
320320
hop?: boolean;
321321
prebuildTx?: PrebuildTransactionResult;
322+
tokenName?: string;
322323
}
323324

324325
interface VerifyEthTransactionOptions extends VerifyTransactionOptions {
@@ -2375,14 +2376,21 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
23752376
await this.validateHopPrebuild(wallet, txPrebuild.hopTransaction, { recipients });
23762377
} else if (txParams.recipients.length > 1) {
23772378
// Check total amount for batch transaction
2378-
let expectedTotalAmount = new BigNumber(0);
2379-
for (let i = 0; i < txParams.recipients.length; i++) {
2380-
expectedTotalAmount = expectedTotalAmount.plus(txParams.recipients[i].amount);
2381-
}
2382-
if (!expectedTotalAmount.isEqualTo(txPrebuild.recipients[0].amount)) {
2383-
throw new Error(
2384-
'batch transaction amount in txPrebuild received from BitGo servers does not match txParams supplied by client'
2385-
);
2379+
if (txParams.tokenName) {
2380+
const expectedTotalAmount = new BigNumber(0);
2381+
if (!expectedTotalAmount.isEqualTo(txPrebuild.recipients[0].amount)) {
2382+
throw new Error('batch token transaction amount in txPrebuild should be zero for token transfers');
2383+
}
2384+
} else {
2385+
let expectedTotalAmount = new BigNumber(0);
2386+
for (let i = 0; i < txParams.recipients.length; i++) {
2387+
expectedTotalAmount = expectedTotalAmount.plus(txParams.recipients[i].amount);
2388+
}
2389+
if (!expectedTotalAmount.isEqualTo(txPrebuild.recipients[0].amount)) {
2390+
throw new Error(
2391+
'batch transaction amount in txPrebuild received from BitGo servers does not match txParams supplied by client'
2392+
);
2393+
}
23862394
}
23872395

23882396
// Check batch transaction is sent to the batcher contract address for the chain

modules/sdk-coin-opeth/test/unit/opeth.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { OfflineVaultTxInfo, optionalDeps, SignTransactionOptions } from '@bitgo
1010
import { Opeth, Topeth, TransactionBuilder, TransferBuilder } from '../../src/index';
1111
import * as mockData from '../fixtures/opeth';
1212
import { getBuilder } from '../getBuilder';
13+
import { EthereumNetwork } from '@bitgo/statics';
1314

1415
nock.enableNetConnect();
1516

@@ -578,6 +579,105 @@ describe('Optimism', function () {
578579
.verifyTransaction({ txParams, txPrebuild, wallet, verification })
579580
.should.be.rejectedWith('coin in txPrebuild did not match that in txParams supplied by client');
580581
});
582+
583+
it('should verify a txPrebuild with more than one recipient in case of token batch transfer', async function () {
584+
const wallet = new Wallet(bitgo, basecoin, {});
585+
586+
const txParams = {
587+
tokenName: 'topeth:terc18dp',
588+
recipients: [
589+
{ amount: '1', address: address1 },
590+
{ amount: '2', address: address2 },
591+
{ amount: '3', address: address2 },
592+
],
593+
wallet: wallet,
594+
walletPassphrase: 'fakeWalletPassphrase',
595+
};
596+
597+
const txPrebuild = {
598+
recipients: [
599+
{ amount: '0', address: (basecoin?.staticsCoin?.network as EthereumNetwork).batcherContractAddress },
600+
],
601+
nextContractSequenceId: 0,
602+
gasPrice: 20000000000,
603+
gasLimit: 500000,
604+
isBatch: true,
605+
coin: 'topeth',
606+
walletId: 'fakeWalletId',
607+
walletContractAddress: 'fakeWalletContractAddress',
608+
};
609+
610+
const verification = {};
611+
612+
const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet, verification });
613+
isTransactionVerified.should.equal(true);
614+
});
615+
616+
it('should reject a txPrebuild with more than one recipient in case of token batch transfer with wrong amount', async function () {
617+
const wallet = new Wallet(bitgo, basecoin, {});
618+
619+
const txParams = {
620+
tokenName: 'topeth:terc18dp',
621+
recipients: [
622+
{ amount: '1', address: address1 },
623+
{ amount: '2', address: address2 },
624+
{ amount: '3', address: address2 },
625+
],
626+
wallet: wallet,
627+
walletPassphrase: 'fakeWalletPassphrase',
628+
};
629+
630+
const txPrebuild = {
631+
recipients: [
632+
{ amount: '6', address: (basecoin?.staticsCoin?.network as EthereumNetwork).batcherContractAddress },
633+
],
634+
nextContractSequenceId: 0,
635+
gasPrice: 20000000000,
636+
gasLimit: 500000,
637+
isBatch: true,
638+
coin: 'topeth',
639+
walletId: 'fakeWalletId',
640+
walletContractAddress: 'fakeWalletContractAddress',
641+
};
642+
643+
const verification = {};
644+
645+
await basecoin
646+
.verifyTransaction({ txParams, txPrebuild, wallet, verification })
647+
.should.be.rejectedWith(`batch token transaction amount in txPrebuild should be zero for token transfers`);
648+
});
649+
650+
it('should reject a txPrebuild with more than one recipient in case of token batch transfer with wrong batcher contract address', async function () {
651+
const wallet = new Wallet(bitgo, basecoin, {});
652+
653+
const txParams = {
654+
tokenName: 'topeth:terc18dp',
655+
recipients: [
656+
{ amount: '1', address: address1 },
657+
{ amount: '2', address: address2 },
658+
{ amount: '3', address: address2 },
659+
],
660+
wallet: wallet,
661+
walletPassphrase: 'fakeWalletPassphrase',
662+
};
663+
664+
const txPrebuild = {
665+
recipients: [{ amount: '0', address: 'fakeContractAddress' }],
666+
nextContractSequenceId: 0,
667+
gasPrice: 20000000000,
668+
gasLimit: 500000,
669+
isBatch: true,
670+
coin: 'topeth',
671+
walletId: 'fakeWalletId',
672+
walletContractAddress: 'fakeWalletContractAddress',
673+
};
674+
675+
const verification = {};
676+
677+
await basecoin
678+
.verifyTransaction({ txParams, txPrebuild, wallet, verification })
679+
.should.be.rejectedWith(`recipient address of txPrebuild does not match batcher address`);
680+
});
581681
});
582682

583683
describe('Recover transaction:', function () {

modules/statics/src/networks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,7 @@ class OptimismTestnet extends Testnet implements EthereumNetwork {
10781078
forwarderImplementationAddress = '0xd5fe1c1f216b775dfd30638fa7164d41321ef79b';
10791079
walletFactoryAddress = '0x809ee567e413543af1caebcdb247f6a67eafc8dd';
10801080
walletImplementationAddress = '0x944fef03af368414f29dc31a72061b8d64f568d2';
1081+
batcherContractAddress = '0xc84c7eb4c84271ec03ca9e3dbf12cfa42146309e';
10811082
}
10821083

10831084
class ZkSync extends Mainnet implements EthereumNetwork {

0 commit comments

Comments
 (0)