Skip to content

Instantly share code, notes, and snippets.

@darkerego
Last active August 8, 2023 21:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darkerego/bb1b0660e724e181100c34b7cdb84154 to your computer and use it in GitHub Desktop.
Save darkerego/bb1b0660e724e181100c34b7cdb84154 to your computer and use it in GitHub Desktop.
Solidity Assembly Call & Get Return Data / Revert with Reason
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2
contract TestExec {
address owner;
constructor() {
owner = msg.sender;
}
modifier auth {
require(msg.sender == owner, "Unauthorized");
_;
}
function transfer(address token, address dest, uint value) public returns(bytes32) {
//(bool success, bytes memory retData) = token.call(getTransfer(dest, value));
bytes32(execute(token, 0, getTransfer(dest, value)));
}
function getTransfer(address dest, uint256 amount) public pure returns(bytes memory){
return abi.encodeWithSignature(
"transfer(address,uint256)",
dest,
amount
);
}
function parseRetdata(bytes memory _returnData) internal pure returns (string memory) {
assembly {
// Slice the sighash.
_returnData := add(_returnData, 0x04)
}
return abi.decode(_returnData, (string));
}
function _getRevertMsg(bytes memory _returnData) internal pure returns (string memory) {
// If the _res length is less than 68, then the transaction failed silently (without a revert message)
if (_returnData.length < 68) return 'Transaction reverted silently';
assembly {
// Slice the sighash.
_returnData := add(_returnData, 0x04)
}
return abi.decode(_returnData, (string)); // All that remains is the revert string
}
function execute(
/*
@dev: Function to execute a transaction with arbitrary parameters. Handles
all withdrawals, etc. Can be used for token transfers, eth transfers,
or anything else.
*/
address recipient,
uint256 _value,
bytes memory data
) private returns(bytes memory) {
assembly {
let ptr := mload(0x40)
let success_ := call(gas(), recipient, _value, add(data, 0x20), mload(data), 0x00, 0x00)
let success := eq(success_, 0x1)
let retSz := returndatasize()
let retData := mload(0x40)
returndatacopy(mload(0x40), 0 , returndatasize())
if iszero(success) {
revert(retData, retSz)}
// return the result from memory
return(retData, retSz)
}
}
function testTransfer(address recipient, uint amount) public auth {
bytes memory data = getTransfer(recipient, amount);
execute(recipient, 0, data);
}
function arbitraryCall(address recipient, uint _value, bytes memory data) public auth {
execute(recipient, _value, data);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment