From c3a21c4cc470f2147c80e235607011bd4896f911 Mon Sep 17 00:00:00 2001 From: Akash Gianchandani Date: Wed, 3 Jan 2024 22:42:08 +0530 Subject: [PATCH] fix(abstract-eth): fix chainid related changes WIN-1446 TICKET: WIN-1446 --- modules/sdk-coin-arbeth/package.json | 4 +- modules/sdk-coin-arbeth/test/resources.ts | 9 + .../test/unit/transactionBuilder/send.ts | 158 ++++++++++++++++++ .../test/unit/transferBuilder.ts | 3 +- modules/sdk-coin-opeth/package.json | 4 +- .../sdk-coin-opeth/src/lib/transferBuilder.ts | 23 ++- modules/sdk-coin-opeth/test/resources.ts | 21 ++- .../test/unit/transactionBuilder/send.ts | 158 ++++++++++++++++++ .../test/unit/transferBuilder.ts | 2 +- modules/sdk-coin-zketh/test/resources.ts | 21 +++ .../test/unit/transferBuilder.ts | 107 ++++++++++++ modules/sdk-coin-zketh/test/unit/zketh.ts | 4 +- modules/statics/src/networks.ts | 16 +- 13 files changed, 508 insertions(+), 22 deletions(-) create mode 100644 modules/sdk-coin-arbeth/test/unit/transactionBuilder/send.ts create mode 100644 modules/sdk-coin-opeth/test/unit/transactionBuilder/send.ts create mode 100644 modules/sdk-coin-zketh/test/unit/transferBuilder.ts diff --git a/modules/sdk-coin-arbeth/package.json b/modules/sdk-coin-arbeth/package.json index b7254f4f95..2e59c404fa 100644 --- a/modules/sdk-coin-arbeth/package.json +++ b/modules/sdk-coin-arbeth/package.json @@ -45,7 +45,9 @@ "@bitgo/statics": "^39.0.0", "@bitgo/utxo-lib": "^9.26.0", "@ethereumjs/common": "^2.6.5", - "superagent": "^3.8.3" + "superagent": "^3.8.3", + "ethereumjs-abi": "^0.6.5", + "ethereumjs-util": "7.1.5" }, "devDependencies": { "@bitgo/sdk-api": "^1.34.0", diff --git a/modules/sdk-coin-arbeth/test/resources.ts b/modules/sdk-coin-arbeth/test/resources.ts index d070067a63..c07e3fded0 100644 --- a/modules/sdk-coin-arbeth/test/resources.ts +++ b/modules/sdk-coin-arbeth/test/resources.ts @@ -56,3 +56,12 @@ export const SEND_TOKEN_AMOUNT_ZERO_DATA = export const SEND_FUNDS_NO_KEY_DATA = '0x391252150000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; + +export const SEND_TX_BROADCAST_LEGACY = + '0xf901cd02843b9aca0083b8a1a0948f977e912ef500548a0c3be6ddde9899f1199b8180b901643912521500000000000000000000000019645032c7f1533395d44a629462e751084d3e4c000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec67e28000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410374eff4ca3b3d8c7b37ac7515ea4d212847bdc08a5ede459436c3ebcfd7f9b855d021e7590b6fa36d68ba1c58fc568d52d6794e465f6687da90cc70aa3335231b00000000000000000000000000000000000000000000000000000000000000830cde00a074b64b8ffaf205436aa4bfcbb78e98329f4fed4f11bf3b40f9eef5a9a16bc165a01740883cc0236ab97286398d114d8bebc1a0717558d45533bebb7e5c130eeff6'; + +export const SEND_TOKEN_TX_BROADCAST = + '0xf901ad02843b9aca0083b8a1a094df7decb1baa8f529f0c8982cbb4be5035719529980b901440dcd7a6c00000000000000000000000072c2c8e08bf91d755cd7d26b49a2ee3dc99de1b90000000000000000000000000000000000000000000000000000000000000064000000000000000000000000143e1dae4f018ff86051a01d44a1b49b13704056000000000000000000000000000000000000000000000000000000005ec67e28000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000041bec4f4b3c7f2b3701694d615794a5fa9ee2e097e50d2873e6b17b565b44900920b6e2fbc97cdc7fc690a71a509ad08851bd69c99e999660a892ccf67b9c2c8a31c00000000000000000000000000000000000000000000000000000000000000830cddffa0c12178bc3bd603a415f7510a9160a774828176b86105913685309f3e64bbd00fa01d8593a7d051656bb0023219f98f6da708fade85f26e7c974a8eaa0246c2e795'; + +export const SEND_TX_AMOUNT_ZERO_BROADCAST = + '0xf901cd02843b9aca0083b8a1a0948f977e912ef500548a0c3be6ddde9899f1199b8180b901643912521500000000000000000000000019645032c7f1533395d44a629462e751084d3e4c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec67e28000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415bba6d3d5288d585cbb01997410bce555295a19ab7ede922866ae0c9b50698754f494bd624ea91a4b098e9d17080cc3af571cedad6334c4be1e6e49498af68481c00000000000000000000000000000000000000000000000000000000000000830cde00a0e0421465dee286fd38937b8ea67807fc30265ac5fb5e7ea23ae73074ef22a1b8a032ed7887c90ade813e659e63145409d7ac896342eb02674524184e806004945f'; diff --git a/modules/sdk-coin-arbeth/test/unit/transactionBuilder/send.ts b/modules/sdk-coin-arbeth/test/unit/transactionBuilder/send.ts new file mode 100644 index 0000000000..38534e0ccd --- /dev/null +++ b/modules/sdk-coin-arbeth/test/unit/transactionBuilder/send.ts @@ -0,0 +1,158 @@ +import { TransactionType, BaseTransaction } from '@bitgo/sdk-core'; +import { coins } from '@bitgo/statics'; +import EthereumAbi from 'ethereumjs-abi'; +import should from 'should'; +import * as ethUtil from 'ethereumjs-util'; + +import { decodeTransferData, KeyPair } from '@bitgo/abstract-eth'; +import * as testData from '../../resources'; +import { getBuilder } from '../../getBuilder'; +import { TransactionBuilder } from '../../../src'; + +describe('Arbeth transaction builder send', () => { + describe('should sign and build', () => { + let txBuilder; + let key; + let contractAddress; + + const getOperationHash = function (tx: BaseTransaction): string { + const { data } = tx.toJson(); + const { tokenContractAddress, expireTime, sequenceId, amount, to } = decodeTransferData(data); + const operationParams = [ + ['string', 'address', 'uint', 'address', 'uint', 'uint'], + [ + '421614-ERC20', + new ethUtil.BN(ethUtil.stripHexPrefix(to), 16), + amount, + new ethUtil.BN(ethUtil.stripHexPrefix(tokenContractAddress || ''), 16), + expireTime, + sequenceId, + ], + ]; + return EthereumAbi.soliditySHA3(...operationParams); + }; + + beforeEach(() => { + contractAddress = '0x8f977e912ef500548a0c3be6ddde9899f1199b81'; + txBuilder = getBuilder('tarbeth') as TransactionBuilder; + key = testData.KEYPAIR_PRV.getKeys().prv as string; + txBuilder.fee({ + fee: '1000000000', + gasLimit: '12100000', + }); + txBuilder.counter(2); + txBuilder.type(TransactionType.Send); + txBuilder.contract(contractAddress); + }); + + it('a send funds transaction', async () => { + const recipient = '0x19645032c7f1533395d44a629462e751084d3e4c'; + const amount = '1000000000'; + const expireTime = 1590066728; + const sequenceId = 5; + txBuilder + .transfer() + .coin('tarbeth') + .amount(amount) + .to(recipient) + .expirationTime(expireTime) + .contractSequenceId(sequenceId) + .key(key); + txBuilder.sign({ key: testData.PRIVATE_KEY_1 }); + const tx = await txBuilder.build(); + + should.equal(tx.toJson().chainId, 421614); + should.equal(tx.toBroadcastFormat(), testData.SEND_TX_BROADCAST_LEGACY); + should.equal(tx.signature.length, 2); + should.equal(tx.inputs.length, 1); + should.equal(tx.inputs[0].address, contractAddress); + should.equal(tx.inputs[0].value, amount); + + should.equal(tx.outputs.length, 1); + should.equal(tx.outputs[0].address, recipient); + should.equal(tx.outputs[0].value, amount); + + const data = tx.toJson().data; + const { + to, + amount: parsedAmount, + expireTime: parsedExpireTime, + sequenceId: parsedSequenceId, + } = decodeTransferData(data); + should.equal(to, recipient); + should.equal(parsedAmount, amount); + should.equal(parsedExpireTime, expireTime); + should.equal(parsedSequenceId, sequenceId); + }); + + it('a send funds with amount 0 transaction', async () => { + txBuilder + .transfer() + .coin('tarbeth') + .amount('0') + .to('0x19645032c7f1533395d44a629462e751084d3e4c') + .expirationTime(1590066728) + .contractSequenceId(5) + .key(key); + txBuilder.sign({ key: testData.PRIVATE_KEY_1 }); + const tx = await txBuilder.build(); + should.equal(tx.toBroadcastFormat(), testData.SEND_TX_AMOUNT_ZERO_BROADCAST); + }); + + it('a send token transaction', async () => { + const recipient = '0x72c2c8e08bf91d755cd7d26b49a2ee3dc99de1b9'; + const contractAddress = '0xdf7decb1baa8f529f0c8982cbb4be50357195299'; + const amount = '100'; + txBuilder.contract(contractAddress); + txBuilder + .transfer() + .coin('tarbeth:link') + .amount(amount) + .to(recipient) + .expirationTime(1590066728) + .contractSequenceId(5) + .key(key); + txBuilder.sign({ + key: testData.PRIVATE_KEY_1, + }); + const tx = await txBuilder.build(); + + should.equal(tx.toBroadcastFormat(), testData.SEND_TOKEN_TX_BROADCAST); + should.equal(tx.signature.length, 2); + should.equal(tx.inputs.length, 1); + should.equal(tx.inputs[0].address, contractAddress); + should.equal(tx.inputs[0].value, amount); + should.equal(tx.inputs[0].coin, 'tarbeth:link'); + + should.equal(tx.outputs.length, 1); + should.equal(tx.outputs[0].address, recipient); + should.equal(tx.outputs[0].value, amount); + should.equal(tx.outputs[0].coin, 'tarbeth:link'); + + const { signature } = decodeTransferData(tx.toJson().data); + const operationHash = getOperationHash(tx); + + const { v, r, s } = ethUtil.fromRpcSig(signature); + const senderPubKey = ethUtil.ecrecover(Buffer.from(operationHash, 'hex'), v, r, s); + const senderAddress = ethUtil.pubToAddress(senderPubKey); + const senderKey = new KeyPair({ prv: testData.PRIVATE_KEY_1 }); + ethUtil.bufferToHex(senderAddress).should.equal(senderKey.getAddress()); + }); + + it('a send token transactions from serialized', async () => { + const txBuilder = new TransactionBuilder(coins.get('tarbeth')); + txBuilder.from(testData.SEND_TOKEN_TX_BROADCAST); + const tx = await txBuilder.build(); + should.equal(tx.toBroadcastFormat(), testData.SEND_TOKEN_TX_BROADCAST); + + const { signature } = decodeTransferData(tx.toJson().data); + const operationHash = getOperationHash(tx); + + const { v, r, s } = ethUtil.fromRpcSig(signature); + const senderPubKey = ethUtil.ecrecover(Buffer.from(operationHash || ''), v, r, s); + const senderAddress = ethUtil.pubToAddress(senderPubKey); + const senderKey = new KeyPair({ prv: testData.PRIVATE_KEY_1 }); + ethUtil.bufferToHex(senderAddress).should.equal(senderKey.getAddress()); + }); + }); +}); diff --git a/modules/sdk-coin-arbeth/test/unit/transferBuilder.ts b/modules/sdk-coin-arbeth/test/unit/transferBuilder.ts index 33504a48af..4bf1fd9bd2 100644 --- a/modules/sdk-coin-arbeth/test/unit/transferBuilder.ts +++ b/modules/sdk-coin-arbeth/test/unit/transferBuilder.ts @@ -1,9 +1,8 @@ import should from 'should'; import { KeyPair, TransferBuilder } from '../../src'; - import * as testData from '../resources'; -describe('Eth send multi sig builder', function () { +describe('Arbeth send multi sig builder', function () { const toAddress = '0x7325A3F7d4f9E86AE62Cf742426078C3755730d5'; const xprv = 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2'; diff --git a/modules/sdk-coin-opeth/package.json b/modules/sdk-coin-opeth/package.json index 61ba12ab57..68479336d1 100644 --- a/modules/sdk-coin-opeth/package.json +++ b/modules/sdk-coin-opeth/package.json @@ -45,7 +45,9 @@ "@bitgo/statics": "^39.0.0", "@bitgo/utxo-lib": "^9.26.0", "@ethereumjs/common": "^2.6.5", - "superagent": "^3.8.3" + "superagent": "^3.8.3", + "ethereumjs-abi": "^0.6.5", + "ethereumjs-util": "7.1.5" }, "devDependencies": { "@bitgo/sdk-api": "^1.34.0", diff --git a/modules/sdk-coin-opeth/src/lib/transferBuilder.ts b/modules/sdk-coin-opeth/src/lib/transferBuilder.ts index 7447c0cf3d..e9096398e6 100644 --- a/modules/sdk-coin-opeth/src/lib/transferBuilder.ts +++ b/modules/sdk-coin-opeth/src/lib/transferBuilder.ts @@ -1 +1,22 @@ -export { TransferBuilder } from '@bitgo/abstract-eth'; +import { TransferBuilder as EthTransferBuilder } from '@bitgo/abstract-eth'; + +/** OPETH transfer builder */ +export class TransferBuilder extends EthTransferBuilder { + /** + * Get the prefix used in generating an operation hash for sending tokens + * + * @returns the string prefix + */ + protected getTokenOperationHashPrefix(): string { + return 'OPETH-ERC20'; + } + + /** + * Get the prefix used in generating an operation hash for sending native coins + * + * @returns the string prefix + */ + protected getNativeOperationHashPrefix(): string { + return 'OPETH'; + } +} diff --git a/modules/sdk-coin-opeth/test/resources.ts b/modules/sdk-coin-opeth/test/resources.ts index 879b76eee6..9700c9db70 100644 --- a/modules/sdk-coin-opeth/test/resources.ts +++ b/modules/sdk-coin-opeth/test/resources.ts @@ -37,22 +37,31 @@ export const PUBLIC_KEY_2 = 'xpub661MyMwAqRbcFXrZT6GpipqTPdFdhYX5DFDGv5ws1iW8ViCWSTK3zVhVntpiKDjPqXrqP1hhQscJZhVpbmZt9qygxgPdmN9RAZVKqovPfLw'; export const SEND_FUNDS_DATA = - '0x391252150000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004106935b57df83e029901bb12028bcd86feff0724699ae71bee552dd5ed99766b2794d4cc6dfd8f94949f21fea3188c2cd502c89bd0adb939bcf9dd7e79e8f7aca1b00000000000000000000000000000000000000000000000000000000000000'; + '0x391252150000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000413c61769ec75530fc1bfff46ab8ae8c9fe5d2f7cc3d40819e19151bdec0a8cf6a57209734d0552068b687db41997341e93db10af25d37f08f1e7b87c1cfe8c0411c00000000000000000000000000000000000000000000000000000000000000'; export const SEND_FUNDS_SEQUENCE_ZERO_DATA = - '0x391252150000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041d731e3bd73bff7f803cbd38a2d96b1b3474a58e31afd25f8f900f284963ae29305924d5445bc17c54aea5bb20947cfaadaa642812dc5bec4e9709a4b3de777d11b00000000000000000000000000000000000000000000000000000000000000'; + '0x391252150000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415813fee6c842129d6e5646d0a8ed2bde0821a89cc80ef18fd2351e5da2c29f375c3700b231c44da7fa422d91a67bc87b59aa131ff10ddb759dbd449d403c96071b00000000000000000000000000000000000000000000000000000000000000'; export const SEND_FUNDS_AMOUNT_ZERO_DATA = - '0x391252150000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041861d26b3e1451d9445c71c7bfd51b98297840e5ff39649a936f05b0c4b30f30c6d2a8ecb1ab7764dd895241bab17a9d4cab04d453102eef90e5d1d61642c33d51c00000000000000000000000000000000000000000000000000000000000000'; + '0x391252150000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004179b60f4c8b3cdc2746b82cd962e1498ea33e555418a570ee28f6bafca666238f0fd9f1fe454c744add268ca487033d311d93af1fbfcd90ccdc43d748757697211c00000000000000000000000000000000000000000000000000000000000000'; export const SEND_OPETH_TERC_DATA = - '0x0dcd7a6c0000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000e9df68a54bba438c8a6192e95f0f2c53ac93d997000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000041db3a377de4367e5a77a337b71967fd815ab0a1b29da576adc6e0d74420d2d16d6d49c5bbeefc49f29e9164a665234c7b3664e8e66899f6b0d3b0d855504d52e81c00000000000000000000000000000000000000000000000000000000000000'; + '0x0dcd7a6c0000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000e9df68a54bba438c8a6192e95f0f2c53ac93d997000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000041b504e162009ba445e058974c69361fdfbd311662d963ec39b0fd9025d2a165287fc4ccf13de3b5dd028ab5cdbe604c4db6e600dcff18e1eb24c155556c0985331c00000000000000000000000000000000000000000000000000000000000000'; export const SEND_TOKEN_SEQUENCE_ZERO_DATA = - '0x0dcd7a6c0000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000e9df68a54bba438c8a6192e95f0f2c53ac93d997000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000004194dd7978c79c9edf402c9ae09adb721d42aadd621b79908ec52eafb79b3d536c2498fdb30c59d29529dc0c19c6c1f26cd281257c7ff02f7d0dd02eccf7923cc21b00000000000000000000000000000000000000000000000000000000000000'; + '0x0dcd7a6c0000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000e9df68a54bba438c8a6192e95f0f2c53ac93d997000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000004193d441133728858e524cdd559f834be942fa07b7f8898be6db0cb89a25096ef23a42232dc6a7ce701093587cf81423ff1172b39e0bcf9cd29e2efba0f79539431b00000000000000000000000000000000000000000000000000000000000000'; export const SEND_TOKEN_AMOUNT_ZERO_DATA = - '0x0dcd7a6c0000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e9df68a54bba438c8a6192e95f0f2c53ac93d997000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000041dff2b15181f683875e6463ac5abf9be92ed3aae99a5351028610264d3ae724cf04e69d4ab31fb4e127885fc63712e9a8950a204660a1a4d65bfc8de98fcfc1571b00000000000000000000000000000000000000000000000000000000000000'; + '0x0dcd7a6c0000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e9df68a54bba438c8a6192e95f0f2c53ac93d997000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000041d488ba5245b92566e6099f99a9670cbbb4266c1fc8e8b32a3cc14ab0d177ad16026b6599dc90ce51c5bd1ce5cf78ff8143ad3b115c94a034f9e8e8bd8f12fb8c1c00000000000000000000000000000000000000000000000000000000000000'; export const SEND_FUNDS_NO_KEY_DATA = '0x391252150000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; + +export const SEND_TX_BROADCAST_LEGACY = + '0xf901cd02843b9aca0083b8a1a0948f977e912ef500548a0c3be6ddde9899f1199b8180b901643912521500000000000000000000000019645032c7f1533395d44a629462e751084d3e4c000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec67e28000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041c3d3fae4a6726897cda48a8be084fab0ad37208d4723b5138b0c6d499bdec6f938b205ac08792eccf826883d4a0aa10b12cf70a661222a09fc43887e5de075f71c000000000000000000000000000000000000000000000000000000000000008401546fdca010039d899f5bda5680e37af37b0671f627a25923e10d9c57824e615440f704079fbd16e98669c4f2400421cf63c2d815b7b46b99c948d793fa3832845660b642'; + +export const SEND_TOKEN_TX_BROADCAST = + '0xf901ae02843b9aca0083b8a1a094df7decb1baa8f529f0c8982cbb4be5035719529980b901440dcd7a6c00000000000000000000000072c2c8e08bf91d755cd7d26b49a2ee3dc99de1b90000000000000000000000000000000000000000000000000000000000000064000000000000000000000000e9df68a54bba438c8a6192e95f0f2c53ac93d997000000000000000000000000000000000000000000000000000000005ec67e28000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000041f6858e734e2f1e74a22e3df40c01cc1c272ffe755a4097f1d4888b7924b7be99445b347323577a76b0bd8170c98070b4af59dd9f63c4f11a8ad5b7dafccc7e711b000000000000000000000000000000000000000000000000000000000000008401546fdba0ff00e9d6205787b3146b119c58136b3df1b32fcafadbb0c35724b817eca73e2ea0693a32d0fe2f810fbcd26cef0e1c26a018e403b167604e9a35ab3b09dddbc651'; + +export const SEND_TX_AMOUNT_ZERO_BROADCAST = + '0xf901ce02843b9aca0083b8a1a0948f977e912ef500548a0c3be6ddde9899f1199b8180b901643912521500000000000000000000000019645032c7f1533395d44a629462e751084d3e4c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec67e28000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041c7a790268bbe8c51026b74f36f3a705eb0aa00cb1f32f16df33c2631a658621b3722a33ee813a343e2ef369fddaf9a12642cbc53a578bda0af852bd61fe8193f1b000000000000000000000000000000000000000000000000000000000000008401546fdba066ff8804d2e4a43b9882049cc32652aae6d6ebd9d204adf941e223e3ad8d8dafa0328cfd9e5abbe0e04720dbdff58b8ef932b2c8a1ccce2631c3266b5aece86377'; diff --git a/modules/sdk-coin-opeth/test/unit/transactionBuilder/send.ts b/modules/sdk-coin-opeth/test/unit/transactionBuilder/send.ts new file mode 100644 index 0000000000..4bab53881e --- /dev/null +++ b/modules/sdk-coin-opeth/test/unit/transactionBuilder/send.ts @@ -0,0 +1,158 @@ +import { TransactionType, BaseTransaction } from '@bitgo/sdk-core'; +import { coins } from '@bitgo/statics'; +import EthereumAbi from 'ethereumjs-abi'; +import should from 'should'; +import * as ethUtil from 'ethereumjs-util'; + +import { decodeTransferData, KeyPair } from '@bitgo/abstract-eth'; +import * as testData from '../../resources'; +import { getBuilder } from '../../getBuilder'; +import { TransactionBuilder } from '../../../src'; + +describe('Opeth transaction builder send', () => { + describe('should sign and build', () => { + let txBuilder; + let key; + let contractAddress; + + const getOperationHash = function (tx: BaseTransaction): string { + const { data } = tx.toJson(); + const { tokenContractAddress, expireTime, sequenceId, amount, to } = decodeTransferData(data); + const operationParams = [ + ['string', 'address', 'uint', 'address', 'uint', 'uint'], + [ + 'OPETH-ERC20', + new ethUtil.BN(ethUtil.stripHexPrefix(to), 16), + amount, + new ethUtil.BN(ethUtil.stripHexPrefix(tokenContractAddress || ''), 16), + expireTime, + sequenceId, + ], + ]; + return EthereumAbi.soliditySHA3(...operationParams); + }; + + beforeEach(() => { + contractAddress = '0x8f977e912ef500548a0c3be6ddde9899f1199b81'; + txBuilder = getBuilder('topeth') as TransactionBuilder; + key = testData.KEYPAIR_PRV.getKeys().prv as string; + txBuilder.fee({ + fee: '1000000000', + gasLimit: '12100000', + }); + txBuilder.counter(2); + txBuilder.type(TransactionType.Send); + txBuilder.contract(contractAddress); + }); + + it('a send funds transaction', async () => { + const recipient = '0x19645032c7f1533395d44a629462e751084d3e4c'; + const amount = '1000000000'; + const expireTime = 1590066728; + const sequenceId = 5; + txBuilder + .transfer() + .coin('topeth') + .amount(amount) + .to(recipient) + .expirationTime(expireTime) + .contractSequenceId(sequenceId) + .key(key); + txBuilder.sign({ key: testData.PRIVATE_KEY_1 }); + const tx = await txBuilder.build(); + + should.equal(tx.toJson().chainId, 11155420); + should.equal(tx.toBroadcastFormat(), testData.SEND_TX_BROADCAST_LEGACY); + should.equal(tx.signature.length, 2); + should.equal(tx.inputs.length, 1); + should.equal(tx.inputs[0].address, contractAddress); + should.equal(tx.inputs[0].value, amount); + + should.equal(tx.outputs.length, 1); + should.equal(tx.outputs[0].address, recipient); + should.equal(tx.outputs[0].value, amount); + + const data = tx.toJson().data; + const { + to, + amount: parsedAmount, + expireTime: parsedExpireTime, + sequenceId: parsedSequenceId, + } = decodeTransferData(data); + should.equal(to, recipient); + should.equal(parsedAmount, amount); + should.equal(parsedExpireTime, expireTime); + should.equal(parsedSequenceId, sequenceId); + }); + + it('a send funds with amount 0 transaction', async () => { + txBuilder + .transfer() + .coin('topeth') + .amount('0') + .to('0x19645032c7f1533395d44a629462e751084d3e4c') + .expirationTime(1590066728) + .contractSequenceId(5) + .key(key); + txBuilder.sign({ key: testData.PRIVATE_KEY_1 }); + const tx = await txBuilder.build(); + should.equal(tx.toBroadcastFormat(), testData.SEND_TX_AMOUNT_ZERO_BROADCAST); + }); + + it('a send token transaction', async () => { + const recipient = '0x72c2c8e08bf91d755cd7d26b49a2ee3dc99de1b9'; + const contractAddress = '0xdf7decb1baa8f529f0c8982cbb4be50357195299'; + const amount = '100'; + txBuilder.contract(contractAddress); + txBuilder + .transfer() + .coin('topeth:terc18dp') + .amount(amount) + .to(recipient) + .expirationTime(1590066728) + .contractSequenceId(5) + .key(key); + txBuilder.sign({ + key: testData.PRIVATE_KEY_1, + }); + const tx = await txBuilder.build(); + + should.equal(tx.toBroadcastFormat(), testData.SEND_TOKEN_TX_BROADCAST); + should.equal(tx.signature.length, 2); + should.equal(tx.inputs.length, 1); + should.equal(tx.inputs[0].address, contractAddress); + should.equal(tx.inputs[0].value, amount); + should.equal(tx.inputs[0].coin, 'topeth:terc18dp'); + + should.equal(tx.outputs.length, 1); + should.equal(tx.outputs[0].address, recipient); + should.equal(tx.outputs[0].value, amount); + should.equal(tx.outputs[0].coin, 'topeth:terc18dp'); + + const { signature } = decodeTransferData(tx.toJson().data); + const operationHash = getOperationHash(tx); + + const { v, r, s } = ethUtil.fromRpcSig(signature); + const senderPubKey = ethUtil.ecrecover(Buffer.from(operationHash, 'hex'), v, r, s); + const senderAddress = ethUtil.pubToAddress(senderPubKey); + const senderKey = new KeyPair({ prv: testData.PRIVATE_KEY_1 }); + ethUtil.bufferToHex(senderAddress).should.equal(senderKey.getAddress()); + }); + + it('a send token transactions from serialized', async () => { + const txBuilder = new TransactionBuilder(coins.get('topeth')); + txBuilder.from(testData.SEND_TOKEN_TX_BROADCAST); + const tx = await txBuilder.build(); + should.equal(tx.toBroadcastFormat(), testData.SEND_TOKEN_TX_BROADCAST); + + const { signature } = decodeTransferData(tx.toJson().data); + const operationHash = getOperationHash(tx); + + const { v, r, s } = ethUtil.fromRpcSig(signature); + const senderPubKey = ethUtil.ecrecover(Buffer.from(operationHash || ''), v, r, s); + const senderAddress = ethUtil.pubToAddress(senderPubKey); + const senderKey = new KeyPair({ prv: testData.PRIVATE_KEY_1 }); + ethUtil.bufferToHex(senderAddress).should.equal(senderKey.getAddress()); + }); + }); +}); diff --git a/modules/sdk-coin-opeth/test/unit/transferBuilder.ts b/modules/sdk-coin-opeth/test/unit/transferBuilder.ts index e12bf8f233..9e7619d0f4 100644 --- a/modules/sdk-coin-opeth/test/unit/transferBuilder.ts +++ b/modules/sdk-coin-opeth/test/unit/transferBuilder.ts @@ -3,7 +3,7 @@ import { KeyPair, TransferBuilder } from '../../src'; import * as testData from '../resources'; -describe('Eth send multi sig builder', function () { +describe('Opeth send multi sig builder', function () { const toAddress = '0x7325A3F7d4f9E86AE62Cf742426078C3755730d5'; const xprv = 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2'; diff --git a/modules/sdk-coin-zketh/test/resources.ts b/modules/sdk-coin-zketh/test/resources.ts index 1ff0ba9255..51ea2d61ec 100644 --- a/modules/sdk-coin-zketh/test/resources.ts +++ b/modules/sdk-coin-zketh/test/resources.ts @@ -35,3 +35,24 @@ export const PRIVATE_KEY_2 = export const PUBLIC_KEY_2 = 'xpub661MyMwAqRbcFXrZT6GpipqTPdFdhYX5DFDGv5ws1iW8ViCWSTK3zVhVntpiKDjPqXrqP1hhQscJZhVpbmZt9qygxgPdmN9RAZVKqovPfLw'; + +export const SEND_FUNDS_DATA = + '0x391252150000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041f55a216a3b1f6081fb388d3b67eb6328af9ceb5a478a19f998cd9e23e06d696a368de5d212ec04c2366a27d1bde9ad775675cf1a5d2cb6a5eefd40c57846a04a1b00000000000000000000000000000000000000000000000000000000000000'; + +export const SEND_FUNDS_SEQUENCE_ZERO_DATA = + '0x391252150000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004193f1238aadb183f98356438bebb811ffe9a936679d27117f0623c53d8fa8431e102603745a25df49af0921d5b3902810caabb3a57b90b9cefef0971dabb6183a1b00000000000000000000000000000000000000000000000000000000000000'; + +export const SEND_FUNDS_AMOUNT_ZERO_DATA = + '0x391252150000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041fdfb5e9d7944ca296534feb025ad980106bf4060d5b60ff2e57cf0dfb370573975e077d4ba73e5784b9e4893e1738c88a7876313ca4d812d69b0bf9e9c4281f11b00000000000000000000000000000000000000000000000000000000000000'; + +export const SEND_ZKETH_LINK_DATA = + '0x0dcd7a6c0000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000cccb29bac5ad81290383643c6fb38130cda9d881000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000041075389c62b993ab6f17cb485353135435943cea945c25b14fa0d23f71f8a51b174dd89a26174ec78e96e3d308d7d70894bea664a0366f2a42cd43e1988b50c3b1b00000000000000000000000000000000000000000000000000000000000000'; + +export const SEND_TOKEN_SEQUENCE_ZERO_DATA = + '0x0dcd7a6c0000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000cccb29bac5ad81290383643c6fb38130cda9d881000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000417ee1a280874dec97d85b5bd533362f25b71f1a67efd4d74a66f270c46a7d93024b755335adb272fe99e937e911b80b3967f213088563ab2c16c48490303858011c00000000000000000000000000000000000000000000000000000000000000'; + +export const SEND_TOKEN_AMOUNT_ZERO_DATA = + '0x0dcd7a6c0000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cccb29bac5ad81290383643c6fb38130cda9d881000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000414b8b37af8b28462a1dfbb5cd42ad8a4ff5b3f0600163106cd6df849e107775f0206b19f1299f6310fdcb69363c4a3f0df387d8f9f9a7176a807690908d0b61321c00000000000000000000000000000000000000000000000000000000000000'; + +export const SEND_FUNDS_NO_KEY_DATA = + '0x391252150000000000000000000000007325a3f7d4f9e86ae62cf742426078c3755730d5000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005ec6ab34000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; diff --git a/modules/sdk-coin-zketh/test/unit/transferBuilder.ts b/modules/sdk-coin-zketh/test/unit/transferBuilder.ts new file mode 100644 index 0000000000..cfec435e5c --- /dev/null +++ b/modules/sdk-coin-zketh/test/unit/transferBuilder.ts @@ -0,0 +1,107 @@ +import should from 'should'; +import { KeyPair, TransferBuilder } from '../../src'; + +import * as testData from '../resources'; + +describe('Zketh send multi sig builder', function () { + const toAddress = '0x7325A3F7d4f9E86AE62Cf742426078C3755730d5'; + const xprv = + 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2'; + const key = new KeyPair({ prv: xprv }).getKeys().prv as string; + const amount = '100000000000000000'; // equivalent to 0.1 ether + + describe('should build', () => { + it('native coin transfer should succeed', async () => { + const builder = new TransferBuilder() + .coin('tzketh') + .expirationTime(1590078260) + .amount(amount) + .to(toAddress) + .contractSequenceId(2) + .key(key) + .data('0x'); + const result = builder.signAndBuild(); + should.equal(result, testData.SEND_FUNDS_DATA); + }); + + it('native coin transfer with sequenceId zero should succeed', async () => { + const builder = new TransferBuilder() + .coin('tzketh') + .expirationTime(1590078260) + .amount(amount) + .to(toAddress) + .contractSequenceId(0) + .key(key) + .data('0x'); + const result = builder.signAndBuild(); + should.equal(result, testData.SEND_FUNDS_SEQUENCE_ZERO_DATA); + }); + + it('native coin transfer with amount 0 should succeed', async () => { + const builder = new TransferBuilder() + .coin('tzketh') + .expirationTime(1590078260) + .amount('0') + .to(toAddress) + .contractSequenceId(2) + .key(key) + .data('0x'); + const result = builder.signAndBuild(); + should.equal(result, testData.SEND_FUNDS_AMOUNT_ZERO_DATA); + }); + + it('ERC20 token transfer should succeed', async () => { + const builder = new TransferBuilder() + .coin('tzketh:link') + .expirationTime(1590078260) + .amount(amount) + .to(toAddress) + .contractSequenceId(2) + .key(key); + const result = builder.signAndBuild(); + should.equal(result, testData.SEND_ZKETH_LINK_DATA); + }); + + it('erc20 transfer should succeed', async () => { + const builder = new TransferBuilder() + .coin('tzketh:link') + .expirationTime(1590078260) + .amount(amount) + .to(toAddress) + .contractSequenceId(0) + .key(key); + const result = builder.signAndBuild(); + should.equal(result, testData.SEND_TOKEN_SEQUENCE_ZERO_DATA); + }); + + it('erc20 transfer with amount 0 should succeed', async () => { + const builder = new TransferBuilder() + .coin('tzketh:link') + .expirationTime(1590078260) + .amount('0') + .to(toAddress) + .contractSequenceId(2) + .key(key); + const result = builder.signAndBuild(); + should.equal(result, testData.SEND_TOKEN_AMOUNT_ZERO_DATA); + }); + + it('should build without a signature set', () => { + const builder = new TransferBuilder() + .expirationTime(1590078260) + .amount(amount) + .to(toAddress) + .contractSequenceId(2) + .data('0x'); + const result = builder.signAndBuild(); + should.equal(result, testData.SEND_FUNDS_NO_KEY_DATA); + }); + + it('should build from a non signed serialized data', () => { + const builder = new TransferBuilder(testData.SEND_FUNDS_NO_KEY_DATA); + builder.coin('tzketh').key(key); + const result = builder.signAndBuild(); + should.equal(result, testData.SEND_FUNDS_DATA); + }); + }); +}); diff --git a/modules/sdk-coin-zketh/test/unit/zketh.ts b/modules/sdk-coin-zketh/test/unit/zketh.ts index 948c65dbdc..a3e2eb5bcb 100644 --- a/modules/sdk-coin-zketh/test/unit/zketh.ts +++ b/modules/sdk-coin-zketh/test/unit/zketh.ts @@ -172,7 +172,7 @@ describe('zkSync', function () { builder.counter(1); builder.type(TransactionType.Send); builder.contract(account_1.address); - builder.transfer().amount('1').to(account_2.address).expirationTime(10000).contractSequenceId(1); + builder.transfer().coin('tzketh').amount('1').to(account_2.address).expirationTime(10000).contractSequenceId(1); const unsignedTx = await builder.build(); const unsignedTxForBroadcasting = unsignedTx.toBroadcastFormat(); @@ -207,7 +207,7 @@ describe('zkSync', function () { builder.counter(1); builder.type(TransactionType.Send); builder.contract(account_1.address); - builder.transfer().amount('1').to(account_2.address).expirationTime(10000).contractSequenceId(1); + builder.transfer().coin('tzketh').amount('1').to(account_2.address).expirationTime(10000).contractSequenceId(1); const unsignedTx = await builder.build(); const unsignedTxForBroadcasting = unsignedTx.toBroadcastFormat(); diff --git a/modules/statics/src/networks.ts b/modules/statics/src/networks.ts index 065f38330a..6530085e98 100644 --- a/modules/statics/src/networks.ts +++ b/modules/statics/src/networks.ts @@ -922,8 +922,8 @@ class Optimism extends Mainnet implements EthereumNetwork { explorerUrl = 'https://optimistic.etherscan.io/tx/'; accountExplorerUrl = 'https://optimistic.etherscan.io/address/'; chainId = 10; - nativeCoinOperationHashPrefix = '10'; - tokenOperationHashPrefix = '10-ERC20'; + nativeCoinOperationHashPrefix = 'OPETH'; + tokenOperationHashPrefix = 'OPETH-ERC20'; } class OptimismTestnet extends Testnet implements EthereumNetwork { @@ -932,8 +932,8 @@ class OptimismTestnet extends Testnet implements EthereumNetwork { explorerUrl = 'https://sepolia-optimism.etherscan.io/tx/'; accountExplorerUrl = 'https://sepolia-optimism.etherscan.io/address/'; chainId = 11155420; - nativeCoinOperationHashPrefix = '11155420'; - tokenOperationHashPrefix = '11155420-ERC20'; + nativeCoinOperationHashPrefix = 'OPETH'; + tokenOperationHashPrefix = 'OPETH-ERC20'; } class ZkSync extends Mainnet implements EthereumNetwork { @@ -942,8 +942,8 @@ class ZkSync extends Mainnet implements EthereumNetwork { explorerUrl = 'https://explorer.zksync.io/tx/'; accountExplorerUrl = 'https://explorer.zksync.io/address/'; chainId = 324; - nativeCoinOperationHashPrefix = 'ZKETH'; - tokenOperationHashPrefix = 'ZKETH-ERC20'; + nativeCoinOperationHashPrefix = '324'; + tokenOperationHashPrefix = '324-ERC20'; } class ZkSyncTestnet extends Testnet implements EthereumNetwork { @@ -952,8 +952,8 @@ class ZkSyncTestnet extends Testnet implements EthereumNetwork { explorerUrl = 'https://sepolia.explorer.zksync.io/tx/'; accountExplorerUrl = 'https://sepolia.explorer.zksync.io/address/'; chainId = 300; - nativeCoinOperationHashPrefix = 'ZKETH'; - tokenOperationHashPrefix = 'ZKETH-ERC20'; + nativeCoinOperationHashPrefix = '300'; + tokenOperationHashPrefix = '300-ERC20'; } export const Networks = {