Skip to content

Commit 7c83e4f

Browse files
committed
feat: decode abi error payloads
1 parent 7f7f63e commit 7c83e4f

2 files changed

Lines changed: 74 additions & 7 deletions

File tree

‎src/main/java/org/arkecosystem/crypto/utils/AbiDecoder.java‎

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,44 @@ public Map<String, Object> decodeFunctionData(String data) throws Exception {
3333
return result;
3434
}
3535

36+
public String decodeError(String data) throws Exception {
37+
data = stripHexPrefix(data);
38+
39+
String errorSelector = data.substring(0, 8);
40+
41+
Map<String, Object> abiItem = findErrorBySelector(errorSelector);
42+
if (abiItem == null) {
43+
throw new Exception("Function selector not found in ABI: " + errorSelector);
44+
}
45+
46+
return (String) abiItem.get("name");
47+
}
48+
3649
private Map<String, Object> findFunctionBySelector(String selector) {
3750
for (Map<String, Object> item : this.abi) {
38-
if ("function".equals(item.get("type"))) {
39-
String functionSignature = getFunctionSignature(item);
40-
String functionSelector =
41-
stripHexPrefix(keccak256(functionSignature)).substring(0, 8);
42-
if (functionSelector.equals(selector)) {
43-
return item;
44-
}
51+
if (!"function".equals(item.get("type"))) {
52+
continue;
53+
}
54+
55+
String functionSignature = getFunctionSignature(item);
56+
String functionSelector = stripHexPrefix(keccak256(functionSignature)).substring(0, 8);
57+
if (functionSelector.equals(selector)) {
58+
return item;
59+
}
60+
}
61+
return null;
62+
}
63+
64+
private Map<String, Object> findErrorBySelector(String selector) {
65+
for (Map<String, Object> item : this.abi) {
66+
if (!"error".equals(item.get("type"))) {
67+
continue;
68+
}
69+
70+
String errorSignature = getFunctionSignature(item);
71+
String errorSelector = stripHexPrefix(keccak256(errorSignature)).substring(0, 8);
72+
if (errorSelector.equals(selector)) {
73+
return item;
4574
}
4675
}
4776
return null;

‎src/test/java/org/arkecosystem/crypto/utils/AbiDecoderTest.java‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,4 +191,42 @@ void it_should_decode_vote_payload() throws Exception {
191191

192192
assertEquals(expectedData, decodedData);
193193
}
194+
195+
@Test
196+
void it_should_decode_error_payload() throws Exception {
197+
assertEquals("CallerIsNotValidator", decoder.decodeError("cd03235e"));
198+
}
199+
200+
@Test
201+
void it_should_decode_error_payload_with_hex_prefix() throws Exception {
202+
assertEquals("CallerIsNotValidator", decoder.decodeError("0xcd03235e"));
203+
}
204+
205+
@Test
206+
void it_should_decode_error_with_parameters() throws Exception {
207+
String selector = stripSelector("InvalidRange(uint256,uint256)");
208+
209+
assertEquals("InvalidRange", decoder.decodeError(selector));
210+
}
211+
212+
@Test
213+
void it_should_throw_when_error_selector_is_not_found() {
214+
Exception thrown = assertThrows(Exception.class, () -> decoder.decodeError("123456ab"));
215+
216+
assertEquals("Function selector not found in ABI: 123456ab", thrown.getMessage());
217+
}
218+
219+
@Test
220+
void it_should_not_decode_function_selectors_as_errors() {
221+
String voteSelector = "6dd7d8ea";
222+
223+
Exception thrown = assertThrows(Exception.class, () -> decoder.decodeError(voteSelector));
224+
225+
assertEquals("Function selector not found in ABI: " + voteSelector, thrown.getMessage());
226+
}
227+
228+
private String stripSelector(String signature) {
229+
String hash = org.web3j.crypto.Hash.sha3String(signature);
230+
return hash.startsWith("0x") ? hash.substring(2, 10) : hash.substring(0, 8);
231+
}
194232
}

0 commit comments

Comments
 (0)