Remove auto-cancellation of failed tx, change revert reason level

- remove auto cancellation of failed tx (during estimate gas)
- add asynclock to populate transaction, to ensure nonce sequence (signer level)
- move checking of receipt status and obtaining revert reason from contract level to provider level
This commit is contained in:
Eric 2023-10-20 13:52:36 +11:00
parent 06dc6c4d65
commit 21de34ced9
No known key found for this signature in database
2 changed files with 28 additions and 20 deletions

View File

@ -250,31 +250,13 @@ proc confirm*(tx: Future[?TransactionResponse],
## `await token.connect(signer0)
## .mint(accounts[1], 100.u256)
## .confirm(3)`
## Will raise ContractError with revert reason if TransactionReceipt.Status
## is Failed
without response =? (await tx):
raise newException(
EthersError,
"Transaction hash required. Possibly was a call instead of a send?"
)
let receipt = await response.confirm(confirmations, timeout)
# TODO: handle TransactionStatus.Invalid?
if receipt.status == TransactionStatus.Failure:
logScope:
transactionHash = receipt.transactionHash.to0xHex
trace "transaction failed, replaying transaction to get revert reason"
if revertReason =? await response.provider.getRevertReason(receipt):
trace "transaction revert reason obtained", revertReason
raiseContractError(revertReason)
else:
trace "transaction replay completed, no revert reason obtained"
raiseContractError("Transaction reverted with unknown reason")
return receipt
return await response.confirm(confirmations, timeout)
proc queryFilter[E: Event](contract: Contract,
_: type E,

View File

@ -81,6 +81,9 @@ const EthersReceiptTimeoutBlks* {.intdefine.} = 50 # in blocks
logScope:
topics = "ethers provider"
template raiseProviderError(msg: string) =
raise newException(ProviderError, msg)
func toTransaction*(past: PastTransaction): Transaction =
Transaction(
sender: some past.sender,
@ -194,11 +197,33 @@ method getRevertReason*(
return await provider.getRevertReason(receipt.transactionHash, blockNumber - 1)
proc ensureSuccess(
provider: Provider,
receipt: TransactionReceipt
) {.async, upraises: [ProviderError].} =
## If the receipt.status is Failed, the tx is replayed to obtain a revert
## reason, after which a ProviderError with the revert reason is raised.
## If no revert reason was obtained
# TODO: handle TransactionStatus.Invalid?
if receipt.status == TransactionStatus.Failure:
logScope:
transactionHash = receipt.transactionHash.to0xHex
trace "transaction failed, replaying transaction to get revert reason"
if revertReason =? await provider.getRevertReason(receipt):
trace "transaction revert reason obtained", revertReason
raiseProviderError(revertReason)
else:
trace "transaction replay completed, no revert reason obtained"
raiseProviderError("Transaction reverted with unknown reason")
proc confirm*(tx: TransactionResponse,
confirmations = EthersDefaultConfirmations,
timeout = EthersReceiptTimeoutBlks):
Future[TransactionReceipt]
{.async, upraises: [EthersError].} =
{.async, upraises: [ProviderError, EthersError].} =
## Waits for a transaction to be mined and for the specified number of blocks
## to pass since it was mined (confirmations).
## A timeout, in blocks, can be specified that will raise an error if too many
@ -237,6 +262,7 @@ proc confirm*(tx: TransactionResponse,
if txBlockNumber + confirmations.u256 <= blockNumber + 1:
await subscription.unsubscribe()
await tx.provider.ensureSuccess(receipt)
return receipt
proc confirm*(tx: Future[TransactionResponse],