Address Contract Verified
Address
0x0000000a3Fc396B89e4c11841B39D9dff85a5D05
Balance
0 ETH
Nonce
1
Code Size
4706 bytes
Creator
0x00000000...9497 at tx 0xa6435c9d...66c9f4
Indexed Transactions
1 (24,445,529 → 24,445,529)
Gas Used (indexed)
909,725
Contract Bytecode
4706 bytes
0x60806040526004361061008a5760003560e01c80638070c503116100595780638070c5031461012a578063b7c58d7a1461014a578063babcc5391461016a578063d38bfff4146101aa578063de792d5f146101ca57600080fd5b806308af4d8814610096578063238efcbc146100b857806326f91506146100cd5780635aa6e675146100ed57600080fd5b3661009157005b600080fd5b3480156100a257600080fd5b506100b66100b1366004610d35565b6101f7565b005b3480156100c457600080fd5b506100b6610246565b3480156100d957600080fd5b506100b66100e8366004610d9c565b6102af565b3480156100f957600080fd5b5060005461010d906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561013657600080fd5b5060015461010d906001600160a01b031681565b34801561015657600080fd5b506100b6610165366004610d35565b6103c6565b34801561017657600080fd5b5061019a610185366004610d35565b60026020526000908152604090205460ff1681565b6040519015158152602001610121565b3480156101b657600080fd5b506100b66101c5366004610d35565b610412565b3480156101d657600080fd5b506101ea6101e5366004610eb0565b610487565b604051610121919061101d565b6000546001600160a01b03163314610222576040516305189e0d60e21b815260040160405180910390fd5b6001600160a01b03166000908152600260205260409020805460ff19166001179055565b6001546001600160a01b03163314610271576040516305189e0d60e21b815260040160405180910390fd5b600080546001600160a01b03191633908117825560405190917fa6a85f15b976d399f39ad43e515e75910bac714bc55eeff6131fb90780d6f74691a2565b6000546001600160a01b031633146102da576040516305189e0d60e21b815260040160405180910390fd5b8382146102fa57604051632aa3c3bf60e11b815260040160405180910390fd5b60005b848110156103be5760008686838181106103195761031961107f565b905060200201602081019061032e9190610d35565b6001600160a01b0316036103635761035e828585848181106103525761035261107f565b905060200201356104cf565b6103ac565b6103ac8686838181106103785761037861107f565b905060200201602081019061038d9190610d35565b838686858181106103a0576103a061107f565b905060200201356104ef565b806103b6816110ab565b9150506102fd565b505050505050565b6000546001600160a01b031633146103f1576040516305189e0d60e21b815260040160405180910390fd5b6001600160a01b03166000908152600260205260409020805460ff19169055565b6000546001600160a01b0316331461043d576040516305189e0d60e21b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517f1f95fb40be3a947982072902a887b521248d1d8931a39eb38f84f4d6fd758b6990600090a250565b3360009081526002602052604090205460609060ff166104ba57604051634ae18d2b60e11b815260040160405180910390fd5b6104c5848484610535565b90505b9392505050565b60005a60005a84865af16104eb5763b12d13eb6000526004601cfd5b5050565b816014528060345263a9059cbb60601b60005260206000604460106000875af13d15600160005114171661052b576390b8ec186000526004601cfd5b6000603452505050565b606060008080808487825b818110156108f0578a8a8281811061055a5761055a61107f565b90506020020135965060d887901c60001c60ff169550604086166000146105a6578a8a610586836110ab565b9250828181106105985761059861107f565b9050602002013594506105b7565b602887901b6001600160d01b031794505b6003861661062c576001600160a01b0387166105d48a89886108ff565b6040516105e191906110c4565b600060405180830381855af49150503d806000811461061c576040519150601f19603f3d011682016040523d82523d6000602084013e610621565b606091505b509094509250610854565b60016003871603610696576001600160a01b03871661064c8a89886108ff565b60405161065991906110c4565b6000604051808303816000865af19150503d806000811461061c576040519150601f19603f3d011682016040523d82523d6000602084013e610621565b600260038716036106fe576001600160a01b0387166106b68a89886108ff565b6040516106c391906110c4565b600060405180830381855afa9150503d806000811461061c576040519150601f19603f3d011682016040523d82523d6000602084013e610621565b600380871603610819576000808a8760f81c60ff16815181106107235761072361107f565b6020026020010151905080516020146107985760405162461bcd60e51b815260206004820152602c60248201527f5f657865637574653a2076616c75652063616c6c20686173206e6f2076616c7560448201526b329034b73234b1b0ba32b21760a11b60648201526084015b60405180910390fd5b602081015191506001600160a01b038916826107bc8d8c60088c901b60ff176108ff565b6040516107c991906110c4565b60006040518083038185875af1925050503d8060008114610806576040519150601f19603f3d011682016040523d82523d6000602084013e61080b565b606091505b509096509450610854915050565b60405162461bcd60e51b815260206004820152601060248201526f496e76616c69642063616c6c7479706560801b604482015260640161078f565b836108b957825115610867576044830192505b60008760001c600085511161089b57604051806040016040528060078152602001662ab735b737bbb760c91b81525061089d565b845b60405163ef3dcb2f60e01b815260040161078f939291906110e0565b60808616156108d6576108d189605889901b85610aff565b6108e8565b6108e589605889901b85610ba7565b98505b600101610540565b50969998505050505050505050565b606060008060005b602081101561093e578481602081106109225761092261107f565b1a915060fe1982011561093e5760209290920191600101610907565b5060408051808201909152602081018690529250600460006060815b6020811015610af0578781602081106109755761097561107f565b1a945060fe19850115610af0576080851615610aa15760fe8503610a3157601f19605f850116870160405260248388010186905281516020909401936000036109db57896040516020016109c9919061101d565b60405160208183030381529060405291505b8151603f9401938401601f19168701604052610a12826020896109ff8a6004611113565b60208751610a0d919061112c565b610cff565b60208251610a20919061112c565b610a2a9087611113565b9550610ae1565b60008a607f871681518110610a4857610a4861107f565b6020908102919091018101518051868b016024018a9052968701605f8101601f19168b0160405290910195909150610a8e8260008b610a888c6004611113565b85610cff565b610a988189611113565b97505050610ae1565b60008a607f871681518110610ab857610ab861107f565b6020908102919091018101518051603f9701968701601f19168a01604052015184890160240152505b6020929092019160010161095a565b50505083525090949350505050565b60f882901c60fe198101610b135750505050565b600082516020610b239190611113565b67ffffffffffffffff811115610b3b57610b3b610e1d565b6040519080825280601f01601f191660200182016040528015610b65576020820181803683370190505b5085607f841681518110610b7b57610b7b61107f565b602002602001018190529050610b978360008360208751610cff565b8251806020830152505050505050565b606060f883901c60fe198101610bc057849150506104c8565b6080811615610c725760fe8103610bec5782806020019051810190610be5919061113f565b9450610cf6565b602083810151908114610c545760405162461bcd60e51b815260206004820152602a60248201527f4f6e6c79206f6e652072657475726e2076616c7565207065726d697474656420604482015269287661726961626c652960b01b606482015260840161078f565b508251601f19016020848101918252607f8316810287010152610cf6565b8251602014610cd45760405162461bcd60e51b815260206004820152602860248201527f4f6e6c79206f6e652072657475726e2076616c7565207065726d697474656420604482015267287374617469632960c01b606482015260840161078f565b8285607f831681518110610cea57610cea61107f565b60200260200101819052505b50929392505050565b808260208501018286602089010160045afa505050505050565b80356001600160a01b0381168114610d3057600080fd5b919050565b600060208284031215610d4757600080fd5b6104c882610d19565b60008083601f840112610d6257600080fd5b50813567ffffffffffffffff811115610d7a57600080fd5b6020830191508360208260051b8501011115610d9557600080fd5b9250929050565b600080600080600060608688031215610db457600080fd5b853567ffffffffffffffff80821115610dcc57600080fd5b610dd889838a01610d50565b90975095506020880135915080821115610df157600080fd5b50610dfe88828901610d50565b9094509250610e11905060408701610d19565b90509295509295909350565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610e5c57610e5c610e1d565b604052919050565b600067ffffffffffffffff821115610e7e57610e7e610e1d565b5060051b60200190565b600067ffffffffffffffff821115610ea257610ea2610e1d565b50601f01601f191660200190565b60008060006040808587031215610ec657600080fd5b843567ffffffffffffffff80821115610ede57600080fd5b610eea88838901610d50565b9096509450602091508682013581811115610f0457600080fd5b8701601f81018913610f1557600080fd5b8035610f28610f2382610e64565b610e33565b81815260059190911b8201840190848101908b831115610f4757600080fd5b8584015b83811015610fbb57803586811115610f635760008081fd5b8501603f81018e13610f755760008081fd5b87810135610f85610f2382610e88565b8181528f8b838501011115610f9a5760008081fd5b818b84018b83013760009181018a0191909152845250918601918601610f4b565b50809750505050505050509250925092565b60005b83811015610fe8578181015183820152602001610fd0565b50506000910152565b60008151808452611009816020860160208601610fcd565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561107257603f19888603018452611060858351610ff1565b94509285019290850190600101611044565b5092979650505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016110bd576110bd611095565b5060010190565b600082516110d6818460208701610fcd565b9190910192915050565b8381526001600160a01b038316602082015260606040820181905260009061110a90830184610ff1565b95945050505050565b8082018082111561112657611126611095565b92915050565b8181038181111561112657611126611095565b6000602080838503121561115257600080fd5b825167ffffffffffffffff8082111561116a57600080fd5b818501915085601f83011261117e57600080fd5b815161118c610f2382610e64565b81815260059190911b830184019084810190888311156111ab57600080fd5b8585015b8381101561121f578051858111156111c75760008081fd5b8601603f81018b136111d95760008081fd5b8781015160406111eb610f2383610e88565b8281528d828486010111156112005760008081fd5b61120f838c8301848701610fcd565b86525050509186019186016111af565b509897505050505050505056fea264697066735822122039f30b6c89c5285ba3c20f26762735734a91cf327793e6c497ac42094598a39b64736f6c63430008140033
Verified Source Code Full Match
Compiler: v0.8.20+commit.a1b79de6
EVM: paris
Optimization: Yes (200 runs)
AllMight.sol 116 lines
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.20; import "src/weiroll/VM.sol"; import "solady/utils/SafeTransferLib.sol"; /// @title AllMight /// @notice Weiroll implementation that allow to do literally anything. /// @author Stake DAO /// @custom:contact [email protected] contract AllMight is VM { using SafeTransferLib for address; /// @notice Address of the governance contract. address public governance; /// @notice Address of the future governance contract. address public futureGovernance; /// @notice Address authorized to call the execute function. mapping(address => bool) public isAllowed; //////////////////////////////////////////////////////////////// /// --- EVENTS & ERRORS /////////////////////////////////////////////////////////////// /// @notice Event emitted when a new governance is proposed. event GovernanceProposed(address indexed newGovernance); /// @notice Event emitted when the governance is changed. event GovernanceChanged(address indexed newGovernance); /// @notice Throws if caller is not the governance. error GOVERNANCE(); /// @notice Throws if caller is not allowed. error NOT_ALLOWED(); /// @notice Throws if the length of the tokens and amounts arrays are not equal. error WRONG_LENGTH(); //////////////////////////////////////////////////////////////// /// --- MODIFIERS /////////////////////////////////////////////////////////////// modifier onlyGovernance() { if (msg.sender != governance) revert GOVERNANCE(); _; } modifier onlyAllowed() { if (!isAllowed[msg.sender]) revert NOT_ALLOWED(); _; } constructor(address _governance) { governance = _governance; } //////////////////////////////////////////////////////////////// /// --- ADMIN FUNCTIONS /////////////////////////////////////////////////////////////// /// @notice Allow an address to call the execute function. /// @param _address Address to allow. function allowAddress(address _address) external onlyGovernance { isAllowed[_address] = true; } /// @notice Disallow an address to call the execute function. /// @param _address Address to disallow. function disallowAddress(address _address) external onlyGovernance { isAllowed[_address] = false; } /// @notice Transfer the governance to a new address. /// @param _governance Address of the new governance. function transferGovernance(address _governance) external onlyGovernance { emit GovernanceProposed(futureGovernance = _governance); } /// @notice Accept the governance transfer. function acceptGovernance() external { if (msg.sender != futureGovernance) revert GOVERNANCE(); emit GovernanceChanged(governance = msg.sender); } /// @notice Withdraw ETH or ERC20 tokens from the contract. function withdraw(address[] calldata _tokens, uint256[] calldata _amount, address _recipient) external onlyGovernance { if (_tokens.length != _amount.length) revert WRONG_LENGTH(); for (uint256 i = 0; i < _tokens.length; i++) { if (_tokens[i] == address(0)) { SafeTransferLib.safeTransferETH(_recipient, _amount[i]); } else { SafeTransferLib.safeTransfer(_tokens[i], _recipient, _amount[i]); } } } //////////////////////////////////////////////////////////////// /// --- EXECUTE FUNCTION /////////////////////////////////////////////////////////////// /// @notice Execute a list of commands. /// @param commands List of commands to execute. /// @param state State to execute the commands on. function execute(bytes32[] calldata commands, bytes[] memory state) external onlyAllowed returns (bytes[] memory) { return _execute(commands, state); } receive() external payable {} }
VM.sol 120 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
import "src/weiroll/CommandBuilder.sol";
abstract contract VM {
using CommandBuilder for bytes[];
uint256 constant FLAG_CT_DELEGATECALL = 0x00;
uint256 constant FLAG_CT_CALL = 0x01;
uint256 constant FLAG_CT_STATICCALL = 0x02;
uint256 constant FLAG_CT_VALUECALL = 0x03;
uint256 constant FLAG_CT_MASK = 0x03;
uint256 constant FLAG_EXTENDED_COMMAND = 0x40;
uint256 constant FLAG_TUPLE_RETURN = 0x80;
uint256 constant SHORT_COMMAND_FILL = 0x000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
address immutable self;
error ExecutionFailed(uint256 command_index, address target, string message);
constructor() {
self = address(this);
}
function _execute(bytes32[] calldata commands, bytes[] memory state) internal returns (bytes[] memory) {
bytes32 command;
uint256 flags;
bytes32 indices;
bool success;
bytes memory outdata;
uint256 commandsLength = commands.length;
for (uint256 i; i < commandsLength;) {
command = commands[i];
flags = uint256(command >> 216) & 0xFF; // more efficient
// flags = uint256(uint8(bytes1(command << 32))); // more readable
if (flags & FLAG_EXTENDED_COMMAND != 0) {
indices = commands[++i];
} else {
indices = bytes32(uint256(command << 40) | SHORT_COMMAND_FILL);
}
if (flags & FLAG_CT_MASK == FLAG_CT_DELEGATECALL) {
(success, outdata) = address(uint160(uint256(command))).delegatecall( // target
// inputs
state.buildInputs(
//selector
bytes4(command),
indices
)
);
} else if (flags & FLAG_CT_MASK == FLAG_CT_CALL) {
(success, outdata) = address(uint160(uint256(command))).call( // target
// inputs
state.buildInputs(
//selector
bytes4(command),
indices
)
);
} else if (flags & FLAG_CT_MASK == FLAG_CT_STATICCALL) {
(success, outdata) = address(uint160(uint256(command))).staticcall( // target
// inputs
state.buildInputs(
//selector
bytes4(command),
indices
)
);
} else if (flags & FLAG_CT_MASK == FLAG_CT_VALUECALL) {
uint256 callEth;
bytes memory v = state[uint8(bytes1(indices))];
require(v.length == 32, "_execute: value call has no value indicated.");
assembly {
callEth := mload(add(v, 0x20))
}
(success, outdata) = address(uint160(uint256(command))).call{ // target
value: callEth
}(
// inputs
state.buildInputs(
//selector
bytes4(command),
bytes32(uint256(indices << 8) | CommandBuilder.IDX_END_OF_ARGS)
)
);
} else {
revert("Invalid calltype");
}
if (!success) {
if (outdata.length > 0) {
assembly {
outdata := add(outdata, 68)
}
}
revert ExecutionFailed({
command_index: 0,
target: address(uint160(uint256(command))),
message: outdata.length > 0 ? string(outdata) : "Unknown"
});
}
if (flags & FLAG_TUPLE_RETURN != 0) {
state.writeTuple(bytes1(command << 88), outdata);
} else {
state = state.writeOutputs(bytes1(command << 88), outdata);
}
unchecked {
++i;
}
}
return state;
}
}
CommandBuilder.sol 152 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
library CommandBuilder {
uint256 constant IDX_VARIABLE_LENGTH = 0x80;
uint256 constant IDX_VALUE_MASK = 0x7f;
uint256 constant IDX_END_OF_ARGS = 0xff;
uint256 constant IDX_USE_STATE = 0xfe;
function buildInputs(bytes[] memory state, bytes4 selector, bytes32 indices)
internal
view
returns (bytes memory ret)
{
uint256 free; // Pointer to first free byte in tail part of message
uint256 idx;
// Determine the length of the encoded data
for (uint256 i; i < 32;) {
idx = uint8(indices[i]);
if (idx == IDX_END_OF_ARGS) break;
unchecked {
free += 32;
}
unchecked {
++i;
}
}
// Encode it
uint256 bytesWritten;
assembly {
ret := mload(0x40)
bytesWritten := add(bytesWritten, 4)
mstore(0x40, add(ret, and(add(add(bytesWritten, 0x20), 0x1f), not(0x1f))))
mstore(add(ret, 32), selector)
}
uint256 count = 0;
bytes memory stateData; // Optionally encode the current state if the call requires it
for (uint256 i; i < 32;) {
idx = uint8(indices[i]);
if (idx == IDX_END_OF_ARGS) break;
if (idx & IDX_VARIABLE_LENGTH != 0) {
if (idx == IDX_USE_STATE) {
assembly {
bytesWritten := add(bytesWritten, 32)
mstore(0x40, add(ret, and(add(add(bytesWritten, 0x20), 0x1f), not(0x1f))))
mstore(add(add(ret, 36), count), free)
}
if (stateData.length == 0) {
stateData = abi.encode(state);
}
assembly {
bytesWritten := add(bytesWritten, mload(stateData))
mstore(0x40, add(ret, and(add(add(bytesWritten, 0x20), 0x1f), not(0x1f))))
}
memcpy(stateData, 32, ret, free + 4, stateData.length - 32);
free += stateData.length - 32;
} else {
bytes memory stateVar = state[idx & IDX_VALUE_MASK];
uint256 arglen = stateVar.length;
// Variable length data; put a pointer in the slot and write the data at the end
assembly {
bytesWritten := add(bytesWritten, 32)
mstore(0x40, add(ret, and(add(add(bytesWritten, 0x20), 0x1f), not(0x1f))))
mstore(add(add(ret, 36), count), free)
}
assembly {
bytesWritten := add(bytesWritten, arglen)
mstore(0x40, add(ret, and(add(add(bytesWritten, 0x20), 0x1f), not(0x1f))))
}
memcpy(stateVar, 0, ret, free + 4, arglen);
free += arglen;
}
} else {
// Fixed length data; write it directly
bytes memory stateVar = state[idx & IDX_VALUE_MASK];
assembly {
bytesWritten := add(bytesWritten, mload(stateVar))
mstore(0x40, add(ret, and(add(add(bytesWritten, 0x20), 0x1f), not(0x1f))))
mstore(add(add(ret, 36), count), mload(add(stateVar, 32)))
}
}
unchecked {
count += 32;
}
unchecked {
++i;
}
}
assembly {
mstore(ret, bytesWritten)
}
}
function writeOutputs(bytes[] memory state, bytes1 index, bytes memory output)
internal
pure
returns (bytes[] memory)
{
uint256 idx = uint8(index);
if (idx == IDX_END_OF_ARGS) return state;
if (idx & IDX_VARIABLE_LENGTH != 0) {
if (idx == IDX_USE_STATE) {
state = abi.decode(output, (bytes[]));
} else {
// Check the first field is 0x20 (because we have only a single return value)
uint256 argptr;
assembly {
argptr := mload(add(output, 32))
}
require(argptr == 32, "Only one return value permitted (variable)");
assembly {
// Overwrite the first word of the return data with the length - 32
mstore(add(output, 32), sub(mload(output), 32))
// Insert a pointer to the return data, starting at the second word, into state
mstore(add(add(state, 32), mul(and(idx, IDX_VALUE_MASK), 32)), add(output, 32))
}
}
} else {
// Single word
require(output.length == 32, "Only one return value permitted (static)");
state[idx & IDX_VALUE_MASK] = output;
}
return state;
}
function writeTuple(bytes[] memory state, bytes1 index, bytes memory output) internal view {
uint256 idx = uint256(uint8(index));
if (idx == IDX_END_OF_ARGS) return;
bytes memory entry = state[idx & IDX_VALUE_MASK] = new bytes(output.length + 32);
memcpy(output, 0, entry, 32, output.length);
assembly {
let l := mload(output)
mstore(add(entry, 32), l)
}
}
function memcpy(bytes memory src, uint256 srcidx, bytes memory dest, uint256 destidx, uint256 len) internal view {
assembly {
pop(staticcall(gas(), 4, add(add(src, 32), srcidx), len, add(add(dest, 32), destidx), len))
}
}
}
SafeTransferLib.sol 381 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for gas griefing protection.
/// - For ERC20s, this implementation won't check that a token has code,
/// responsibility is delegated to the caller.
library SafeTransferLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ETH transfer has failed.
error ETHTransferFailed();
/// @dev The ERC20 `transferFrom` has failed.
error TransferFromFailed();
/// @dev The ERC20 `transfer` has failed.
error TransferFailed();
/// @dev The ERC20 `approve` has failed.
error ApproveFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;
/// @dev Suggested gas stipend for contract receiving ETH to perform a few
/// storage reads and writes, but low enough to prevent griefing.
uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ETH OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// If gas griefing protection is needed, please use the force variants.
//
// The regular variants:
// - Forwards all remaining gas to the target.
// - Reverts if the target reverts.
// - Reverts if the current contract has insufficient balance.
//
// The force variants:
// - Forwards with an optional gas stipend
// (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
// - If the target reverts, or if the gas stipend is exhausted,
// creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
// Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
// - Reverts if the current contract has insufficient balance.
//
// The try variants:
// - Forwards with a mandatory gas stipend.
// - Instead of reverting, returns whether the transfer succeeded.
/// @dev Sends `amount` (in wei) ETH to `to`.
function safeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gas(), to, amount, gas(), 0x00, gas(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Sends all the ETH in the current contract to `to`.
function safeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// Transfer all the ETH and check if it succeeded or not.
if iszero(call(gas(), to, selfbalance(), gas(), 0x00, gas(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(gasStipend, to, amount, gas(), 0x00, gas(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) {
returndatacopy(gas(), returndatasize(), shr(20, gas())) // For gas estimation.
}
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gasStipend, to, selfbalance(), gas(), 0x00, gas(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) {
returndatacopy(gas(), returndatasize(), shr(20, gas())) // For gas estimation.
}
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, gas(), 0x00, gas(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) {
returndatacopy(gas(), returndatasize(), shr(20, gas())) // For gas estimation.
}
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), gas(), 0x00, gas(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) {
returndatacopy(gas(), returndatasize(), shr(20, gas())) // For gas estimation.
}
}
}
}
/// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, amount, gas(), 0x00, gas(), 0x00)
}
}
/// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
function trySafeTransferAllETH(address to, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, selfbalance(), gas(), 0x00, gas(), 0x00)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have at least `amount` approved for
/// the current contract to manage.
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, amount) // Store the `amount` argument.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends all of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have their entire balance approved for
/// the current contract to manage.
function safeTransferAllFrom(address token, address from, address to)
internal
returns (uint256 amount)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransfer(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sends all of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransferAll(address token, address to) internal returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
mstore(0x20, address()) // Store the address of the current contract.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x14, to) // Store the `to` argument.
amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// Reverts upon failure.
function safeApprove(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
/// then retries the approval again (some tokens, e.g. USDT, requires this).
/// Reverts upon failure.
function safeApproveWithRetry(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, retrying upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x34, 0) // Store 0 for the `amount`.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
pop(call(gas(), token, 0, 0x10, 0x44, 0x00, 0x00)) // Reset the approval.
mstore(0x34, amount) // Store back the original `amount`.
// Retry the approval, reverting upon failure.
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Returns the amount of ERC20 `token` owned by `account`.
/// Returns zero if the `token` does not exist.
function balanceOf(address token, address account) internal view returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, account) // Store the `account` argument.
mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
amount :=
mul(
mload(0x20),
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
)
}
}
}
Read Contract
futureGovernance 0x8070c503 → address
governance 0x5aa6e675 → address
isAllowed 0xbabcc539 → bool
Write Contract 6 functions
These functions modify contract state and require a wallet transaction to execute.
acceptGovernance 0x238efcbc
No parameters
allowAddress 0x08af4d88
address _address
disallowAddress 0xb7c58d7a
address _address
execute 0xde792d5f
bytes32[] commands
bytes[] state
returns: bytes[]
transferGovernance 0xd38bfff4
address _governance
withdraw 0x26f91506
address[] _tokens
uint256[] _amount
address _recipient
Top Interactions
| Address | Txns | Sent | Received |
|---|---|---|---|
| 0x90569D8A...Fc75 | 1 | 1 |
Token Balances (3)
View Transfers →Recent Transactions
|
| Hash | Block | Age | From/To | Value | |
|---|---|---|---|---|---|
| 0x80f63c2a...d3f7f6 | 24,445,529 | IN | 0x90569D8A...Fc75 | 0 ETH |