Argument decoding and initial deploy contract testing
This commit is contained in:
parent
332b0ccfc8
commit
aff05ca240
|
@ -9,7 +9,7 @@ contract(TestContract):
|
||||||
proc ChainStart(deposit_root: bytes32, time: bytes) {.event.}
|
proc ChainStart(deposit_root: bytes32, time: bytes) {.event.}
|
||||||
proc deposit(deposit_input: bytes) {.payable.}
|
proc deposit(deposit_input: bytes) {.payable.}
|
||||||
proc get_deposit_root(): bytes32 {.view.}
|
proc get_deposit_root(): bytes32 {.view.}
|
||||||
#proc get_branch(leaf: uint256): bytes32[32] {.pure.}
|
proc get_branch(leaf: uint256): bytes32[32] {.view.}
|
||||||
|
|
||||||
#var
|
#var
|
||||||
# x2 = TestContract(address:
|
# x2 = TestContract(address:
|
||||||
|
@ -21,13 +21,15 @@ contract(TestContract):
|
||||||
|
|
||||||
var
|
var
|
||||||
x = TestContract(address:
|
x = TestContract(address:
|
||||||
"4e7f73f0bbee44db86fbf8b957cf7c8bf330c2fe".toAddress,
|
"630170976aBc526b1408Cc2Dd7b7B5599862c02f".toAddress,
|
||||||
client: newRpcHttpClient()
|
client: newRpcHttpClient()
|
||||||
)
|
)
|
||||||
sender = x.initSender("127.0.0.1", 8545,
|
sender = x.initSender("127.0.0.1", 8545,
|
||||||
"45b6fc37a833d2f20dc25917f0a632f351be474b".toAddress)
|
"c9f03520257dd207a159164c534c2b2664d8fd22".toAddress)
|
||||||
receiver = x.initReceiver("127.0.0.1", 8545)
|
#receiver = x.initReceiver("127.0.0.1", 8545)
|
||||||
eventListener = receiver.initEventListener()
|
#eventListener = receiver.initEventListener()
|
||||||
|
|
||||||
|
echo waitFor sender.getDepositRoot()
|
||||||
|
|
||||||
#x.callbacks.Transfer.add proc (fromAddr, toAddr: Address, value: Uint256) =
|
#x.callbacks.Transfer.add proc (fromAddr, toAddr: Address, value: Uint256) =
|
||||||
# echo $value, " coins were transferred from ", fromAddr.toHex, " to ", toAddr.toHex
|
# echo $value, " coins were transferred from ", fromAddr.toHex, " to ", toAddr.toHex
|
||||||
|
@ -52,4 +54,4 @@ var
|
||||||
# 10.to(Stuint[256])
|
# 10.to(Stuint[256])
|
||||||
#))
|
#))
|
||||||
|
|
||||||
waitFor eventListener.listen()
|
#waitFor eventListener.listen()
|
||||||
|
|
|
@ -27,7 +27,7 @@ proc eth_getCode(data: array[20, byte], quantityTag: string): seq[byte]
|
||||||
proc eth_sign(data: array[20, byte], message: seq[byte]): seq[byte]
|
proc eth_sign(data: array[20, byte], message: seq[byte]): seq[byte]
|
||||||
proc eth_sendTransaction(obj: EthSend): UInt256
|
proc eth_sendTransaction(obj: EthSend): UInt256
|
||||||
proc eth_sendRawTransaction(data: string, quantityTag: int): UInt256
|
proc eth_sendRawTransaction(data: string, quantityTag: int): UInt256
|
||||||
proc eth_call(call: EthCall, quantityTag: string): seq[byte]#UInt256
|
proc eth_call(call: EthCall, quantityTag: string): string #UInt256
|
||||||
proc eth_estimateGas(call: EthCall, quantityTag: string): UInt256
|
proc eth_estimateGas(call: EthCall, quantityTag: string): UInt256
|
||||||
proc eth_getBlockByHash(data: array[32, byte], fullTransactions: bool): BlockObject
|
proc eth_getBlockByHash(data: array[32, byte], fullTransactions: bool): BlockObject
|
||||||
proc eth_getBlockByNumber(quantityTag: string, fullTransactions: bool): BlockObject
|
proc eth_getBlockByNumber(quantityTag: string, fullTransactions: bool): BlockObject
|
||||||
|
|
|
@ -8,11 +8,6 @@ contract(TestContract):
|
||||||
proc sendCoin(receiver: Address, amount: Uint): Bool
|
proc sendCoin(receiver: Address, amount: Uint): Bool
|
||||||
proc getBalance(address: Address): Uint {.view.}
|
proc getBalance(address: Address): Uint {.view.}
|
||||||
proc Transfer(fromAddr: indexed[Address], toAddr: indexed[Address], value: Uint256) {.event.}
|
proc Transfer(fromAddr: indexed[Address], toAddr: indexed[Address], value: Uint256) {.event.}
|
||||||
proc Deposit(previous_deposit_root: Bytes32, data: Byte[2064], merkle_tree_index: bytes[8]) {.event.}
|
|
||||||
proc ChainStart(deposit_root: bytes32, time: byte[8])
|
|
||||||
proc deposit(deposit_input: byte[2048]) {.payable.}
|
|
||||||
proc get_deposit_root(): bytes32 {.pure.}
|
|
||||||
proc get_branch(leaf: uint256): bytes32 {.pure.}
|
|
||||||
|
|
||||||
#var
|
#var
|
||||||
# x2 = TestContract(address:
|
# x2 = TestContract(address:
|
||||||
|
|
84
src/web3.nim
84
src/web3.nim
|
@ -37,12 +37,12 @@ type
|
||||||
# result = new Web3
|
# result = new Web3
|
||||||
# result.eth = client
|
# result.eth = client
|
||||||
|
|
||||||
func encode[bits: static[int]](x: Stuint[bits]): EncodeResult =
|
func encode*[bits: static[int]](x: Stuint[bits]): EncodeResult =
|
||||||
## Encodes a `Stuint` to a textual representation for use in the JsonRPC
|
## Encodes a `Stuint` to a textual representation for use in the JsonRPC
|
||||||
## `sendTransaction` call.
|
## `sendTransaction` call.
|
||||||
(dynamic: false, data: '0'.repeat((256 - bits) div 4) & x.dumpHex)
|
(dynamic: false, data: '0'.repeat((256 - bits) div 4) & x.dumpHex)
|
||||||
|
|
||||||
func encode[bits: static[int]](x: Stint[bits]): EncodeResult =
|
func encode*[bits: static[int]](x: Stint[bits]): EncodeResult =
|
||||||
## Encodes a `Stint` to a textual representation for use in the JsonRPC
|
## Encodes a `Stint` to a textual representation for use in the JsonRPC
|
||||||
## `sendTransaction` call.
|
## `sendTransaction` call.
|
||||||
(dynamic: false,
|
(dynamic: false,
|
||||||
|
@ -53,6 +53,13 @@ func encode[bits: static[int]](x: Stint[bits]): EncodeResult =
|
||||||
'0'.repeat((256 - bits) div 4) & x.dumpHex
|
'0'.repeat((256 - bits) div 4) & x.dumpHex
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func decode*[bits: static[int]](input: string, to: type Stuint[bits]): Stuint[bits] =
|
||||||
|
fromHex(to, input)
|
||||||
|
|
||||||
|
func decode*[bits: static[int]](input: string, to: type Stint[bits]): Stint[bits] =
|
||||||
|
cast[Stint[bits]](fromHex(Stuint[bits], input))
|
||||||
|
|
||||||
|
|
||||||
macro makeTypeEnum(): untyped =
|
macro makeTypeEnum(): untyped =
|
||||||
## This macro creates all the various types of Solidity contracts and maps
|
## 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
|
## them to the type used for their encoding. It also creates an enum to
|
||||||
|
@ -85,6 +92,7 @@ macro makeTypeEnum(): untyped =
|
||||||
`identInt`* = Int256
|
`identInt`* = Int256
|
||||||
`identBool`* = distinct Int256
|
`identBool`* = distinct Int256
|
||||||
func encode*(x: `identBool`): EncodeResult = encode(Int256(x))
|
func encode*(x: `identBool`): EncodeResult = encode(Int256(x))
|
||||||
|
func decode*(input: string, x: `identBool`): `identBool` = `identBool`(decode(input, Stint[256]))
|
||||||
fields.add [
|
fields.add [
|
||||||
identAddress,
|
identAddress,
|
||||||
identUint,
|
identUint,
|
||||||
|
@ -117,6 +125,12 @@ macro makeTypeEnum(): untyped =
|
||||||
func encode*[N: static[int]](x: `identUfixed`[N]): EncodeResult =
|
func encode*[N: static[int]](x: `identUfixed`[N]): EncodeResult =
|
||||||
encode(`identUint`(x) * (10 ^ N).to(`identUint`))
|
encode(`identUint`(x) * (10 ^ N).to(`identUint`))
|
||||||
|
|
||||||
|
func decode*[N: static[int]](input: string, to: `identFixed`[N]): `identFixed`[N] =
|
||||||
|
decode(input, `identInt`) div / (10 ^ N).to(`identInt`)
|
||||||
|
|
||||||
|
func decode*[N: static[int]](input: string, to: `identUfixed`[N]): `identFixed`[N] =
|
||||||
|
decode(input, `identUint`) div / (10 ^ N).to(`identUint`)
|
||||||
|
|
||||||
fields.add ident("Fixed" & $m)
|
fields.add ident("Fixed" & $m)
|
||||||
fields.add ident("Ufixed" & $m)
|
fields.add ident("Ufixed" & $m)
|
||||||
let
|
let
|
||||||
|
@ -145,6 +159,8 @@ macro makeTypeEnum(): untyped =
|
||||||
func fromHex*(x: type `identBytes`, s: string): `identBytes` =
|
func fromHex*(x: type `identBytes`, s: string): `identBytes` =
|
||||||
for i in 0..(`i`-1):
|
for i in 0..(`i`-1):
|
||||||
`identResult`[i] = parseHexInt(s[i*2..i*2+1]).uint8
|
`identResult`[i] = parseHexInt(s[i*2..i*2+1]).uint8
|
||||||
|
func decode*(input: string, to: type `identBytes`): `identBytes` =
|
||||||
|
fromHex(to, input)
|
||||||
|
|
||||||
fields.add [
|
fields.add [
|
||||||
ident("Function"),
|
ident("Function"),
|
||||||
|
@ -165,6 +181,8 @@ macro makeTypeEnum(): untyped =
|
||||||
`identResult`.data &= "00".repeat(32 - (x.len mod 32))
|
`identResult`.data &= "00".repeat(32 - (x.len mod 32))
|
||||||
func fromHex*(x: type `identBytes`, s: string): `identBytes` =
|
func fromHex*(x: type `identBytes`, s: string): `identBytes` =
|
||||||
fromHex(s)
|
fromHex(s)
|
||||||
|
func decode*(input: string, to: type `identBytes`): `identBytes` =
|
||||||
|
fromHex(to, input)
|
||||||
|
|
||||||
result.add newEnum(ident "FieldKind", fields, public = true, pure = true)
|
result.add newEnum(ident "FieldKind", fields, public = true, pure = true)
|
||||||
echo result.repr
|
echo result.repr
|
||||||
|
@ -175,7 +193,7 @@ type
|
||||||
Encodable = concept x
|
Encodable = concept x
|
||||||
encode(x) is EncodeResult
|
encode(x) is EncodeResult
|
||||||
|
|
||||||
func encode(x: seq[Encodable]): EncodeResult =
|
func encode*(x: seq[Encodable]): EncodeResult =
|
||||||
result.dynamic = true
|
result.dynamic = true
|
||||||
result.data = x.len.toHex(64).toLower
|
result.data = x.len.toHex(64).toLower
|
||||||
var
|
var
|
||||||
|
@ -191,7 +209,13 @@ func encode(x: seq[Encodable]): EncodeResult =
|
||||||
offset += encoded.data.len
|
offset += encoded.data.len
|
||||||
result.data &= data
|
result.data &= data
|
||||||
|
|
||||||
func encode(x: openArray[Encodable]): EncodeResult =
|
func decode*[T](input: string, to: seq[T]): seq[T] =
|
||||||
|
var count = input[0..64].decode(Stuint)
|
||||||
|
result = newSeq[T](count)
|
||||||
|
for i in 0..count:
|
||||||
|
result[i] = input[i*64 .. (i+1)*64].decode(T)
|
||||||
|
|
||||||
|
func encode*(x: openArray[Encodable]): EncodeResult =
|
||||||
result.dynamic = false
|
result.dynamic = false
|
||||||
result.data = ""
|
result.data = ""
|
||||||
var
|
var
|
||||||
|
@ -206,6 +230,11 @@ func encode(x: openArray[Encodable]): EncodeResult =
|
||||||
result.data &= encoded.data
|
result.data &= encoded.data
|
||||||
offset += encoded.data.len
|
offset += encoded.data.len
|
||||||
|
|
||||||
|
func decode*[T; I: static int](input: string, to: array[0..I, T]): array[0..I, T] =
|
||||||
|
for i in 0..I:
|
||||||
|
result[i] = input[i*64 .. (i+1)*64].decode(T)
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
InterfaceObjectKind = enum
|
InterfaceObjectKind = enum
|
||||||
function, constructor, event
|
function, constructor, event
|
||||||
|
@ -282,11 +311,31 @@ proc getEventSignature(event: EventObject): string =
|
||||||
|
|
||||||
proc parseContract(body: NimNode): seq[InterfaceObject] =
|
proc parseContract(body: NimNode): seq[InterfaceObject] =
|
||||||
proc parseOutputs(outputNode: NimNode): seq[FunctionInputOutput] =
|
proc parseOutputs(outputNode: NimNode): seq[FunctionInputOutput] =
|
||||||
if outputNode.kind == nnkIdent:
|
#if outputNode.kind == nnkIdent:
|
||||||
|
# result.add FunctionInputOutput(
|
||||||
|
# name: "",
|
||||||
|
# kind: parseEnum[FieldKind]($outputNode.ident)
|
||||||
|
# )
|
||||||
|
case outputNode.kind:
|
||||||
|
of nnkBracketExpr:
|
||||||
result.add FunctionInputOutput(
|
result.add FunctionInputOutput(
|
||||||
name: "",
|
name: "",
|
||||||
kind: parseEnum[FieldKind]($outputNode.ident)
|
kind: parseEnum[FieldKind]($outputNode[0].ident),
|
||||||
|
sequenceKind: if outputNode.len == 1:
|
||||||
|
dynamic
|
||||||
|
else:
|
||||||
|
fixed
|
||||||
)
|
)
|
||||||
|
if outputNode.len == 2:
|
||||||
|
result[^1].count = outputNode[1].intVal.int
|
||||||
|
of nnkIdent:
|
||||||
|
result.add FunctionInputOutput(
|
||||||
|
name: "",
|
||||||
|
kind: parseEnum[FieldKind]($outputNode.ident),
|
||||||
|
sequenceKind: single
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
discard
|
||||||
proc parseInputs(inputNodes: NimNode): seq[FunctionInputOutput] =
|
proc parseInputs(inputNodes: NimNode): seq[FunctionInputOutput] =
|
||||||
for i in 1..<inputNodes.len:
|
for i in 1..<inputNodes.len:
|
||||||
let input = inputNodes[i]
|
let input = inputNodes[i]
|
||||||
|
@ -436,7 +485,7 @@ macro contract*(cname: untyped, body: untyped): untyped =
|
||||||
ident "Address"
|
ident "Address"
|
||||||
else:
|
else:
|
||||||
if obj.functionObject.outputs.len != 1:
|
if obj.functionObject.outputs.len != 1:
|
||||||
newEmptyNode()
|
ident "void"#newEmptyNode()
|
||||||
else:
|
else:
|
||||||
ident $obj.functionObject.outputs[0].kind
|
ident $obj.functionObject.outputs[0].kind
|
||||||
var
|
var
|
||||||
|
@ -499,16 +548,23 @@ macro contract*(cname: untyped, body: untyped): untyped =
|
||||||
)
|
)
|
||||||
case obj.functionObject.stateMutability:
|
case obj.functionObject.stateMutability:
|
||||||
of view:
|
of view:
|
||||||
|
let cc = ident "cc"
|
||||||
procDef[6].add quote do:
|
procDef[6].add quote do:
|
||||||
var cc: EthCall
|
var `cc`: EthCall
|
||||||
cc.source = some(`senderName`.address)
|
`cc`.source = some(`senderName`.address)
|
||||||
#cc.to = `senderName`.contract.Contract.address
|
#cc.to = `senderName`.contract.Contract.address
|
||||||
cc.to = `senderName`.contract.address
|
`cc`.to = `senderName`.contract.address
|
||||||
`encoder`
|
`encoder`
|
||||||
cc.data = some("0x" & ($keccak_256.digest(`signature`))[0..<8].toLower & `encodedParams`)
|
`cc`.data = some("0x" & ($keccak_256.digest(`signature`))[0..<8].toLower & `encodedParams`)
|
||||||
echo cc.data
|
echo `cc`.data
|
||||||
let response = await `senderName`.contract.`client`.eth_call(cc, "latest")
|
if output != ident "void":
|
||||||
return response
|
procDef[6].add quote do:
|
||||||
|
let response = await `senderName`.contract.`client`.eth_call(`cc`, "latest")
|
||||||
|
echo response
|
||||||
|
return response[2..^1].decode(`output`)
|
||||||
|
else:
|
||||||
|
procDef[6].add quote do:
|
||||||
|
await `senderName`.contract.`client`.eth_call(`cc`, "latest")
|
||||||
else:
|
else:
|
||||||
procDef[6].add quote do:
|
procDef[6].add quote do:
|
||||||
var cc: EthSend
|
var cc: EthSend
|
||||||
|
|
Loading…
Reference in New Issue