Support calculation of solidity function selectors

This commit is contained in:
Mark Spanbroek 2022-01-19 09:18:46 +01:00
parent e3c9aa4368
commit ad3d2f7a4b
5 changed files with 101 additions and 0 deletions

View File

@ -1,5 +1,7 @@
import contractabi/encoding
import contractabi/decoding
import contractabi/selector
export encoding
export decoding
export selector

View File

@ -5,5 +5,6 @@ license = "MIT"
requires "stint"
requires "stew"
requires "nimcrypto >= 0.5.4 & < 0.6.0"
requires "questionable >= 0.10.0 & < 0.11.0"
requires "upraises >= 0.1.0 & < 0.2.0"

66
contractabi/selector.nim Normal file
View File

@ -0,0 +1,66 @@
import std/strutils
import pkg/nimcrypto
import pkg/stint
import pkg/stew/byteutils
import ./address
export address
export stint
type FunctionSelector* = distinct array[4, byte]
proc toArray*(selector: FunctionSelector): array[4, byte] =
array[4, byte](selector)
proc `$`*(selector: FunctionSelector): string =
"0x" & selector.toArray.toHex
template solidityType(T: type, s: string) =
func solidityType*(_: type T): string = s
solidityType uint8, "uint8"
solidityType uint16, "uint16"
solidityType uint32, "uint32"
solidityType uint64, "uint64"
solidityType UInt128, "uint128"
solidityType UInt256, "uint256"
solidityType int8, "int8"
solidityType int16, "int16"
solidityType int32, "int32"
solidityType int64, "int64"
solidityType Int128, "int128"
solidityType Int256, "int256"
solidityType bool, "bool"
solidityType string, "string"
solidityType Address, "address"
func solidityType*[N: static int](_: type array[N, byte]): string =
"bytes" & $N
func solidityType*(_: type seq[byte]): string =
"bytes"
func solidityType*[T, N](_: type array[N, T]): string =
solidityType(T) & "[" & $array[N, T].default.len & "]"
func solidityType*[T](_: type seq[T]): string =
solidityType(T) & "[]"
func solidityType*(Tuple: type tuple): string =
var names: seq[string]
for parameter in Tuple.default.fields:
names.add(solidityType(typeof parameter))
"(" & names.join(",") & ")"
func signature*(function: string, Parameters: type tuple = ()): string =
function & solidityType(Parameters)
func hash(s: string): array[32, byte] =
keccak256.digest(s.toBytes).data
func selector*(function: string, parameters: type tuple): FunctionSelector =
let signature = signature(function, parameters)
let hash = hash(signature)
var selector: array[4, byte]
selector[0..<4] = hash[0..<4]
FunctionSelector(selector)

View File

@ -0,0 +1,31 @@
import std/unittest
import pkg/contractabi/selector
suite "function selector":
test "translates nim types into solidity types":
check solidityType(uint8) == "uint8"
check solidityType(uint16) == "uint16"
check solidityType(uint32) == "uint32"
check solidityType(uint64) == "uint64"
check solidityType(UInt128) == "uint128"
check solidityType(UInt256) == "uint256"
check solidityType(int8) == "int8"
check solidityType(int16) == "int16"
check solidityType(int32) == "int32"
check solidityType(int64) == "int64"
check solidityType(Int128) == "int128"
check solidityType(Int256) == "int256"
check solidityType(bool) == "bool"
check solidityType(string) == "string"
check solidityType(Address) == "address"
check solidityType(array[4, byte]) == "bytes4"
check solidityType(array[16, byte]) == "bytes16"
check solidityType(seq[byte]) == "bytes"
check solidityType(array[4, string]) == "string[4]"
check solidityType(seq[string]) == "string[]"
check solidityType((Address, string, bool)) == "(address,string,bool)"
test "calculates solidity function selector":
check $selector("transfer", (Address, UInt256)) == "0xa9059cbb"
check $selector("transferFrom", (Address, Address, UInt256)) == "0x23b872dd"

View File

@ -2,5 +2,6 @@ import ./contractabi/testAddress
import ./contractabi/testEncoding
import ./contractabi/testDecoding
import ./contractabi/testCustomTypes
import ./contractabi/testSelector
{.warning[UnusedImport]:off.}