diff --git a/src/Utils/AbiDecoder.php b/src/Utils/AbiDecoder.php index f0efc1f..b8a97f3 100644 --- a/src/Utils/AbiDecoder.php +++ b/src/Utils/AbiDecoder.php @@ -28,6 +28,20 @@ public function decodeFunctionData(string $data): array ]; } + public function decodeError(string $data): string + { + $data = $this->stripHexPrefix($data); + + $errorSelector = substr($data, 0, 8); + + $abiItem = $this->findErrorBySelector($errorSelector); + if (! $abiItem) { + throw new Exception('Function selector not found in ABI: '.$errorSelector); + } + + return $abiItem['name']; + } + public static function decodeAddress(string $bytes, int $offset): array { $data = substr($bytes, $offset, 32); @@ -152,12 +166,31 @@ public static function decodeFunctionWithAbi(string $functionSignature, string $ private function findFunctionBySelector(string $selector): ?array { foreach ($this->abi as $item) { - if ($item['type'] === 'function') { - $functionSignature = $this->getFunctionSignature($item); - $functionSelector = substr($this->keccak256($functionSignature), 2, 8); - if ($functionSelector === $selector) { - return $item; - } + if ($item['type'] !== 'function') { + continue; + } + + $functionSignature = $this->getFunctionSignature($item); + $functionSelector = substr($this->keccak256($functionSignature), 2, 8); + if ($functionSelector === $selector) { + return $item; + } + } + + return null; + } + + private function findErrorBySelector(string $selector): ?array + { + foreach ($this->abi as $item) { + if ($item['type'] !== 'error') { + continue; + } + + $errorSignature = $this->getFunctionSignature($item); + $errorSelector = substr($this->keccak256($errorSignature), 2, 8); + if ($errorSelector === $selector) { + return $item; } } diff --git a/tests/Unit/Utils/AbiDecoderTest.php b/tests/Unit/Utils/AbiDecoderTest.php index 7e6330d..2868dc3 100644 --- a/tests/Unit/Utils/AbiDecoderTest.php +++ b/tests/Unit/Utils/AbiDecoderTest.php @@ -359,3 +359,17 @@ $param, ]); })->throws(Exception::class, 'Unsupported type: testing'); + +test('should decode error payload', function () { + $decoder = new AbiDecoder(); + + $decodedData = $decoder->decodeError('cd03235e'); + + expect($decodedData)->toBe('CallerIsNotValidator'); +}); + +test('should throw exception if error payload does not exist', function () { + $decoder = new AbiDecoder(); + + $decoder->decodeError('123456'); +})->throws(Exception::class, 'Function selector not found in ABI: 123456');