Implemented proper dynamic sizes
This commit is contained in:
parent
99c3667184
commit
e3c34bdcd4
127
src/web3.nim
127
src/web3.nim
|
@ -25,6 +25,8 @@ type
|
||||||
receiver: Receiver[T]
|
receiver: Receiver[T]
|
||||||
lastBlock: string
|
lastBlock: string
|
||||||
|
|
||||||
|
EncodeResult = tuple[dynamic: bool, data: string]
|
||||||
|
|
||||||
#proc initWeb3*(address: string, port: int): Web3 =
|
#proc initWeb3*(address: string, port: int): Web3 =
|
||||||
# ## Just creates a simple dummy wrapper object for now. Functionality should
|
# ## Just creates a simple dummy wrapper object for now. Functionality should
|
||||||
# ## increase as the web3 interface is fleshed out.
|
# ## increase as the web3 interface is fleshed out.
|
||||||
|
@ -35,18 +37,21 @@ type
|
||||||
# result = new Web3
|
# result = new Web3
|
||||||
# result.eth = client
|
# result.eth = client
|
||||||
|
|
||||||
func encode[bits: static[int]](x: Stuint[bits]): string =
|
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.
|
||||||
'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]): string =
|
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.
|
||||||
if x.isNegative:
|
(dynamic: false,
|
||||||
'f'.repeat((256 - bits) div 4) & x.dumpHex
|
data:
|
||||||
else:
|
if x.isNegative:
|
||||||
'0'.repeat((256 - bits) div 4) & x.dumpHex
|
'f'.repeat((256 - bits) div 4) & x.dumpHex
|
||||||
|
else:
|
||||||
|
'0'.repeat((256 - bits) div 4) & x.dumpHex
|
||||||
|
)
|
||||||
|
|
||||||
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
|
||||||
|
@ -79,7 +84,7 @@ macro makeTypeEnum(): untyped =
|
||||||
`identUint`* = Uint256
|
`identUint`* = Uint256
|
||||||
`identInt`* = Int256
|
`identInt`* = Int256
|
||||||
`identBool`* = distinct Int256
|
`identBool`* = distinct Int256
|
||||||
func encode*(x: `identBool`): string = encode(Int256(x))
|
func encode*(x: `identBool`): EncodeResult = encode(Int256(x))
|
||||||
fields.add [
|
fields.add [
|
||||||
identAddress,
|
identAddress,
|
||||||
identUint,
|
identUint,
|
||||||
|
@ -106,10 +111,10 @@ macro makeTypeEnum(): untyped =
|
||||||
func to*(x: `identUint`, `identT`: typedesc[`identUfixed`]): `identT` =
|
func to*(x: `identUint`, `identT`: typedesc[`identUfixed`]): `identT` =
|
||||||
T(x)
|
T(x)
|
||||||
|
|
||||||
func encode*[N: static[int]](x: `identFixed`[N]): string =
|
func encode*[N: static[int]](x: `identFixed`[N]): EncodeResult =
|
||||||
encode(`identInt`(x) * (10 ^ N).to(`identInt`))
|
encode(`identInt`(x) * (10 ^ N).to(`identInt`))
|
||||||
|
|
||||||
func encode*[N: static[int]](x: `identUfixed`[N]): string =
|
func encode*[N: static[int]](x: `identUfixed`[N]): EncodeResult =
|
||||||
encode(`identUint`(x) * (10 ^ N).to(`identUint`))
|
encode(`identUint`(x) * (10 ^ N).to(`identUint`))
|
||||||
|
|
||||||
fields.add ident("Fixed" & $m)
|
fields.add ident("Fixed" & $m)
|
||||||
|
@ -131,11 +136,12 @@ macro makeTypeEnum(): untyped =
|
||||||
result.add quote do:
|
result.add quote do:
|
||||||
type
|
type
|
||||||
`identBytes` = array[0..(`i`-1), byte]
|
`identBytes` = array[0..(`i`-1), byte]
|
||||||
func encode(x: `identBytes`): string =
|
func encode(x: `identBytes`): EncodeResult =
|
||||||
`identResult` = ""
|
`identResult`.dynamic = false
|
||||||
|
`identResult`.data = ""
|
||||||
for y in x:
|
for y in x:
|
||||||
`identResult` &= y.toHex.toLower
|
`identResult`.data &= y.toHex.toLower
|
||||||
`identResult` &= "00".repeat(32 - x.len)
|
`identResult`.data &= "00".repeat(32 - x.len)
|
||||||
|
|
||||||
fields.add [
|
fields.add [
|
||||||
ident("Function"),
|
ident("Function"),
|
||||||
|
@ -152,17 +158,38 @@ makeTypeEnum()
|
||||||
|
|
||||||
type
|
type
|
||||||
Encodable = concept x
|
Encodable = concept x
|
||||||
encode(x) is string
|
encode(x) is EncodeResult
|
||||||
|
|
||||||
func encode(x: seq[Encodable]): string =
|
func encode(x: seq[Encodable]): EncodeResult =
|
||||||
result = encode(x.len)
|
result.dynamic = true
|
||||||
|
result.data = x.len.toHex(64).toLower
|
||||||
|
var
|
||||||
|
offset = 32*x.len
|
||||||
|
data = ""
|
||||||
for i in x:
|
for i in x:
|
||||||
result &= encode(i)
|
let encoded = encode(i)
|
||||||
|
if encoded.dynamic:
|
||||||
|
result.data &= offset.toHex(64).toLower
|
||||||
|
data &= encoded.data
|
||||||
|
else:
|
||||||
|
result.data &= encoded.data
|
||||||
|
offset += encoded.data.len
|
||||||
|
result.data &= data
|
||||||
|
|
||||||
func encode(x: openArray[Encodable]): string =
|
func encode(x: openArray[Encodable]): EncodeResult =
|
||||||
result = ""
|
result.dynamic = false
|
||||||
|
result.data = ""
|
||||||
|
var
|
||||||
|
offset = 32*x.len
|
||||||
|
data = ""
|
||||||
for i in x:
|
for i in x:
|
||||||
result &= encode(i)
|
let encoded = encode(i)
|
||||||
|
if encoded.dynamic:
|
||||||
|
result.data &= offset.toHex(64).toLower
|
||||||
|
data &= encoded.data
|
||||||
|
else:
|
||||||
|
result.data &= encoded.data
|
||||||
|
offset += encoded.data.len
|
||||||
|
|
||||||
type
|
type
|
||||||
InterfaceObjectKind = enum
|
InterfaceObjectKind = enum
|
||||||
|
@ -397,13 +424,41 @@ macro contract(cname: untyped, body: untyped): untyped =
|
||||||
newEmptyNode()
|
newEmptyNode()
|
||||||
else:
|
else:
|
||||||
ident $obj.functionObject.outputs[0].kind
|
ident $obj.functionObject.outputs[0].kind
|
||||||
var encodedParams = newLit("")
|
var
|
||||||
|
encodedParams = genSym(nskVar)#newLit("")
|
||||||
|
offset = genSym(nskVar)
|
||||||
|
dataBuf = genSym(nskVar)
|
||||||
|
encodings = genSym(nskVar)
|
||||||
|
encoder = newStmtList()
|
||||||
|
encoder.add quote do:
|
||||||
|
var
|
||||||
|
`offset` = 0
|
||||||
|
`encodedParams` = ""
|
||||||
|
`dataBuf` = ""
|
||||||
|
`encodings`: seq[EncodeResult]
|
||||||
for input in obj.functionObject.inputs:
|
for input in obj.functionObject.inputs:
|
||||||
encodedParams = nnkInfix.newTree(
|
let inputName = ident input.name
|
||||||
ident "&",
|
encoder.add quote do:
|
||||||
encodedParams,
|
let encoding = encode(`inputName`)
|
||||||
nnkCall.newTree(ident "encode", ident input.name)
|
`offset` += (if encoding.dynamic:
|
||||||
)
|
32
|
||||||
|
else:
|
||||||
|
encoding.data.len)
|
||||||
|
`encodings`.add encoding
|
||||||
|
#encodedParams = nnkInfix.newTree(
|
||||||
|
# ident "&",
|
||||||
|
# encodedParams,
|
||||||
|
# nnkCall.newTree(ident "encode", ident input.name)
|
||||||
|
#)
|
||||||
|
encoder.add quote do:
|
||||||
|
for encoding in `encodings`:
|
||||||
|
if encoding.dynamic:
|
||||||
|
`encodedParams` &= `offset`.toHex(64).toLower
|
||||||
|
`offset` += encoding.data.len
|
||||||
|
`dataBuf` &= encoding.data
|
||||||
|
else:
|
||||||
|
`encodedParams` &= encoding.data
|
||||||
|
`encodedParams` &= `dataBuf`
|
||||||
var procDef = quote do:
|
var procDef = quote do:
|
||||||
proc `procName`(`senderName`: Sender[`cname`]): Future[`output`] {.async.} =
|
proc `procName`(`senderName`: Sender[`cname`]): Future[`output`] {.async.} =
|
||||||
`senderName`.contract.`client`.httpMethod(MethodPost)
|
`senderName`.contract.`client`.httpMethod(MethodPost)
|
||||||
|
@ -434,7 +489,9 @@ macro contract(cname: untyped, body: untyped): untyped =
|
||||||
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`
|
||||||
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
|
||||||
let response = await `senderName`.contract.`client`.eth_call(cc, "latest")
|
let response = await `senderName`.contract.`client`.eth_call(cc, "latest")
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
|
@ -443,7 +500,9 @@ macro contract(cname: untyped, body: untyped): untyped =
|
||||||
cc.source = `senderName`.address
|
cc.source = `senderName`.address
|
||||||
#cc.to = some(`senderName`.contract.Contract.address)
|
#cc.to = some(`senderName`.contract.Contract.address)
|
||||||
cc.to = some(`senderName`.contract.address)
|
cc.to = some(`senderName`.contract.address)
|
||||||
|
`encoder`
|
||||||
cc.data = "0x" & ($keccak_256.digest(`signature`))[0..<8].toLower & `encodedParams`
|
cc.data = "0x" & ($keccak_256.digest(`signature`))[0..<8].toLower & `encodedParams`
|
||||||
|
echo cc.data
|
||||||
let response = await `senderName`.contract.`client`.eth_sendTransaction(cc)
|
let response = await `senderName`.contract.`client`.eth_sendTransaction(cc)
|
||||||
return response
|
return response
|
||||||
result.add procDef
|
result.add procDef
|
||||||
|
@ -470,7 +529,7 @@ macro contract(cname: untyped, body: untyped): untyped =
|
||||||
`receipt`.topics[`i`]
|
`receipt`.topics[`i`]
|
||||||
else:
|
else:
|
||||||
quote do:
|
quote do:
|
||||||
`receipt`.data[(`ii` - `i` + 1)*256..(`ii` - `i` + 2)*256]
|
`receipt`.data[(`ii` - `i` + 1)*64+2..<(`ii` - `i` + 2)*64+2]
|
||||||
if input.indexed:
|
if input.indexed:
|
||||||
i += 1
|
i += 1
|
||||||
arguments.add argument
|
arguments.add argument
|
||||||
|
@ -600,8 +659,16 @@ 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 Transfers(fromAddr: indexed[Address], toAddr: indexed[Address], value: Uint256[]) {.event.}
|
#proc Transfers(fromAddr: indexed[Address], toAddr: indexed[Address], value: Uint256[]) {.event.}
|
||||||
proc sendCoins(receiver: Address, amount: Uint[10]): Bool
|
#proc sendCoins(receiver: Address, amount: Uint[]): Bool
|
||||||
|
|
||||||
|
#var
|
||||||
|
# x2 = TestContract(address:
|
||||||
|
# "254dffcd3277C0b1660F6d42EFbB754edaBAbC2B".toAddress,
|
||||||
|
# client: newRpcHttpClient()
|
||||||
|
# )
|
||||||
|
# sender2 = x2.initSender("127.0.0.1", 8545,
|
||||||
|
# "90f8bf6a479f320ead074411a4b0e7944ea8c9c1".toAddress)
|
||||||
|
|
||||||
var
|
var
|
||||||
x = TestContract(address:
|
x = TestContract(address:
|
||||||
|
|
Loading…
Reference in New Issue