Last active
August 8, 2023 21:34
-
-
Save darkerego/bb1b0660e724e181100c34b7cdb84154 to your computer and use it in GitHub Desktop.
Solidity Assembly Call & Get Return Data / Revert with Reason
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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