nim-ethers/ethers/contracts/transactions.nim
2025-04-15 10:45:52 +02:00

72 lines
2.6 KiB
Nim

import pkg/contractabi
import pkg/chronicles
import ../basics
import ../provider
import ../signer
import ../transaction
import ./contract
import ./contractcall
import ./overrides
{.push raises: [].}
logScope:
topics = "ethers contract"
proc createTransaction*(call: ContractCall): Transaction =
let selector = selector(call.function, typeof call.arguments).toArray
let data = @selector & AbiEncoder.encode(call.arguments)
Transaction(
to: call.contract.address,
data: data,
nonce: call.overrides.nonce,
chainId: call.overrides.chainId,
gasPrice: call.overrides.gasPrice,
maxFee: call.overrides.maxFee,
maxPriorityFee: call.overrides.maxPriorityFee,
gasLimit: call.overrides.gasLimit,
)
proc decodeResponse(T: type, bytes: seq[byte]): T {.raises: [ContractError].} =
without decoded =? AbiDecoder.decode(bytes, T):
raise newException(ContractError, "unable to decode return value as " & $T)
return decoded
proc call(
provider: Provider, transaction: Transaction, overrides: TransactionOverrides
): Future[seq[byte]] {.async: (raises: [ProviderError, CancelledError]).} =
if overrides of CallOverrides and blockTag =? CallOverrides(overrides).blockTag:
await provider.call(transaction, blockTag)
else:
await provider.call(transaction)
proc callTransaction*(call: ContractCall) {.async: (raises: [ProviderError, SignerError, CancelledError]).} =
var transaction = createTransaction(call)
if signer =? call.contract.signer and transaction.sender.isNone:
transaction.sender = some(await signer.getAddress())
discard await call.contract.provider.call(transaction, call.overrides)
proc callTransaction*(call: ContractCall, ReturnType: type): Future[ReturnType] {.async: (raises: [ProviderError, SignerError, ContractError, CancelledError]).} =
var transaction = createTransaction(call)
if signer =? call.contract.signer and transaction.sender.isNone:
transaction.sender = some(await signer.getAddress())
let response = await call.contract.provider.call(transaction, call.overrides)
return decodeResponse(ReturnType, response)
proc sendTransaction*(call: ContractCall): Future[?TransactionResponse] {.async: (raises: [SignerError, ProviderError, CancelledError]).} =
if signer =? call.contract.signer:
withLock(signer):
let transaction = createTransaction(call)
let populated = await signer.populateTransaction(transaction)
trace "sending contract transaction", function = call.function, params = $call.arguments
let txResp = await signer.sendTransaction(populated)
return txResp.some
else:
await callTransaction(call)
return TransactionResponse.none