v0.2.0: Revamp data types
This commit is contained in:
parent
428b931e7c
commit
dcabb8f29e
|
@ -1,4 +1,5 @@
|
|||
nimcache/
|
||||
vendor/
|
||||
|
||||
# Executables shall be put in an ignored build/ directory
|
||||
# Ignore dynamic, static libs and libtool archive files
|
||||
|
@ -9,6 +10,7 @@ build/
|
|||
*.la
|
||||
*.exe
|
||||
*.dll
|
||||
nimble.paths
|
||||
|
||||
node_modules
|
||||
nohup.out
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
|
||||
[![License: Apache](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
|
||||
![Stability: experimental](https://img.shields.io/badge/stability-experimental-orange.svg)
|
||||
![Github action](https://github.com/status-im/nim-web3/workflows/nim-web3%20CI/badge.svg)
|
||||
![Github action](https://github.com/status-im/nim-web3/workflows/CI/badge.svg)
|
||||
|
||||
The humble beginnings of a Nim library similar to web3.[js|py]
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ touch hardhat.config.js
|
|||
nohup npx hardhat node &
|
||||
nimble install -y --depsOnly
|
||||
|
||||
# Wait until ganache responds
|
||||
# Wait until hardhat responds
|
||||
while ! curl -X POST --data '{"jsonrpc":"2.0","method":"net_version","params":[],"id":67}' localhost:8545 2>/dev/null
|
||||
do
|
||||
sleep 1
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# begin Nimble config (version 1)
|
||||
when fileExists("nimble.paths"):
|
||||
include "nimble.paths"
|
||||
# end Nimble config
|
9
nim.cfg
9
nim.cfg
|
@ -1,3 +1,12 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2019-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
# nim.cfg
|
||||
@if nimHasWarningObservableStores:
|
||||
warning[ObservableStores]: off
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
# web3
|
||||
# Copyright (c) 2018-2022 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license: [LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT
|
||||
# * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
# nim-web3
|
||||
# Copyright (c) 2018-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
{. warning[UnusedImport]:off .}
|
||||
|
||||
import
|
||||
test,
|
||||
test_primitives,
|
||||
test_contracts,
|
||||
test_deposit_contract,
|
||||
test_ethhexstrings,
|
||||
test_logs,
|
||||
test_json_marshalling,
|
||||
test_signed_tx
|
||||
test_signed_tx,
|
||||
test_execution_types
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import
|
||||
std/options,
|
||||
chronos, stint,
|
||||
stew/byteutils,
|
||||
../../web3,
|
||||
../../web3/primitives
|
||||
|
||||
proc deployContract*(web3: Web3, code: string, gasPrice = 0): Future[ReceiptObject] {.async.} =
|
||||
let provider = web3.provider
|
||||
let accounts = await provider.eth_accounts()
|
||||
|
||||
var code = code
|
||||
var tr: EthSend
|
||||
tr.`from` = web3.defaultAccount
|
||||
tr.data = hexToSeqByte(code)
|
||||
tr.gas = Quantity(3000000).some
|
||||
if gasPrice != 0:
|
||||
tr.gasPrice = some(gasPrice.Quantity)
|
||||
|
||||
let r = await web3.send(tr)
|
||||
return await web3.getMinedTransactionReceipt(r)
|
||||
|
||||
func ethToWei*(eth: UInt256): UInt256 =
|
||||
eth * 1000000000000000000.u256
|
||||
|
||||
type
|
||||
BlobData* = DynamicBytes[0, 512]
|
||||
|
||||
func conv*(T: type, x: int): T =
|
||||
type BaseType = distinctBase T
|
||||
var res: BaseType
|
||||
when BaseType is seq:
|
||||
res.setLen(1)
|
||||
res[^1] = x.byte
|
||||
T(res)
|
||||
|
||||
func address*(x: int): Address =
|
||||
conv(typeof result, x)
|
||||
|
||||
func txhash*(x: int): TxHash =
|
||||
conv(typeof result, x)
|
||||
|
||||
func blob*(x: int): BlobData =
|
||||
conv(typeof result, x)
|
||||
|
||||
func h256*(x: int): Hash256 =
|
||||
conv(typeof result, x)
|
|
@ -1,3 +1,12 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
# Avoid some rare stack corruption while using exceptions with a SEH-enabled
|
||||
# toolchain: https://github.com/status-im/nimbus-eth2/issues/3121
|
||||
@if windows and not vcc:
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
import pkg/unittest2
|
||||
import ../web3
|
||||
import chronos, options, json, stint
|
||||
import test_utils
|
||||
# nim-web3
|
||||
# Copyright (c) 2018-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
std/[options, json],
|
||||
pkg/unittest2,
|
||||
chronos, stint,
|
||||
../web3,
|
||||
./helpers/utils
|
||||
|
||||
contract(EncodingTest):
|
||||
proc setBool(val: Bool)
|
||||
|
@ -80,6 +90,12 @@ contract(MetaCoin):
|
|||
|
||||
const MetaCoinCode = "608060405234801561001057600080fd5b5032600090815260208190526040902061271090556101c2806100346000396000f30060806040526004361061004b5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166390b98a118114610050578063f8b2cb4f14610095575b600080fd5b34801561005c57600080fd5b5061008173ffffffffffffffffffffffffffffffffffffffff600435166024356100d5565b604080519115158252519081900360200190f35b3480156100a157600080fd5b506100c373ffffffffffffffffffffffffffffffffffffffff6004351661016e565b60408051918252519081900360200190f35b336000908152602081905260408120548211156100f457506000610168565b336000818152602081815260408083208054879003905573ffffffffffffffffffffffffffffffffffffffff871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a35060015b92915050565b73ffffffffffffffffffffffffffffffffffffffff16600090815260208190526040902054905600a165627a7a72305820000313ec0ebbff4ffefbe79d615d0ab019d8566100c40eb95a4eee617a87d1090029"
|
||||
|
||||
proc `$`(list: seq[Address]): string =
|
||||
result.add '['
|
||||
for x in list:
|
||||
result.add $x
|
||||
result.add ", "
|
||||
result.add ']'
|
||||
|
||||
suite "Contracts":
|
||||
setup:
|
|
@ -1,8 +1,19 @@
|
|||
import pkg/unittest2
|
||||
import ../web3
|
||||
import chronos, options, json, stint
|
||||
import test_utils
|
||||
import ./depositcontract
|
||||
# nim-web3
|
||||
# Copyright (c) 2018-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
std/[options, json],
|
||||
pkg/unittest2,
|
||||
chronos, stint,
|
||||
../web3,
|
||||
./helpers/utils,
|
||||
./helpers/depositcontract
|
||||
|
||||
contract(DepositContract):
|
||||
proc deposit(pubkey: DynamicBytes[0, 48], withdrawalCredentials: DynamicBytes[0, 32], signature: DynamicBytes[0, 96], deposit_data_root: FixedBytes[32])
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2018-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
unittest, json,
|
||||
unittest2, json,
|
||||
../web3/ethhexstrings
|
||||
|
||||
suite "Hex quantity":
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2018-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
std/typetraits,
|
||||
pkg/unittest2,
|
||||
stew/byteutils,
|
||||
../web3/execution_types,
|
||||
./helpers/utils
|
||||
|
||||
suite "Execution types tests":
|
||||
let
|
||||
wd = WithdrawalV1(
|
||||
index: 1.Quantity,
|
||||
validatorIndex: 2.Quantity,
|
||||
address: address(3),
|
||||
amount: 4.Quantity,
|
||||
)
|
||||
|
||||
payload = ExecutionPayload(
|
||||
parentHash: h256(1),
|
||||
feeRecipient: address(2),
|
||||
stateRoot: h256(3),
|
||||
receiptsRoot: h256(4),
|
||||
logsBloom: FixedBytes[256].conv(5),
|
||||
prevRandao: h256(6),
|
||||
blockNumber: 7.Quantity,
|
||||
gasLimit: 8.Quantity,
|
||||
gasUsed: 9.Quantity,
|
||||
timestamp: 10.Quantity,
|
||||
extraData: DynamicBytes[0, 32].conv(11),
|
||||
baseFeePerGas: 12.u256,
|
||||
blockHash: h256(13),
|
||||
transactions: @[TypedTransaction.conv(14)],
|
||||
withdrawals: some(@[wd]),
|
||||
blobGasUsed: some(15.Quantity),
|
||||
excessBlobGas: some(16.Quantity),
|
||||
)
|
||||
|
||||
attr = PayloadAttributes(
|
||||
timestamp: 1.Quantity,
|
||||
prevRandao: h256(2),
|
||||
suggestedFeeRecipient: address(3),
|
||||
withdrawals: some(@[wd]),
|
||||
parentBeaconBlockRoot: some(h256(4)),
|
||||
)
|
||||
|
||||
blobs = BlobsBundleV1(
|
||||
commitments: @[KZGCommitment.conv(1)],
|
||||
proofs: @[KZGProof.conv(2)],
|
||||
blobs: @[Blob.conv(3)],
|
||||
)
|
||||
|
||||
response = GetPayloadResponse(
|
||||
executionPayload: payload,
|
||||
blockValue: some(1.u256),
|
||||
blobsBundle: some(blobs),
|
||||
shouldOverrideBuilder: some(false),
|
||||
)
|
||||
|
||||
test "payload version":
|
||||
var badv31 = payload
|
||||
badv31.excessBlobGas = none(Quantity)
|
||||
var badv32 = payload
|
||||
badv32.blobGasUsed = none(Quantity)
|
||||
var v2 = payload
|
||||
v2.excessBlobGas = none(Quantity)
|
||||
v2.blobGasUsed = none(Quantity)
|
||||
var v1 = v2
|
||||
v1.withdrawals = none(seq[WithdrawalV1])
|
||||
check badv31.version == Version.V2
|
||||
check badv32.version == Version.V2
|
||||
check v2.version == Version.V2
|
||||
check v1.version == Version.V1
|
||||
check payload.version == Version.V3
|
||||
|
||||
test "attr version":
|
||||
var v2 = attr
|
||||
v2.parentBeaconBlockRoot = none(Hash256)
|
||||
var v1 = v2
|
||||
v1.withdrawals = none(seq[WithdrawalV1])
|
||||
check attr.version == Version.V3
|
||||
check v2.version == Version.V2
|
||||
check v1.version == Version.V1
|
||||
|
||||
test "response version":
|
||||
var badv31 = response
|
||||
badv31.blobsBundle = none(BlobsBundleV1)
|
||||
var badv32 = response
|
||||
badv32.shouldOverrideBuilder = none(bool)
|
||||
var v2 = response
|
||||
v2.blobsBundle = none(BlobsBundleV1)
|
||||
v2.shouldOverrideBuilder = none(bool)
|
||||
var v1 = v2
|
||||
v1.blockValue = none(UInt256)
|
||||
check badv31.version == Version.V2
|
||||
check badv32.version == Version.V2
|
||||
check v2.version == Version.V2
|
||||
check v1.version == Version.V1
|
||||
check response.version == Version.V3
|
||||
|
||||
test "ExecutionPayload roundtrip":
|
||||
let v3 = payload.V3
|
||||
check v3 == v3.executionPayload.V3
|
||||
|
||||
let v2 = payload.V2
|
||||
check v2 == v2.executionPayload.V2
|
||||
|
||||
let v1 = payload.V1
|
||||
check v1 == v1.executionPayload.V1
|
||||
|
||||
test "PayloadAttributes roundtrip":
|
||||
let v3 = attr.V3
|
||||
check v3 == v3.payloadAttributes.V3
|
||||
|
||||
let v2 = attr.V2
|
||||
check v2 == v2.payloadAttributes.V2
|
||||
|
||||
let v1 = attr.V1
|
||||
check v1 == v1.payloadAttributes.V1
|
||||
|
||||
test "GetPayloadResponse roundtrip":
|
||||
let v3 = response.V3
|
||||
check v3 == v3.getPayloadResponse.V3
|
||||
|
||||
let v2 = response.V2
|
||||
check v2 == v2.getPayloadResponse.V2
|
||||
|
||||
let v1 = response.V1
|
||||
check v1 == v1.getPayloadResponse.V1
|
||||
|
|
@ -1,8 +1,18 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2018-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
std/typetraits,
|
||||
unittest, std/json, json_rpc/jsonmarshal, json_serialization,
|
||||
std/[typetraits, json],
|
||||
stint,
|
||||
../web3/[conversions, ethtypes]
|
||||
unittest2,
|
||||
json_rpc/jsonmarshal, json_serialization,
|
||||
../web3/[conversions, eth_api_types]
|
||||
|
||||
proc `==`(x, y: Quantity): bool {.borrow, noSideEffect.}
|
||||
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
import pkg/unittest2
|
||||
import ../web3
|
||||
import chronos, options, json, stint
|
||||
import test_utils
|
||||
# nim-web3
|
||||
# Copyright (c) 2018-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import random
|
||||
import
|
||||
std/[options, json, random],
|
||||
pkg/unittest2,
|
||||
../web3,
|
||||
chronos, stint,
|
||||
./helpers/utils
|
||||
|
||||
#[ Contract LoggerContract
|
||||
pragma solidity >=0.4.25 <0.6.0;
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2018-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
std/typetraits,
|
||||
pkg/unittest2,
|
||||
stew/byteutils,
|
||||
../web3/primitives,
|
||||
./helpers/utils
|
||||
|
||||
suite "Primitives":
|
||||
const
|
||||
addr1 = address(1)
|
||||
txhash1 = txhash(1)
|
||||
blob1 = blob(1)
|
||||
|
||||
addr2 = address(2)
|
||||
txhash2 = txhash(2)
|
||||
blob2 = blob(2)
|
||||
|
||||
test "Comparators":
|
||||
check addr1 == addr1
|
||||
check addr1 != addr2
|
||||
|
||||
check txhash1 == txhash1
|
||||
check txhash1 != txhash2
|
||||
|
||||
check blob1 == blob1
|
||||
check blob1 != blob2
|
||||
|
||||
test "toHex":
|
||||
check addr1.toHex == "0000000000000000000000000000000000000001"
|
||||
check addr2.toHex == "0000000000000000000000000000000000000002"
|
||||
|
||||
check txhash1.toHex == "0000000000000000000000000000000000000000000000000000000000000001"
|
||||
check txhash2.toHex == "0000000000000000000000000000000000000000000000000000000000000002"
|
||||
|
||||
check blob1.toHex == "01"
|
||||
check blob2.toHex == "02"
|
||||
|
||||
test "fromHex":
|
||||
let
|
||||
addr3 = Address.fromHex("0000000000000000000000000000000000000123")
|
||||
txhash3 = TxHash.fromHex("0000000000000000000000000000000000000000000000000000000000000456")
|
||||
blob3 = BlobData.fromHex("7890")
|
||||
|
||||
check addr3.toHex == "0000000000000000000000000000000000000123"
|
||||
check txhash3.toHex == "0000000000000000000000000000000000000000000000000000000000000456"
|
||||
check blob3.toHex == "7890"
|
||||
|
||||
test "to bytes":
|
||||
let
|
||||
ab2 = addr2.bytes
|
||||
tb2 = txhash2.bytes
|
||||
bb2 = blob2.bytes
|
||||
|
||||
check ab2.toHex == "0000000000000000000000000000000000000002"
|
||||
check tb2.toHex == "0000000000000000000000000000000000000000000000000000000000000002"
|
||||
check bb2.toHex == "02"
|
||||
|
||||
test "len":
|
||||
check addr1.len == 20
|
||||
check txhash1.len == 32
|
||||
check blob1.len == 1
|
||||
|
||||
test "dollar":
|
||||
check $addr1 == "0x0000000000000000000000000000000000000001"
|
||||
check $txhash1 == "0x0000000000000000000000000000000000000000000000000000000000000001"
|
||||
check $blob1 == "0x01"
|
|
@ -1,7 +1,18 @@
|
|||
import pkg/unittest2
|
||||
import ../web3
|
||||
import chronos, options, json, stint, eth/keys
|
||||
import test_utils
|
||||
# nim-web3
|
||||
# Copyright (c) 2018-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
std/[options, json],
|
||||
pkg/unittest2,
|
||||
chronos, stint, eth/keys,
|
||||
../web3,
|
||||
./helpers/utils
|
||||
|
||||
#[ Contract NumberStorage
|
||||
pragma solidity ^0.4.18;
|
||||
|
@ -39,10 +50,10 @@ suite "Signed transactions":
|
|||
let acc = Address(toCanonicalAddress(pk.toPublicKey()))
|
||||
|
||||
var tx: EthSend
|
||||
tx.source = accounts[0]
|
||||
tx.`from` = accounts[0]
|
||||
tx.value = some(ethToWei(10.u256))
|
||||
tx.to = some(acc)
|
||||
tx.gasPrice = some(gasPrice)
|
||||
tx.gasPrice = some(gasPrice.Quantity)
|
||||
|
||||
# Send 10 eth to acc
|
||||
discard await web3.send(tx)
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import ../web3, chronos, options, stint
|
||||
|
||||
proc deployContract*(web3: Web3, code: string, gasPrice = 0): Future[ReceiptObject] {.async.} =
|
||||
let provider = web3.provider
|
||||
let accounts = await provider.eth_accounts()
|
||||
|
||||
var code = code
|
||||
if code[1] notin {'x', 'X'}:
|
||||
code = "0x" & code
|
||||
var tr: EthSend
|
||||
tr.source = web3.defaultAccount
|
||||
tr.data = code
|
||||
tr.gas = Quantity(3000000).some
|
||||
if gasPrice != 0:
|
||||
tr.gasPrice = some(gasPrice)
|
||||
|
||||
let r = await web3.send(tr)
|
||||
return await web3.getMinedTransactionReceipt(r)
|
||||
|
||||
func ethToWei*(eth: UInt256): UInt256 =
|
||||
eth * 1000000000000000000.u256
|
63
web3.nim
63
web3.nim
|
@ -1,5 +1,14 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2019-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
std/[macros, strutils, options, math, json, tables, uri, strformat]
|
||||
std/[macros, strutils, options, json, tables, uri, strformat]
|
||||
|
||||
from os import DirSep, AltSep
|
||||
|
||||
|
@ -7,15 +16,15 @@ import
|
|||
stint, httputils, chronicles, chronos, nimcrypto/keccak,
|
||||
json_rpc/[rpcclient, jsonmarshal], stew/byteutils, eth/keys,
|
||||
chronos/apps/http/httpclient,
|
||||
web3/[ethtypes, conversions, ethhexstrings, transaction_signing, encoding]
|
||||
web3/[eth_api_types, conversions, ethhexstrings, transaction_signing, encoding]
|
||||
|
||||
template sourceDir: string = currentSourcePath.rsplit({DirSep, AltSep}, 1)[0]
|
||||
|
||||
## Generate client convenience marshalling wrappers from forward declarations
|
||||
createRpcSigs(RpcClient, sourceDir & "/web3/ethcallsigs.nim")
|
||||
createRpcSigs(RpcClient, sourceDir & "/web3/eth_api_callsigs.nim")
|
||||
|
||||
export UInt256, Int256, Uint128, Int128
|
||||
export ethtypes, conversions, encoding, HttpClientFlag, HttpClientFlags
|
||||
export eth_api_types, conversions, encoding, HttpClientFlag, HttpClientFlags
|
||||
|
||||
type
|
||||
Web3* = ref object
|
||||
|
@ -23,7 +32,7 @@ type
|
|||
subscriptions*: Table[string, Subscription]
|
||||
defaultAccount*: Address
|
||||
privateKey*: Option[PrivateKey]
|
||||
lastKnownNonce*: Option[Nonce]
|
||||
lastKnownNonce*: Option[Quantity]
|
||||
onDisconnect*: proc() {.gcsafe, raises: [].}
|
||||
|
||||
Sender*[T] = ref object
|
||||
|
@ -48,7 +57,7 @@ type
|
|||
|
||||
ContractCallBase = ref object of RootObj
|
||||
web3: Web3
|
||||
data: string
|
||||
data: seq[byte]
|
||||
to: Address
|
||||
value: UInt256
|
||||
|
||||
|
@ -194,7 +203,10 @@ template typeSignature(T: typedesc): string =
|
|||
unknownType(T)
|
||||
|
||||
proc initContractCall[T](web3: Web3, data: string, to: Address): ContractCall[T] {.inline.} =
|
||||
ContractCall[T](web3: web3, data: data, to: to)
|
||||
try:
|
||||
ContractCall[T](web3: web3, data: hexToSeqByte(data), to: to)
|
||||
except ValueError as ex:
|
||||
raise newException(AssertionDefect, ex.msg)
|
||||
|
||||
type
|
||||
InterfaceObjectKind = enum
|
||||
|
@ -545,7 +557,7 @@ proc getJsonLogs*(s: Sender,
|
|||
options["topics"] = topics
|
||||
if blockHash.isSome:
|
||||
doAssert fromBlock.isNone and toBlock.isNone
|
||||
options["blockhash"] = %blockHash.unsafeGet
|
||||
options["blockHash"] = %blockHash.unsafeGet
|
||||
else:
|
||||
if fromBlock.isSome:
|
||||
options["fromBlock"] = %fromBlock.unsafeGet
|
||||
|
@ -554,13 +566,13 @@ proc getJsonLogs*(s: Sender,
|
|||
|
||||
s.web3.provider.eth_getLogs(options)
|
||||
|
||||
proc nextNonce*(web3: Web3): Future[Nonce] {.async.} =
|
||||
proc nextNonce*(web3: Web3): Future[Quantity] {.async.} =
|
||||
if web3.lastKnownNonce.isSome:
|
||||
inc web3.lastKnownNonce.get
|
||||
return web3.lastKnownNonce.get
|
||||
else:
|
||||
let fromAddress = web3.privateKey.get().toPublicKey().toCanonicalAddress.Address
|
||||
result = int(await web3.provider.eth_getTransactionCount(fromAddress, "latest"))
|
||||
result = await web3.provider.eth_getTransactionCount(fromAddress, "latest")
|
||||
web3.lastKnownNonce = some result
|
||||
|
||||
proc send*(web3: Web3, c: EthSend): Future[TxHash] {.async.} =
|
||||
|
@ -568,7 +580,7 @@ proc send*(web3: Web3, c: EthSend): Future[TxHash] {.async.} =
|
|||
var cc = c
|
||||
if cc.nonce.isNone:
|
||||
cc.nonce = some(await web3.nextNonce())
|
||||
let t = "0x" & encodeTransaction(cc, web3.privateKey.get())
|
||||
let t = encodeTransaction(cc, web3.privateKey.get())
|
||||
return await web3.provider.eth_sendRawTransaction(t)
|
||||
else:
|
||||
return await web3.provider.eth_sendTransaction(c)
|
||||
|
@ -579,19 +591,20 @@ proc send*(c: ContractCallBase,
|
|||
gasPrice = 0): Future[TxHash] {.async.} =
|
||||
let
|
||||
web3 = c.web3
|
||||
gasPrice = if web3.privateKey.isSome() or gasPrice != 0: some(gasPrice)
|
||||
else: none(int)
|
||||
gasPrice = if web3.privateKey.isSome() or gasPrice != 0: some(gasPrice.Quantity)
|
||||
else: none(Quantity)
|
||||
nonce = if web3.privateKey.isSome(): some(await web3.nextNonce())
|
||||
else: none(Nonce)
|
||||
else: none(Quantity)
|
||||
|
||||
cc = EthSend(
|
||||
data: "0x" & c.data,
|
||||
source: web3.defaultAccount,
|
||||
data: c.data,
|
||||
`from`: web3.defaultAccount,
|
||||
to: some(c.to),
|
||||
gas: some(Quantity(gas)),
|
||||
value: some(value),
|
||||
nonce: nonce,
|
||||
gasPrice: gasPrice)
|
||||
gasPrice: gasPrice,
|
||||
)
|
||||
|
||||
return await web3.send(cc)
|
||||
|
||||
|
@ -600,12 +613,12 @@ proc call*[T](c: ContractCall[T],
|
|||
gas = 3000000'u64,
|
||||
blockNumber = high(uint64)): Future[T] {.async.} =
|
||||
var cc: EthCall
|
||||
cc.data = some("0x" & c.data)
|
||||
cc.data = some(c.data)
|
||||
cc.source = some(c.web3.defaultAccount)
|
||||
cc.to = c.to
|
||||
cc.to = some(c.to)
|
||||
cc.gas = some(Quantity(gas))
|
||||
cc.value = some(value)
|
||||
let response = strip0xPrefix:
|
||||
let response =
|
||||
if blockNumber != high(uint64):
|
||||
await c.web3.provider.eth_call(cc, &"0x{blockNumber:X}")
|
||||
else:
|
||||
|
@ -613,7 +626,7 @@ proc call*[T](c: ContractCall[T],
|
|||
|
||||
if response.len > 0:
|
||||
var res: T
|
||||
discard decode(response, 0, res)
|
||||
discard decode(response.toHex, 0, res)
|
||||
return res
|
||||
else:
|
||||
raise newException(CatchableError, "No response from the Web3 provider")
|
||||
|
@ -622,12 +635,12 @@ proc getMinedTransactionReceipt*(web3: Web3, tx: TxHash): Future[ReceiptObject]
|
|||
## Returns the receipt for the transaction. Waits for it to be mined if necessary.
|
||||
# TODO: Potentially more optimal solution is to subscribe and wait for appropriate
|
||||
# notification. Now we're just polling every 500ms which should be ok for most cases.
|
||||
var r: Option[ReceiptObject]
|
||||
while r.isNone:
|
||||
var r: ReceiptObject
|
||||
while r.isNil:
|
||||
r = await web3.provider.eth_getTransactionReceipt(tx)
|
||||
if r.isNone:
|
||||
if r.isNil:
|
||||
await sleepAsync(500.milliseconds)
|
||||
result = r.get
|
||||
result = r
|
||||
|
||||
proc exec*[T](c: ContractCall[T], value = 0.u256, gas = 3000000'u64): Future[T] {.async.} =
|
||||
let h = await c.send(value, gas)
|
||||
|
|
11
web3.nimble
11
web3.nimble
|
@ -1,6 +1,15 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2019-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
mode = ScriptMode.Verbose
|
||||
|
||||
version = "0.0.1"
|
||||
version = "0.2.0"
|
||||
author = "Status Research & Development GmbH"
|
||||
description = "This is the humble begginings of library similar to web3.[js|py]"
|
||||
license = "MIT or Apache License 2.0"
|
||||
|
|
|
@ -1,18 +1,27 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
ethtypes
|
||||
./primitives
|
||||
|
||||
func parseCmdArg*(T: type Address, input: TaintedString): T
|
||||
func parseCmdArg*(T: type Address, input: string): T
|
||||
{.raises: [ValueError].} =
|
||||
fromHex(T, string input)
|
||||
|
||||
func completeCmdArg*(T: type Address, input: TaintedString): seq[string] =
|
||||
func completeCmdArg*(T: type Address, input: string): seq[string] =
|
||||
@[]
|
||||
|
||||
func parseCmdArg*(T: type BlockHash, input: TaintedString): T
|
||||
func parseCmdArg*(T: type BlockHash, input: string): T
|
||||
{.raises: [ValueError].} =
|
||||
fromHex(T, string input)
|
||||
|
||||
func completeCmdArg*(T: type BlockHash, input: TaintedString): seq[string] =
|
||||
func completeCmdArg*(T: type BlockHash, input: string): seq[string] =
|
||||
@[]
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
# Copyright (c) 2019-2022 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
# nim-web3
|
||||
# Copyright (c) 2019-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
std/[json, options, strutils, strformat, tables, typetraits],
|
||||
stint, stew/byteutils, json_serialization, faststreams/textio,
|
||||
ethtypes, ethhexstrings,
|
||||
./eth_api_types, ./ethhexstrings,
|
||||
./engine_api_types
|
||||
|
||||
from json_rpc/jsonmarshal import expect
|
||||
from json_rpc/jsonmarshal import expect, fromJson
|
||||
|
||||
template invalidQuantityPrefix(s: string): bool =
|
||||
# https://ethereum.org/en/developers/docs/apis/json-rpc/#hex-value-encoding
|
||||
|
@ -129,6 +132,37 @@ func fromJson*(
|
|||
raise newException(
|
||||
ValueError, "Parameter \"" & argName & "\" value invalid: " & n.getStr)
|
||||
|
||||
func fromJson*(n: JsonNode, argName: string, result: var RtBlockIdentifier) =
|
||||
n.kind.expect(JString, argName)
|
||||
let hexStr = n.getStr()
|
||||
if validate(hexStr.HexQuantityStr):
|
||||
result = RtBlockIdentifier(kind: bidNumber, number: fromHex[uint64](hexStr))
|
||||
else:
|
||||
result = RtBlockIdentifier(kind: bidAlias, alias: hexStr)
|
||||
|
||||
func fromJson*(n: JsonNode, argName: string, result: var TxOrHash) =
|
||||
if n.kind == JString:
|
||||
var hash: TxHash
|
||||
fromJson(n, argName, hash)
|
||||
result = TxOrHash(kind: tohHash, hash: hash)
|
||||
else:
|
||||
var tx: TransactionObject
|
||||
fromJson(n, argName, tx)
|
||||
result = TxOrHash(kind: tohTx, tx: tx)
|
||||
|
||||
func fromJson*(n: JsonNode, argName: string, result: var EthSend) =
|
||||
n.kind.expect(JObject, argName)
|
||||
for k, v in n:
|
||||
case k
|
||||
of "from": fromJson(v, argName, result.`from`)
|
||||
of "to": fromJson(v, argName, result.to)
|
||||
of "gas": fromJson(v, argName, result.gas)
|
||||
of "gasPrice": fromJson(v, argName, result.gasPrice)
|
||||
of "value": fromJson(v, argName, result.value)
|
||||
of "data": fromJson(v, argName, result.data)
|
||||
of "nonce": fromJson(v, argName, result.nonce)
|
||||
else: discard
|
||||
|
||||
func `%`*(v: Quantity): JsonNode =
|
||||
%encodeQuantity(v.uint64)
|
||||
|
||||
|
@ -147,6 +181,9 @@ func `%`*(v: TypedTransaction): JsonNode =
|
|||
func `%`*(v: RlpEncodedBytes): JsonNode =
|
||||
%("0x" & distinctBase(v).toHex)
|
||||
|
||||
func `%`*(v: openArray[byte]): JsonNode =
|
||||
%("0x" & v.toHex)
|
||||
|
||||
proc writeHexValue(w: JsonWriter, v: openArray[byte]) =
|
||||
w.stream.write "\"0x"
|
||||
w.stream.writeHex v
|
||||
|
@ -197,30 +234,21 @@ proc readValue*(r: var JsonReader, T: type Quantity): T =
|
|||
func `$`*(v: Quantity): string {.inline.} =
|
||||
encodeQuantity(v.uint64)
|
||||
|
||||
func `$`*[N](v: FixedBytes[N]): string {.inline.} =
|
||||
"0x" & array[N, byte](v).toHex
|
||||
|
||||
func `$`*(v: Address): string {.inline.} =
|
||||
"0x" & array[20, byte](v).toHex
|
||||
|
||||
func `$`*(v: TypedTransaction): string {.inline.} =
|
||||
"0x" & distinctBase(v).toHex
|
||||
|
||||
func `$`*(v: RlpEncodedBytes): string {.inline.} =
|
||||
"0x" & distinctBase(v).toHex
|
||||
|
||||
func `$`*(v: DynamicBytes): string {.inline.} =
|
||||
"0x" & toHex(v)
|
||||
|
||||
func `%`*(x: EthSend): JsonNode =
|
||||
result = newJObject()
|
||||
result["from"] = %x.source
|
||||
result["from"] = %x.`from`
|
||||
if x.to.isSome:
|
||||
result["to"] = %x.to.unsafeGet
|
||||
if x.gas.isSome:
|
||||
result["gas"] = %x.gas.unsafeGet
|
||||
if x.gasPrice.isSome:
|
||||
result["gasPrice"] = %Quantity(x.gasPrice.unsafeGet)
|
||||
result["gasPrice"] = %x.gasPrice.unsafeGet
|
||||
if x.value.isSome:
|
||||
result["value"] = %x.value.unsafeGet
|
||||
if x.data.len > 0:
|
||||
|
@ -245,18 +273,23 @@ func `%`*(x: EthCall): JsonNode =
|
|||
func `%`*(x: byte): JsonNode =
|
||||
%x.int
|
||||
|
||||
func `%`*(x: RtBlockIdentifier): JsonNode =
|
||||
case x.kind
|
||||
of bidNumber: %(&"0x{x.number:X}")
|
||||
of bidAlias: %x.alias
|
||||
|
||||
func `%`*(x: FilterOptions): JsonNode =
|
||||
result = newJObject()
|
||||
if x.fromBlock.isSome:
|
||||
result["fromBlock"] = %x.fromBlock.unsafeGet
|
||||
if x.toBlock.isSome:
|
||||
result["toBlock"] = %x.toBlock.unsafeGet
|
||||
if x.address.isSome:
|
||||
result["address"] = %x.address.unsafeGet
|
||||
if x.topics.isSome:
|
||||
result["topics"] = %x.topics.unsafeGet
|
||||
result["address"] = %x.address
|
||||
if x.blockHash.isSome:
|
||||
result["blockHash"] = %x.blockHash.unsafeGet
|
||||
result["topics"] = %x.topics
|
||||
|
||||
func `%`*(x: RtBlockIdentifier): JsonNode =
|
||||
func `%`*(x: TxOrHash): JsonNode =
|
||||
case x.kind
|
||||
of bidNumber: %(&"0x{x.number:X}")
|
||||
of bidAlias: %x.alias
|
||||
of tohHash: %x.hash
|
||||
of tohTx: %x.tx
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
std/[typetraits, strutils, macros, math]
|
||||
|
||||
import
|
||||
stint, stew/byteutils, ./ethtypes
|
||||
stint, stew/byteutils, ./eth_api_types
|
||||
|
||||
type
|
||||
EncodeResult* = tuple[dynamic: bool, data: string]
|
||||
|
|
|
@ -1,11 +1,24 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2022-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
strutils,
|
||||
json_serialization/std/[sets, net], serialization/errors,
|
||||
json_rpc/[client, jsonmarshal],
|
||||
conversions, engine_api_types
|
||||
./conversions,
|
||||
./engine_api_types,
|
||||
./execution_types
|
||||
|
||||
export
|
||||
engine_api_types, conversions
|
||||
engine_api_types,
|
||||
conversions,
|
||||
execution_types
|
||||
|
||||
from os import DirSep, AltSep
|
||||
template sourceDir: string = currentSourcePath.rsplit({DirSep, AltSep}, 1)[0]
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2022-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.3/src/engine/paris.md#methods
|
||||
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.3/src/engine/shanghai.md#methods
|
||||
# https://github.com/ethereum/execution-apis/blob/ee3df5bc38f28ef35385cefc9d9ca18d5e502778/src/engine/cancun.md#methods
|
||||
|
||||
import ethtypes, engine_api_types
|
||||
import execution_types, engine_api_types
|
||||
|
||||
proc engine_newPayloadV1(payload: ExecutionPayloadV1): PayloadStatusV1
|
||||
proc engine_newPayloadV2(payload: ExecutionPayloadV2): PayloadStatusV1
|
||||
|
@ -20,3 +29,13 @@ proc engine_getPayloadBodiesByRangeV1(start: Quantity, count: Quantity): seq[Opt
|
|||
|
||||
# https://github.com/ethereum/execution-apis/blob/9301c0697e4c7566f0929147112f6d91f65180f6/src/engine/common.md
|
||||
proc engine_exchangeCapabilities(methods: seq[string]): seq[string]
|
||||
|
||||
# convenience apis
|
||||
proc engine_newPayloadV1(payload: ExecutionPayload): PayloadStatusV1
|
||||
proc engine_newPayloadV2(payload: ExecutionPayload): PayloadStatusV1
|
||||
proc engine_newPayloadV2(payload: ExecutionPayloadV1OrV2): PayloadStatusV1
|
||||
proc engine_newPayloadV3(payload: ExecutionPayload,
|
||||
expectedBlobVersionedHashes: Option[seq[VersionedHash]],
|
||||
parentBeaconBlockRoot: Option[FixedBytes[32]]): PayloadStatusV1
|
||||
proc engine_forkchoiceUpdatedV2(forkchoiceState: ForkchoiceStateV1, payloadAttributes: Option[PayloadAttributes]): ForkchoiceUpdatedResponse
|
||||
proc engine_forkchoiceUpdatedV3(forkchoiceState: ForkchoiceStateV1, payloadAttributes: Option[PayloadAttributes]): ForkchoiceUpdatedResponse
|
||||
|
|
|
@ -1,12 +1,134 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2022-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
std/options,
|
||||
std/[options, typetraits],
|
||||
stint,
|
||||
ethtypes
|
||||
primitives
|
||||
|
||||
export
|
||||
options, stint, ethtypes
|
||||
options, stint, primitives
|
||||
|
||||
const
|
||||
# https://github.com/ethereum/execution-apis/blob/c4089414bbbe975bbc4bf1ccf0a3d31f76feb3e1/src/engine/cancun.md#blobsbundlev1
|
||||
fieldElementsPerBlob = 4096
|
||||
|
||||
type
|
||||
TypedTransaction* = distinct seq[byte]
|
||||
|
||||
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.3/src/engine/shanghai.md#withdrawalv1
|
||||
WithdrawalV1* = object
|
||||
index*: Quantity
|
||||
validatorIndex*: Quantity
|
||||
address*: Address
|
||||
amount*: Quantity
|
||||
|
||||
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.3/src/engine/paris.md#executionpayloadv1
|
||||
ExecutionPayloadV1* = object
|
||||
parentHash*: Hash256
|
||||
feeRecipient*: Address
|
||||
stateRoot*: Hash256
|
||||
receiptsRoot*: Hash256
|
||||
logsBloom*: FixedBytes[256]
|
||||
prevRandao*: FixedBytes[32]
|
||||
blockNumber*: Quantity
|
||||
gasLimit*: Quantity
|
||||
gasUsed*: Quantity
|
||||
timestamp*: Quantity
|
||||
extraData*: DynamicBytes[0, 32]
|
||||
baseFeePerGas*: UInt256
|
||||
blockHash*: Hash256
|
||||
transactions*: seq[TypedTransaction]
|
||||
|
||||
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.3/src/engine/shanghai.md#executionpayloadv2
|
||||
ExecutionPayloadV2* = object
|
||||
parentHash*: Hash256
|
||||
feeRecipient*: Address
|
||||
stateRoot*: Hash256
|
||||
receiptsRoot*: Hash256
|
||||
logsBloom*: FixedBytes[256]
|
||||
prevRandao*: FixedBytes[32]
|
||||
blockNumber*: Quantity
|
||||
gasLimit*: Quantity
|
||||
gasUsed*: Quantity
|
||||
timestamp*: Quantity
|
||||
extraData*: DynamicBytes[0, 32]
|
||||
baseFeePerGas*: UInt256
|
||||
blockHash*: Hash256
|
||||
transactions*: seq[TypedTransaction]
|
||||
withdrawals*: seq[WithdrawalV1]
|
||||
|
||||
# This is ugly, but I don't think the RPC library will handle
|
||||
# ExecutionPayloadV1 | ExecutionPayloadV2. (Am I wrong?)
|
||||
# Note that the spec currently says that various V2 methods
|
||||
# (e.g. engine_newPayloadV2) need to accept *either* V1 or V2
|
||||
# of the data structure (e.g. either ExecutionPayloadV1 or
|
||||
# ExecutionPayloadV2); it's not like V2 of the method only
|
||||
# needs to accept V2 of the structure. Anyway, the best way
|
||||
# I've found to handle this is to make this structure with an
|
||||
# Option for the withdrawals field. If you've got a better idea,
|
||||
# please fix this. (Maybe the RPC library does handle sum types?
|
||||
# Or maybe we can enhance it to do so?) --Adam
|
||||
#
|
||||
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.3/src/engine/shanghai.md
|
||||
ExecutionPayloadV1OrV2* = object
|
||||
parentHash*: BlockHash
|
||||
feeRecipient*: Address
|
||||
stateRoot*: BlockHash
|
||||
receiptsRoot*: BlockHash
|
||||
logsBloom*: FixedBytes[256]
|
||||
prevRandao*: FixedBytes[32]
|
||||
blockNumber*: Quantity
|
||||
gasLimit*: Quantity
|
||||
gasUsed*: Quantity
|
||||
timestamp*: Quantity
|
||||
extraData*: DynamicBytes[0, 32]
|
||||
baseFeePerGas*: UInt256
|
||||
blockHash*: BlockHash
|
||||
transactions*: seq[TypedTransaction]
|
||||
withdrawals*: Option[seq[WithdrawalV1]]
|
||||
|
||||
# https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#executionpayloadv3
|
||||
ExecutionPayloadV3* = object
|
||||
parentHash*: Hash256
|
||||
feeRecipient*: Address
|
||||
stateRoot*: Hash256
|
||||
receiptsRoot*: Hash256
|
||||
logsBloom*: FixedBytes[256]
|
||||
prevRandao*: FixedBytes[32]
|
||||
blockNumber*: Quantity
|
||||
gasLimit*: Quantity
|
||||
gasUsed*: Quantity
|
||||
timestamp*: Quantity
|
||||
extraData*: DynamicBytes[0, 32]
|
||||
baseFeePerGas*: UInt256
|
||||
blockHash*: Hash256
|
||||
transactions*: seq[TypedTransaction]
|
||||
withdrawals*: seq[WithdrawalV1]
|
||||
blobGasUsed*: Quantity
|
||||
excessBlobGas*: Quantity
|
||||
|
||||
SomeExecutionPayload* =
|
||||
ExecutionPayloadV1 |
|
||||
ExecutionPayloadV2 |
|
||||
ExecutionPayloadV3
|
||||
|
||||
KZGCommitment* = FixedBytes[48]
|
||||
KZGProof* = FixedBytes[48]
|
||||
Blob* = FixedBytes[fieldElementsPerBlob * 32]
|
||||
|
||||
# https://github.com/ethereum/execution-apis/blob/ee3df5bc38f28ef35385cefc9d9ca18d5e502778/src/engine/cancun.md#blobsbundlev1
|
||||
BlobsBundleV1* = object
|
||||
commitments*: seq[KZGCommitment]
|
||||
proofs*: seq[KZGProof]
|
||||
blobs*: seq[Blob]
|
||||
|
||||
# https://github.com/ethereum/execution-apis/blob/d03c193dc317538e2a1a098030c21bacc2fd1333/src/engine/shanghai.md#executionpayloadbodyv1
|
||||
# For optional withdrawals field, see:
|
||||
# https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md#engine_getpayloadbodiesbyhashv1
|
||||
|
@ -43,6 +165,11 @@ type
|
|||
suggestedFeeRecipient*: Address
|
||||
withdrawals*: Option[seq[WithdrawalV1]]
|
||||
|
||||
SomePayloadAttributes* =
|
||||
PayloadAttributesV1 |
|
||||
PayloadAttributesV2 |
|
||||
PayloadAttributesV3
|
||||
|
||||
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.3/src/engine/paris.md#payloadstatusv1
|
||||
PayloadExecutionStatus* {.pure.} = enum
|
||||
syncing = "SYNCING"
|
||||
|
@ -109,3 +236,8 @@ const
|
|||
engineApiInvalidPayloadAttributes* = -38003
|
||||
engineApiTooLargeRequest* = -38004
|
||||
engineApiUnsupportedFork* = -38005
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
template `==`*(a, b: TypedTransaction): bool =
|
||||
distinctBase(a) == distinctBase(b)
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2019-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0)
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
# http://opensource.org/licenses/MIT)
|
||||
# at your option. This file may not be copied, modified, or distributed except
|
||||
# according to those terms.
|
||||
|
||||
import
|
||||
strutils,
|
||||
json_serialization/std/[sets, net],
|
||||
json_rpc/[client, jsonmarshal],
|
||||
stint,
|
||||
./conversions,
|
||||
./eth_api_types
|
||||
|
||||
export
|
||||
eth_api_types,
|
||||
conversions
|
||||
|
||||
from os import DirSep, AltSep
|
||||
template sourceDir: string = currentSourcePath.rsplit({DirSep, AltSep}, 1)[0]
|
||||
|
||||
createRpcSigs(RpcClient, sourceDir & "/eth_api_callsigs.nim")
|
|
@ -1,43 +1,53 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2019-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
## This module contains signatures for the Ethereum client RPCs.
|
||||
## The signatures are not imported directly, but read and processed with parseStmt,
|
||||
## then a procedure body is generated to marshal native Nim parameters to json and visa versa.
|
||||
import json, options, stint, ethtypes
|
||||
import json, options, stint, eth_api_types
|
||||
|
||||
proc web3_clientVersion(): string
|
||||
proc web3_sha3(data: string): string
|
||||
proc web3_sha3(data: seq[byte]): Hash256
|
||||
proc net_version(): string
|
||||
proc net_peerCount(): int
|
||||
proc net_peerCount(): Quantity
|
||||
proc net_listening(): bool
|
||||
proc eth_protocolVersion(): string
|
||||
proc eth_syncing(): JsonNode
|
||||
proc eth_coinbase(): string
|
||||
proc eth_coinbase(): Address
|
||||
proc eth_mining(): bool
|
||||
proc eth_hashrate(): int
|
||||
proc eth_hashrate(): Quantity
|
||||
proc eth_gasPrice(): Quantity
|
||||
proc eth_accounts(): seq[Address]
|
||||
proc eth_blockNumber(): Quantity
|
||||
proc eth_getBalance(data: Address, blockId: BlockIdentifier): UInt256
|
||||
proc eth_getStorageAt(data: Address, quantity: int, blockId: BlockIdentifier): seq[byte]
|
||||
proc eth_getStorageAt(data: Address, slot: UInt256, blockId: BlockIdentifier): UInt256
|
||||
proc eth_getTransactionCount(data: Address, blockId: BlockIdentifier): Quantity
|
||||
proc eth_getBlockTransactionCountByHash(data: BlockHash)
|
||||
proc eth_getBlockTransactionCountByNumber(blockId: BlockIdentifier)
|
||||
proc eth_getUncleCountByBlockHash(data: BlockHash)
|
||||
proc eth_getUncleCountByBlockNumber(blockId: BlockIdentifier)
|
||||
proc eth_getBlockTransactionCountByHash(data: BlockHash): Quantity
|
||||
proc eth_getBlockTransactionCountByNumber(blockId: BlockIdentifier): Quantity
|
||||
proc eth_getUncleCountByBlockHash(data: BlockHash): Quantity
|
||||
proc eth_getUncleCountByBlockNumber(blockId: BlockIdentifier): Quantity
|
||||
proc eth_getCode(data: Address, blockId: BlockIdentifier): seq[byte]
|
||||
proc eth_sign(address: Address, data: string): seq[byte]
|
||||
proc eth_sign(address: Address, data: seq[byte]): seq[byte]
|
||||
proc eth_signTransaction(data: EthSend): seq[byte]
|
||||
proc eth_sendTransaction(obj: EthSend): TxHash
|
||||
proc eth_sendRawTransaction(data: string): TxHash
|
||||
proc eth_call(call: EthCall, blockId: BlockIdentifier): string #UInt256
|
||||
proc eth_estimateGas(call: EthCall, blockId: BlockIdentifier): UInt256
|
||||
proc eth_sendRawTransaction(data: seq[byte]): TxHash
|
||||
proc eth_call(call: EthCall, blockId: BlockIdentifier): seq[byte]
|
||||
proc eth_estimateGas(call: EthCall, blockId: BlockIdentifier): Quantity
|
||||
proc eth_createAccessList(call: EthCall, blockId: BlockIdentifier): AccessListResult
|
||||
proc eth_getBlockByHash(data: BlockHash, fullTransactions: bool): BlockObject
|
||||
proc eth_getBlockByNumber(blockId: BlockIdentifier, fullTransactions: bool): BlockObject
|
||||
proc eth_getTransactionByHash(data: TxHash): TransactionObject
|
||||
proc eth_getTransactionByBlockHashAndIndex(data: UInt256, quantity: int): TransactionObject
|
||||
proc eth_getTransactionByBlockNumberAndIndex(blockId: BlockIdentifier, quantity: int): TransactionObject
|
||||
proc eth_getTransactionReceipt(data: TxHash): Option[ReceiptObject]
|
||||
proc eth_getUncleByBlockHashAndIndex(data: UInt256, quantity: int64): BlockObject
|
||||
proc eth_getUncleByBlockNumberAndIndex(blockId: BlockIdentifier, quantity: int64): BlockObject
|
||||
proc eth_getTransactionByBlockHashAndIndex(data: Hash256, quantity: Quantity): TransactionObject
|
||||
proc eth_getTransactionByBlockNumberAndIndex(blockId: BlockIdentifier, quantity: Quantity): TransactionObject
|
||||
proc eth_getTransactionReceipt(data: TxHash): ReceiptObject
|
||||
proc eth_getUncleByBlockHashAndIndex(data: Hash256, quantity: Quantity): BlockObject
|
||||
proc eth_getUncleByBlockNumberAndIndex(blockId: BlockIdentifier, quantity: Quantity): BlockObject
|
||||
proc eth_getCompilers(): seq[string]
|
||||
proc eth_compileLLL(): seq[byte]
|
||||
proc eth_compileSolidity(): seq[byte]
|
||||
|
@ -53,8 +63,8 @@ proc eth_getLogs(filterOptions: JsonNode): JsonNode
|
|||
proc eth_chainId(): Quantity
|
||||
|
||||
proc eth_getWork(): seq[UInt256]
|
||||
proc eth_submitWork(nonce: int64, powHash: Uint256, mixDigest: Uint256): bool
|
||||
proc eth_submitHashrate(hashRate: UInt256, id: Uint256): bool
|
||||
proc eth_submitWork(nonce: int64, powHash: Hash256, mixDigest: Hash256): bool
|
||||
proc eth_submitHashrate(hashRate: UInt256, id: UInt256): bool
|
||||
proc eth_subscribe(name: string, options: JsonNode): string
|
||||
proc eth_subscribe(name: string): string
|
||||
proc eth_unsubscribe(id: string)
|
|
@ -0,0 +1,250 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2019-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
stint,
|
||||
./primitives
|
||||
|
||||
export
|
||||
primitives
|
||||
|
||||
type
|
||||
SyncObject* = object
|
||||
startingBlock*: Quantity
|
||||
currentBlock*: Quantity
|
||||
highestBlock*: Quantity
|
||||
|
||||
HistoricExtraData* = DynamicBytes[0, 4096]
|
||||
## In the current specs, the maximum is 32, but historically this value was
|
||||
## used as Clique metadata which is dynamic in lenght and exceeds 32 bytes.
|
||||
## Since we still need to support syncing old blocks, we use this more relaxed
|
||||
## setting. Downstream libraries that want to enforce the up-to-date limit are
|
||||
## expected to do this on their own.
|
||||
|
||||
EthSend* = object
|
||||
`from`*: Address # the address the transaction is sent from.
|
||||
to*: Option[Address] # (optional when creating new contract) the address the transaction is directed to.
|
||||
gas*: Option[Quantity] # (optional, default: 90000) integer of the gas provided for the transaction execution. It will return unused gas.
|
||||
gasPrice*: Option[Quantity] # (optional, default: To-Be-Determined) integer of the gasPrice used for each paid gas.
|
||||
value*: Option[UInt256] # (optional) integer of the value sent with this transaction.
|
||||
data*: seq[byte] # the compiled code of a contract OR the hash of the invoked method signature and encoded parameters.
|
||||
# For details see Ethereum Contract ABI.
|
||||
nonce*: Option[Quantity] # (optional) integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce
|
||||
|
||||
# TODO: Both `EthSend` and `EthCall` are super outdated, according to new spec
|
||||
# those should be merged into one type `GenericTransaction` with a lot more fields
|
||||
# see: https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml#L244
|
||||
EthCall* = object
|
||||
source*: Option[Address] # (optional) The address the transaction is sent from.
|
||||
to*: Option[Address] # The address the transaction is directed to.
|
||||
gas*: Option[Quantity] # (optional) Integer of the gas provided for the transaction execution. eth_call consumes zero gas, but this parameter may be needed by some executions.
|
||||
gasPrice*: Option[Quantity] # (optional) Integer of the gasPrice used for each paid gas.
|
||||
value*: Option[UInt256] # (optional) Integer of the value sent with this transaction.
|
||||
data*: Option[seq[byte]] # (optional) Hash of the method signature and encoded parameters. For details see Ethereum Contract ABI.
|
||||
maxFeePerGas*: Option[Quantity] # (optional) MaxFeePerGas is the maximum fee per gas offered, in wei.
|
||||
maxPriorityFeePerGas*: Option[Quantity] # (optional) MaxPriorityFeePerGas is the maximum miner tip per gas offered, in wei.
|
||||
|
||||
## A block header object
|
||||
BlockHeader* = ref object
|
||||
number*: Quantity
|
||||
hash*: Hash256
|
||||
parentHash*: Hash256
|
||||
sha3Uncles*: Hash256
|
||||
logsBloom*: FixedBytes[256]
|
||||
transactionsRoot*: Hash256
|
||||
stateRoot*: Hash256
|
||||
receiptsRoot*: Hash256
|
||||
miner*: Address
|
||||
difficulty*: UInt256
|
||||
extraData*: HistoricExtraData
|
||||
gasLimit*: Quantity
|
||||
gasUsed*: Quantity
|
||||
timestamp*: Quantity
|
||||
nonce*: FixedBytes[8]
|
||||
mixHash*: Hash256
|
||||
baseFeePerGas*: Option[UInt256] # EIP-1559
|
||||
withdrawalsRoot*: Option[Hash256] # EIP-4895
|
||||
blobGasUsed*: Option[Quantity] # EIP-4844
|
||||
excessBlobGas*: Option[Quantity] # EIP-4844
|
||||
parentBeaconBlockRoot*: Option[Hash256] # EIP-4788
|
||||
|
||||
WithdrawalObject* = object
|
||||
index*: Quantity
|
||||
validatorIndex*: Quantity
|
||||
address*: Address
|
||||
amount*: Quantity
|
||||
|
||||
## A block object, or null when no block was found
|
||||
BlockObject* = ref object
|
||||
number*: Quantity # the block number. null when its pending block.
|
||||
hash*: Hash256 # hash of the block. null when its pending block.
|
||||
parentHash*: Hash256 # hash of the parent block.
|
||||
sha3Uncles*: Hash256 # SHA3 of the uncles data in the block.
|
||||
logsBloom*: FixedBytes[256] # the bloom filter for the logs of the block. null when its pending block.
|
||||
transactionsRoot*: Hash256 # the root of the transaction trie of the block.
|
||||
stateRoot*: Hash256 # the root of the final state trie of the block.
|
||||
receiptsRoot*: Hash256 # the root of the receipts trie of the block.
|
||||
miner*: Address # the address of the beneficiary to whom the mining rewards were given.
|
||||
difficulty*: UInt256 # integer of the difficulty for this block.
|
||||
extraData*: HistoricExtraData # the "extra data" field of this block.
|
||||
gasLimit*: Quantity # the maximum gas allowed in this block.
|
||||
gasUsed*: Quantity # the total used gas by all transactions in this block.
|
||||
timestamp*: Quantity # the unix timestamp for when the block was collated.
|
||||
nonce*: Option[FixedBytes[8]] # hash of the generated proof-of-work. null when its pending block.
|
||||
mixHash*: Hash256
|
||||
size*: Quantity # integer the size of this block in bytes.
|
||||
totalDifficulty*: UInt256 # integer of the total difficulty of the chain until this block.
|
||||
transactions*: seq[TxOrHash] # list of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter.
|
||||
uncles*: seq[Hash256] # list of uncle hashes.
|
||||
baseFeePerGas*: Option[UInt256] # EIP-1559
|
||||
withdrawals*: Option[seq[WithdrawalObject]] # EIP-4895
|
||||
withdrawalsRoot*: Option[Hash256] # EIP-4895
|
||||
blobGasUsed*: Option[Quantity] # EIP-4844
|
||||
excessBlobGas*: Option[Quantity] # EIP-4844
|
||||
parentBeaconBlockRoot*: Option[Hash256] # EIP-4788
|
||||
|
||||
TxOrHashKind* = enum
|
||||
tohHash
|
||||
tohTx
|
||||
|
||||
TxOrHash* = object
|
||||
case kind*: TxOrHashKind
|
||||
of tohHash:
|
||||
hash*: TxHash
|
||||
of tohTx:
|
||||
tx*: TransactionObject
|
||||
|
||||
AccessTuple* = object
|
||||
address*: Address
|
||||
storageKeys*: seq[FixedBytes[32]]
|
||||
|
||||
AccessListResult* = object
|
||||
accessList*: seq[AccessTuple]
|
||||
error*: string
|
||||
gasUsed: Quantity
|
||||
|
||||
TransactionObject* = ref object # A transaction object, or null when no transaction was found:
|
||||
hash*: TxHash # hash of the transaction.
|
||||
nonce*: Quantity # TODO: Is int? the number of transactions made by the sender prior to this one.
|
||||
blockHash*: Option[BlockHash] # hash of the block where this transaction was in. null when its pending.
|
||||
blockNumber*: Option[Quantity] # block number where this transaction was in. null when its pending.
|
||||
transactionIndex*: Option[Quantity] # integer of the transactions index position in the block. null when its pending.
|
||||
`from`*: Address # address of the sender.
|
||||
to*: Option[Address] # address of the receiver. null when its a contract creation transaction.
|
||||
value*: UInt256 # value transferred in Wei.
|
||||
gasPrice*: Quantity # gas price provided by the sender in Wei.
|
||||
gas*: Quantity # gas provided by the sender.
|
||||
input*: seq[byte] # the data send along with the transaction.
|
||||
v*: Quantity # ECDSA recovery id
|
||||
r*: UInt256 # ECDSA signature r
|
||||
s*: UInt256 # ECDSA signature s
|
||||
`type`*: Option[Quantity] # EIP-2718, with 0x0 for Legacy
|
||||
chainId*: Option[Quantity] # EIP-159
|
||||
accessList*: Option[seq[AccessTuple]] # EIP-2930
|
||||
maxFeePerGas*: Option[Quantity] # EIP-1559
|
||||
maxPriorityFeePerGas*: Option[Quantity] # EIP-1559
|
||||
maxFeePerBlobGas*: Option[UInt256] # EIP-4844
|
||||
versionedHashes*: Option[seq[VersionedHash]] # EIP-4844
|
||||
|
||||
ReceiptObject* = ref object # A transaction receipt object, or null when no receipt was found:
|
||||
transactionHash*: TxHash # hash of the transaction.
|
||||
transactionIndex*: Quantity # integer of the transactions index position in the block.
|
||||
blockHash*: BlockHash # hash of the block where this transaction was in.
|
||||
blockNumber*: Quantity # block number where this transaction was in.
|
||||
`from`*: Address # address of the sender.
|
||||
to*: Option[Address] # address of the receiver. null when its a contract creation transaction.
|
||||
cumulativeGasUsed*: Quantity # the total amount of gas used when this transaction was executed in the block.
|
||||
effectiveGasPrice*: Quantity # The sum of the base fee and tip paid per unit of gas.
|
||||
gasUsed*: Quantity # the amount of gas used by this specific transaction alone.
|
||||
contractAddress*: Option[Address] # the contract address created, if the transaction was a contract creation, otherwise null.
|
||||
logs*: seq[LogObject] # TODO: See Wiki for details. list of log objects, which this transaction generated.
|
||||
logsBloom*: FixedBytes[256] # bloom filter for light clients to quickly retrieve related logs.
|
||||
`type`*: Option[Quantity] # integer of the transaction type, 0x0 for legacy transactions, 0x1 for access list types, 0x2 for dynamic fees.
|
||||
root*: Option[Hash256] # 32 bytes of post-transaction stateroot (pre Byzantium)
|
||||
status*: Option[Quantity] # either 1 (success) or 0 (failure)
|
||||
blobGasUsed*: Option[Quantity] # uint64
|
||||
blobGasPrice*: Option[UInt256] # UInt256
|
||||
|
||||
FilterDataKind* = enum fkItem, fkList
|
||||
FilterData* = object
|
||||
# Difficult to process variant objects in input data, as kind is immutable.
|
||||
# TODO: This might need more work to handle "or" options
|
||||
kind*: FilterDataKind
|
||||
items*: seq[FilterData]
|
||||
item*: UInt256
|
||||
# TODO: I don't think this will work as input, need only one value that is either UInt256 or seq[UInt256]
|
||||
|
||||
Topic* = FixedBytes[32]
|
||||
|
||||
FilterOptions* = object
|
||||
fromBlock*: Option[RtBlockIdentifier] # (optional, default: "latest") integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.
|
||||
toBlock*: Option[RtBlockIdentifier] # (optional, default: "latest") integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.
|
||||
# TODO: address as optional list of address or optional address
|
||||
address*: seq[Address] # (optional) contract address or a list of addresses from which logs should originate.
|
||||
topics*: seq[Option[seq[Topic]]] # (optional) list of DATA topics. Topics are order-dependent. Each topic can also be a list of DATA with "or" options.
|
||||
blockHash*: Option[BlockHash] # (optional) hash of the block. If its present, fromBlock and toBlock, should be none. Introduced in EIP234
|
||||
|
||||
LogObject* = object
|
||||
removed*: bool # true when the log was removed, due to a chain reorganization. false if its a valid log.
|
||||
logIndex*: Option[Quantity] # integer of the log index position in the block. null when its pending log.
|
||||
transactionIndex*: Option[Quantity] # integer of the transactions index position log was created from. null when its pending log.
|
||||
transactionHash*: Option[TxHash] # hash of the transactions this log was created from. null when its pending log.
|
||||
blockHash*: Option[BlockHash] # hash of the block where this log was in. null when its pending. null when its pending log.
|
||||
blockNumber*: Option[Quantity] # the block number where this log was in. null when its pending. null when its pending log.
|
||||
address*: Address # address from which this log originated.
|
||||
data*: seq[byte] # contains one or more 32 Bytes non-indexed arguments of the log.
|
||||
topics*: seq[Topic] # array of 0 to 4 32 Bytes DATA of indexed log arguments.
|
||||
# (In solidity: The first topic is the hash of the signature of the event.
|
||||
# (e.g. Deposit(address,bytes32,uint256)), except you declared the event with the anonymous specifier.)
|
||||
|
||||
RlpEncodedBytes* = distinct seq[byte]
|
||||
|
||||
StorageProof* = object
|
||||
key*: UInt256
|
||||
value*: UInt256
|
||||
proof*: seq[RlpEncodedBytes]
|
||||
|
||||
ProofResponse* = object
|
||||
address*: Address
|
||||
accountProof*: seq[RlpEncodedBytes]
|
||||
balance*: UInt256
|
||||
codeHash*: CodeHash
|
||||
nonce*: Quantity
|
||||
storageHash*: StorageHash
|
||||
storageProof*: seq[StorageProof]
|
||||
|
||||
BlockIdentifier* = string|BlockNumber|RtBlockIdentifier
|
||||
|
||||
BlockIdentifierKind* = enum
|
||||
bidNumber
|
||||
bidAlias
|
||||
|
||||
RtBlockIdentifier* = object
|
||||
case kind*: BlockIdentifierKind
|
||||
of bidNumber:
|
||||
number*: BlockNumber
|
||||
of bidAlias:
|
||||
alias*: string
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
func blockId*(n: BlockNumber): RtBlockIdentifier =
|
||||
RtBlockIdentifier(kind: bidNumber, number: n)
|
||||
|
||||
func blockId*(b: BlockObject): RtBlockIdentifier =
|
||||
RtBlockIdentifier(kind: bidNumber, number: BlockNumber b.number)
|
||||
|
||||
func blockId*(a: string): RtBlockIdentifier =
|
||||
RtBlockIdentifier(kind: bidAlias, alias: a)
|
||||
|
||||
func txOrHash*(hash: TxHash): TxOrHash =
|
||||
TxOrHash(kind: tohHash, hash: hash)
|
||||
|
||||
func txOrHash*(tx: TransactionObject): TxOrHash =
|
||||
TxOrHash(kind: tohTx, tx: tx)
|
|
@ -1,3 +1,12 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2019-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
std/[json, strutils]
|
||||
|
||||
|
@ -20,7 +29,7 @@ template stripLeadingZeros(value: string): string =
|
|||
|
||||
func encodeQuantity*(value: SomeUnsignedInt): string =
|
||||
var hValue = value.toHex.stripLeadingZeros
|
||||
result = "0x" & hValue
|
||||
result = "0x" & hValue.toLowerAscii
|
||||
|
||||
func hasHexHeader*(value: string): bool =
|
||||
value.len >= 2 and value[0] == '0' and value[1] in {'x', 'X'}
|
||||
|
|
|
@ -1,542 +0,0 @@
|
|||
import
|
||||
std/[options, hashes, typetraits],
|
||||
stint, stew/[byteutils, results]
|
||||
|
||||
export
|
||||
hashes, options, typetraits
|
||||
|
||||
const
|
||||
# https://github.com/ethereum/execution-apis/blob/c4089414bbbe975bbc4bf1ccf0a3d31f76feb3e1/src/engine/cancun.md#blobsbundlev1
|
||||
fieldElementsPerBlob = 4096
|
||||
|
||||
type
|
||||
SyncObject* = object
|
||||
startingBlock*: int
|
||||
currentBlock*: int
|
||||
highestBlock*: int
|
||||
|
||||
FixedBytes*[N: static[int]] = distinct array[N, byte]
|
||||
DynamicBytes*[
|
||||
minLen: static[int] = 0,
|
||||
maxLen: static[int] = high(int)] = distinct seq[byte]
|
||||
|
||||
HistoricExtraData = DynamicBytes[0, 4096]
|
||||
## In the current specs, the maximum is 32, but historically this value was
|
||||
## used as Clique metadata which is dynamic in lenght and exceeds 32 bytes.
|
||||
## Since we still need to support syncing old blocks, we use this more relaxed
|
||||
## setting. Downstream libraries that want to enforce the up-to-date limit are
|
||||
## expected to do this on their own.
|
||||
|
||||
Address* = distinct array[20, byte]
|
||||
TxHash* = FixedBytes[32]
|
||||
Hash256* = FixedBytes[32]
|
||||
BlockHash* = Hash256
|
||||
BlockNumber* = uint64
|
||||
BlockIdentifier* = string|BlockNumber|RtBlockIdentifier
|
||||
Nonce* = int
|
||||
CodeHash* = FixedBytes[32]
|
||||
StorageHash* = FixedBytes[32]
|
||||
VersionedHash* = FixedBytes[32]
|
||||
|
||||
BlockIdentifierKind* = enum
|
||||
bidNumber
|
||||
bidAlias
|
||||
|
||||
RtBlockIdentifier* = object
|
||||
case kind*: BlockIdentifierKind
|
||||
of bidNumber:
|
||||
number*: BlockNumber
|
||||
of bidAlias:
|
||||
alias*: string
|
||||
|
||||
Quantity* = distinct uint64
|
||||
|
||||
KZGCommitment* = FixedBytes[48]
|
||||
KZGProof* = FixedBytes[48]
|
||||
Blob* = FixedBytes[fieldElementsPerBlob * 32]
|
||||
|
||||
EthSend* = object
|
||||
source*: Address # the address the transaction is sent from.
|
||||
to*: Option[Address] # (optional when creating new contract) the address the transaction is directed to.
|
||||
gas*: Option[Quantity] # (optional, default: 90000) integer of the gas provided for the transaction execution. It will return unused gas.
|
||||
gasPrice*: Option[int] # (optional, default: To-Be-Determined) integer of the gasPrice used for each paid gas.
|
||||
value*: Option[UInt256] # (optional) integer of the value sent with this transaction.
|
||||
data*: string # the compiled code of a contract OR the hash of the invoked method signature and encoded parameters.
|
||||
# For details see Ethereum Contract ABI.
|
||||
nonce*: Option[Nonce] # (optional) integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce
|
||||
|
||||
#EthSend* = object
|
||||
# source*: Address # the address the transaction is sent from.
|
||||
# to*: Address # (optional when creating new contract) the address the transaction is directed to.
|
||||
# gas*: int # (optional, default: 90000) integer of the gas provided for the transaction execution. It will return unused gas.
|
||||
# gasPrice*: int # (optional, default: To-Be-Determined) integer of the gasPrice used for each paid gas.
|
||||
# value*: int # (optional) integer of the value sent with this transaction.
|
||||
# data*: string # the compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see Ethereum Contract ABI.
|
||||
# nonce*: int # (optional) integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce
|
||||
|
||||
|
||||
# TODO: Both `EthSend` and `EthCall` are super outdated, according to new spec
|
||||
# those should be merged into one type `GenericTransaction` with a lot more fields
|
||||
# see: https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml#L244
|
||||
EthCall* = object
|
||||
source*: Option[Address] # (optional) The address the transaction is sent from.
|
||||
to*: Address # The address the transaction is directed to.
|
||||
gas*: Option[Quantity] # (optional) Integer of the gas provided for the transaction execution. eth_call consumes zero gas, but this parameter may be needed by some executions.
|
||||
gasPrice*: Option[int] # (optional) Integer of the gasPrice used for each paid gas.
|
||||
value*: Option[UInt256] # (optional) Integer of the value sent with this transaction.
|
||||
data*: Option[string] # (optional) Hash of the method signature and encoded parameters. For details see Ethereum Contract ABI.
|
||||
|
||||
#EthCall* = object
|
||||
# source*: Address # (optional) The address the transaction is sent from.
|
||||
# to*: Address # The address the transaction is directed to.
|
||||
# gas*: int # (optional) Integer of the gas provided for the transaction execution. eth_call consumes zero gas, but this parameter may be needed by some executions.
|
||||
# gasPrice*: int # (optional) Integer of the gasPrice used for each paid gas.
|
||||
# value*: int # (optional) Integer of the value sent with this transaction.
|
||||
# data*: int # (optional) Hash of the method signature and encoded parameters. For details see Ethereum Contract ABI.
|
||||
|
||||
## A block header object
|
||||
BlockHeader* = ref object
|
||||
number*: Quantity
|
||||
hash*: Hash256
|
||||
parentHash*: Hash256
|
||||
sha3Uncles*: Hash256
|
||||
logsBloom*: FixedBytes[256]
|
||||
transactionsRoot*: Hash256
|
||||
stateRoot*: Hash256
|
||||
receiptsRoot*: Hash256
|
||||
miner*: Address
|
||||
difficulty*: UInt256
|
||||
extraData*: HistoricExtraData
|
||||
gasLimit*: Quantity
|
||||
gasUsed*: Quantity
|
||||
timestamp*: Quantity
|
||||
nonce*: FixedBytes[8]
|
||||
mixHash*: Hash256
|
||||
baseFeePerGas*: Option[UInt256] # EIP-1559
|
||||
withdrawalsRoot*: Option[Hash256] # EIP-4895
|
||||
blobGasUsed*: Option[Quantity] # EIP-4844
|
||||
excessBlobGas*: Option[Quantity] # EIP-4844
|
||||
parentBeaconBlockRoot*: Option[Hash256] # EIP-4788
|
||||
|
||||
WithdrawalObject* = object
|
||||
index*: Quantity
|
||||
validatorIndex*: Quantity
|
||||
address*: Address
|
||||
amount*: Quantity
|
||||
|
||||
## A block object, or null when no block was found
|
||||
BlockObject* = ref object
|
||||
number*: Quantity # the block number. null when its pending block.
|
||||
hash*: Hash256 # hash of the block. null when its pending block.
|
||||
parentHash*: Hash256 # hash of the parent block.
|
||||
sha3Uncles*: Hash256 # SHA3 of the uncles data in the block.
|
||||
logsBloom*: FixedBytes[256] # the bloom filter for the logs of the block. null when its pending block.
|
||||
transactionsRoot*: Hash256 # the root of the transaction trie of the block.
|
||||
stateRoot*: Hash256 # the root of the final state trie of the block.
|
||||
receiptsRoot*: Hash256 # the root of the receipts trie of the block.
|
||||
miner*: Address # the address of the beneficiary to whom the mining rewards were given.
|
||||
difficulty*: UInt256 # integer of the difficulty for this block.
|
||||
extraData*: HistoricExtraData # the "extra data" field of this block.
|
||||
gasLimit*: Quantity # the maximum gas allowed in this block.
|
||||
gasUsed*: Quantity # the total used gas by all transactions in this block.
|
||||
timestamp*: Quantity # the unix timestamp for when the block was collated.
|
||||
nonce*: Option[FixedBytes[8]] # hash of the generated proof-of-work. null when its pending block.
|
||||
mixHash*: Hash256
|
||||
size*: Quantity # integer the size of this block in bytes.
|
||||
totalDifficulty*: UInt256 # integer of the total difficulty of the chain until this block.
|
||||
transactions*: seq[TxHash] # list of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter.
|
||||
uncles*: seq[Hash256] # list of uncle hashes.
|
||||
baseFeePerGas*: Option[UInt256] # EIP-1559
|
||||
withdrawals*: Option[seq[WithdrawalObject]] # EIP-4895
|
||||
withdrawalsRoot*: Option[Hash256] # EIP-4895
|
||||
blobGasUsed*: Option[Quantity] # EIP-4844
|
||||
excessBlobGas*: Option[Quantity] # EIP-4844
|
||||
parentBeaconBlockRoot*: Option[Hash256] # EIP-4788
|
||||
|
||||
AccessTuple* = object
|
||||
address*: Address
|
||||
storageKeys*: seq[Hash256]
|
||||
|
||||
TransactionObject* = object # A transaction object, or null when no transaction was found:
|
||||
hash*: TxHash # hash of the transaction.
|
||||
nonce*: Quantity # TODO: Is int? the number of transactions made by the sender prior to this one.
|
||||
blockHash*: Option[BlockHash] # hash of the block where this transaction was in. null when its pending.
|
||||
blockNumber*: Option[Quantity] # block number where this transaction was in. null when its pending.
|
||||
transactionIndex*: Option[Quantity] # integer of the transactions index position in the block. null when its pending.
|
||||
`from`*: Address # address of the sender.
|
||||
to*: Option[Address] # address of the receiver. null when its a contract creation transaction.
|
||||
value*: UInt256 # value transferred in Wei.
|
||||
gasPrice*: Quantity # gas price provided by the sender in Wei.
|
||||
gas*: Quantity # gas provided by the sender.
|
||||
input*: seq[byte] # the data send along with the transaction.
|
||||
v*: UInt256 # ECDSA recovery id
|
||||
r*: UInt256 # ECDSA signature r
|
||||
s*: UInt256 # ECDSA signature s
|
||||
`type`*: Option[Quantity] # EIP-2718, with 0x0 for Legacy
|
||||
chainId*: Option[UInt256] # EIP-159
|
||||
accessList*: Option[seq[AccessTuple]] # EIP-2930
|
||||
maxFeePerGas*: Option[Quantity] # EIP-1559
|
||||
maxPriorityFeePerGas*: Option[Quantity] # EIP-1559
|
||||
maxFeePerBlobGas*: Option[UInt256] # EIP-4844
|
||||
blobVersionedHashes*: Option[seq[VersionedHash]] # EIP-4844
|
||||
|
||||
ReceiptKind* = enum rkRoot, rkStatus
|
||||
ReceiptObject* = object
|
||||
# A transaction receipt object, or null when no receipt was found:
|
||||
transactionHash*: TxHash # hash of the transaction.
|
||||
transactionIndex*: Quantity # integer of the transactions index position in the block.
|
||||
blockHash*: BlockHash # hash of the block where this transaction was in.
|
||||
blockNumber*: Quantity # block number where this transaction was in.
|
||||
`from`*: Address # address of the sender.
|
||||
to*: Option[Address] # address of the receiver. null when its a contract creation transaction.
|
||||
cumulativeGasUsed*: Quantity # the total amount of gas used when this transaction was executed in the block.
|
||||
effectiveGasPrice*: Quantity # The sum of the base fee and tip paid per unit of gas.
|
||||
gasUsed*: Quantity # the amount of gas used by this specific transaction alone.
|
||||
contractAddress*: Option[Address] # the contract address created, if the transaction was a contract creation, otherwise null.
|
||||
logs*: seq[LogObject] # TODO: See Wiki for details. list of log objects, which this transaction generated.
|
||||
logsBloom*: FixedBytes[256] # bloom filter for light clients to quickly retrieve related logs.
|
||||
`type`*: Option[Quantity] # integer of the transaction type, 0x0 for legacy transactions, 0x1 for access list types, 0x2 for dynamic fees.
|
||||
root*: Option[Hash256] # 32 bytes of post-transaction stateroot (pre Byzantium)
|
||||
status*: Option[Quantity] # either 1 (success) or 0 (failure)
|
||||
|
||||
FilterDataKind* = enum fkItem, fkList
|
||||
FilterData* = object
|
||||
# Difficult to process variant objects in input data, as kind is immutable.
|
||||
# TODO: This might need more work to handle "or" options
|
||||
kind*: FilterDataKind
|
||||
items*: seq[FilterData]
|
||||
item*: UInt256
|
||||
# TODO: I don't think this will work as input, need only one value that is either UInt256 or seq[UInt256]
|
||||
|
||||
FilterOptions* = object
|
||||
fromBlock*: Option[string] # (optional, default: "latest") integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.
|
||||
toBlock*: Option[string] # (optional, default: "latest") integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.
|
||||
address*: Option[Address] # (optional) contract address or a list of addresses from which logs should originate.
|
||||
topics*: Option[seq[string]]#Option[seq[FilterData]] # (optional) list of DATA topics. Topics are order-dependent. Each topic can also be a list of DATA with "or" options.
|
||||
blockhash*: Option[BlockHash]
|
||||
|
||||
LogObject* = object
|
||||
removed*: bool # true when the log was removed, due to a chain reorganization. false if its a valid log.
|
||||
logIndex*: Quantity # integer of the log index position in the block. null when its pending log.
|
||||
transactionIndex*: Quantity # integer of the transactions index position log was created from. null when its pending log.
|
||||
transactionHash*: TxHash # hash of the transactions this log was created from. null when its pending log.
|
||||
blockHash*: BlockHash # hash of the block where this log was in. null when its pending. null when its pending log.
|
||||
blockNumber*: Quantity # the block number where this log was in. null when its pending. null when its pending log.
|
||||
address*: Address # address from which this log originated.
|
||||
data*: seq[byte] # contains one or more 32 Bytes non-indexed arguments of the log.
|
||||
topics*: seq[FixedBytes[32]] # array of 0 to 4 32 Bytes DATA of indexed log arguments.
|
||||
# (In solidity: The first topic is the hash of the signature of the event.
|
||||
# (e.g. Deposit(address,bytes32,uint256)), except you declared the event with the anonymous specifier.)
|
||||
|
||||
# EthSend* = object
|
||||
# source*: Address # the address the transaction is sent from.
|
||||
# to*: Option[Address] # (optional when creating new contract) the address the transaction is directed to.
|
||||
# gas*: Option[int] # (optional, default: 90000) integer of the gas provided for the transaction execution. It will return unused gas.
|
||||
# gasPrice*: Option[int] # (optional, default: To-Be-Determined) integer of the gasPrice used for each paid gas.
|
||||
# value*: Option[int] # (optional) integer of the value sent with this transaction.
|
||||
# data*: string # the compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see Ethereum Contract ABI.
|
||||
# nonce*: Option[int] # (optional) integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce
|
||||
|
||||
# var x: array[20, byte] = [1.byte, 2, 3, 4, 5, 6, 7, 0xab, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
|
||||
|
||||
TypedTransaction* = distinct seq[byte]
|
||||
|
||||
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.3/src/engine/shanghai.md#withdrawalv1
|
||||
WithdrawalV1* = object
|
||||
index*: Quantity
|
||||
validatorIndex*: Quantity
|
||||
address*: Address
|
||||
amount*: Quantity
|
||||
|
||||
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.3/src/engine/paris.md#executionpayloadv1
|
||||
ExecutionPayloadV1* = object
|
||||
parentHash*: Hash256
|
||||
feeRecipient*: Address
|
||||
stateRoot*: Hash256
|
||||
receiptsRoot*: Hash256
|
||||
logsBloom*: FixedBytes[256]
|
||||
prevRandao*: FixedBytes[32]
|
||||
blockNumber*: Quantity
|
||||
gasLimit*: Quantity
|
||||
gasUsed*: Quantity
|
||||
timestamp*: Quantity
|
||||
extraData*: DynamicBytes[0, 32]
|
||||
baseFeePerGas*: UInt256
|
||||
blockHash*: Hash256
|
||||
transactions*: seq[TypedTransaction]
|
||||
|
||||
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.3/src/engine/shanghai.md#executionpayloadv2
|
||||
ExecutionPayloadV2* = object
|
||||
parentHash*: Hash256
|
||||
feeRecipient*: Address
|
||||
stateRoot*: Hash256
|
||||
receiptsRoot*: Hash256
|
||||
logsBloom*: FixedBytes[256]
|
||||
prevRandao*: FixedBytes[32]
|
||||
blockNumber*: Quantity
|
||||
gasLimit*: Quantity
|
||||
gasUsed*: Quantity
|
||||
timestamp*: Quantity
|
||||
extraData*: DynamicBytes[0, 32]
|
||||
baseFeePerGas*: UInt256
|
||||
blockHash*: Hash256
|
||||
transactions*: seq[TypedTransaction]
|
||||
withdrawals*: seq[WithdrawalV1]
|
||||
|
||||
# This is ugly, but I don't think the RPC library will handle
|
||||
# ExecutionPayloadV1 | ExecutionPayloadV2. (Am I wrong?)
|
||||
# Note that the spec currently says that various V2 methods
|
||||
# (e.g. engine_newPayloadV2) need to accept *either* V1 or V2
|
||||
# of the data structure (e.g. either ExecutionPayloadV1 or
|
||||
# ExecutionPayloadV2); it's not like V2 of the method only
|
||||
# needs to accept V2 of the structure. Anyway, the best way
|
||||
# I've found to handle this is to make this structure with an
|
||||
# Option for the withdrawals field. If you've got a better idea,
|
||||
# please fix this. (Maybe the RPC library does handle sum types?
|
||||
# Or maybe we can enhance it to do so?) --Adam
|
||||
#
|
||||
# https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.3/src/engine/shanghai.md
|
||||
ExecutionPayloadV1OrV2* = object
|
||||
parentHash*: BlockHash
|
||||
feeRecipient*: Address
|
||||
stateRoot*: BlockHash
|
||||
receiptsRoot*: BlockHash
|
||||
logsBloom*: FixedBytes[256]
|
||||
prevRandao*: FixedBytes[32]
|
||||
blockNumber*: Quantity
|
||||
gasLimit*: Quantity
|
||||
gasUsed*: Quantity
|
||||
timestamp*: Quantity
|
||||
extraData*: DynamicBytes[0, 32]
|
||||
baseFeePerGas*: UInt256
|
||||
blockHash*: BlockHash
|
||||
transactions*: seq[TypedTransaction]
|
||||
withdrawals*: Option[seq[WithdrawalV1]]
|
||||
|
||||
# https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#executionpayloadv3
|
||||
ExecutionPayloadV3* = object
|
||||
parentHash*: Hash256
|
||||
feeRecipient*: Address
|
||||
stateRoot*: Hash256
|
||||
receiptsRoot*: Hash256
|
||||
logsBloom*: FixedBytes[256]
|
||||
prevRandao*: FixedBytes[32]
|
||||
blockNumber*: Quantity
|
||||
gasLimit*: Quantity
|
||||
gasUsed*: Quantity
|
||||
timestamp*: Quantity
|
||||
extraData*: DynamicBytes[0, 32]
|
||||
baseFeePerGas*: UInt256
|
||||
blockHash*: Hash256
|
||||
transactions*: seq[TypedTransaction]
|
||||
withdrawals*: seq[WithdrawalV1]
|
||||
blobGasUsed*: Quantity
|
||||
excessBlobGas*: Quantity
|
||||
|
||||
SomeExecutionPayload* =
|
||||
ExecutionPayloadV1 |
|
||||
ExecutionPayloadV2 |
|
||||
ExecutionPayloadV3
|
||||
|
||||
# https://github.com/ethereum/execution-apis/blob/ee3df5bc38f28ef35385cefc9d9ca18d5e502778/src/engine/cancun.md#blobsbundlev1
|
||||
BlobsBundleV1* = object
|
||||
commitments*: seq[KZGCommitment]
|
||||
proofs*: seq[KZGProof]
|
||||
blobs*: seq[Blob]
|
||||
|
||||
RlpEncodedBytes* = distinct seq[byte]
|
||||
|
||||
StorageProof* = object
|
||||
key*: UInt256
|
||||
value*: UInt256
|
||||
proof*: seq[RlpEncodedBytes]
|
||||
|
||||
ProofResponse* = object
|
||||
address*: Address
|
||||
accountProof*: seq[RlpEncodedBytes]
|
||||
balance*: UInt256
|
||||
codeHash*: CodeHash
|
||||
nonce*: Quantity
|
||||
storageHash*: StorageHash
|
||||
storageProof*: seq[StorageProof]
|
||||
|
||||
AccessListEntry* = object
|
||||
address*: Address
|
||||
storageKeys*: seq[FixedBytes[32]]
|
||||
|
||||
AccessList* = seq[AccessListEntry]
|
||||
|
||||
AccessListResult* = object
|
||||
accessList*: AccessList
|
||||
error*: string
|
||||
gasUsed: Quantity
|
||||
|
||||
template `==`*[N](a, b: FixedBytes[N]): bool =
|
||||
distinctBase(a) == distinctBase(b)
|
||||
|
||||
template `==`*(a, b: Quantity): bool =
|
||||
distinctBase(a) == distinctBase(b)
|
||||
|
||||
template `==`*[minLen, maxLen](a, b: DynamicBytes[minLen, maxLen]): bool =
|
||||
distinctBase(a) == distinctBase(b)
|
||||
|
||||
func `==`*(a, b: Address): bool {.inline.} =
|
||||
array[20, byte](a) == array[20, byte](b)
|
||||
|
||||
func blockId*(n: BlockNumber): RtBlockIdentifier =
|
||||
RtBlockIdentifier(kind: bidNumber, number: n)
|
||||
|
||||
func blockId*(b: BlockObject): RtBlockIdentifier =
|
||||
RtBlockIdentifier(kind: bidNumber, number: BlockNumber b.number)
|
||||
|
||||
func blockId*(a: string): RtBlockIdentifier =
|
||||
RtBlockIdentifier(kind: bidAlias, alias: a)
|
||||
|
||||
func hash*[N](bytes: FixedBytes[N]): Hash =
|
||||
hash(distinctBase bytes)
|
||||
|
||||
template toHex*[N](x: FixedBytes[N]): string =
|
||||
toHex(distinctBase x)
|
||||
|
||||
template toHex*[minLen, maxLen](x: DynamicBytes[minLen, maxLen]): string =
|
||||
toHex(distinctBase x)
|
||||
|
||||
template toHex*(x: Address): string =
|
||||
toHex(distinctBase x)
|
||||
|
||||
template fromHex*(T: type Address, hexStr: string): T =
|
||||
T fromHex(distinctBase(T), hexStr)
|
||||
|
||||
template skip0xPrefix(hexStr: string): int =
|
||||
## Returns the index of the first meaningful char in `hexStr` by skipping
|
||||
## "0x" prefix
|
||||
if hexStr.len > 1 and hexStr[0] == '0' and hexStr[1] in {'x', 'X'}: 2
|
||||
else: 0
|
||||
|
||||
func strip0xPrefix*(s: string): string =
|
||||
let prefixLen = skip0xPrefix(s)
|
||||
if prefixLen != 0:
|
||||
s[prefixLen .. ^1]
|
||||
else:
|
||||
s
|
||||
|
||||
func fromHex*[minLen, maxLen](T: type DynamicBytes[minLen, maxLen], hexStr: string): T =
|
||||
let prefixLen = skip0xPrefix(hexStr)
|
||||
let hexDataLen = hexStr.len - prefixLen
|
||||
|
||||
if hexDataLen < minLen * 2:
|
||||
raise newException(ValueError, "hex input too small")
|
||||
|
||||
if hexDataLen > maxLen * 2:
|
||||
raise newException(ValueError, "hex input too large")
|
||||
|
||||
T hexToSeqByte(hexStr)
|
||||
|
||||
template fromHex*[N](T: type FixedBytes[N], hexStr: string): T =
|
||||
T fromHex(distinctBase(T), hexStr)
|
||||
|
||||
func toArray*[N](data: DynamicBytes[N, N]): array[N, byte] =
|
||||
copyMem(addr result[0], unsafeAddr distinctBase(data)[0], N)
|
||||
|
||||
template bytes*(data: DynamicBytes): seq[byte] =
|
||||
distinctBase data
|
||||
|
||||
template bytes*(data: FixedBytes): auto =
|
||||
distinctBase data
|
||||
|
||||
template len*(data: DynamicBytes): int =
|
||||
len(distinctBase data)
|
||||
|
||||
func `$`*[minLen, maxLen](data: DynamicBytes[minLen, maxLen]): string =
|
||||
"0x" & byteutils.toHex(distinctBase(data))
|
||||
|
||||
|
||||
# These conversion functions are very ugly, but at least
|
||||
# they're very straightforward and simple. If anyone has
|
||||
# a better idea, I'm all ears. (See the above comment on
|
||||
# ExecutionPayloadV1OrV2.) --Adam
|
||||
|
||||
func toExecutionPayloadV1OrExecutionPayloadV2*(p: ExecutionPayloadV1OrV2): Result[ExecutionPayloadV1, ExecutionPayloadV2] =
|
||||
if p.withdrawals.isNone:
|
||||
ok(
|
||||
ExecutionPayloadV1(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions
|
||||
)
|
||||
)
|
||||
else:
|
||||
err(
|
||||
ExecutionPayloadV2(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions,
|
||||
withdrawals: p.withdrawals.get
|
||||
)
|
||||
)
|
||||
|
||||
func toExecutionPayloadV1*(p: ExecutionPayloadV1OrV2): ExecutionPayloadV1 =
|
||||
p.toExecutionPayloadV1OrExecutionPayloadV2.get
|
||||
|
||||
func toExecutionPayloadV2*(p: ExecutionPayloadV1OrV2): ExecutionPayloadV2 =
|
||||
p.toExecutionPayloadV1OrExecutionPayloadV2.error
|
||||
|
||||
func toExecutionPayloadV1OrV2*(p: ExecutionPayloadV1): ExecutionPayloadV1OrV2 =
|
||||
ExecutionPayloadV1OrV2(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions,
|
||||
withdrawals: none[seq[WithdrawalV1]]()
|
||||
)
|
||||
|
||||
func toExecutionPayloadV1OrV2*(p: ExecutionPayloadV2): ExecutionPayloadV1OrV2 =
|
||||
ExecutionPayloadV1OrV2(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions,
|
||||
withdrawals: some(p.withdrawals)
|
||||
)
|
|
@ -0,0 +1,393 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
stint,
|
||||
./engine_api_types
|
||||
|
||||
export
|
||||
stint,
|
||||
engine_api_types
|
||||
|
||||
type
|
||||
ExecutionPayload* = object
|
||||
parentHash*: Hash256
|
||||
feeRecipient*: Address
|
||||
stateRoot*: Hash256
|
||||
receiptsRoot*: Hash256
|
||||
logsBloom*: FixedBytes[256]
|
||||
prevRandao*: FixedBytes[32]
|
||||
blockNumber*: Quantity
|
||||
gasLimit*: Quantity
|
||||
gasUsed*: Quantity
|
||||
timestamp*: Quantity
|
||||
extraData*: DynamicBytes[0, 32]
|
||||
baseFeePerGas*: UInt256
|
||||
blockHash*: Hash256
|
||||
transactions*: seq[TypedTransaction]
|
||||
withdrawals*: Option[seq[WithdrawalV1]]
|
||||
blobGasUsed*: Option[Quantity]
|
||||
excessBlobGas*: Option[Quantity]
|
||||
|
||||
PayloadAttributes* = object
|
||||
timestamp*: Quantity
|
||||
prevRandao*: FixedBytes[32]
|
||||
suggestedFeeRecipient*: Address
|
||||
withdrawals*: Option[seq[WithdrawalV1]]
|
||||
parentBeaconBlockRoot*: Option[FixedBytes[32]]
|
||||
|
||||
SomeOptionalPayloadAttributes* =
|
||||
Option[PayloadAttributesV1] |
|
||||
Option[PayloadAttributesV2] |
|
||||
Option[PayloadAttributesV3]
|
||||
|
||||
GetPayloadResponse* = object
|
||||
executionPayload*: ExecutionPayload
|
||||
blockValue*: Option[UInt256]
|
||||
blobsBundle*: Option[BlobsBundleV1]
|
||||
shouldOverrideBuilder*: Option[bool]
|
||||
|
||||
Version* {.pure.} = enum
|
||||
V1
|
||||
V2
|
||||
V3
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
func version*(payload: ExecutionPayload): Version =
|
||||
if payload.blobGasUsed.isSome and payload.excessBlobGas.isSome:
|
||||
Version.V3
|
||||
elif payload.withdrawals.isSome:
|
||||
Version.V2
|
||||
else:
|
||||
Version.V1
|
||||
|
||||
func version*(attr: PayloadAttributes): Version =
|
||||
if attr.parentBeaconBlockRoot.isSome:
|
||||
Version.V3
|
||||
elif attr.withdrawals.isSome:
|
||||
Version.V2
|
||||
else:
|
||||
Version.V1
|
||||
|
||||
func version*(res: GetPayloadResponse): Version =
|
||||
if res.blobsBundle.isSome and res.shouldOverrideBuilder.isSome:
|
||||
Version.V3
|
||||
elif res.blockValue.isSome:
|
||||
Version.V2
|
||||
else:
|
||||
Version.V1
|
||||
|
||||
func V1V2*(attr: PayloadAttributes): PayloadAttributesV1OrV2 =
|
||||
PayloadAttributesV1OrV2(
|
||||
timestamp: attr.timestamp,
|
||||
prevRandao: attr.prevRandao,
|
||||
suggestedFeeRecipient: attr.suggestedFeeRecipient,
|
||||
withdrawals: attr.withdrawals
|
||||
)
|
||||
|
||||
func V1*(attr: PayloadAttributes): PayloadAttributesV1 =
|
||||
PayloadAttributesV1(
|
||||
timestamp: attr.timestamp,
|
||||
prevRandao: attr.prevRandao,
|
||||
suggestedFeeRecipient: attr.suggestedFeeRecipient
|
||||
)
|
||||
|
||||
func V2*(attr: PayloadAttributes): PayloadAttributesV2 =
|
||||
PayloadAttributesV2(
|
||||
timestamp: attr.timestamp,
|
||||
prevRandao: attr.prevRandao,
|
||||
suggestedFeeRecipient: attr.suggestedFeeRecipient,
|
||||
withdrawals: attr.withdrawals.get
|
||||
)
|
||||
|
||||
func V3*(attr: PayloadAttributes): PayloadAttributesV3 =
|
||||
PayloadAttributesV3(
|
||||
timestamp: attr.timestamp,
|
||||
prevRandao: attr.prevRandao,
|
||||
suggestedFeeRecipient: attr.suggestedFeeRecipient,
|
||||
withdrawals: attr.withdrawals.get(newSeq[WithdrawalV1]()),
|
||||
parentBeaconBlockRoot: attr.parentBeaconBlockRoot.get
|
||||
)
|
||||
|
||||
func V1*(attr: Option[PayloadAttributes]): Option[PayloadAttributesV1] =
|
||||
if attr.isNone:
|
||||
return none(PayloadAttributesV1)
|
||||
some(attr.get.V1)
|
||||
|
||||
func V2*(attr: Option[PayloadAttributes]): Option[PayloadAttributesV2] =
|
||||
if attr.isNone:
|
||||
return none(PayloadAttributesV2)
|
||||
some(attr.get.V2)
|
||||
|
||||
func V3*(attr: Option[PayloadAttributes]): Option[PayloadAttributesV3] =
|
||||
if attr.isNone:
|
||||
return none(PayloadAttributesV3)
|
||||
some(attr.get.V3)
|
||||
|
||||
func payloadAttributes*(attr: PayloadAttributesV1): PayloadAttributes =
|
||||
PayloadAttributes(
|
||||
timestamp: attr.timestamp,
|
||||
prevRandao: attr.prevRandao,
|
||||
suggestedFeeRecipient: attr.suggestedFeeRecipient
|
||||
)
|
||||
|
||||
func payloadAttributes*(attr: PayloadAttributesV2): PayloadAttributes =
|
||||
PayloadAttributes(
|
||||
timestamp: attr.timestamp,
|
||||
prevRandao: attr.prevRandao,
|
||||
suggestedFeeRecipient: attr.suggestedFeeRecipient,
|
||||
withdrawals: some(attr.withdrawals)
|
||||
)
|
||||
|
||||
func payloadAttributes*(attr: PayloadAttributesV3): PayloadAttributes =
|
||||
PayloadAttributes(
|
||||
timestamp: attr.timestamp,
|
||||
prevRandao: attr.prevRandao,
|
||||
suggestedFeeRecipient: attr.suggestedFeeRecipient,
|
||||
withdrawals: some(attr.withdrawals),
|
||||
parentBeaconBlockRoot: some(attr.parentBeaconBlockRoot)
|
||||
)
|
||||
|
||||
func payloadAttributes*(x: Option[PayloadAttributesV1]): Option[PayloadAttributes] =
|
||||
if x.isNone: none(PayloadAttributes)
|
||||
else: some(payloadAttributes x.get)
|
||||
|
||||
func payloadAttributes*(x: Option[PayloadAttributesV2]): Option[PayloadAttributes] =
|
||||
if x.isNone: none(PayloadAttributes)
|
||||
else: some(payloadAttributes x.get)
|
||||
|
||||
func payloadAttributes*(x: Option[PayloadAttributesV3]): Option[PayloadAttributes] =
|
||||
if x.isNone: none(PayloadAttributes)
|
||||
else: some(payloadAttributes x.get)
|
||||
|
||||
func V1V2*(p: ExecutionPayload): ExecutionPayloadV1OrV2 =
|
||||
ExecutionPayloadV1OrV2(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions,
|
||||
withdrawals: p.withdrawals
|
||||
)
|
||||
|
||||
func V1*(p: ExecutionPayload): ExecutionPayloadV1 =
|
||||
ExecutionPayloadV1(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions
|
||||
)
|
||||
|
||||
func V2*(p: ExecutionPayload): ExecutionPayloadV2 =
|
||||
ExecutionPayloadV2(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions,
|
||||
withdrawals: p.withdrawals.get
|
||||
)
|
||||
|
||||
func V3*(p: ExecutionPayload): ExecutionPayloadV3 =
|
||||
ExecutionPayloadV3(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions,
|
||||
withdrawals: p.withdrawals.get,
|
||||
blobGasUsed: p.blobGasUsed.get,
|
||||
excessBlobGas: p.excessBlobGas.get
|
||||
)
|
||||
|
||||
func V1*(p: ExecutionPayloadV1OrV2): ExecutionPayloadV1 =
|
||||
ExecutionPayloadV1(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions
|
||||
)
|
||||
|
||||
func V2*(p: ExecutionPayloadV1OrV2): ExecutionPayloadV2 =
|
||||
ExecutionPayloadV2(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions,
|
||||
withdrawals: p.withdrawals.get
|
||||
)
|
||||
|
||||
func executionPayload*(p: ExecutionPayloadV1): ExecutionPayload =
|
||||
ExecutionPayload(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions
|
||||
)
|
||||
|
||||
func executionPayload*(p: ExecutionPayloadV2): ExecutionPayload =
|
||||
ExecutionPayload(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions,
|
||||
withdrawals: some(p.withdrawals)
|
||||
)
|
||||
|
||||
func executionPayload*(p: ExecutionPayloadV3): ExecutionPayload =
|
||||
ExecutionPayload(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions,
|
||||
withdrawals: some(p.withdrawals),
|
||||
blobGasUsed: some(p.blobGasUsed),
|
||||
excessBlobGas: some(p.excessBlobGas)
|
||||
)
|
||||
|
||||
func executionPayload*(p: ExecutionPayloadV1OrV2): ExecutionPayload =
|
||||
ExecutionPayload(
|
||||
parentHash: p.parentHash,
|
||||
feeRecipient: p.feeRecipient,
|
||||
stateRoot: p.stateRoot,
|
||||
receiptsRoot: p.receiptsRoot,
|
||||
logsBloom: p.logsBloom,
|
||||
prevRandao: p.prevRandao,
|
||||
blockNumber: p.blockNumber,
|
||||
gasLimit: p.gasLimit,
|
||||
gasUsed: p.gasUsed,
|
||||
timestamp: p.timestamp,
|
||||
extraData: p.extraData,
|
||||
baseFeePerGas: p.baseFeePerGas,
|
||||
blockHash: p.blockHash,
|
||||
transactions: p.transactions,
|
||||
withdrawals: p.withdrawals
|
||||
)
|
||||
|
||||
func V1*(res: GetPayloadResponse): ExecutionPayloadV1 =
|
||||
res.executionPayload.V1
|
||||
|
||||
func V2*(res: GetPayloadResponse): GetPayloadV2Response =
|
||||
GetPayloadV2Response(
|
||||
executionPayload: res.executionPayload.V1V2,
|
||||
blockValue: res.blockValue.get
|
||||
)
|
||||
|
||||
func V3*(res: GetPayloadResponse): GetPayloadV3Response =
|
||||
GetPayloadV3Response(
|
||||
executionPayload: res.executionPayload.V3,
|
||||
blockValue: res.blockValue.get,
|
||||
blobsBundle: res.blobsBundle.get,
|
||||
shouldOverrideBuilder: res.shouldOverrideBuilder.get
|
||||
)
|
||||
|
||||
func getPayloadResponse*(x: ExecutionPayloadV1): GetPayloadResponse =
|
||||
GetPayloadResponse(executionPayload: x.executionPayload)
|
||||
|
||||
func getPayloadResponse*(x: GetPayloadV2Response): GetPayloadResponse =
|
||||
GetPayloadResponse(
|
||||
executionPayload: x.executionPayload.executionPayload,
|
||||
blockValue: some(x.blockValue)
|
||||
)
|
||||
|
||||
func getPayloadResponse*(x: GetPayloadV3Response): GetPayloadResponse =
|
||||
GetPayloadResponse(
|
||||
executionPayload: x.executionPayload.executionPayload,
|
||||
blockValue: some(x.blockValue),
|
||||
blobsBundle: some(x.blobsBundle),
|
||||
shouldOverrideBuilder: some(x.shouldOverrideBuilder)
|
||||
)
|
|
@ -0,0 +1,123 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
std/[options, hashes, typetraits],
|
||||
stint, stew/[byteutils, results]
|
||||
|
||||
export
|
||||
hashes, options, typetraits
|
||||
|
||||
type
|
||||
FixedBytes*[N: static[int]] = distinct array[N, byte]
|
||||
|
||||
DynamicBytes*[
|
||||
minLen: static[int] = 0,
|
||||
maxLen: static[int] = high(int)] = distinct seq[byte]
|
||||
|
||||
Address* = distinct array[20, byte]
|
||||
TxHash* = FixedBytes[32]
|
||||
Hash256* = FixedBytes[32]
|
||||
BlockHash* = FixedBytes[32]
|
||||
BlockNumber* = uint64
|
||||
Quantity* = distinct uint64
|
||||
|
||||
CodeHash* = FixedBytes[32]
|
||||
StorageHash* = FixedBytes[32]
|
||||
VersionedHash* = FixedBytes[32]
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
template `==`*[N](a, b: FixedBytes[N]): bool =
|
||||
distinctBase(a) == distinctBase(b)
|
||||
|
||||
template `==`*(a, b: Quantity): bool =
|
||||
distinctBase(a) == distinctBase(b)
|
||||
|
||||
template `==`*[minLen, maxLen](a, b: DynamicBytes[minLen, maxLen]): bool =
|
||||
distinctBase(a) == distinctBase(b)
|
||||
|
||||
func `==`*(a, b: Address): bool {.inline.} =
|
||||
distinctBase(a) == distinctBase(b)
|
||||
|
||||
func hash*[N](bytes: FixedBytes[N]): Hash =
|
||||
hash(distinctBase bytes)
|
||||
|
||||
func hash*(bytes: Address): Hash =
|
||||
hash(distinctBase bytes)
|
||||
|
||||
template toHex*[N](x: FixedBytes[N]): string =
|
||||
toHex(distinctBase x)
|
||||
|
||||
template toHex*[minLen, maxLen](x: DynamicBytes[minLen, maxLen]): string =
|
||||
toHex(distinctBase x)
|
||||
|
||||
template toHex*(x: Address): string =
|
||||
toHex(distinctBase x)
|
||||
|
||||
template fromHex*(T: type Address, hexStr: string): T =
|
||||
T fromHex(distinctBase(T), hexStr)
|
||||
|
||||
template skip0xPrefix(hexStr: string): int =
|
||||
## Returns the index of the first meaningful char in `hexStr` by skipping
|
||||
## "0x" prefix
|
||||
if hexStr.len > 1 and hexStr[0] == '0' and hexStr[1] in {'x', 'X'}: 2
|
||||
else: 0
|
||||
|
||||
func strip0xPrefix*(s: string): string =
|
||||
let prefixLen = skip0xPrefix(s)
|
||||
if prefixLen != 0:
|
||||
s[prefixLen .. ^1]
|
||||
else:
|
||||
s
|
||||
|
||||
func fromHex*[minLen, maxLen](T: type DynamicBytes[minLen, maxLen], hexStr: string): T {.raises: [ValueError].} =
|
||||
let prefixLen = skip0xPrefix(hexStr)
|
||||
let hexDataLen = hexStr.len - prefixLen
|
||||
|
||||
if hexDataLen < minLen * 2:
|
||||
raise newException(ValueError, "hex input too small")
|
||||
|
||||
if hexDataLen > maxLen * 2:
|
||||
raise newException(ValueError, "hex input too large")
|
||||
|
||||
T hexToSeqByte(hexStr)
|
||||
|
||||
template fromHex*[N](T: type FixedBytes[N], hexStr: string): T =
|
||||
T fromHex(distinctBase(T), hexStr)
|
||||
|
||||
func toArray*[N](data: DynamicBytes[N, N]): array[N, byte] =
|
||||
copyMem(addr result[0], unsafeAddr distinctBase(data)[0], N)
|
||||
|
||||
template bytes*(data: DynamicBytes): seq[byte] =
|
||||
distinctBase data
|
||||
|
||||
template bytes*(data: FixedBytes): auto =
|
||||
distinctBase data
|
||||
|
||||
template bytes*(data: Address): auto =
|
||||
distinctBase data
|
||||
|
||||
template len*(data: DynamicBytes): int =
|
||||
len(distinctBase data)
|
||||
|
||||
template len*(data: FixedBytes): int =
|
||||
len(distinctBase data)
|
||||
|
||||
template len*(data: Address): int =
|
||||
len(distinctBase data)
|
||||
|
||||
func `$`*[minLen, maxLen](data: DynamicBytes[minLen, maxLen]): string =
|
||||
"0x" & byteutils.toHex(distinctBase(data))
|
||||
|
||||
func `$`*[N](data: FixedBytes[N]): string =
|
||||
"0x" & byteutils.toHex(distinctBase(data))
|
||||
|
||||
func `$`*(data: Address): string =
|
||||
"0x" & byteutils.toHex(distinctBase(data))
|
|
@ -1,6 +1,15 @@
|
|||
# nim-web3
|
||||
# Copyright (c) 2019-2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import
|
||||
options,
|
||||
ethtypes, stew/byteutils, stint,
|
||||
eth_api_types, stew/byteutils, stint,
|
||||
eth/[common, keys, rlp], eth/common/transaction
|
||||
|
||||
func signTransaction(tr: var Transaction, pk: PrivateKey) =
|
||||
|
@ -15,19 +24,16 @@ func signTransaction(tr: var Transaction, pk: PrivateKey) =
|
|||
|
||||
tr.V = int64(v) + 27 # TODO! Complete this
|
||||
|
||||
func encodeTransaction*(s: EthSend, pk: PrivateKey): string =
|
||||
func encodeTransaction*(s: EthSend, pk: PrivateKey): seq[byte] =
|
||||
var tr = Transaction(txType: TxLegacy)
|
||||
tr.gasLimit = GasInt(s.gas.get.uint64)
|
||||
tr.gasPrice = s.gasPrice.get
|
||||
tr.gasPrice = s.gasPrice.get.GasInt
|
||||
if s.to.isSome:
|
||||
tr.to = some(EthAddress(s.to.get))
|
||||
|
||||
if s.value.isSome:
|
||||
tr.value = s.value.get
|
||||
tr.nonce = uint64(s.nonce.get)
|
||||
# TODO: The following is a misdesign indication.
|
||||
# All the encodings should be done into seq[byte], not a hex string.
|
||||
if s.data.len != 0:
|
||||
tr.payload = hexToSeqByte(s.data)
|
||||
tr.payload = s.data
|
||||
signTransaction(tr, pk)
|
||||
return rlp.encode(tr).toHex
|
||||
return rlp.encode(tr)
|
||||
|
|
Loading…
Reference in New Issue