From 90baaf968ed9de2b44c0cfd261663c4c019d55e0 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Wed, 10 Apr 2024 16:59:38 -0700 Subject: [PATCH] Use input as data in eth_sendTransaction --- src/wallet.test.ts | 99 ++++++++++++++++++++++++++++++++++++++++++++++ src/wallet.ts | 20 ++++++++-- 2 files changed, 115 insertions(+), 4 deletions(-) diff --git a/src/wallet.test.ts b/src/wallet.test.ts index 96cc5e2f..d6b9f6da 100644 --- a/src/wallet.test.ts +++ b/src/wallet.test.ts @@ -67,6 +67,7 @@ describe('wallet', () => { engine.push(createWalletMiddleware({ getAccounts, processTransaction })); const txParams = { from: testAddresses[0], + data: '0x0', }; const payload = { method: 'eth_sendTransaction', params: [txParams] }; @@ -117,6 +118,103 @@ describe('wallet', () => { ); }); + it('processes transaction with data field but without input field', async () => { + const { engine } = createTestSetup(); + const getAccounts = async () => testAddresses.slice(0, 2); + const witnessedTxParams: TransactionParams[] = []; + const processTransaction = async (_txParams: TransactionParams) => { + witnessedTxParams.push(_txParams); + return testTxHash; + }; + engine.push(createWalletMiddleware({ getAccounts, processTransaction })); + const txParams = { + from: testAddresses[0], + data: '0x0', + }; + + const payload = { method: 'eth_sendTransaction', params: [txParams] }; + const sendTxResponse = await pify(engine.handle).call(engine, payload); + const sendTxResult = sendTxResponse.result; + expect(sendTxResult).toBeDefined(); + expect(sendTxResult).toStrictEqual(testTxHash); + expect(witnessedTxParams).toHaveLength(1); + expect(witnessedTxParams[0]).toStrictEqual(txParams); + }); + + it('processes transaction with input field but without data field', async () => { + const { engine } = createTestSetup(); + const getAccounts = async () => testAddresses.slice(0, 2); + const witnessedTxParams: TransactionParams[] = []; + const processTransaction = async (_txParams: TransactionParams) => { + witnessedTxParams.push(_txParams); + return testTxHash; + }; + engine.push(createWalletMiddleware({ getAccounts, processTransaction })); + const txParams = { + from: testAddresses[0], + input: '0x0', + }; + + const payload = { method: 'eth_sendTransaction', params: [txParams] }; + const sendTxResponse = await pify(engine.handle).call(engine, payload); + const sendTxResult = sendTxResponse.result; + expect(sendTxResult).toBeDefined(); + expect(sendTxResult).toStrictEqual(testTxHash); + expect(witnessedTxParams).toHaveLength(1); + expect(witnessedTxParams[0]).toStrictEqual({ + from: txParams.from, + data: txParams.input, + }); + }); + + it('processes transaction with matching input and data field', async () => { + const { engine } = createTestSetup(); + const getAccounts = async () => testAddresses.slice(0, 2); + const witnessedTxParams: TransactionParams[] = []; + const processTransaction = async (_txParams: TransactionParams) => { + witnessedTxParams.push(_txParams); + return testTxHash; + }; + engine.push(createWalletMiddleware({ getAccounts, processTransaction })); + const txParams = { + from: testAddresses[0], + data: '0x0', + input: '0x0', + }; + + const payload = { method: 'eth_sendTransaction', params: [txParams] }; + const sendTxResponse = await pify(engine.handle).call(engine, payload); + const sendTxResult = sendTxResponse.result; + expect(sendTxResult).toBeDefined(); + expect(sendTxResult).toStrictEqual(testTxHash); + expect(witnessedTxParams).toHaveLength(1); + expect(witnessedTxParams[0]).toStrictEqual({ + from: txParams.from, + data: txParams.data, + }); + }); + + it('throws when input and data fields are both defined but do not match', async () => { + const { engine } = createTestSetup(); + const getAccounts = async () => testAddresses.slice(0, 2); + const witnessedTxParams: TransactionParams[] = []; + const processTransaction = async (_txParams: TransactionParams) => { + witnessedTxParams.push(_txParams); + return testTxHash; + }; + engine.push(createWalletMiddleware({ getAccounts, processTransaction })); + const txParams = { + from: testAddresses[0], + data: '0x0', + input: '0x1', + }; + + const payload = { method: 'eth_sendTransaction', params: [txParams] }; + await expect(pify(engine.handle).call(engine, payload)).rejects.toThrow( + new Error('Invalid input.'), + ); + }); + it('should not override other request params', async () => { const { engine } = createTestSetup(); const getAccounts = async () => testAddresses.slice(0, 2); @@ -129,6 +227,7 @@ describe('wallet', () => { const txParams = { from: testAddresses[0], to: testAddresses[1], + data: '0x0', }; const payload = { method: 'eth_sendTransaction', params: [txParams] }; diff --git a/src/wallet.ts b/src/wallet.ts index 190fba82..f57c2ef6 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -159,10 +159,22 @@ WalletMiddlewareOptions): JsonRpcMiddleware { throw rpcErrors.invalidInput(); } - const params = req.params[0] as TransactionParams | undefined; - const txParams: TransactionParams = { - ...params, - from: await validateAndNormalizeKeyholder(params?.from || '', req), + const params = req.params[0] as + | (TransactionParams & { + input?: string; + data?: string; + }) + | undefined; + + const { from, data, input, ...restParams } = params || {}; + if (data && input && data !== input) { + throw rpcErrors.invalidInput(); + } + + const txParams: TransactionParams & { data?: string } = { + ...restParams, + data: data || input, + from: await validateAndNormalizeKeyholder(from || '', req), }; res.result = await processTransaction(txParams, req); }