From 11ff6cd98b6f53a78143828ad636ad96e59c59ab Mon Sep 17 00:00:00 2001 From: Eric <5089238+emizzle@users.noreply.github.com> Date: Mon, 25 Sep 2023 17:25:52 +1000 Subject: [PATCH] Add TransactionType Add transactionType and chainId to PastTransaction, so they can be sent along with replayed txs --- ethers/provider.nim | 8 +- ethers/providers/jsonrpc/conversions.nim | 51 ++++++++++- ethers/transaction.nim | 30 ++++--- .../providers/jsonrpc/testConversions.nim | 90 ++++++++++--------- 4 files changed, 124 insertions(+), 55 deletions(-) diff --git a/ethers/provider.nim b/ethers/provider.nim index 77fc49d..ecb27fb 100644 --- a/ethers/provider.nim +++ b/ethers/provider.nim @@ -48,7 +48,9 @@ type logs*: seq[Log] blockNumber*: ?UInt256 cumulativeGasUsed*: UInt256 + effectiveGasPrice*: ?UInt256 status*: TransactionStatus + transactionType*: TransactionType LogHandler* = proc(log: Log) {.gcsafe, upraises:[].} BlockHandler* = proc(blck: Block) {.gcsafe, upraises:[].} Topic* = array[32, byte] @@ -67,6 +69,8 @@ type nonce*: UInt256 to*: Address transactionIndex*: UInt256 + transactionType*: ?TransactionType + chainId*: ?UInt256 value*: UInt256 v*, r*, s* : UInt256 @@ -85,7 +89,9 @@ func toTransaction*(past: PastTransaction): Transaction = gasPrice: some past.gasPrice, data: past.input, nonce: some past.nonce, - to: past.to + to: past.to, + transactionType: past.transactionType, + chainId: past.chainId ) method getBlockNumber*(provider: Provider): Future[UInt256] {.base, gcsafe.} = diff --git a/ethers/providers/jsonrpc/conversions.nim b/ethers/providers/jsonrpc/conversions.nim index 4a76c69..884889e 100644 --- a/ethers/providers/jsonrpc/conversions.nim +++ b/ethers/providers/jsonrpc/conversions.nim @@ -59,6 +59,16 @@ func `%`*(integer: UInt256): JsonNode = func fromJson*(json: JsonNode, name: string, result: var UInt256) = result = UInt256.fromHex(json.getStr()) +# TransactionType + +func fromJson*(json: JsonNode, name: string, result: var TransactionType) = + let val = fromHex[int](json.getStr) + result = TransactionType(val) + +func `%`*(txType: TransactionType): JsonNode = + debugEcho "serializing tx type: ", txType, " to: 0x", txType.int.toHex(1) + %("0x" & txType.int.toHex(1)) + # Transaction func `%`*(transaction: Transaction): JsonNode = @@ -73,6 +83,8 @@ func `%`*(transaction: Transaction): JsonNode = result["gasPrice"] = %gasPrice if gasLimit =? transaction.gasLimit: result["gas"] = %gasLimit + if txType =? transaction.transactionType: + result["type"] = %txType # BlockTag @@ -98,7 +110,7 @@ func fromJson*(json: JsonNode, name: string, result: var TransactionStatus) = result = TransactionStatus(val) func `%`*(status: TransactionStatus): JsonNode = - %(status.int.toHex) + %("0x" & status.int.toHex(1)) # PastTransaction @@ -125,9 +137,13 @@ func fromJson*(json: JsonNode, name: string, result: var PastTransaction) = r: UInt256.fromJson(json["r"], "r"), s: UInt256.fromJson(json["s"], "s"), ) + if json.hasKey("type"): + result.transactionType = fromJson(?TransactionType, json["type"], "type") + if json.hasKey("chainId"): + result.chainId = fromJson(?UInt256, json["chainId"], "chainId") func `%`*(tx: PastTransaction): JsonNode = - %*{ + let json = %*{ "blockHash": tx.blockHash, "blockNumber": tx.blockNumber, "from": tx.sender, @@ -143,3 +159,34 @@ func `%`*(tx: PastTransaction): JsonNode = "r": tx.r, "s": tx.s } + if txType =? tx.transactionType: + json["type"] = %txType + if chainId =? tx.chainId: + json["chainId"] = %chainId + return json + +# TransactionReceipt + +func fromJson*(json: JsonNode, name: string, result: var TransactionReceipt) = + # Deserializes a transaction receipt, eg eth_getTransactionReceipt. + # Spec: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionreceipt + json.expectFields "transactionHash", "transactionIndex", "cumulativeGasUsed", + "effectiveGasPrice", "gasUsed", "logs", "logsBloom", "type", + "status" + + result = TransactionReceipt( + transactionHash: fromJson(TransactionHash, json["transactionHash"], "transactionHash"), + transactionIndex: UInt256.fromJson(json["transactionIndex"], "transactionIndex"), + blockHash: fromJson(?BlockHash, json["blockHash"], "blockHash"), + blockNumber: fromJson(?UInt256, json["blockNumber"], "blockNumber"), + sender: fromJson(?Address, json["from"], "from"), + to: fromJson(?Address, json["to"], "to"), + cumulativeGasUsed: UInt256.fromJson(json["cumulativeGasUsed"], "cumulativeGasUsed"), + effectiveGasPrice: fromJson(?UInt256, json["effectiveGasPrice"], "effectiveGasPrice"), + gasUsed: UInt256.fromJson(json["gasUsed"], "gasUsed"), + contractAddress: fromJson(?Address, json["contractAddress"], "contractAddress"), + logs: seq[Log].fromJson(json["logs"], "logs"), + logsBloom: seq[byte].fromJson(json["logsBloom"], "logsBloom"), + transactionType: TransactionType.fromJson(json["type"], "type"), + status: TransactionStatus.fromJson(json["status"], "status") + ) diff --git a/ethers/transaction.nim b/ethers/transaction.nim index 29c7418..0ee9d2a 100644 --- a/ethers/transaction.nim +++ b/ethers/transaction.nim @@ -1,17 +1,23 @@ import pkg/stew/byteutils import ./basics -type Transaction* = object - sender*: ?Address - to*: Address - data*: seq[byte] - value*: UInt256 - nonce*: ?UInt256 - chainId*: ?UInt256 - gasPrice*: ?UInt256 - maxFee*: ?UInt256 - maxPriorityFee*: ?UInt256 - gasLimit*: ?UInt256 +type + TransactionType* = enum + Legacy = 0, + AccessList = 1, + Dynamic = 2 + Transaction* = object + sender*: ?Address + to*: Address + data*: seq[byte] + value*: UInt256 + nonce*: ?UInt256 + chainId*: ?UInt256 + gasPrice*: ?UInt256 + maxFee*: ?UInt256 + maxPriorityFee*: ?UInt256 + gasLimit*: ?UInt256 + transactionType*: ?TransactionType func `$`*(transaction: Transaction): string = result = "(" @@ -28,4 +34,6 @@ func `$`*(transaction: Transaction): string = result &= ", gasPrice: " & $gasPrice if gasLimit =? transaction.gasLimit: result &= ", gasLimit: " & $gasLimit + if txType =? transaction.transactionType: + result &= ", type: " & $txType result &= ")" diff --git a/testmodule/providers/jsonrpc/testConversions.nim b/testmodule/providers/jsonrpc/testConversions.nim index 6f47c11..489c8aa 100644 --- a/testmodule/providers/jsonrpc/testConversions.nim +++ b/testmodule/providers/jsonrpc/testConversions.nim @@ -42,7 +42,7 @@ suite "JSON Conversions": test "missing block number in TransactionReceipt isNone": var json = %*{ - "sender": newJNull(), + "from": newJNull(), "to": "0x5fbdb2315678afecb367f032d93f642f64180aa3", "contractAddress": newJNull(), "transactionIndex": "0x0", @@ -62,7 +62,9 @@ suite "JSON Conversions": ], "blockNumber": newJNull(), "cumulativeGasUsed": "0x10db1", - "status": "0000000000000001" + "status": "0x1", + "effectiveGasPrice": "0x3b9aca08", + "type": "0x0" } var receipt = TransactionReceipt.fromJson(json) @@ -75,7 +77,7 @@ suite "JSON Conversions": test "missing block hash in TransactionReceipt isNone": let json = %*{ - "sender": newJNull(), + "from": newJNull(), "to": "0x5fbdb2315678afecb367f032d93f642f64180aa3", "contractAddress": newJNull(), "transactionIndex": "0x0", @@ -95,7 +97,9 @@ suite "JSON Conversions": ], "blockNumber": newJNull(), "cumulativeGasUsed": "0x10db1", - "status": "0000000000000001" + "status": "0x1", + "effectiveGasPrice": "0x3b9aca08", + "type": "0x0" } let receipt = TransactionReceipt.fromJson(json) @@ -157,44 +161,48 @@ suite "JSON Conversions": check tx.to == Address.init("0x92f09aa59dccb892a9f5406ddd9c0b98f02ea57e").get check tx.transactionIndex == 0x3.u256 check tx.value == 0.u256 + check tx.transactionType == some TransactionType.Legacy + check tx.chainId == some 0xc0de4.u256 check tx.v == 0x181bec.u256 check tx.r == UInt256.fromBytesBE(hexToSeqByte("0x57ba18460934526333b80b0fea08737c363f3cd5fbec4a25a8a25e3e8acb362a")) check tx.s == UInt256.fromBytesBE(hexToSeqByte("0x33aa50bc8bd719b6b17ad0bf52006bf8943999198f2bf731eb33c118091000f2")) -test "PastTransaction serializes correctly": - let tx = PastTransaction( - blockHash: BlockHash(array[32, byte].fromHex("0x595bffbe897e025ea2df3213c4cc52c3f3d69bc04b49011d558f1b0e70038922")), - blockNumber: 0x22e.u256, - sender: Address.init("0xe00b677c29ff8d8fe6068530e2bc36158c54dd34").get, - gas: 0x4d4bb.u256, - gasPrice: 0x3b9aca07.u256, - hash: TransactionHash(array[32, byte].fromHex("0xa31608907c338d6497b0c6ec81049d845c7d409490ebf78171f35143897ca790")), - input: hexToSeqByte("0x6368a471d26ff5c7f835c1a8203235e88846ce1a196d6e79df0eaedd1b8ed3deec2ae5c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000012a00000000000000000000000000000000000000000000000000000000000000"), - nonce: 0x3.u256, - to: Address.init("0x92f09aa59dccb892a9f5406ddd9c0b98f02ea57e").get, - transactionIndex: 0x3.u256, - value: 0.u256, - v: 0x181bec.u256, - r: UInt256.fromBytesBE(hexToSeqByte("0x57ba18460934526333b80b0fea08737c363f3cd5fbec4a25a8a25e3e8acb362a")), - s: UInt256.fromBytesBE(hexToSeqByte("0x33aa50bc8bd719b6b17ad0bf52006bf8943999198f2bf731eb33c118091000f2")) - ) - let expected = """ - { - "blockHash":"0x595bffbe897e025ea2df3213c4cc52c3f3d69bc04b49011d558f1b0e70038922", - "blockNumber":"0x22e", - "from":"0xe00b677c29ff8d8fe6068530e2bc36158c54dd34", - "gas":"0x4d4bb", - "gasPrice":"0x3b9aca07", - "hash":"0xa31608907c338d6497b0c6ec81049d845c7d409490ebf78171f35143897ca790", - "input":"0x6368a471d26ff5c7f835c1a8203235e88846ce1a196d6e79df0eaedd1b8ed3deec2ae5c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000012a00000000000000000000000000000000000000000000000000000000000000", - "nonce":"0x3", - "to":"0x92f09aa59dccb892a9f5406ddd9c0b98f02ea57e", - "transactionIndex":"0x3", - "value":"0x0", - "v":"0x181bec", - "r":"0x57ba18460934526333b80b0fea08737c363f3cd5fbec4a25a8a25e3e8acb362a", - "s":"0x33aa50bc8bd719b6b17ad0bf52006bf8943999198f2bf731eb33c118091000f2" - }""".flatten - # "type":"0x0", - # "chainId":"0xc0de4", - check $(%tx) == expected + test "PastTransaction serializes correctly": + let tx = PastTransaction( + blockHash: BlockHash(array[32, byte].fromHex("0x595bffbe897e025ea2df3213c4cc52c3f3d69bc04b49011d558f1b0e70038922")), + blockNumber: 0x22e.u256, + sender: Address.init("0xe00b677c29ff8d8fe6068530e2bc36158c54dd34").get, + gas: 0x4d4bb.u256, + gasPrice: 0x3b9aca07.u256, + hash: TransactionHash(array[32, byte].fromHex("0xa31608907c338d6497b0c6ec81049d845c7d409490ebf78171f35143897ca790")), + input: hexToSeqByte("0x6368a471d26ff5c7f835c1a8203235e88846ce1a196d6e79df0eaedd1b8ed3deec2ae5c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000012a00000000000000000000000000000000000000000000000000000000000000"), + nonce: 0x3.u256, + to: Address.init("0x92f09aa59dccb892a9f5406ddd9c0b98f02ea57e").get, + transactionIndex: 0x3.u256, + value: 0.u256, + v: 0x181bec.u256, + r: UInt256.fromBytesBE(hexToSeqByte("0x57ba18460934526333b80b0fea08737c363f3cd5fbec4a25a8a25e3e8acb362a")), + s: UInt256.fromBytesBE(hexToSeqByte("0x33aa50bc8bd719b6b17ad0bf52006bf8943999198f2bf731eb33c118091000f2")), + transactionType: some TransactionType.Legacy, + chainId: some 0xc0de4.u256 + ) + let expected = """ + { + "blockHash":"0x595bffbe897e025ea2df3213c4cc52c3f3d69bc04b49011d558f1b0e70038922", + "blockNumber":"0x22e", + "from":"0xe00b677c29ff8d8fe6068530e2bc36158c54dd34", + "gas":"0x4d4bb", + "gasPrice":"0x3b9aca07", + "hash":"0xa31608907c338d6497b0c6ec81049d845c7d409490ebf78171f35143897ca790", + "input":"0x6368a471d26ff5c7f835c1a8203235e88846ce1a196d6e79df0eaedd1b8ed3deec2ae5c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000012a00000000000000000000000000000000000000000000000000000000000000", + "nonce":"0x3", + "to":"0x92f09aa59dccb892a9f5406ddd9c0b98f02ea57e", + "transactionIndex":"0x3", + "value":"0x0", + "v":"0x181bec", + "r":"0x57ba18460934526333b80b0fea08737c363f3cd5fbec4a25a8a25e3e8acb362a", + "s":"0x33aa50bc8bd719b6b17ad0bf52006bf8943999198f2bf731eb33c118091000f2", + "type":"0x0", + "chainId":"0xc0de4" + }""".flatten + check $(%tx) == expected