Skip to content

Commit

Permalink
Add abi.decodeData
Browse files Browse the repository at this point in the history
  • Loading branch information
danhper committed Sep 20, 2024
1 parent 5395097 commit 0f7960f
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Add `repl.fork` to start run and use an Anvil instance as a fork of the current URL
* Add `repl.startPrank` / `repl.stopPrank` to start/stop impersonating an address
* Add `FUNC.trace_call` method to contract functions
* Add `abi.decodeData` to decode function calldata and errors from any known ABI

### Other changes

Expand Down
9 changes: 9 additions & 0 deletions docs/src/builtin_values.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,15 @@ Behaves like the regular Solidity `abi.decode` function.
(1, 0x789f8F7B547183Ab8E99A5e0E6D567E90e0EB03B)
```

### `abi.decodeData(bytes data) -> any`

Decodes the data (either function calldata or error data) using any registered ABI.

```javascript
>> abi.decodeData(0xa9059cbb000000000000000000000000789f8f7b547183ab8e99a5e0e6d567e90e0eb03b0000000000000000000000000000000000000000000000000de0b6b3a7640000)
("transfer(address,uint256)", (0x789f8F7B547183Ab8E99A5e0E6D567E90e0EB03B, 1000000000000000000))
```

## `block` functions

### `block.number -> uint256`
Expand Down
48 changes: 38 additions & 10 deletions src/interpreter/builtins/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ impl Decodable for json_abi::Error {
}
}

fn _run_decode(signature: String, decoded: Vec<DynSolValue>) -> Result<Value> {
let values = decoded
.into_iter()
.map(Value::try_from)
.collect::<Result<Vec<_>>>()?;
Ok(Value::Tuple(vec![
Value::Str(signature),
Value::Tuple(values),
]))
}

fn _generic_abi_decode<D: Decodable, F>(
receiver: &Value,
args: &[Value],
Expand All @@ -55,7 +66,7 @@ where
};
let selector = alloy::primitives::FixedBytes::<4>::from_slice(&data[..4]);
let options = get_options(abi);
let error = options
let decodable = options
.iter()
.find(|f| f.selector() == selector)
.ok_or(anyhow!(
Expand All @@ -64,15 +75,27 @@ where
selector,
name
))?;
let decoded = error.abi_decode_input(&data[4..], true)?;
let values = decoded
.into_iter()
.map(Value::try_from)
.collect::<Result<Vec<_>>>()?;
Ok(Value::Tuple(vec![
Value::Str(error.signature()),
Value::Tuple(values),
]))
let decoded = decodable.abi_decode_input(&data[4..], true)?;
_run_decode(decodable.signature(), decoded)
}

fn abi_decode_data(env: &mut Env, _receiver: &Value, args: &[Value]) -> Result<Value> {
let data = match args.first() {
Some(Value::Bytes(bytes)) => bytes,
_ => bail!("abi.decodeData expects bytes as argument"),
};
if data.len() < 4 {
bail!("abi.decodeData expects at least 4 bytes");
}
let selector = alloy::primitives::FixedBytes::<4>::from_slice(&data[..4]);
let (signature, decoded) = if let Some(func) = env.get_function(&selector) {
(func.signature(), func.abi_decode_input(&data[4..], true)?)
} else if let Some(error) = env.get_error(&selector) {
(error.signature(), error.abi_decode_input(&data[4..], true)?)
} else {
bail!("function or error with selector {} not found", selector);
};
_run_decode(signature, decoded)
}

fn abi_decode_calldata(_env: &mut Env, receiver: &Value, args: &[Value]) -> Result<Value> {
Expand Down Expand Up @@ -142,6 +165,11 @@ lazy_static! {
SyncMethod::arc("encodePacked", abi_encode_packed_, vec![]);
pub static ref ABI_DECODE: Arc<dyn FunctionDef> =
SyncMethod::arc("decode", abi_decode_, vec![]);
pub static ref ABI_DECODE_DATA: Arc<dyn FunctionDef> = SyncMethod::arc(
"decodeData",
abi_decode_data,
vec![vec![FunctionParam::new("data", Type::Bytes)]]
);
pub static ref ABI_DECODE_CALLDATA: Arc<dyn FunctionDef> = SyncMethod::arc(
"decode",
abi_decode_calldata,
Expand Down
1 change: 1 addition & 0 deletions src/interpreter/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ lazy_static! {
abi_methods.insert("encode".to_string(), abi::ABI_ENCODE.clone());
abi_methods.insert("encodePacked".to_string(), abi::ABI_ENCODE_PACKED.clone());
abi_methods.insert("decode".to_string(), abi::ABI_DECODE.clone());
abi_methods.insert("decodeData".to_string(), abi::ABI_DECODE_DATA.clone());
m.insert(NonParametricType::Abi, abi_methods);

let mut block_methods = HashMap::new();
Expand Down

0 comments on commit 0f7960f

Please sign in to comment.