From b32602e68e1843b6b9601cea20b63ebf96547874 Mon Sep 17 00:00:00 2001 From: Ivan Folgueira Bande Date: Sun, 19 Jan 2025 23:47:10 +0100 Subject: [PATCH 1/5] Create some ethereum types --- web3/encoding.nim | 9 +++++++++ web3/eth_api_types.nim | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/web3/encoding.nim b/web3/encoding.nim index 89e07e9..63a273d 100644 --- a/web3/encoding.nim +++ b/web3/encoding.nim @@ -11,6 +11,15 @@ import std/macros, stint, ./eth_api_types, stew/[assign2, byteutils] +func encode*(x: EthereumUint32): seq[byte] = + let numTargetBytes = 32 div 8 + let paddingBytes = 32 - numTargetBytes + ## the Ethereum ABI imposes a 32 byte width for every type + let paddingZeros = newSeq[byte](paddingBytes) + let ret = paddingZeros & @(x.toByteArrayBE()) + let retHex = ret.toHex() + ret + func encode*[bits: static[int]](x: StUint[bits]): seq[byte] = @(x.toBytesBE()) diff --git a/web3/eth_api_types.nim b/web3/eth_api_types.nim index 22e661a..1c83c83 100644 --- a/web3/eth_api_types.nim +++ b/web3/eth_api_types.nim @@ -10,6 +10,7 @@ {.push raises: [].} import + std/[macros, math], stint, ./primitives @@ -299,6 +300,37 @@ func payload*(args: TransactionArgs): seq[byte] = func isEIP4844*(args: TransactionArgs): bool = args.maxFeePerBlobGas.isSome or args.blobVersionedHashes.isSome +macro makeEthereumTypeEnum(): untyped = + ## This macro creates all the various types of Solidity contracts and maps + ## them to the type used for their encoding. It also creates an enum to + ## identify these types in the contract signatures, along with encoder + ## functions used in the generated procedures. + result = newStmtList() + var lastpow2: int + for i in countdown(256, 8, 8): + let + identUint = newIdentNode("EthereumUint" & $i) + identInt = newIdentNode("EthereumInt" & $i) + if ceil(log2(i.float)) == floor(log2(i.float)): + lastpow2 = i + + result.add quote do: + type + `identUint`* = StUint[`lastpow2`] + `identInt`* = StInt[`lastpow2`] + + let + identUint = ident("EthereumUint") + identInt = ident("EthereumInt") + identBool = ident("EthereumBool") + result.add quote do: + type + `identUint`* = UInt256 + `identInt`* = Int256 + `identBool`* = distinct Int256 + +makeEthereumTypeEnum() + # Backwards compatibility type From 9de5a8ceec0241d074466f1e36dcd20250f5a0b2 Mon Sep 17 00:00:00 2001 From: Ivan Folgueira Bande Date: Thu, 23 Jan 2025 12:32:06 +0100 Subject: [PATCH 2/5] encoding.nim: simplify encode*(x: EthereumUint32) --- web3/encoding.nim | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/web3/encoding.nim b/web3/encoding.nim index 63a273d..b619091 100644 --- a/web3/encoding.nim +++ b/web3/encoding.nim @@ -16,9 +16,7 @@ func encode*(x: EthereumUint32): seq[byte] = let paddingBytes = 32 - numTargetBytes ## the Ethereum ABI imposes a 32 byte width for every type let paddingZeros = newSeq[byte](paddingBytes) - let ret = paddingZeros & @(x.toByteArrayBE()) - let retHex = ret.toHex() - ret + paddingZeros & @(x.toByteArrayBE()) func encode*[bits: static[int]](x: StUint[bits]): seq[byte] = @(x.toBytesBE()) From eb252715bf6c1d83b6b4686df962b11398326022 Mon Sep 17 00:00:00 2001 From: Ivan Folgueira Bande Date: Thu, 23 Jan 2025 15:47:53 +0100 Subject: [PATCH 3/5] creating a more generic and simplified solution as per Etan comments --- web3/encoding.nim | 25 +++++++++++++++++++------ web3/eth_api_types.nim | 31 ++++++++----------------------- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/web3/encoding.nim b/web3/encoding.nim index b619091..6572326 100644 --- a/web3/encoding.nim +++ b/web3/encoding.nim @@ -11,12 +11,25 @@ import std/macros, stint, ./eth_api_types, stew/[assign2, byteutils] -func encode*(x: EthereumUint32): seq[byte] = - let numTargetBytes = 32 div 8 - let paddingBytes = 32 - numTargetBytes - ## the Ethereum ABI imposes a 32 byte width for every type - let paddingZeros = newSeq[byte](paddingBytes) - paddingZeros & @(x.toByteArrayBE()) +macro makeEncodingEthereumFuncs(): untyped = + ## Creates all the encoding funcs needed to properly interact with Ethereum-like chains + result = newStmtList() + for i in [256, 128, 64, 32, 16, 8]: + let + identUint = newIdentNode("EthereumUint" & $i) + identInt = newIdentNode("EthereumInt" & $i) + + for ident in [`identUint`, `identInt`]: + result.add quote do: + func encode*(x: `ident`): seq[byte] = + ## the Ethereum types are created by makeEthereumType macro in eth_api_types.nim + let numTargetBytes = `i` div 8 + let paddingBytes = 32 - numTargetBytes + ## the Ethereum ABI imposes a 32 byte width for every type + let paddingZeros = newSeq[byte](paddingBytes) + paddingZeros & @(x.toBytesBE()) + +makeEncodingEthereumFuncs() func encode*[bits: static[int]](x: StUint[bits]): seq[byte] = @(x.toBytesBE()) diff --git a/web3/eth_api_types.nim b/web3/eth_api_types.nim index 1c83c83..fd1eb70 100644 --- a/web3/eth_api_types.nim +++ b/web3/eth_api_types.nim @@ -300,36 +300,21 @@ func payload*(args: TransactionArgs): seq[byte] = func isEIP4844*(args: TransactionArgs): bool = args.maxFeePerBlobGas.isSome or args.blobVersionedHashes.isSome -macro makeEthereumTypeEnum(): untyped = - ## This macro creates all the various types of Solidity contracts and maps - ## them to the type used for their encoding. It also creates an enum to - ## identify these types in the contract signatures, along with encoder - ## functions used in the generated procedures. +macro makeEthereumTypes(): untyped = + ## This macro creates all the various types of Eth contracts and maps + ## them to the type used for their encoding. result = newStmtList() - var lastpow2: int - for i in countdown(256, 8, 8): + for i in [256, 128, 64, 32, 16, 8]: let identUint = newIdentNode("EthereumUint" & $i) identInt = newIdentNode("EthereumInt" & $i) - if ceil(log2(i.float)) == floor(log2(i.float)): - lastpow2 = i result.add quote do: type - `identUint`* = StUint[`lastpow2`] - `identInt`* = StInt[`lastpow2`] - - let - identUint = ident("EthereumUint") - identInt = ident("EthereumInt") - identBool = ident("EthereumBool") - result.add quote do: - type - `identUint`* = UInt256 - `identInt`* = Int256 - `identBool`* = distinct Int256 - -makeEthereumTypeEnum() + `identUint`* = StUint[`i`] + `identInt`* = StInt[`i`] + +makeEthereumTypes() # Backwards compatibility From 48bc0c1baa796290f4cdbf919cb8622f4ce968d5 Mon Sep 17 00:00:00 2001 From: Ivan Folgueira Bande Date: Thu, 23 Jan 2025 16:00:49 +0100 Subject: [PATCH 4/5] std/math module not needed --- web3/eth_api_types.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web3/eth_api_types.nim b/web3/eth_api_types.nim index fd1eb70..27e8abf 100644 --- a/web3/eth_api_types.nim +++ b/web3/eth_api_types.nim @@ -10,7 +10,7 @@ {.push raises: [].} import - std/[macros, math], + std/macros, stint, ./primitives From 94aac8a77cd265fe779ce8ed25a028340b925fd1 Mon Sep 17 00:00:00 2001 From: Ivan Folgueira Bande Date: Thu, 23 Jan 2025 20:07:21 +0100 Subject: [PATCH 5/5] simplified working version --- web3/encoding.nim | 25 +++++++++++-------------- web3/eth_api_types.nim | 5 +---- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/web3/encoding.nim b/web3/encoding.nim index 6572326..bc1a20c 100644 --- a/web3/encoding.nim +++ b/web3/encoding.nim @@ -14,20 +14,17 @@ import macro makeEncodingEthereumFuncs(): untyped = ## Creates all the encoding funcs needed to properly interact with Ethereum-like chains result = newStmtList() - for i in [256, 128, 64, 32, 16, 8]: - let - identUint = newIdentNode("EthereumUint" & $i) - identInt = newIdentNode("EthereumInt" & $i) - - for ident in [`identUint`, `identInt`]: - result.add quote do: - func encode*(x: `ident`): seq[byte] = - ## the Ethereum types are created by makeEthereumType macro in eth_api_types.nim - let numTargetBytes = `i` div 8 - let paddingBytes = 32 - numTargetBytes - ## the Ethereum ABI imposes a 32 byte width for every type - let paddingZeros = newSeq[byte](paddingBytes) - paddingZeros & @(x.toBytesBE()) + for numBits in [256, 128, 64, 32, 16, 8]: + let identUint = newIdentNode("EthereumUint" & $numBits) + + result.add quote do: + func encode*(x: `identUint`): seq[byte] = + ## the Ethereum types are created by makeEthereumType macro in eth_api_types.nim + let numTargetBytes = `numBits` div 8 + let paddingBytes = 32 - numTargetBytes + ## the Ethereum ABI imposes a 32 byte width for every type + let paddingZeros = newSeq[byte](paddingBytes) + paddingZeros & @(stint.toBytesBE(x)) makeEncodingEthereumFuncs() diff --git a/web3/eth_api_types.nim b/web3/eth_api_types.nim index 27e8abf..93f2f9f 100644 --- a/web3/eth_api_types.nim +++ b/web3/eth_api_types.nim @@ -307,12 +307,9 @@ macro makeEthereumTypes(): untyped = for i in [256, 128, 64, 32, 16, 8]: let identUint = newIdentNode("EthereumUint" & $i) - identInt = newIdentNode("EthereumInt" & $i) result.add quote do: - type - `identUint`* = StUint[`i`] - `identInt`* = StInt[`i`] + type `identUint`* = StUint[`i`] makeEthereumTypes()