Sepolia Testnet

Contract

0x1f719754FC21E58b628E02659896309354888058
Source Code Source Code

Overview

ETH Balance

0 ETH

More Info

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Amount

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
Amount
0x6101006089281632025-08-06 22:12:00195 days ago1754518320  Contract Creation0 ETH
Loading...
Loading
Loading...
Loading

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
DeactivateInstructionAction

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 {IOtimDelegate} from "../IOtimDelegate.sol";
import {IInstructionStorage} from "../core/interfaces/IInstructionStorage.sol";

import {OtimFee} from "./fee-models/OtimFee.sol";

import {IAction} from "./interfaces/IAction.sol";
import {
    IDeactivateInstructionAction,
    INSTRUCTION_TYPEHASH,
    ARGUMENTS_TYPEHASH
} from "./interfaces/IDeactivateInstructionAction.sol";

import {InvalidArguments, InstructionAlreadyDeactivated} from "./errors/Errors.sol";

/// @title DeactivateInstructionAction
/// @author Otim Labs, Inc.
/// @notice an Action that deactivates an existing instruction and charges a fee
contract DeactivateInstructionAction is IAction, IDeactivateInstructionAction, OtimFee {
    using InstructionLib for InstructionLib.Instruction;

    /// @notice the InstructionStorage contract
    IInstructionStorage public immutable instructionStorage;

    constructor(
        address instructionStorageAddress,
        address feeTokenRegistryAddress,
        address treasuryAddress,
        uint256 gasConstant_
    ) OtimFee(feeTokenRegistryAddress, treasuryAddress, gasConstant_) {
        instructionStorage = IInstructionStorage(instructionStorageAddress);
    }

    /// @inheritdoc IAction
    function argumentsHash(bytes calldata arguments) public pure returns (bytes32, bytes32) {
        return (INSTRUCTION_TYPEHASH, hash(abi.decode(arguments, (DeactivateInstruction))));
    }

    /// @inheritdoc IDeactivateInstructionAction
    function hash(DeactivateInstruction memory arguments) public pure returns (bytes32) {
        return keccak256(abi.encode(ARGUMENTS_TYPEHASH, arguments.instructionId, hash(arguments.fee)));
    }

    /// @inheritdoc IAction
    function execute(
        InstructionLib.Instruction calldata instruction,
        InstructionLib.Signature calldata,
        InstructionLib.ExecutionState calldata
    ) external override returns (bool) {
        // initial gas measurement for fee calculation
        uint256 startGas = gasleft();

        // decode the arguments from the instruction
        DeactivateInstruction memory arguments = abi.decode(instruction.arguments, (DeactivateInstruction));

        // check if arguments are valid
        if (instruction.maxExecutions != 1 || arguments.instructionId == bytes32(0)) {
            revert InvalidArguments();
        }

        // check if the instruction is already deactivated
        if (instructionStorage.isDeactivated(arguments.instructionId)) {
            revert InstructionAlreadyDeactivated();
        }

        // deactivate the instruction
        // slither-disable-next-line reentrancy-events
        instructionStorage.deactivateStorage(arguments.instructionId);

        // emit that the instruction has been deactivated
        emit IOtimDelegate.InstructionDeactivated(arguments.instructionId);

        // charge the fee
        chargeFee(startGas - gasleft(), arguments.fee);

        // this action has no auto-deactivation cases
        return false;
    }
}

// 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;

import {IERC165} from "@openzeppelin-contracts/utils/introspection/IERC165.sol";
import {IERC721Receiver} from "@openzeppelin-contracts/token/ERC721/IERC721Receiver.sol";
import {IERC1155Receiver} from "@openzeppelin-contracts/token/ERC1155/IERC1155Receiver.sol";
import {IERC1271} from "@openzeppelin-contracts/interfaces/IERC1271.sol";

import {IGateway} from "./core/interfaces/IGateway.sol";
import {IInstructionStorage} from "./core/interfaces/IInstructionStorage.sol";
import {IActionManager} from "./core/interfaces/IActionManager.sol";

