Allow for gas estimation of contract calls

This commit is contained in:
Mark Spanbroek 2025-04-09 15:03:38 +02:00 committed by markspanbroek
parent def12bfdc1
commit e37f454761
3 changed files with 61 additions and 3 deletions

View File

@ -5,6 +5,7 @@ import ./contracts/confirmation
import ./contracts/events
import ./contracts/filters
import ./contracts/syntax
import ./contracts/gas
import ./contracts/function
export contract
@ -16,6 +17,7 @@ export syntax.view
export syntax.pure
export syntax.getter
export syntax.errors
export gas.estimateGas
{.push raises: [].}
@ -23,4 +25,7 @@ macro contract*(procedure: untyped{nkProcDef | nkMethodDef}): untyped =
procedure.params.expectMinLen(2) # at least return type and contract instance
procedure.body.expectKind(nnkEmpty)
createContractFunction(procedure)
newStmtList(
createContractFunction(procedure),
createGasEstimationCall(procedure)
)

45
ethers/contracts/gas.nim Normal file
View File

@ -0,0 +1,45 @@
import std/macros
import ../basics
import ../provider
import ../signer
import ./contract
import ./contractcall
import ./transactions
import ./syntax
type ContractGasEstimations[C] = distinct C
func estimateGas*[C: Contract](contract: C): ContractGasEstimations[C] =
ContractGasEstimations[C](contract)
proc estimateGas(
call: ContractCall
): Future[UInt256] {.async: (raises: [CancelledError, ProviderError, EthersError]).} =
var transaction = createTransaction(call)
if signer =? call.contract.signer:
await signer.estimateGas(transaction)
else:
await call.contract.provider.estimateGas(transaction)
func wrapFirstParameter(procedure: var NimNode) =
let contractType = procedure.params[1][1]
let gasEstimationsType = quote do: ContractGasEstimations[`contractType`]
procedure.params[1][1] = gasEstimationsType
func setReturnType(procedure: var NimNode) =
procedure.params[0] = quote do: Future[UInt256]
func addEstimateCall(procedure: var NimNode) =
let contractCall = getContractCall(procedure)
procedure.body = quote do:
return await estimateGas(`contractCall`)
func createGasEstimationCall*(procedure: NimNode): NimNode =
result = copyNimTree(procedure)
result.wrapFirstParameter()
result.addOverridesParameter()
result.setReturnType()
result.addAsyncPragma()
result.addUsedPragma()
result.addEstimateCall()

View File

@ -64,7 +64,7 @@ for url in ["ws://" & providerUrl, "http://" & providerUrl]:
test "can call constant functions without a return type":
token = TestToken.new(token.address, provider.getSigner())
proc mint(token: TestToken, holder: Address, amount: UInt256) {.contract, view.}
await mint(token, accounts[1], 100.u256)
await token.mint(accounts[1], 100.u256)
check (await balanceOf(token, accounts[1])) == 0.u256
test "can call non-constant functions without a return type":
@ -74,7 +74,6 @@ for url in ["ws://" & providerUrl, "http://" & providerUrl]:
check (await balanceOf(token, accounts[1])) == 100.u256
test "can call non-constant functions with a Confirmable return type":
token = TestToken.new(token.address, provider.getSigner())
proc mint(token: TestToken,
holder: Address,
@ -146,6 +145,15 @@ for url in ["ws://" & providerUrl, "http://" & providerUrl]:
discard await token.transfer(accounts[1], 50.u256, beforeMint)
discard await token.transfer(accounts[1], 50.u256, afterMint)
test "can estimate gas of a function call":
proc mint(token: TestToken, holder: Address, amount: UInt256) {.contract.}
let estimate = await token.estimateGas.mint(accounts[1], 100.u256)
let correctGas = TransactionOverrides(gasLimit: some estimate)
await token.mint(accounts[1], 100.u256, correctGas)
let invalidGas = TransactionOverrides(gasLimit: some (estimate - 1))
expect ProviderError:
await token.mint(accounts[1], 100.u256, invalidGas)
test "receives events when subscribed":
var transfers: seq[Transfer]