From 1dfadf80fa8c2665c21715cb6b5e43ea0957f06c Mon Sep 17 00:00:00 2001 From: "ollie.j" Date: Thu, 14 Sep 2023 19:35:24 +0900 Subject: [PATCH] ethers: Fix encodeTxForRPC to separately handle 0x and 0x0 --- ethers-ext/src/core/klaytn_tx.ts | 56 ++++++++++++++++---------- ethers-ext/src/ethers/signer.ts | 4 +- ethers-ext/test/core/klaytn_tx.spec.ts | 37 +++++++++++++++++ 3 files changed, 72 insertions(+), 25 deletions(-) diff --git a/ethers-ext/src/core/klaytn_tx.ts b/ethers-ext/src/core/klaytn_tx.ts index 496085bbb..895c3dbd5 100644 --- a/ethers-ext/src/core/klaytn_tx.ts +++ b/ethers-ext/src/core/klaytn_tx.ts @@ -1,6 +1,7 @@ import { TransactionRequest } from "@ethersproject/abstract-provider"; import { BigNumber } from "ethers"; import { hexValue, parseTransaction } from "ethers/lib/utils"; +import { accessListify } from "@ethersproject/transactions"; import _ from "lodash"; import { FieldSet, FieldSetFactory } from "./field"; @@ -108,28 +109,39 @@ export function objectFromRLP(value: string): any { return tx; } -export function encodeTxForRPC(allowedKeys:string[], tx: TransactionRequest): any { - // TODO: refactoring like below - // https://github.com/ethers-io/ethers.js/blob/master/packages/providers/src.ts/json-rpc-provider.ts#L701 - // return { - // from: hexlify(tx.from), - // gas: tx.gasLimit? fromnumber(tx.gasLimit) : null; - // }; - - const ttx: any = {}; - for (const key in tx) { - if (allowedKeys.indexOf(key) != -1) { - let value = _.get(tx, key); - - if (value == 0 || value === "0x0000000000000000000000000000000000000000") { - value = "0x"; - } else if (typeof(value) == "number" || value instanceof BigNumber) { - // https://github.com/ethers-io/ethers.js/blob/master/packages/providers/src.ts/json-rpc-provider.ts#L701 - ttx[key] = hexValue(value); - } else { - ttx[key] = value; - } +export function encodeTxForRPC(tx: TransactionRequest): any { + const formatted: any = {}; + + const numericFields = ["chainId", "gasLimit", "gasPrice", "type", "maxFeePerGas", "maxPriorityFeePerGas", "nonce", "value"]; + _.each(numericFields, (key) => { + if (!_.has(tx, key)) { + return; + } + + let value = (tx)[key]; + value = hexValue(BigNumber.from(value)); + + if (key == "gasLimit") { + formatted["gas"] = value; + } else { + formatted[key] = value; } + }); + + const bytestrFields = ["from", "to", "data", "input"] + _.each(bytestrFields, (key) => { + if (!_.has(tx, key)) { + return; + } + + let value = (tx)[key]; + value = HexStr.from(value); + formatted[key] = value; + }); + + if (tx.accessList) { + formatted["accessList"] = accessListify(tx.accessList); } - return ttx; + + return formatted; } diff --git a/ethers-ext/src/ethers/signer.ts b/ethers-ext/src/ethers/signer.ts index a79f785c8..c744ea4b5 100644 --- a/ethers-ext/src/ethers/signer.ts +++ b/ethers-ext/src/ethers/signer.ts @@ -143,9 +143,7 @@ export class Wallet extends EthersWallet { if (!(tx.gasLimit) && !!(tx.to)) { if (this.provider instanceof EthersJsonRpcProvider) { - const estimateGasAllowedKeys: string[] = [ - "from", "to", "gasLimit", "gasPrice", "value", "input"]; - const ttx = encodeTxForRPC(estimateGasAllowedKeys, tx); + const ttx = encodeTxForRPC(tx); const result = await this.provider.send("klay_estimateGas", [ttx]); // For the problem that estimateGas does not exactly match, diff --git a/ethers-ext/test/core/klaytn_tx.spec.ts b/ethers-ext/test/core/klaytn_tx.spec.ts index db445851c..af6186e17 100644 --- a/ethers-ext/test/core/klaytn_tx.spec.ts +++ b/ethers-ext/test/core/klaytn_tx.spec.ts @@ -1,6 +1,8 @@ import { assert } from "chai"; +import { TransactionRequest } from "@ethersproject/abstract-provider"; import { KlaytnTxFactory } from "../../src/core"; +import { encodeTxForRPC } from "../../src/core/klaytn_tx"; // Non-canonical types, which are common user-supplied values. const nonce = 1234; @@ -72,3 +74,38 @@ describe("TypedTxFactory", () => { }); } }); + +describe("encodeTxForRPC", () => { + it("success", () => { + let tx: TransactionRequest = { + chainId: 42, + gasLimit: 0x1111, + gasPrice: 0x222, + type: 2, + maxFeePerGas: 0x33, + maxPriorityFeePerGas: 0x4, + nonce: 0, + value: 0, + + from: "0x00000000000000000000000000000000000000aa", + to: "0x00000000000000000000000000000000000000bb", + data: "0x", + }; + + let formatted = encodeTxForRPC(tx); + assert.deepEqual(formatted, { + chainId: '0x2a', + gas: '0x1111', + gasPrice: '0x222', + type: '0x2', + maxFeePerGas: '0x33', + maxPriorityFeePerGas: '0x4', + nonce: '0x0', + value: '0x0', + + from: '0x00000000000000000000000000000000000000aa', + to: '0x00000000000000000000000000000000000000bb', + data: '0x', + }); + }); +});