Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x60e06040 | 22636247 | 39 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
RefuelAction
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 1000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.26; import {InstructionLib} from "../libraries/Instruction.sol"; import {AssemblyUtils} from "./libraries/AssemblyUtils.sol"; import {OtimFee} from "./fee-models/OtimFee.sol"; import {IAction} from "./interfaces/IAction.sol"; import {IRefuelAction, INSTRUCTION_TYPEHASH, ARGUMENTS_TYPEHASH} from "./interfaces/IRefuelAction.sol"; import {InvalidArguments, InsufficientBalance, BalanceOverThreshold} from "./errors/Errors.sol"; /// @title Refuel /// @author Otim Labs, Inc. /// @notice an Action that refuels a target address with native currency when the target's balance is below a threshold contract RefuelAction is IAction, IRefuelAction, OtimFee { using InstructionLib for InstructionLib.Instruction; constructor(address feeTokenRegistryAddress, address treasuryAddress, uint256 gasConstant_) OtimFee(feeTokenRegistryAddress, treasuryAddress, gasConstant_) {} /// @inheritdoc IAction function argumentsHash(bytes calldata arguments) public pure returns (bytes32, bytes32) { return (INSTRUCTION_TYPEHASH, hash(abi.decode(arguments, (Refuel)))); } /// @inheritdoc IRefuelAction function hash(Refuel memory refuel) public pure returns (bytes32) { return keccak256( abi.encode( ARGUMENTS_TYPEHASH, refuel.target, refuel.threshold, refuel.endBalance, refuel.gasLimit, hash(refuel.fee) ) ); } /// @inheritdoc IAction function execute( InstructionLib.Instruction calldata instruction, InstructionLib.Signature calldata, InstructionLib.ExecutionState calldata executionState ) external override returns (bool deactivate) { // initial gas measurement for fee calculation uint256 startGas = gasleft(); // decode the arguments from the instruction Refuel memory refuel = abi.decode(instruction.arguments, (Refuel)); // if first execution, validate the input if (executionState.executionCount == 0) { // validate the arguments if (refuel.target == address(0) || refuel.threshold >= refuel.endBalance) { revert InvalidArguments(); } } // get the target's balance uint256 balance = refuel.target.balance; // if the balance is above the threshold, revert if (balance > refuel.threshold) { revert BalanceOverThreshold(); } // calculate the amount to refuel uint256 refuelAmount = refuel.endBalance - balance; // if the contract doesn't have enough balance to refuel, revert if (address(this).balance < refuelAmount) { revert InsufficientBalance(); } // transfer the value to the target address, with a gas limit, and without returning any data bool success = AssemblyUtils.safeTransferNoReturn(refuel.target, refuelAmount, refuel.gasLimit); // if the transfer fails, charge the user for the gas used, emit an event, and automatically deactivate the instruction // we do this instead of reverting to protect the Executor from gas griefing attacks if (!success) { // if the fee is not sponsored, set the execution fee to 1 to only charge the user for gas used if (refuel.fee.executionFee > 0) { refuel.fee.executionFee = 1; } // emit that the refuel failed emit RefuelActionFailed(refuel.target); // deactivate the instruction deactivate = true; } // charge the fee chargeFee(startGas - gasleft(), refuel.fee); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.26; import {Constants} from "./Constants.sol"; /// @title InstructionLib /// @author Otim Labs, Inc. /// @notice a library defining the Instruction datatype and util functions library InstructionLib { /// @notice defines a signature struct Signature { uint8 v; bytes32 r; bytes32 s; } /// @notice defines the ExecutionState datatype /// @param deactivated - whether the Instruction has been deactivated /// @param executionCount - the number of times the Instruction has been executed /// @param lastExecuted - the unix timestamp of the last time the Instruction was executed struct ExecutionState { bool deactivated; uint120 executionCount; uint120 lastExecuted; } /// @notice defines the Instruction datatype /// @param salt - a number to ensure the uniqueness of the Instruction /// @param maxExecutions - the maximum number of times the Instruction can be executed /// @param action - the address of the Action contract to be executed /// @param arguments - the arguments to be passed to the Action contract struct Instruction { uint256 salt; uint256 maxExecutions; address action; bytes arguments; } /// @notice abi.encodes and hashes an Instruction struct to create a unique Instruction identifier /// @param instruction - an Instruction struct to hash /// @return instructionId - unique identifier for the Instruction function id(Instruction calldata instruction) internal pure returns (bytes32) { return keccak256(abi.encode(instruction)); } /// @notice calculates the EIP-712 hash for activating an Instruction /// @param instruction - an Instruction struct to hash /// @param domainSeparator - the EIP-712 domain separator for the verifying contract /// @return hash - EIP-712 hash for activating `instruction` function signingHash( Instruction calldata instruction, bytes32 domainSeparator, bytes32 instructionTypeHash, bytes32 argumentsHash ) internal pure returns (bytes32) { return keccak256( abi.encodePacked( Constants.EIP712_PREFIX, domainSeparator, keccak256( abi.encode( instructionTypeHash, instruction.salt, instruction.maxExecutions, instruction.action, argumentsHash ) ) ) ); } /// @notice defines a deactivation instruction /// @param instructionId - the unique identifier of the Instruction to deactivate struct InstructionDeactivation { bytes32 instructionId; } /// @notice the EIP-712 type-hash for an InstructionDeactivation bytes32 public constant DEACTIVATION_TYPEHASH = keccak256("InstructionDeactivation(bytes32 instructionId)"); /// @notice calculates the EIP-712 hash for a InstructionDeactivation /// @param deactivation - an InstructionDeactivation struct to hash /// @param domainSeparator - the EIP-712 domain separator for the verifying contract /// @return hash - EIP-712 hash for the `deactivation` function signingHash(InstructionDeactivation calldata deactivation, bytes32 domainSeparator) internal pure returns (bytes32) { return keccak256( abi.encodePacked( Constants.EIP712_PREFIX, domainSeparator, keccak256(abi.encode(DEACTIVATION_TYPEHASH, deactivation.instructionId)) ) ); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.26; /// @title AssemblyUtils /// @author Otim Labs, Inc. /// @notice A library providing low-level assembly utility functions library AssemblyUtils { /// @notice Safely transfers a specified amount of ether to a target address with a gas limit /// @dev This utility avoids return bomb attacks by discarding the return value of the call /// @param target - The address to which the ether will be sent /// @param value - The amount of ether to send (in wei) /// @param gasLimit - The maximum amount of gas to use for the transfer /// @return success - whether the transfer was successful or not function safeTransferNoReturn(address target, uint256 value, uint256 gasLimit) internal returns (bool success) { assembly { // Call the target address with the specified value and gas limit // 1. Set the gas limit for the call // 2. Set the target to send ether to // 3. Set the value to send (in wei) // 4. Set the call data pointer to zero (no calldata needed) // 5. Set the call data size to zero (no calldata needed) // 6. Set the return data pointer to zero (discard return data) // 7. Set the return data size to zero (discard return data) success := call(gasLimit, target, value, 0, 0, 0, 0) } } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.26; import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; import {IFeeTokenRegistry} from "../../infrastructure/interfaces/IFeeTokenRegistry.sol"; import {ITreasury} from "../../infrastructure/interfaces/ITreasury.sol"; import {IOtimFee, FEE_TYPEHASH} from "./interfaces/IOtimFee.sol"; /// @title OtimFee /// @author Otim Labs, Inc. /// @notice abstract contract for the Otim centralized fee model abstract contract OtimFee is IOtimFee { using SafeERC20 for IERC20; /// @notice the Otim fee token registry contract for converting wei to ERC20 tokens IFeeTokenRegistry public immutable feeTokenRegistry; /// @notice the Otim treasury contract that receives fees ITreasury public immutable treasury; /// @notice the gas constant used to calculate the fee uint256 public immutable gasConstant; constructor(address feeTokenRegistryAddress, address treasuryAddress, uint256 gasConstant_) { feeTokenRegistry = IFeeTokenRegistry(feeTokenRegistryAddress); treasury = ITreasury(treasuryAddress); gasConstant = gasConstant_; } /// @inheritdoc IOtimFee function hash(Fee memory fee) public pure returns (bytes32) { return keccak256( abi.encode(FEE_TYPEHASH, fee.token, fee.maxBaseFeePerGas, fee.maxPriorityFeePerGas, fee.executionFee) ); } /// @inheritdoc IOtimFee function chargeFee(uint256 gasUsed, Fee memory fee) public override { // fee.executionFee == 0 is a magic value signifying a sponsored Instruction if (fee.executionFee == 0) return; // check if the base fee is too high if (block.basefee > fee.maxBaseFeePerGas && fee.maxBaseFeePerGas != 0) { revert BaseFeePerGasTooHigh(); } // check if the priority fee is too high if (tx.gasprice - block.basefee > fee.maxPriorityFeePerGas) { revert PriorityFeePerGasTooHigh(); } // calculate the total cost of the gas used in the transaction uint256 weiGasCost = (gasUsed + gasConstant) * tx.gasprice; // if fee.token is address(0), the fee is paid in native currency if (fee.token == address(0)) { // calculate the fee cost based on the gas used and the additional fee uint256 weiTotalCost = weiGasCost + fee.executionFee; // check if the user has enough balance to pay the fee if (address(this).balance < weiTotalCost) { revert InsufficientFeeBalance(); } // transfer to the treasury contract // slither-disable-next-line arbitrary-send-eth treasury.deposit{value: weiTotalCost}(); } else { // calculate the fee cost based on the cost of the gas used (denominated in the fee token) and the execution fee uint256 tokenTotalCost = feeTokenRegistry.weiToToken(fee.token, weiGasCost) + fee.executionFee; // check if the user has enough balance to pay the fee if (IERC20(fee.token).balanceOf(address(this)) < tokenTotalCost) { revert InsufficientFeeBalance(); } // transfer to the treasury contract IERC20(fee.token).safeTransfer(address(treasury), tokenTotalCost); } } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.26; import {InstructionLib} from "../../libraries/Instruction.sol"; /// @title IAction /// @author Otim Labs, Inc. /// @notice interface for Action contracts interface IAction { /// @notice returns the EIP-712 type hash for the Action-specific Instruction and the EIP-712 hash of the Action-specific Instruction arguments /// @param arguments - encoded Instruction arguments /// @return instructionTypeHash - EIP-712 type hash for the Action-specific Instruction /// @return argumentsTypeHash - EIP-712 hash of the Action-specific Instruction arguments function argumentsHash(bytes calldata arguments) external returns (bytes32, bytes32); /// @notice execute Action logic with Instruction arguments /// @param instruction - Instruction /// @param signature - Signature over the Instruction signing hash /// @param executionState - ExecutionState /// @return deactivate - whether the Instruction should be automatically deactivated function execute( InstructionLib.Instruction calldata instruction, InstructionLib.Signature calldata signature, InstructionLib.ExecutionState calldata executionState ) external returns (bool); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.26; import {IOtimFee} from "../fee-models/interfaces/IOtimFee.sol"; bytes32 constant INSTRUCTION_TYPEHASH = keccak256( "Instruction(uint256 salt,uint256 maxExecutions,address action,Refuel refuel)Fee(address token,uint256 maxBaseFeePerGas,uint256 maxPriorityFeePerGas,uint256 executionFee)Refuel(address target,uint256 threshold,uint256 endBalance,uint256 gasLimit,Fee fee)" ); bytes32 constant ARGUMENTS_TYPEHASH = keccak256( "Refuel(address target,uint256 threshold,uint256 endBalance,uint256 gasLimit,Fee fee)Fee(address token,uint256 maxBaseFeePerGas,uint256 maxPriorityFeePerGas,uint256 executionFee)" ); /// @title IRefuelAction /// @author Otim Labs, Inc. /// @notice interface for RefuelAction contract interface IRefuelAction is IOtimFee { /// @notice arguments for the RefuelAction contract /// @param target - the address to refuel /// @param threshold - the minimum balance required to refuel /// @param endBalance - the target balance after refueling /// @param gasLimit - the maximum amount of gas the refuel external call can consume /// @param fee - the fee Otim will charge for the refuel struct Refuel { address payable target; uint256 threshold; uint256 endBalance; uint256 gasLimit; Fee fee; } /// @notice emitted when the Refuel fails event RefuelActionFailed(address indexed target); /// @notice calculates the EIP-712 hash of the Refuel struct function hash(Refuel memory refuel) external pure returns (bytes32); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.26; error InvalidArguments(); error InsufficientBalance(); error BalanceOverThreshold(); error BalanceUnderThreshold(); error UniswapV3PoolDoesNotExist();
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.26; /// @title Constants /// @author Otim Labs, Inc. /// @notice a library defining constants used throughout the protocol library Constants { /// @notice the EIP-712 signature prefix bytes2 public constant EIP712_PREFIX = 0x1901; /// @notice the EIP-7702 delegation designator prefix bytes3 public constant EIP7702_PREFIX = 0xef0100; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC1363} from "../../../interfaces/IERC1363.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC-20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { /** * @dev An operation with an ERC-20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful. */ function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) { return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful. */ function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) { return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. * * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being * set here. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { safeTransfer(token, to, value); } else if (!token.transferAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferFromAndCallRelaxed( IERC1363 token, address from, address to, uint256 value, bytes memory data ) internal { if (to.code.length == 0) { safeTransferFrom(token, from, to, value); } else if (!token.transferFromAndCall(from, to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}. * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall} * once without retrying, and relies on the returned value to be true. * * Reverts if the returned value is other than `true`. */ function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { forceApprove(token, to, value); } else if (!token.approveAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements. */ function _callOptionalReturn(IERC20 token, bytes memory data) private { uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) // bubble errors if iszero(success) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } returnSize := returndatasize() returnValue := mload(0) } if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { bool success; uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) returnSize := returndatasize() returnValue := mload(0) } return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.26; /// @title FeeTokenRegistry /// @author Otim Labs, Inc. /// @notice interface for the FeeTokenRegistry contract interface IFeeTokenRegistry { /// @notice fee token data struct /// @param priceFeed - a price feed of the form <token>/ETH /// @param heartbeat - the time in seconds between price feed updates /// @param priceFeedDecimals - the number of decimals for the price feed /// @param tokenDecimals - the number of decimals for the token /// @param registered - whether the token is registered struct FeeTokenData { address priceFeed; uint40 heartbeat; uint8 priceFeedDecimals; uint8 tokenDecimals; bool registered; } /// @notice emitted when a fee token is added event FeeTokenAdded( address indexed token, address indexed priceFeed, uint40 heartbeat, uint8 priceFeedDecimals, uint8 tokenDecimals ); /// @notice emitted when a fee token is removed event FeeTokenRemoved( address indexed token, address indexed priceFeed, uint40 heartbeat, uint8 priceFeedDecimals, uint8 tokenDecimals ); error InvalidFeeTokenData(); error PriceFeedNotInitialized(); error FeeTokenAlreadyRegistered(); error FeeTokenNotRegistered(); error InvalidPrice(); error StalePrice(); /// @notice adds a fee token to the registry /// @param token - the ERC20 token address /// @param priceFeed - the price feed address /// @param heartbeat - the time in seconds between price feed updates function addFeeToken(address token, address priceFeed, uint40 heartbeat) external; /// @notice removes a fee token from the registry /// @param token - the ERC20 token address function removeFeeToken(address token) external; /// @notice converts a wei amount to a token amount /// @param token - the ERC20 token address to convert to /// @param weiAmount - the amount of wei to convert /// @return tokenAmount - converted token amount function weiToToken(address token, uint256 weiAmount) external view returns (uint256); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.26; /// @title ITreasury /// @author Otim Labs, Inc. /// @notice interface for Treasury contract interface ITreasury { /// @notice thrown when the owner tries to withdraw to the zero address error InvalidTarget(); /// @notice thrown when the withdrawl fails error WithdrawalFailed(bytes result); /// @notice thrown when the owner tries to withdraw more than the contract balance error InsufficientBalance(); /// @notice deposit ether into the treasury function deposit() external payable; /// @notice withdraw ether from the treasury /// @param to - the address to withdraw to /// @param value - the amount to withdraw function withdraw(address to, uint256 value) external; /// @notice withdraw ERC20 tokens from the treasury /// @param token - the ERC20 token to withdraw /// @param to - the address to withdraw to /// @param value - the amount to withdraw function withdrawERC20(address token, address to, uint256 value) external; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.26; bytes32 constant FEE_TYPEHASH = keccak256("Fee(address token,uint256 maxBaseFeePerGas,uint256 maxPriorityFeePerGas,uint256 executionFee)"); /// @title IOtimFee /// @author Otim Labs, Inc. /// @notice interface for the OtimFee contract interface IOtimFee { /// @notice fee struct /// @param token - the token to be used for the fee (address(0) for native currency) /// @param maxBaseFeePerGas - the maximum basefee per gas the user is willing to pay /// @param maxPriorityFeePerGas - the maximum priority fee per gas the user is willing to pay /// @param executionFee - fixed fee to be paid for each execution struct Fee { address token; uint256 maxBaseFeePerGas; uint256 maxPriorityFeePerGas; uint256 executionFee; } /// @notice calculates the EIP-712 hash of the Fee struct function hash(Fee memory fee) external pure returns (bytes32); /// @notice charges a fee for the Instruction execution /// @param gasUsed - amount of gas used during the Instruction execution /// @param fee - additional fee to be paid function chargeFee(uint256 gasUsed, Fee memory fee) external; error InsufficientFeeBalance(); error BaseFeePerGasTooHigh(); error PriorityFeePerGasTooHigh(); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC165} from "./IERC165.sol"; /** * @title IERC1363 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. * * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction. */ interface IERC1363 is IERC20, IERC165 { /* * Note: the ERC-165 identifier for this interface is 0xb0202a11. * 0xb0202a11 === * bytes4(keccak256('transferAndCall(address,uint256)')) ^ * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^ * bytes4(keccak256('approveAndCall(address,uint256)')) ^ * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) */ /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @param data Additional data with no specified format, sent in call to `spender`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "remappings": [ "@chainlink-contracts/=dependencies/smartcontractkit-chainlink-2.22.0/contracts/", "@openzeppelin-contracts/=dependencies/@openzeppelin-contracts-5.3.0/", "@openzeppelin/contracts/=dependencies/@openzeppelin-contracts-5.3.0/", "@uniswap-universal-router/=dependencies/@uniswap-universal-router-2.0.0/", "@uniswap-v3-core/=dependencies/@uniswap-v3-core-1.0.2-solc-0.8-simulate/", "@uniswap-v3-periphery/=dependencies/@uniswap-v3-periphery-1.4.4/", "forge-std/=dependencies/forge-std-1.9.7/", "@openzeppelin-contracts-5.3.0/=dependencies/@openzeppelin-contracts-5.3.0/", "@uniswap-universal-router-2.0.0/=dependencies/@uniswap-universal-router-2.0.0/", "@uniswap-v3-core-1.0.2-solc-0.8-simulate/=dependencies/@uniswap-v3-core-1.0.2-solc-0.8-simulate/contracts/", "@uniswap-v3-periphery-1.4.4/=dependencies/@uniswap-v3-periphery-1.4.4/contracts/", "@uniswap/=dependencies/@uniswap-v3-periphery-1.4.4/node_modules/@uniswap/", "ds-test/=dependencies/@uniswap-universal-router-2.0.0/lib/forge-std/lib/ds-test/src/", "erc4626-tests/=dependencies/@uniswap-universal-router-2.0.0/lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-gas-snapshot/=dependencies/@uniswap-universal-router-2.0.0/lib/permit2/lib/forge-gas-snapshot/src/", "forge-std-1.9.7/=dependencies/forge-std-1.9.7/src/", "openzeppelin-contracts/=dependencies/@uniswap-universal-router-2.0.0/lib/permit2/lib/openzeppelin-contracts/", "permit2/=dependencies/@uniswap-universal-router-2.0.0/lib/permit2/", "smartcontractkit-chainlink-2.22.0/=dependencies/smartcontractkit-chainlink-2.22.0/", "solmate/=dependencies/@uniswap-universal-router-2.0.0/lib/solmate/src/", "v3-periphery/=dependencies/@uniswap-universal-router-2.0.0/lib/v3-periphery/contracts/", "v4-core/=dependencies/@uniswap-universal-router-2.0.0/lib/v4-periphery/lib/v4-core/src/", "v4-periphery/=dependencies/@uniswap-universal-router-2.0.0/lib/v4-periphery/" ], "optimizer": { "enabled": true, "runs": 1000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": false }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"feeTokenRegistryAddress","type":"address"},{"internalType":"address","name":"treasuryAddress","type":"address"},{"internalType":"uint256","name":"gasConstant_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BalanceOverThreshold","type":"error"},{"inputs":[],"name":"BaseFeePerGasTooHigh","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientFeeBalance","type":"error"},{"inputs":[],"name":"InvalidArguments","type":"error"},{"inputs":[],"name":"PriorityFeePerGasTooHigh","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"}],"name":"RefuelActionFailed","type":"event"},{"inputs":[{"internalType":"bytes","name":"arguments","type":"bytes"}],"name":"argumentsHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"maxBaseFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"uint256","name":"executionFee","type":"uint256"}],"internalType":"struct IOtimFee.Fee","name":"fee","type":"tuple"}],"name":"chargeFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint256","name":"maxExecutions","type":"uint256"},{"internalType":"address","name":"action","type":"address"},{"internalType":"bytes","name":"arguments","type":"bytes"}],"internalType":"struct InstructionLib.Instruction","name":"instruction","type":"tuple"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct InstructionLib.Signature","name":"","type":"tuple"},{"components":[{"internalType":"bool","name":"deactivated","type":"bool"},{"internalType":"uint120","name":"executionCount","type":"uint120"},{"internalType":"uint120","name":"lastExecuted","type":"uint120"}],"internalType":"struct InstructionLib.ExecutionState","name":"executionState","type":"tuple"}],"name":"execute","outputs":[{"internalType":"bool","name":"deactivate","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeTokenRegistry","outputs":[{"internalType":"contract IFeeTokenRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasConstant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"target","type":"address"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"uint256","name":"endBalance","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"maxBaseFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"uint256","name":"executionFee","type":"uint256"}],"internalType":"struct IOtimFee.Fee","name":"fee","type":"tuple"}],"internalType":"struct IRefuelAction.Refuel","name":"refuel","type":"tuple"}],"name":"hash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"maxBaseFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"uint256","name":"executionFee","type":"uint256"}],"internalType":"struct IOtimFee.Fee","name":"fee","type":"tuple"}],"name":"hash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"contract ITreasury","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60e060405234801561000f575f80fd5b50604051610d15380380610d1583398101604081905261002e91610064565b6001600160a01b03928316608052911660a05260c05261009d565b80516001600160a01b038116811461005f575f80fd5b919050565b5f805f60608486031215610076575f80fd5b61007f84610049565b925061008d60208501610049565b9150604084015190509250925092565b60805160a05160c051610c346100e15f395f8181608e01526104bf01525f818160c801528181610536015261071d01525f818161017a01526105f30152610c345ff3fe608060405234801561000f575f80fd5b5060043610610085575f3560e01c806399d0dd371161005857806399d0dd37146101385780639fcd91b31461014d578063aebfab1b14610175578063fd89ea0c1461019c575f80fd5b80632cb0f8a21461008957806361d027b3146100c357806369179de314610102578063745835fb14610125575b5f80fd5b6100b07f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b6100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100ba565b610115610110366004610924565b6101af565b60405190151581526020016100ba565b6100b0610133366004610a12565b61037d565b61014b610146366004610a9b565b610415565b005b61016061015b366004610ac6565b610749565b604080519283526020830191909152016100ba565b6100ea7f000000000000000000000000000000000000000000000000000000000000000081565b6100b06101aa366004610b34565b610787565b5f805a90505f6101c26060870187610b55565b8101906101cf9190610a12565b90506101e16040850160208601610b98565b6effffffffffffffffffffffffffffff165f0361024e5780516001600160a01b0316158061021757508060400151816020015110155b1561024e576040517f5f6f132c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160208201516001600160a01b03909116319081111561029b576040517f9a741dc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8183604001516102ac9190610bda565b9050804710156102e8576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6102fb845f01518386606001516107f7565b905080610359576080840151606001511561031e57608084015160016060909101525b83516040516001600160a01b03909116907f562e5484ba6302d3b527d81d8e0785d4219c6fc724fefeaace98fb00b7b5296d905f90a2600195505b6103715a6103679087610bda565b8560800151610415565b50505050509392505050565b5f7f345105fee2b4f83de75717665d9692446c8fcd071758eb6cb93033bf416e88ef825f01518360200151846040015185606001516103bf8760800151610787565b6040805160208101979097526001600160a01b03909516948601949094526060850192909252608084015260a083015260c082015260e0015b604051602081830303815290604052805190602001209050919050565b80606001515f03610424575050565b80602001514811801561043a5750602081015115155b15610471576040517f2f3d0a5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040810151610480483a610bda565b11156104b8576040517f8ef482f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f3a6104e47f000000000000000000000000000000000000000000000000000000000000000085610bf3565b6104ee9190610c06565b82519091506001600160a01b03166105aa575f8260600151826105119190610bf3565b90508047101561053457604051637806a4f560e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b15801561058d575f80fd5b505af115801561059f573d5f803e3d5ffd5b505050505050505050565b606082015182516040517fd251f7ba0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018490525f92917f0000000000000000000000000000000000000000000000000000000000000000169063d251f7ba90604401602060405180830381865afa158015610638573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061065c9190610c1d565b6106669190610bf3565b83516040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925082916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156106c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ed9190610c1d565b101561070c57604051637806a4f560e11b815260040160405180910390fd5b8251610742906001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000083610808565b505b505050565b5f807ff827d1af143d2e40b50ad77d3f6d66db049915c707be0527146e1cf1b44318fc61077b61013385870187610a12565b915091505b9250929050565b5f7f7aff6c7b9b8aafff555894be6cfd4a6211fc7adbcd97db18b05d4a51ed7482a0825f01518360200151846040015185606001516040516020016103f89594939291909485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b5f805f805f868887f1949350505050565b604080516001600160a01b03841660248201526044808201849052825180830390910181526064909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000178152825161074493879390925f9283929183919082885af1806108a4576040513d5f823e3d81fd5b50505f513d915081156108bb5780600114156108c8565b6001600160a01b0384163b155b15610742576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240160405180910390fd5b5f6060828403121561091e575f80fd5b50919050565b5f805f60e08486031215610936575f80fd5b833567ffffffffffffffff81111561094c575f80fd5b84016080818703121561095d575f80fd5b925061096c856020860161090e565b915061097b856080860161090e565b90509250925092565b6001600160a01b0381168114610998575f80fd5b50565b5f608082840312156109ab575f80fd5b6040516080810167ffffffffffffffff811182821017156109da57634e487b7160e01b5f52604160045260245ffd5b60405290508082356109eb81610984565b81526020838101359082015260408084013590820152606092830135920191909152919050565b5f610100828403128015610a24575f80fd5b5060405160a0810167ffffffffffffffff81118282101715610a5457634e487b7160e01b5f52604160045260245ffd5b6040528235610a6281610984565b8152602083810135908201526040808401359082015260608084013590820152610a8f846080850161099b565b60808201529392505050565b5f8060a08385031215610aac575f80fd5b82359150610abd846020850161099b565b90509250929050565b5f8060208385031215610ad7575f80fd5b823567ffffffffffffffff811115610aed575f80fd5b8301601f81018513610afd575f80fd5b803567ffffffffffffffff811115610b13575f80fd5b856020828401011115610b24575f80fd5b6020919091019590945092505050565b5f60808284031215610b44575f80fd5b610b4e838361099b565b9392505050565b5f808335601e19843603018112610b6a575f80fd5b83018035915067ffffffffffffffff821115610b84575f80fd5b602001915036819003821315610780575f80fd5b5f60208284031215610ba8575f80fd5b81356effffffffffffffffffffffffffffff81168114610b4e575f80fd5b634e487b7160e01b5f52601160045260245ffd5b81810381811115610bed57610bed610bc6565b92915050565b80820180821115610bed57610bed610bc6565b8082028115828204841417610bed57610bed610bc6565b5f60208284031215610c2d575f80fd5b505191905056000000000000000000000000a972a2c093456c7298c3527fc87de41f89a2ebae0000000000000000000000001fddc4eeec10e3317b27563ad0126285a329350d0000000000000000000000000000000000000000000000000000000000019640
Deployed Bytecode
0x608060405234801561000f575f80fd5b5060043610610085575f3560e01c806399d0dd371161005857806399d0dd37146101385780639fcd91b31461014d578063aebfab1b14610175578063fd89ea0c1461019c575f80fd5b80632cb0f8a21461008957806361d027b3146100c357806369179de314610102578063745835fb14610125575b5f80fd5b6100b07f000000000000000000000000000000000000000000000000000000000001964081565b6040519081526020015b60405180910390f35b6100ea7f0000000000000000000000001fddc4eeec10e3317b27563ad0126285a329350d81565b6040516001600160a01b0390911681526020016100ba565b610115610110366004610924565b6101af565b60405190151581526020016100ba565b6100b0610133366004610a12565b61037d565b61014b610146366004610a9b565b610415565b005b61016061015b366004610ac6565b610749565b604080519283526020830191909152016100ba565b6100ea7f000000000000000000000000a972a2c093456c7298c3527fc87de41f89a2ebae81565b6100b06101aa366004610b34565b610787565b5f805a90505f6101c26060870187610b55565b8101906101cf9190610a12565b90506101e16040850160208601610b98565b6effffffffffffffffffffffffffffff165f0361024e5780516001600160a01b0316158061021757508060400151816020015110155b1561024e576040517f5f6f132c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160208201516001600160a01b03909116319081111561029b576040517f9a741dc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8183604001516102ac9190610bda565b9050804710156102e8576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6102fb845f01518386606001516107f7565b905080610359576080840151606001511561031e57608084015160016060909101525b83516040516001600160a01b03909116907f562e5484ba6302d3b527d81d8e0785d4219c6fc724fefeaace98fb00b7b5296d905f90a2600195505b6103715a6103679087610bda565b8560800151610415565b50505050509392505050565b5f7f345105fee2b4f83de75717665d9692446c8fcd071758eb6cb93033bf416e88ef825f01518360200151846040015185606001516103bf8760800151610787565b6040805160208101979097526001600160a01b03909516948601949094526060850192909252608084015260a083015260c082015260e0015b604051602081830303815290604052805190602001209050919050565b80606001515f03610424575050565b80602001514811801561043a5750602081015115155b15610471576040517f2f3d0a5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040810151610480483a610bda565b11156104b8576040517f8ef482f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f3a6104e47f000000000000000000000000000000000000000000000000000000000001964085610bf3565b6104ee9190610c06565b82519091506001600160a01b03166105aa575f8260600151826105119190610bf3565b90508047101561053457604051637806a4f560e11b815260040160405180910390fd5b7f0000000000000000000000001fddc4eeec10e3317b27563ad0126285a329350d6001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b15801561058d575f80fd5b505af115801561059f573d5f803e3d5ffd5b505050505050505050565b606082015182516040517fd251f7ba0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018490525f92917f000000000000000000000000a972a2c093456c7298c3527fc87de41f89a2ebae169063d251f7ba90604401602060405180830381865afa158015610638573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061065c9190610c1d565b6106669190610bf3565b83516040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925082916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156106c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ed9190610c1d565b101561070c57604051637806a4f560e11b815260040160405180910390fd5b8251610742906001600160a01b03167f0000000000000000000000001fddc4eeec10e3317b27563ad0126285a329350d83610808565b505b505050565b5f807ff827d1af143d2e40b50ad77d3f6d66db049915c707be0527146e1cf1b44318fc61077b61013385870187610a12565b915091505b9250929050565b5f7f7aff6c7b9b8aafff555894be6cfd4a6211fc7adbcd97db18b05d4a51ed7482a0825f01518360200151846040015185606001516040516020016103f89594939291909485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b5f805f805f868887f1949350505050565b604080516001600160a01b03841660248201526044808201849052825180830390910181526064909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000178152825161074493879390925f9283929183919082885af1806108a4576040513d5f823e3d81fd5b50505f513d915081156108bb5780600114156108c8565b6001600160a01b0384163b155b15610742576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240160405180910390fd5b5f6060828403121561091e575f80fd5b50919050565b5f805f60e08486031215610936575f80fd5b833567ffffffffffffffff81111561094c575f80fd5b84016080818703121561095d575f80fd5b925061096c856020860161090e565b915061097b856080860161090e565b90509250925092565b6001600160a01b0381168114610998575f80fd5b50565b5f608082840312156109ab575f80fd5b6040516080810167ffffffffffffffff811182821017156109da57634e487b7160e01b5f52604160045260245ffd5b60405290508082356109eb81610984565b81526020838101359082015260408084013590820152606092830135920191909152919050565b5f610100828403128015610a24575f80fd5b5060405160a0810167ffffffffffffffff81118282101715610a5457634e487b7160e01b5f52604160045260245ffd5b6040528235610a6281610984565b8152602083810135908201526040808401359082015260608084013590820152610a8f846080850161099b565b60808201529392505050565b5f8060a08385031215610aac575f80fd5b82359150610abd846020850161099b565b90509250929050565b5f8060208385031215610ad7575f80fd5b823567ffffffffffffffff811115610aed575f80fd5b8301601f81018513610afd575f80fd5b803567ffffffffffffffff811115610b13575f80fd5b856020828401011115610b24575f80fd5b6020919091019590945092505050565b5f60808284031215610b44575f80fd5b610b4e838361099b565b9392505050565b5f808335601e19843603018112610b6a575f80fd5b83018035915067ffffffffffffffff821115610b84575f80fd5b602001915036819003821315610780575f80fd5b5f60208284031215610ba8575f80fd5b81356effffffffffffffffffffffffffffff81168114610b4e575f80fd5b634e487b7160e01b5f52601160045260245ffd5b81810381811115610bed57610bed610bc6565b92915050565b80820180821115610bed57610bed610bc6565b8082028115828204841417610bed57610bed610bc6565b5f60208284031215610c2d575f80fd5b505191905056
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a972a2c093456c7298c3527fc87de41f89a2ebae0000000000000000000000001fddc4eeec10e3317b27563ad0126285a329350d0000000000000000000000000000000000000000000000000000000000019640
-----Decoded View---------------
Arg [0] : feeTokenRegistryAddress (address): 0xa972A2C093456c7298C3527fc87DE41F89A2eBaE
Arg [1] : treasuryAddress (address): 0x1FDdC4EEEc10E3317B27563Ad0126285A329350d
Arg [2] : gasConstant_ (uint256): 104000
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000a972a2c093456c7298c3527fc87de41f89a2ebae
Arg [1] : 0000000000000000000000001fddc4eeec10e3317b27563ad0126285a329350d
Arg [2] : 0000000000000000000000000000000000000000000000000000000000019640
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.