import {InstructionLib} from "./libraries/Instruction.sol";

/// @title IOtimDelegate
/// @author Otim Labs, Inc.
/// @notice interface for OtimDelegate contract
interface IOtimDelegate is IERC165, IERC721Receiver, IERC1155Receiver, IERC1271 {
    /// @notice emitted when an Instruction is executed on behalf of a user
    event InstructionExecuted(bytes32 indexed instructionId, uint256 executionCount);
    /// @notice emitted when an Instruction is deactivated by the user before its natural completion
    event InstructionDeactivated(bytes32 indexed instructionId);

    error InvalidSignature(bytes32 instructionId);
    error ActionNotExecutable(bytes32 instructionId);
    error ActionExecutionFailed(bytes32 instructionId, bytes result);
    error ExecutionSameBlock(bytes32 instructionId);
    error InstructionAlreadyDeactivated(bytes32 instructionId);

    function gateway() external view returns (IGateway);
    function instructionStorage() external view returns (IInstructionStorage);
    function actionManager() external view returns (IActionManager);

    /// @notice execute an Instruction
    /// @dev the first execution "activates" the Instruction, subsequent calls ignore signature
    /// @param instruction - a conditional or scheduled recurring task to be carried out on behalf of the user
    /// @param signature - user signature over the Instruction activation hash
    function executeInstruction(
        InstructionLib.Instruction calldata instruction,
        InstructionLib.Signature calldata signature
    ) external;

    /// @notice deactivate an Instruction
    /// @param deactivation - a InstructionDeactivation struct
    /// @param signature - user signature over the Instruction deactivation hash
    function deactivateInstruction(
        InstructionLib.InstructionDeactivation calldata deactivation,
        InstructionLib.Signature calldata signature
    ) external;
}

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.26;

import {InstructionLib} from "../../libraries/Instruction.sol";

/// @title IInstructionStorage
/// @author Otim Labs, Inc.
/// @notice interface for InstructionStorage contract
interface IInstructionStorage {
    error DataCorruptionAttempted();

    /// @notice increments the execution counter for an Instruction and sets `lastExecuted` to current block.timestamp
    /// @param instructionId - unique identifier for an Instruction
    function incrementExecutionCounter(bytes32 instructionId) external;

    /// @notice increments the execution counter for an Instruction, sets `lastExecuted` to current block.timestamp, and deactivates
    /// @param instructionId - unique identifier for an Instruction
    function incrementAndDeactivate(bytes32 instructionId) external;

    /// @notice deactivates an Instruction's execution state in storage
    /// @param instructionId - unique identifier for an Instruction
    function deactivateStorage(bytes32 instructionId) external;

    /// @notice returns the execution state of an Instruction for a particular user
    /// @param user - the user the Instruction pertains to
    /// @param instructionId - unique identifier for an Instruction
    /// @return executionState - the current execution state of the Instruction
    function getExecutionState(address user, bytes32 instructionId)
        external
        view
        returns (InstructionLib.ExecutionState memory);

    /// @notice returns the execution state of an Instruction for msg.sender
    /// @param instructionId - unique identifier for an Instruction
    /// @return executionState - the current execution state of the Instruction
    function getExecutionState(bytes32 instructionId) external view returns (InstructionLib.ExecutionState memory);

    /// @notice checks if an Instruction is deactivated for msg.sender
    /// @param instructionId - unique identifier for an Instruction
    /// @return deactivated - true if the Instruction is deactivated
    function isDeactivated(bytes32 instructionId) external view returns (bool);
}

// 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,DeactivateInstruction deactivateInstruction)DeactivateInstruction(bytes32 instructionId,Fee fee)Fee(address token,uint256 maxBaseFeePerGas,uint256 maxPriorityFeePerGas,uint256 executionFee)"
);

bytes32 constant ARGUMENTS_TYPEHASH = keccak256(
    "DeactivateInstruction(bytes32 instructionId,Fee fee)Fee(address token,uint256 maxBaseFeePerGas,uint256 maxPriorityFeePerGas,uint256 executionFee)"
);

