Allow contract calls to override the block tag

This commit is contained in:
Mark Spanbroek 2023-04-18 17:28:28 +02:00 committed by markspanbroek
parent 3c12a65769
commit 1ca90d0b3c
2 changed files with 35 additions and 12 deletions

View File

@ -16,13 +16,15 @@ type
provider: Provider provider: Provider
signer: ?Signer signer: ?Signer
address: Address address: Address
TransactionOverrides* = object TransactionOverrides* = ref object of RootObj
nonce*: ?UInt256 nonce*: ?UInt256
chainId*: ?UInt256 chainId*: ?UInt256
gasPrice*: ?UInt256 gasPrice*: ?UInt256
maxFee*: ?UInt256 maxFee*: ?UInt256
maxPriorityFee*: ?UInt256 maxPriorityFee*: ?UInt256
gasLimit*: ?UInt256 gasLimit*: ?UInt256
CallOverrides* = ref object of TransactionOverrides
blockTag*: ?BlockTag
ContractError* = object of EthersError ContractError* = object of EthersError
Confirmable* = ?TransactionResponse Confirmable* = ?TransactionResponse
@ -56,7 +58,7 @@ template raiseContractError(message: string) =
proc createTransaction(contract: Contract, proc createTransaction(contract: Contract,
function: string, function: string,
parameters: tuple, parameters: tuple,
overrides = TransactionOverrides.default): Transaction = overrides = TransactionOverrides()): Transaction =
let selector = selector(function, typeof parameters).toArray let selector = selector(function, typeof parameters).toArray
let data = @selector & AbiEncoder.encode(parameters) let data = @selector & AbiEncoder.encode(parameters)
Transaction( Transaction(
@ -78,27 +80,36 @@ proc decodeResponse(T: type, multiple: static bool, bytes: seq[byte]): T =
else: else:
return decodeResponse((T,), true, bytes)[0] return decodeResponse((T,), true, bytes)[0]
proc call(provider: Provider,
transaction: Transaction,
overrides: TransactionOverrides): Future[seq[byte]] =
if overrides of CallOverrides and
blockTag =? CallOverrides(overrides).blockTag:
provider.call(transaction, blockTag)
else:
provider.call(transaction)
proc call(contract: Contract, proc call(contract: Contract,
function: string, function: string,
parameters: tuple, parameters: tuple,
blockTag = BlockTag.latest) {.async.} = overrides = TransactionOverrides()) {.async.} =
let transaction = createTransaction(contract, function, parameters) let transaction = createTransaction(contract, function, parameters, overrides)
discard await contract.provider.call(transaction, blockTag) discard await contract.provider.call(transaction, overrides)
proc call(contract: Contract, proc call(contract: Contract,
function: string, function: string,
parameters: tuple, parameters: tuple,
ReturnType: type, ReturnType: type,
returnMultiple: static bool, returnMultiple: static bool,
blockTag = BlockTag.latest): Future[ReturnType] {.async.} = overrides = TransactionOverrides()): Future[ReturnType] {.async.} =
let transaction = createTransaction(contract, function, parameters) let transaction = createTransaction(contract, function, parameters, overrides)
let response = await contract.provider.call(transaction, blockTag) let response = await contract.provider.call(transaction, overrides)
return decodeResponse(ReturnType, returnMultiple, response) return decodeResponse(ReturnType, returnMultiple, response)
proc send(contract: Contract, proc send(contract: Contract,
function: string, function: string,
parameters: tuple, parameters: tuple,
overrides = TransactionOverrides.default): overrides = TransactionOverrides()):
Future[?TransactionResponse] {.async.} = Future[?TransactionResponse] {.async.} =
if signer =? contract.signer: if signer =? contract.signer:
let transaction = createTransaction(contract, function, parameters, overrides) let transaction = createTransaction(contract, function, parameters, overrides)
@ -136,7 +147,7 @@ func addOverrides(procedure: var NimNode) =
newIdentDefs( newIdentDefs(
ident("overrides"), ident("overrides"),
newEmptyNode(), newEmptyNode(),
quote do: TransactionOverrides.default quote do: TransactionOverrides()
) )
) )
@ -152,11 +163,11 @@ func addContractCall(procedure: var NimNode) =
func call: NimNode = func call: NimNode =
if returnType.kind == nnkEmpty: if returnType.kind == nnkEmpty:
quote: quote:
await call(`contract`, `function`, `parameters`) await call(`contract`, `function`, `parameters`, overrides)
else: else:
quote: quote:
return await call( return await call(
`contract`, `function`, `parameters`, `returnType`, `returnMultiple`) `contract`, `function`, `parameters`, `returnType`, `returnMultiple`, overrides)
func send: NimNode = func send: NimNode =
if returnType.kind == nnkEmpty: if returnType.kind == nnkEmpty:

View File

@ -116,6 +116,18 @@ suite "Contracts":
check signer.transactions[0].gasPrice == overrides.gasPrice check signer.transactions[0].gasPrice == overrides.gasPrice
check signer.transactions[0].gasLimit == overrides.gasLimit check signer.transactions[0].gasLimit == overrides.gasLimit
test "can call functions for different block heights":
let block1 = await provider.getBlockNumber()
let signer = provider.getSigner(accounts[0])
discard await token.connect(signer).mint(accounts[0], 100.u256)
let block2 = await provider.getBlockNumber()
let beforeMint = CallOverrides(blockTag: some BlockTag.init(block1))
let afterMint = CallOverrides(blockTag: some BlockTag.init(block2))
check (await token.balanceOf(accounts[0], beforeMint)) == 0
check (await token.balanceOf(accounts[0], afterMint)) == 100
test "receives events when subscribed": test "receives events when subscribed":
var transfers: seq[Transfer] var transfers: seq[Transfer]