From 6b57e56a3932d5e7bdef4e7254cad8c247e76b9e Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Tue, 19 Mar 2024 09:39:32 +0100 Subject: [PATCH] abi decoding of simple custom errors Only supports errors without arguments for now --- ethers/errors.nim | 17 +++++++++++++++++ testmodule/test.nim | 1 + testmodule/testErrorDecoding.nim | 30 ++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 ethers/errors.nim create mode 100644 testmodule/testErrorDecoding.nim diff --git a/ethers/errors.nim b/ethers/errors.nim new file mode 100644 index 0000000..508e485 --- /dev/null +++ b/ethers/errors.nim @@ -0,0 +1,17 @@ +import pkg/contractabi/selector +import ./basics + +type SolidityError* = object of EthersError + +{.push raises:[].} + +template errors*(types) {.pragma.} + +func decode*[E: SolidityError](_: type E, data: seq[byte]): ?!(ref E) = + const name = $E + const selector = selector(name, typeof(())) + if data.len < 4: + return failure "unable to decode " & name & ": signature too short" + if selector.toArray[0..<4] != data[0..<4]: + return failure "unable to decode " & name & ": signature doesn't match" + success (ref E)() diff --git a/testmodule/test.nim b/testmodule/test.nim index eb8b23a..854579b 100644 --- a/testmodule/test.nim +++ b/testmodule/test.nim @@ -7,5 +7,6 @@ import ./testWallet import ./testTesting import ./testErc20 import ./testGasEstimation +import ./testErrorDecoding {.warning[UnusedImport]:off.} diff --git a/testmodule/testErrorDecoding.nim b/testmodule/testErrorDecoding.nim new file mode 100644 index 0000000..fa1d67f --- /dev/null +++ b/testmodule/testErrorDecoding.nim @@ -0,0 +1,30 @@ +import std/unittest +import pkg/questionable/results +import pkg/ethers/errors + +suite "Decoding of custom errors": + + type SimpleError = object of SolidityError + + test "decodes a simple error": + let decoded = SimpleError.decode(@[0xc2'u8, 0xbb, 0x94, 0x7c]) + check decoded is ?!(ref SimpleError) + check decoded.isSuccess + check (!decoded) != nil + + test "returns failure when decoding fails": + let invalid = @[0xc2'u8, 0xbb, 0x94, 0x0] # last byte is wrong + let decoded = SimpleError.decode(invalid) + check decoded.isFailure + + test "returns failure when data is less than 4 bytes": + let invalid = @[0xc2'u8, 0xbb, 0x94] + let decoded = SimpleError.decode(invalid) + check decoded.isFailure + + test "decoding only works for SolidityErrors": + type InvalidError = ref object of CatchableError + const works = compiles: + InvalidError.decode(@[0x1'u8, 0x2, 0x3, 0x4]) + check not works +