/// @title IDeactivateInstructionAction
/// @author Otim Labs, Inc.
/// @notice interface for DeactivateInstructionAction contract
interface IDeactivateInstructionAction is IOtimFee {
    /// @notice arguments for the DeactivateInstructionAction contract
    /// @param instructionId - the instructionId of the instruction to deactivate
    /// @param fee - the fee Otim will charge for the deactivation
    struct DeactivateInstruction {
        bytes32 instructionId;
        Fee fee;
    }

    /// @notice calculates the EIP-712 hash of the DeactivateInstruction struct
    function hash(DeactivateInstruction memory arguments) external pure returns (bytes32);
}

File 8 of 23 : Errors.sol
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.26;

error InvalidArguments();

error InsufficientBalance();

error BalanceOverThreshold();
error BalanceUnderThreshold();

error UniswapV3PoolDoesNotExist();

error InstructionAlreadyDeactivated();

error CallOnceFailed(address target, bytes4 selector, bytes result);

error CCTPTokenNotSupported();

error MaxDepositZero();
error MaxWithdrawZero();
error TotalAssetsTooLow();

File 9 of 23 : Constants.sol
// 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.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @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);
}

File 11 of 23 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity >=0.5.0;

/**
 * @title ERC-721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC-721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be
     * reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity >=0.6.2;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Interface that must be implemented by smart contracts in order to receive
 * ERC-1155 token transfers.
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC-1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC-1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1271.sol)

pragma solidity >=0.5.0;

/**
 * @dev Interface of the ERC-1271 standard signature validation method for
 * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
 */
interface IERC1271 {
    /**
     * @dev Should return whether the signature provided is valid for the provided data
     * @param hash      Hash of the data to be signed
     * @param signature Signature byte array associated with `hash`
     */
    function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4 magicValue);
}

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.26;

import {InstructionLib} from "../../libraries/Instruction.sol";

/// @title IGateway
/// @author Otim Labs, Inc.
/// @notice interface for the Gateway contract
interface IGateway {
    error TargetNotDelegated();

    /// @notice checks if the target address is delegated to OtimDelegate
    /// @param target - the target address to check
    /// @return delegated - if the target address is delegated to OtimDelegate
    function isDelegated(address target) external view returns (bool);

    /// @notice executes an Instruction on the target address if it is delegated to OtimDelegate
    /// @param target - the target account to execute the Instruction on
    /// @param instruction - the Instruction to execute
    /// @param signature - the Signature over the Instruction signing hash
    function safeExecuteInstruction(
        address target,
        InstructionLib.Instruction calldata instruction,
        InstructionLib.Signature calldata signature
    ) external;

    /// @notice executes an Instruction on the target address if it is delegated to OtimDelegate
    /// @dev After the first execution of an Instruction, the Signature is no longer checked, so we can omit the Signature in this case
    /// @param target - the target account to execute the Instruction on
    /// @param instruction - the Instruction to execute
    function safeExecuteInstruction(address target, InstructionLib.Instruction calldata instruction) external;

    /// @notice deactivates an Instruction on the target address if it is delegated to OtimDelegate
    /// @param target - the target account to deactivate the Instruction on
    /// @param deactivation - the InstructionDeactivation
    /// @param signature - the Signature over the InstructionDeactivation signing hash
    function safeDeactivateInstruction(
        address target,
        InstructionLib.InstructionDeactivation calldata deactivation,
        InstructionLib.Signature calldata signature
    ) external;
}

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.26;

/// @title IActionManager
/// @author Otim Labs, Inc.
/// @notice interface for ActionManager contract
interface IActionManager {
    /// @notice emitted when an Action is added
    event ActionAdded(address indexed action);
    /// @notice emitted when an Action is removed
    event ActionRemoved(address indexed action);
    /// @notice emitted when all Actions are globally locked
    event ActionsGloballyLocked();
    /// @notice emitted when all Actions are globally unlocked
    event ActionsGloballyUnlocked();

