Address Contract Verified
Address
0xADfBFd06633eB92fc9b58b3152Fe92B0A24eB1FF
Balance
0 ETH
Nonce
1
Code Size
1592 bytes
Creator
0x90569D8A...Fc75 at tx 0x171aadf6...2481d0
Indexed Transactions
0
Contract Bytecode
1592 bytes
0x60806040526004361061007f5760003560e01c80638070c5031161004e5780638070c5031461011f578063b7c58d7a1461013f578063babcc5391461015f578063d38bfff41461019f57600080fd5b806308af4d881461008b578063238efcbc146100ad57806326f91506146100c25780635aa6e675146100e257600080fd5b3661008657005b600080fd5b34801561009757600080fd5b506100ab6100a63660046104d6565b6101bf565b005b3480156100b957600080fd5b506100ab61020e565b3480156100ce57600080fd5b506100ab6100dd366004610544565b610277565b3480156100ee57600080fd5b50600054610102906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561012b57600080fd5b50600154610102906001600160a01b031681565b34801561014b57600080fd5b506100ab61015a3660046104d6565b610393565b34801561016b57600080fd5b5061018f61017a3660046104d6565b60026020526000908152604090205460ff1681565b6040519015158152602001610116565b3480156101ab57600080fd5b506100ab6101ba3660046104d6565b6103df565b6000546001600160a01b031633146101ea576040516305189e0d60e21b815260040160405180910390fd5b6001600160a01b03166000908152600260205260409020805460ff19166001179055565b6001546001600160a01b03163314610239576040516305189e0d60e21b815260040160405180910390fd5b600080546001600160a01b03191633908117825560405190917fa6a85f15b976d399f39ad43e515e75910bac714bc55eeff6131fb90780d6f74691a2565b3360009081526002602052604090205460ff166102a757604051634ae18d2b60e11b815260040160405180910390fd5b8382146102c757604051632aa3c3bf60e11b815260040160405180910390fd5b60005b8481101561038b5760008686838181106102e6576102e66105c5565b90506020020160208101906102fb91906104d6565b6001600160a01b0316036103305761032b8285858481811061031f5761031f6105c5565b90506020020135610454565b610379565b610379868683818110610345576103456105c5565b905060200201602081019061035a91906104d6565b8386868581811061036d5761036d6105c5565b90506020020135610474565b80610383816105db565b9150506102ca565b505050505050565b6000546001600160a01b031633146103be576040516305189e0d60e21b815260040160405180910390fd5b6001600160a01b03166000908152600260205260409020805460ff19169055565b6000546001600160a01b0316331461040a576040516305189e0d60e21b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517f1f95fb40be3a947982072902a887b521248d1d8931a39eb38f84f4d6fd758b6990600090a250565b60005a60005a84865af16104705763b12d13eb6000526004601cfd5b5050565b816014528060345263a9059cbb60601b60005260206000604460106000875af13d1560016000511417166104b0576390b8ec186000526004601cfd5b6000603452505050565b80356001600160a01b03811681146104d157600080fd5b919050565b6000602082840312156104e857600080fd5b6104f1826104ba565b9392505050565b60008083601f84011261050a57600080fd5b50813567ffffffffffffffff81111561052257600080fd5b6020830191508360208260051b850101111561053d57600080fd5b9250929050565b60008060008060006060868803121561055c57600080fd5b853567ffffffffffffffff8082111561057457600080fd5b61058089838a016104f8565b9097509550602088013591508082111561059957600080fd5b506105a6888289016104f8565b90945092506105b99050604087016104ba565b90509295509295909350565b634e487b7160e01b600052603260045260246000fd5b6000600182016105fb57634e487b7160e01b600052601160045260246000fd5b506001019056fea2646970667358221220882fac56baffaea64a5bea5e70a1ce88553306c443a4395d062cc17cf7c93a5164736f6c63430008140033
Verified Source Code Full Match
Compiler: v0.8.20+commit.a1b79de6
EVM: paris
Optimization: Yes (200 runs)
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;
}
}
Botmarket.sol 105 lines
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.20; import "src/weiroll/VM.sol"; import "solady/utils/SafeTransferLib.sol"; /// @title Botmarket /// @notice Contract recipient from sdToken bounties on Votemarket. /// @author Stake DAO /// @custom:contact [email protected] contract Botmarket { 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 onlyAllowed { 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]); } } } receive() external payable {} }
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 5 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
transferGovernance 0xd38bfff4
address _governance
withdraw 0x26f91506
address[] _tokens
uint256[] _amount
address _recipient
Token Balances (3)
View Transfers →Recent Transactions
No transactions found for this address