Support calculation of solidity function selectors
This commit is contained in:
parent
e3c9aa4368
commit
ad3d2f7a4b
|
@ -1,5 +1,7 @@
|
||||||
import contractabi/encoding
|
import contractabi/encoding
|
||||||
import contractabi/decoding
|
import contractabi/decoding
|
||||||
|
import contractabi/selector
|
||||||
|
|
||||||
export encoding
|
export encoding
|
||||||
export decoding
|
export decoding
|
||||||
|
export selector
|
||||||
|
|
|
@ -5,5 +5,6 @@ license = "MIT"
|
||||||
|
|
||||||
requires "stint"
|
requires "stint"
|
||||||
requires "stew"
|
requires "stew"
|
||||||
|
requires "nimcrypto >= 0.5.4 & < 0.6.0"
|
||||||
requires "questionable >= 0.10.0 & < 0.11.0"
|
requires "questionable >= 0.10.0 & < 0.11.0"
|
||||||
requires "upraises >= 0.1.0 & < 0.2.0"
|
requires "upraises >= 0.1.0 & < 0.2.0"
|
||||||
|
|
|
@ -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)
|
|
@ -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"
|
|
@ -2,5 +2,6 @@ import ./contractabi/testAddress
|
||||||
import ./contractabi/testEncoding
|
import ./contractabi/testEncoding
|
||||||
import ./contractabi/testDecoding
|
import ./contractabi/testDecoding
|
||||||
import ./contractabi/testCustomTypes
|
import ./contractabi/testCustomTypes
|
||||||
|
import ./contractabi/testSelector
|
||||||
|
|
||||||
{.warning[UnusedImport]:off.}
|
{.warning[UnusedImport]:off.}
|
||||||
|
|
Loading…
Reference in New Issue