    error AlreadyAdded();
    error AlreadyRemoved();
    error AlreadyLocked();
    error AlreadyUnlocked();

    /// @notice returns Action metadata
    /// @param action - the address of the Action
    /// @return executable - true if the Action exists and is not locked
    function isExecutable(address action) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

/**
 * @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.4.0) (interfaces/IERC1363.sol)

pragma solidity >=0.6.2;

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);
}

File 22 of 23 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)

pragma solidity >=0.4.16;

import {IERC20} from "../token/ERC20/IERC20.sol";

File 23 of 23 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

import {IERC165} from "../utils/introspection/IERC165.sol";

Settings
{
  "remappings": [
    "@chainlink-contracts/=dependencies/smartcontractkit-chainlink-evm-1.5.0-beta.1/contracts/",
    "@openzeppelin-contracts/=dependencies/@openzeppelin-contracts-5.4.0/",
    "@openzeppelin/contracts/=dependencies/@openzeppelin-contracts-5.4.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.10.0/",
    "smartcontractkit-chainlink-evm/=dependencies/smartcontractkit-chainlink-evm-1.5.0-beta.1/",
    "@openzeppelin-contracts-5.4.0/=dependencies/@openzeppelin-contracts-5.4.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/solmate/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.10.0/=dependencies/forge-std-1.10.0/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.25.0/=dependencies/smartcontractkit-chainlink-2.25.0/",
    "smartcontractkit-chainlink-evm-1.5.0-beta.1/=dependencies/smartcontractkit-chainlink-evm-1.5.0-beta.1/",
    "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
}

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"instructionStorageAddress","type":"address"},{"internalType":"address","name":"feeTokenRegistryAddress","type":"address"},{"internalType":"address","name":"treasuryAddress","type":"address"},{"internalType":"uint256","name":"gasConstant_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BaseFeePerGasTooHigh","type":"error"},{"inputs":[],"name":"InstructionAlreadyDeactivated","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":"bytes32","name":"instructionId","type":"bytes32"}],"name":"InstructionDeactivated","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":"","type":"tuple"}],"name":"execute","outputs":[{"internalType":"bool","name":"","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":"bytes32","name":"instructionId","type":"bytes32"},{"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 IDeactivateInstructionAction.DeactivateInstruction","name":"arguments","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":"instructionStorage","outputs":[{"internalType":"contract IInstructionStorage","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"contract ITreasury","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

610100604052348015610010575f80fd5b50604051610d59380380610d5983398101604081905261002f9161006a565b6001600160a01b0392831660805290821660a05260c0521660e0526100b2565b80516001600160a01b0381168114610065575f80fd5b919050565b5f805f806080858703121561007d575f80fd5b6100868561004f565b93506100946020860161004f565b92506100a26040860161004f565b6060959095015193969295505050565b60805160a05160c05160e051610c4c61010d5f395f81816101a80152818161028e015261036801525f818160a801526104c001525f818160e201528181610537015261071e01525f818161018101526105f40152610c4c5ff3fe608060405234801561000f575f80fd5b506004361061009f575f3560e01c80639fcd91b311610072578063ce0dafae11610058578063ce0dafae146101a3578063e85ea1a1146101ca578063fd89ea0c146101dd575f80fd5b80639fcd91b314610154578063aebfab1b1461017c575f80fd5b80632cb0f8a2146100a357806361d027b3146100dd57806369179de31461011c57806399d0dd371461013f575b5f80fd5b6100ca7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b6101047f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100d4565b61012f61012a36600461097f565b6101f0565b60405190151581526020016100d4565b61015261014d366004610a61565b610416565b005b610167610162366004610a8c565b61074a565b604080519283526020830191909152016100d4565b6101047f000000000000000000000000000000000000000000000000000000000000000081565b6101047f000000000000000000000000000000000000000000000000000000000000000081565b6100ca6101d8366004610afa565b610788565b6100ca6101eb366004610b5b565b6107f3565b5f805a90505f6102036060870187610b7c565b8101906102109190610afa565b90508560200135600114158061022557508051155b1561025c576040517f5f6f132c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516040517fcb4cf15b00000000000000000000000000000000000000000000000000000000815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063cb4cf15b90602401602060405180830381865afa1580156102db573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102ff9190610bbf565b15610336576040517fa8dea50300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516040517f8d5066a900000000000000000000000000000000000000000000000000000000815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690638d5066a9906024015f604051808303815f87803b1580156103b1575f80fd5b505af11580156103c3573d5f803e3d5ffd5b505082516040519092507f1082dc6fb1ba8d32f074a5e83864cf6cc4b447170a99e122100a5ed6107bd57491505f90a261040b5a6104019084610bf2565b8260200151610416565b505f95945050505050565b80606001515f03610425575050565b80602001514811801561043b5750602081015115155b15610472576040517f2f3d0a5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040810151610481483a610bf2565b11156104b9576040517f8ef482f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f3a6104e57f000000000000000000000000000000000000000000000000000000000000000085610c0b565b6104ef9190610c1e565b82519091506001600160a01b03166105ab575f8260600151826105129190610c0b565b90508047101561053557604051637806a4f560e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b15801561058e575f80fd5b505af11580156105a0573d5f803e3d5ffd5b505050505050505050565b606082015182516040517fd251f7ba0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018490525f92917f0000000000000000000000000000000000000000000000000000000000000000169063d251f7ba90604401602060405180830381865afa158015610639573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061065d9190610c35565b6106679190610c0b565b83516040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925082916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156106ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ee9190610c35565b101561070d57604051637806a4f560e11b815260040160405180910390fd5b8251610743906001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000083610863565b505b505050565b5f807f5501059da533d4c16b7329ec5ff22a401fd84a1cf2ce1808a52150ff6eaf028561077c6101d885870187610afa565b915091505b9250929050565b5f7fd126c9405f46de536c951dce6a20eced3f5ac9fc7cae9120f53566934179b757825f01516107bb84602001516107f3565b60408051602081019490945283019190915260608201526080015b604051602081830303815290604052805190602001209050919050565b5f7f7aff6c7b9b8aafff555894be6cfd4a6211fc7adbcd97db18b05d4a51ed7482a0825f01518360200151846040015185606001516040516020016107d69594939291909485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b604080516001600160a01b03841660248201526044808201849052825180830390910181526064909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000178152825161074593879390925f9283929183919082885af1806108ff576040513d5f823e3d81fd5b50505f513d91508115610916578060011415610923565b6001600160a01b0384163b155b15610743576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240160405180910390fd5b5f60608284031215610979575f80fd5b50919050565b5f805f60e08486031215610991575f80fd5b833567ffffffffffffffff8111156109a7575f80fd5b8401608081870312156109b8575f80fd5b92506109c78560208601610969565b91506109d68560808601610969565b90509250925092565b5f608082840312156109ef575f80fd5b6040516080810167ffffffffffffffff81118282101715610a1e57634e487b7160e01b5f52604160045260245ffd5b60405290508082356001600160a01b0381168114610a3a575f80fd5b81526020838101359082015260408084013590820152606092830135920191909152919050565b5f8060a08385031215610a72575f80fd5b82359150610a8384602085016109df565b90509250929050565b5f8060208385031215610a9d575f80fd5b823567ffffffffffffffff811115610ab3575f80fd5b8301601f81018513610ac3575f80fd5b803567ffffffffffffffff811115610ad9575f80fd5b856020828401011115610aea575f80fd5b6020919091019590945092505050565b5f60a0828403128015610b0b575f80fd5b506040805190810167ffffffffffffffff81118282101715610b3b57634e487b7160e01b5f52604160045260245ffd5b60405282358152610b4f84602085016109df565b60208201529392505050565b5f60808284031215610b6b575f80fd5b610b7583836109df565b9392505050565b5f808335601e19843603018112610b91575f80fd5b83018035915067ffffffffffffffff821115610bab575f80fd5b602001915036819003821315610781575f80fd5b5f60208284031215610bcf575f80fd5b81518015158114610b75575f80fd5b634e487b7160e01b5f52601160045260245ffd5b81810381811115610c0557610c05610bde565b92915050565b80820180821115610c0557610c05610bde565b8082028115828204841417610c0557610c05610bde565b5f60208284031215610c45575f80fd5b5051919050560000000000000000000000008a26da63b7300f93c18a472ce440508c284c77d600000000000000000000000019c370a2e300429f98c17803984dc5413faac02e000000000000000000000000c7536a1e8205c139d25165f6305e20299b7925110000000000000000000000000000000000000000000000000000000000019258

Deployed Bytecode

0x608060405234801561000f575f80fd5b506004361061009f575f3560e01c80639fcd91b311610072578063ce0dafae11610058578063ce0dafae146101a3578063e85ea1a1146101ca578063fd89ea0c146101dd575f80fd5b80639fcd91b314610154578063aebfab1b1461017c575f80fd5b80632cb0f8a2146100a357806361d027b3146100dd57806369179de31461011c57806399d0dd371461013f575b5f80fd5b6100ca7f000000000000000000000000000000000000000000000000000000000001925881565b6040519081526020015b60405180910390f35b6101047f000000000000000000000000c7536a1e8205c139d25165f6305e20299b79251181565b6040516001600160a01b0390911681526020016100d4565b61012f61012a36600461097f565b6101f0565b60405190151581526020016100d4565b61015261014d366004610a61565b610416565b005b610167610162366004610a8c565b61074a565b604080519283526020830191909152016100d4565b6101047f00000000000000000000000019c370a2e300429f98c17803984dc5413faac02e81565b6101047f0000000000000000000000008a26da63b7300f93c18a472ce440508c284c77d681565b6100ca6101d8366004610afa565b610788565b6100ca6101eb366004610b5b565b6107f3565b5f805a90505f6102036060870187610b7c565b8101906102109190610afa565b90508560200135600114158061022557508051155b1561025c576040517f5f6f132c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516040517fcb4cf15b00000000000000000000000000000000000000000000000000000000815260048101919091527f0000000000000000000000008a26da63b7300f93c18a472ce440508c284c77d66001600160a01b03169063cb4cf15b90602401602060405180830381865afa1580156102db573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102ff9190610bbf565b15610336576040517fa8dea50300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516040517f8d5066a900000000000000000000000000000000000000000000000000000000815260048101919091527f0000000000000000000000008a26da63b7300f93c18a472ce440508c284c77d66001600160a01b031690638d5066a9906024015f604051808303815f87803b1580156103b1575f80fd5b505af11580156103c3573d5f803e3d5ffd5b505082516040519092507f1082dc6fb1ba8d32f074a5e83864cf6cc4b447170a99e122100a5ed6107bd57491505f90a261040b5a6104019084610bf2565b8260200151610416565b505f95945050505050565b80606001515f03610425575050565b80602001514811801561043b5750602081015115155b15610472576040517f2f3d0a5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040810151610481483a610bf2565b11156104b9576040517f8ef482f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f3a6104e57f000000000000000000000000000000000000000000000000000000000001925885610c0b565b6104ef9190610c1e565b82519091506001600160a01b03166105ab575f8260600151826105129190610c0b565b90508047101561053557604051637806a4f560e11b815260040160405180910390fd5b7f000000000000000000000000c7536a1e8205c139d25165f6305e20299b7925116001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b15801561058e575f80fd5b505af11580156105a0573d5f803e3d5ffd5b505050505050505050565b606082015182516040517fd251f7ba0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018490525f92917f00000000000000000000000019c370a2e300429f98c17803984dc5413faac02e169063d251f7ba90604401602060405180830381865afa158015610639573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061065d9190610c35565b6106679190610c0b565b83516040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925082916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156106ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ee9190610c35565b101561070d57604051637806a4f560e11b815260040160405180910390fd5b8251610743906001600160a01b03167f000000000000000000000000c7536a1e8205c139d25165f6305e20299b79251183610863565b505b505050565b5f807f5501059da533d4c16b7329ec5ff22a401fd84a1cf2ce1808a52150ff6eaf028561077c6101d885870187610afa565b915091505b9250929050565b5f7fd126c9405f46de536c951dce6a20eced3f5ac9fc7cae9120f53566934179b757825f01516107bb84602001516107f3565b60408051602081019490945283019190915260608201526080015b604051602081830303815290604052805190602001209050919050565b5f7f7aff6c7b9b8aafff555894be6cfd4a6211fc7adbcd97db18b05d4a51ed7482a0825f01518360200151846040015185606001516040516020016107d69594939291909485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b604080516001600160a01b03841660248201526044808201849052825180830390910181526064909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000178152825161074593879390925f9283929183919082885af1806108ff576040513d5f823e3d81fd5b50505f513d91508115610916578060011415610923565b6001600160a01b0384163b155b15610743576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240160405180910390fd5b5f60608284031215610979575f80fd5b50919050565b5f805f60e08486031215610991575f80fd5b833567ffffffffffffffff8111156109a7575f80fd5b8401608081870312156109b8575f80fd5b92506109c78560208601610969565b91506109d68560808601610969565b90509250925092565b5f608082840312156109ef575f80fd5b6040516080810167ffffffffffffffff81118282101715610a1e57634e487b7160e01b5f52604160045260245ffd5b60405290508082356001600160a01b0381168114610a3a575f80fd5b81526020838101359082015260408084013590820152606092830135920191909152919050565b5f8060a08385031215610a72575f80fd5b82359150610a8384602085016109df565b90509250929050565b5f8060208385031215610a9d575f80fd5b823567ffffffffffffffff811115610ab3575f80fd5b8301601f81018513610ac3575f80fd5b803567ffffffffffffffff811115610ad9575f80fd5b856020828401011115610aea575f80fd5b6020919091019590945092505050565b5f60a0828403128015610b0b575f80fd5b506040805190810167ffffffffffffffff81118282101715610b3b57634e487b7160e01b5f52604160045260245ffd5b60405282358152610b4f84602085016109df565b60208201529392505050565b5f60808284031215610b6b575f80fd5b610b7583836109df565b9392505050565b5f808335601e19843603018112610b91575f80fd5b83018035915067ffffffffffffffff821115610bab575f80fd5b602001915036819003821315610781575f80fd5b5f60208284031215610bcf575f80fd5b81518015158114610b75575f80fd5b634e487b7160e01b5f52601160045260245ffd5b81810381811115610c0557610c05610bde565b92915050565b80820180821115610c0557610c05610bde565b8082028115828204841417610c0557610c05610bde565b5f60208284031215610c45575f80fd5b505191905056

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000008a26da63b7300f93c18a472ce440508c284c77d600000000000000000000000019c370a2e300429f98c17803984dc5413faac02e000000000000000000000000c7536a1e8205c139d25165f6305e20299b7925110000000000000000000000000000000000000000000000000000000000019258

-----Decoded View---------------
Arg [0] : instructionStorageAddress (address): 0x8A26dA63B7300f93c18A472cE440508C284C77d6
Arg [1] : feeTokenRegistryAddress (address): 0x19c370A2e300429F98c17803984DC5413faAc02E
Arg [2] : treasuryAddress (address): 0xc7536a1e8205C139d25165F6305e20299b792511
Arg [3] : gasConstant_ (uint256): 103000

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000008a26da63b7300f93c18a472ce440508c284c77d6
Arg [1] : 00000000000000000000000019c370a2e300429f98c17803984dc5413faac02e
Arg [2] : 000000000000000000000000c7536a1e8205c139d25165f6305e20299b792511
Arg [3] : 0000000000000000000000000000000000000000000000000000000000019258


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
0x1f719754FC21E58b628E02659896309354888058
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.