2024-03-19 14:27:51 +00:00
|
|
|
import std/json
|
|
|
|
import pkg/asynctest
|
|
|
|
import pkg/ethers
|
|
|
|
import ./hardhat
|
|
|
|
|
|
|
|
suite "Contract custom errors":
|
|
|
|
|
|
|
|
type
|
|
|
|
TestCustomErrors = ref object of Contract
|
|
|
|
SimpleError = object of SolidityError
|
2024-03-20 10:24:53 +00:00
|
|
|
ErrorWithArguments = object of SolidityError
|
|
|
|
arguments: tuple[one: UInt256, two: bool]
|
2024-03-20 10:40:59 +00:00
|
|
|
ErrorWithStaticStruct = object of SolidityError
|
|
|
|
arguments: tuple[one: Static, two: Static]
|
|
|
|
ErrorWithDynamicStruct = object of SolidityError
|
|
|
|
arguments: tuple[one: Dynamic, two: Dynamic]
|
|
|
|
ErrorWithDynamicAndStaticStruct = object of SolidityError
|
|
|
|
arguments: tuple[one: Dynamic, two: Static]
|
|
|
|
Static = (UInt256, UInt256)
|
|
|
|
Dynamic = (string, UInt256)
|
2024-03-19 14:27:51 +00:00
|
|
|
|
|
|
|
var contract: TestCustomErrors
|
|
|
|
var provider: JsonRpcProvider
|
|
|
|
var snapshot: JsonNode
|
|
|
|
|
|
|
|
setup:
|
|
|
|
provider = JsonRpcProvider.new()
|
|
|
|
snapshot = await provider.send("evm_snapshot")
|
|
|
|
let deployment = readDeployment()
|
|
|
|
let address = !deployment.address(TestCustomErrors)
|
|
|
|
contract = TestCustomErrors.new(address, provider)
|
|
|
|
|
|
|
|
teardown:
|
|
|
|
discard await provider.send("evm_revert", @[snapshot])
|
|
|
|
await provider.close()
|
|
|
|
|
|
|
|
test "handles simple errors":
|
|
|
|
proc revertsSimpleError(contract: TestCustomErrors)
|
|
|
|
{.contract, pure, errors:[SimpleError].}
|
|
|
|
|
|
|
|
expect SimpleError:
|
|
|
|
await contract.revertsSimpleError()
|
2024-03-20 10:24:53 +00:00
|
|
|
|
|
|
|
test "handles error with arguments":
|
|
|
|
proc revertsErrorWithArguments(contract: TestCustomErrors)
|
|
|
|
{.contract, pure, errors:[ErrorWithArguments].}
|
|
|
|
|
|
|
|
try:
|
|
|
|
await contract.revertsErrorWithArguments()
|
|
|
|
fail()
|
|
|
|
except ErrorWithArguments as error:
|
|
|
|
check error.arguments.one == 1
|
|
|
|
check error.arguments.two == true
|
2024-03-20 10:40:59 +00:00
|
|
|
|
|
|
|
test "handles error with static struct arguments":
|
|
|
|
proc revertsErrorWithStaticStruct(contract: TestCustomErrors)
|
|
|
|
{.contract, pure, errors:[ErrorWithStaticStruct].}
|
|
|
|
|
|
|
|
try:
|
|
|
|
await contract.revertsErrorWithStaticStruct()
|
|
|
|
fail()
|
|
|
|
except ErrorWithStaticStruct as error:
|
|
|
|
check error.arguments.one == (1.u256, 2.u256)
|
|
|
|
check error.arguments.two == (3.u256, 4.u256)
|
|
|
|
|
|
|
|
test "handles error with dynamic struct arguments":
|
|
|
|
proc revertsErrorWithDynamicStruct(contract: TestCustomErrors)
|
|
|
|
{.contract, pure, errors:[ErrorWithDynamicStruct].}
|
|
|
|
|
|
|
|
try:
|
|
|
|
await contract.revertsErrorWithDynamicStruct()
|
|
|
|
fail()
|
|
|
|
except ErrorWithDynamicStruct as error:
|
|
|
|
check error.arguments.one == ("1", 2.u256)
|
|
|
|
check error.arguments.two == ("3", 4.u256)
|
|
|
|
|
|
|
|
test "handles error with dynamic and static struct arguments":
|
|
|
|
proc revertsErrorWithDynamicAndStaticStruct(contract: TestCustomErrors)
|
|
|
|
{.contract, pure, errors:[ErrorWithDynamicAndStaticStruct].}
|
|
|
|
|
|
|
|
try:
|
|
|
|
await contract.revertsErrorWithDynamicAndStaticStruct()
|
|
|
|
fail()
|
|
|
|
except ErrorWithDynamicAndStaticStruct as error:
|
|
|
|
check error.arguments.one == ("1", 2.u256)
|
|
|
|
check error.arguments.two == (3.u256, 4.u256)
|
2024-03-21 07:21:12 +00:00
|
|
|
|
2024-05-15 11:43:42 +00:00
|
|
|
test "handles multiple error types":
|
|
|
|
proc revertsMultipleErrors(contract: TestCustomErrors, simple: bool)
|
|
|
|
{.contract, errors:[SimpleError, ErrorWithArguments].}
|
|
|
|
|
|
|
|
let contract = contract.connect(provider.getSigner())
|
|
|
|
expect SimpleError:
|
|
|
|
await contract.revertsMultipleErrors(simple = true)
|
|
|
|
expect ErrorWithArguments:
|
|
|
|
await contract.revertsMultipleErrors(simple = false)
|
|
|
|
|
2024-03-21 07:21:12 +00:00
|
|
|
test "handles gas estimation errors":
|
|
|
|
proc revertsTransaction(contract: TestCustomErrors)
|
|
|
|
{.contract, errors:[ErrorWithArguments].}
|
|
|
|
|
|
|
|
let contract = contract.connect(provider.getSigner())
|
|
|
|
try:
|
|
|
|
await contract.revertsTransaction()
|
|
|
|
fail()
|
|
|
|
except ErrorWithArguments as error:
|
|
|
|
check error.arguments.one == 1.u256
|
|
|
|
check error.arguments.two == true
|
|
|
|
|
|
|
|
test "handles transaction submission errors":
|
|
|
|
proc revertsTransaction(contract: TestCustomErrors)
|
|
|
|
{.contract, errors:[ErrorWithArguments].}
|
|
|
|
|
|
|
|
# skip gas estimation
|
|
|
|
let overrides = TransactionOverrides(gasLimit: some 1000000.u256)
|
|
|
|
|
|
|
|
let contract = contract.connect(provider.getSigner())
|
|
|
|
try:
|
|
|
|
await contract.revertsTransaction(overrides = overrides)
|
|
|
|
fail()
|
|
|
|
except ErrorWithArguments as error:
|
|
|
|
check error.arguments.one == 1.u256
|
|
|
|
check error.arguments.two == true
|
2024-03-21 08:32:15 +00:00
|
|
|
|
|
|
|
test "handles transaction confirmation errors":
|
2024-05-14 09:00:45 +00:00
|
|
|
proc revertsTransaction(contract: TestCustomErrors): Confirmable
|
2024-03-21 08:32:15 +00:00
|
|
|
{.contract, errors:[ErrorWithArguments].}
|
|
|
|
|
|
|
|
# skip gas estimation
|
|
|
|
let overrides = TransactionOverrides(gasLimit: some 1000000.u256)
|
|
|
|
|
|
|
|
# ensure that transaction is not immediately checked by hardhat
|
|
|
|
discard await provider.send("evm_setAutomine", @[%false])
|
|
|
|
|
|
|
|
let contract = contract.connect(provider.getSigner())
|
|
|
|
try:
|
|
|
|
let future = contract.revertsTransaction(overrides = overrides).confirm(0)
|
|
|
|
await sleepAsync(100.millis) # wait for transaction to be submitted
|
|
|
|
discard await provider.send("evm_mine", @[]) # mine the transaction
|
|
|
|
discard await future # wait for confirmation
|
|
|
|
fail()
|
|
|
|
except ErrorWithArguments as error:
|
|
|
|
check error.arguments.one == 1.u256
|
|
|
|
check error.arguments.two == true
|
|
|
|
|
|
|
|
# re-enable auto mining
|
|
|
|
discard await provider.send("evm_setAutomine", @[%true])
|