ETH Price: $2,946.10 (-3.03%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

4 Internal Transactions found.

Latest 4 internal transactions

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x60806040226361122025-06-05 4:42:5939 days ago1749098579
0x23E5F9C4...01D66fcE8
 Contract Creation0 ETH
0x60a06040226361122025-06-05 4:42:5939 days ago1749098579
0x23E5F9C4...01D66fcE8
 Contract Creation0 ETH
0x60a06040226361122025-06-05 4:42:5939 days ago1749098579
0x23E5F9C4...01D66fcE8
 Contract Creation0 ETH
0x61010060226361122025-06-05 4:42:5939 days ago1749098579  Contract Creation0 ETH

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:
OtimDelegate

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 1000 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.26;

// dependencies
import {IERC165} from "@openzeppelin-contracts/utils/introspection/IERC165.sol";
import {IERC1271} from "@openzeppelin-contracts/interfaces/IERC1271.sol";
import {ReentrancyGuardTransient} from "@openzeppelin-contracts/utils/ReentrancyGuardTransient.sol";
import {ECDSA} from "@openzeppelin-contracts/utils/cryptography/ECDSA.sol";

// receiver abstract contract
import {Receiver} from "./context/Receiver.sol";

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

// core contracts
import {Gateway} from "./core/Gateway.sol";
import {InstructionStorage} from "./core/InstructionStorage.sol";
import {ActionManager} from "./core/ActionManager.sol";

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

/// @title OtimDelegate
/// @author Otim Labs, Inc.
/// @notice the EIP-7702 delegate contract for the Otim protocol
contract OtimDelegate is IOtimDelegate, Receiver, ReentrancyGuardTransient {
    using InstructionLib for InstructionLib.Instruction;
    using InstructionLib for InstructionLib.InstructionDeactivation;

    /// @notice a helper contract for checking user delegation status
    IGateway public immutable gateway;

    /// @notice a helper contract for storing user Instruction execution state
    IInstructionStorage public immutable instructionStorage;
    /// @notice a helper contract for managing access to Actions
    IActionManager public immutable actionManager;

    /// @notice the EIP-712 domain separator for OtimDelegate
    bytes32 public immutable domainSeparator;

    constructor(address owner) {
        gateway = new Gateway();

        instructionStorage = new InstructionStorage();
        actionManager = new ActionManager(owner);

        domainSeparator = keccak256(
            abi.encode(
                keccak256(
                    "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)"
                ),
                keccak256("OtimDelegate"),
                keccak256("1"),
                block.chainid,
                address(this),
                keccak256("ON_TIME_INSTRUCTED_MONEY")
            )
        );
    }

    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public pure override(IERC165, Receiver) returns (bool) {
        return super.supportsInterface(interfaceId) || interfaceId == type(IERC1271).interfaceId
            || interfaceId == type(IOtimDelegate).interfaceId;
    }

    /// @inheritdoc IERC1271
    function isValidSignature(bytes32 hash, bytes memory signature) public view returns (bytes4) {
        // try to recover the signer from the hash and signature
        // slither-disable-next-line unused-return
        (address signer,,) = ECDSA.tryRecover(hash, signature);

        // return the selector if the signer is the current EOA
        return signer == address(this) ? this.isValidSignature.selector : bytes4(0);
    }

    /// @inheritdoc IOtimDelegate
    function executeInstruction(
        InstructionLib.Instruction calldata instruction,
        InstructionLib.Signature calldata signature
    ) external nonReentrant {
        // calculate the unique identifier for this Instruction
        bytes32 instructionId = instruction.id();

        // read execution state from external storage using the unique identifier
        InstructionLib.ExecutionState memory executionState = instructionStorage.getExecutionState(instructionId);

        // revert if the Instruction has already been deactivated
        if (executionState.deactivated) revert InstructionAlreadyDeactivated(instructionId);

        // revert if the Action contract is not executable
        bool executable = actionManager.isExecutable(instruction.action);
        if (!executable) revert ActionNotExecutable(instructionId);

        // if this is the first execution, carry out validation checks
        if (executionState.executionCount == 0) {
            // call the Action contract to return EIP-712 Instruction type and arguments hash
            (bytes32 instructionTypeHash, bytes32 argumentsHash) =
                IAction(instruction.action).argumentsHash(instruction.arguments);

            // calculate the signing hash for the Instruction
            bytes32 signingHash = instruction.signingHash(domainSeparator, instructionTypeHash, argumentsHash);

            // recover the signer from the signing hash and signature
            // slither-disable-next-line unused-return
            (address signer,,) = ECDSA.tryRecover(signingHash, signature.v, signature.r, signature.s);

            // revert if the signer is not the current EOA
            if (signer != address(this)) revert InvalidSignature(instructionId);
        }

        // ensures that the Instruction is not executed twice in the same block
        if (block.timestamp <= executionState.lastExecuted) {
            revert ExecutionSameBlock(instructionId);
        }

        // execute the Action contract
        // slither-disable-start controlled-delegatecall
        // slither-disable-next-line reentrancy-events
        (bool success, bytes memory executionResult) = instruction.action.delegatecall(
            abi.encodeWithSelector(IAction.execute.selector, instruction, signature, executionState)
        );
        // slither-disable-end controlled-delegatecall

        // revert if the Action contract execution reverted
        if (!success) revert ActionExecutionFailed(instructionId, executionResult);

        // if the Action succeeds but returns deactivate = true, this means the Instruction should be automatically deactivated
        if (abi.decode(executionResult, (bool))) {
            // deactivate the Instruction, don't increment executionCount or update lastExecuted
            instructionStorage.deactivateStorage(instructionId);

            // emit that the Instruction was deactivated
            emit InstructionDeactivated(instructionId);

            return;
        } else if (++executionState.executionCount == instruction.maxExecutions) {
            // if this is the Instruction's final successful execution, increment executionCount and deactivate
            instructionStorage.incrementAndDeactivate(instructionId);
        } else {
            // if this is not the final successful execution, just increment the executionCount
            instructionStorage.incrementExecutionCounter(instructionId);
        }

        // emit that the Instruction was executed successfully
        emit InstructionExecuted(instructionId, executionState.executionCount);
    }

    /// @inheritdoc IOtimDelegate
    function deactivateInstruction(
        InstructionLib.InstructionDeactivation calldata deactivation,
        InstructionLib.Signature calldata signature
    ) external {
        // read deactivation status from external storage, revert if already deactivated
        bool deactivated = instructionStorage.isDeactivated(deactivation.instructionId);
        if (deactivated) revert InstructionAlreadyDeactivated(deactivation.instructionId);

        // calculate deactivation signing hash
        bytes32 signingHash = deactivation.signingHash(domainSeparator);

        // recover the signer from the signing hash and signature
        // slither-disable-next-line unused-return
        (address signer,,) = ECDSA.tryRecover(signingHash, signature.v, signature.r, signature.s);

        // revert if the signer is not the current EOA
        if (signer != address(this)) revert InvalidSignature(deactivation.instructionId);

        // deactivate the Instruction in external storage
        // slither-disable-next-line reentrancy-events
        instructionStorage.deactivateStorage(deactivation.instructionId);

        // emit that the Instruction was deactivated successfully
        emit InstructionDeactivated(deactivation.instructionId);
    }
}

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

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

pragma solidity ^0.8.20;

/**
 * @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 memory signature) external view returns (bytes4 magicValue);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/ReentrancyGuardTransient.sol)

pragma solidity ^0.8.24;

import {TransientSlot} from "./TransientSlot.sol";

/**
 * @dev Variant of {ReentrancyGuard} that uses transient storage.
 *
 * NOTE: This variant only works on networks where EIP-1153 is available.
 *
 * _Available since v5.1._
 */
abstract contract ReentrancyGuardTransient {
    using TransientSlot for *;

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant REENTRANCY_GUARD_STORAGE =
        0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, REENTRANCY_GUARD_STORAGE.asBoolean().tload() will be false
        if (_reentrancyGuardEntered()) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true);
    }

    function _nonReentrantAfter() private {
        REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false);
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return REENTRANCY_GUARD_STORAGE.asBoolean().tload();
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(
        bytes32 hash,
        bytes memory signature
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly ("memory-safe") {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}

// SPDX-License-Identifier: MIT
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";

/// @title Receiver
/// @author Otim Labs, Inc.
/// @notice abstract contract for receiving ERC721 and ERC1155 tokens
abstract contract Receiver is IERC165, IERC721Receiver, IERC1155Receiver {
    /// @notice allows contract to receive ether
    receive() external payable {}

    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId || interfaceId == type(IERC721Receiver).interfaceId
            || interfaceId == type(IERC1155Receiver).interfaceId;
    }

    /// @inheritdoc IERC721Receiver
    function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) {
        return this.onERC721Received.selector;
    }

    /// @inheritdoc IERC1155Receiver
    function onERC1155Received(address, address, uint256, uint256, bytes calldata)
        external
        pure
        override
        returns (bytes4)
    {
        return this.onERC1155Received.selector;
    }

    /// @inheritdoc IERC1155Receiver
    function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata)
        external
        pure
        override
        returns (bytes4)
    {
        return this.onERC1155BatchReceived.selector;
    }
}

// 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 {Constants} from "../libraries/Constants.sol";
import {InstructionLib} from "../libraries/Instruction.sol";

import {IGateway} from "./interfaces/IGateway.sol";
import {IOtimDelegate} from "../IOtimDelegate.sol";

/// @title Gateway
/// @author Otim Labs, Inc.
/// @notice a helper contract that protects the Otim Executor from delegation front-running attacks
contract Gateway is IGateway {
    /// @notice hash of the "delegation designator" i.e. keccak256(0xef0100 || delegate_address)
    bytes32 public immutable designatorHash;

    constructor() {
        designatorHash = keccak256(abi.encodePacked(Constants.EIP7702_PREFIX, msg.sender));
    }

    /// @inheritdoc IGateway
    function isDelegated(address target) external view override returns (bool) {
        return target.codehash == designatorHash;
    }

    /// @inheritdoc IGateway
    function safeExecuteInstruction(
        address target,
        InstructionLib.Instruction calldata instruction,
        InstructionLib.Signature calldata signature
    ) external {
        // revert if the target is not delegated to OtimDelegate at runtime
        if (target.codehash != designatorHash) {
            revert TargetNotDelegated();
        }

        // execute the Instruction on the target account
        IOtimDelegate(target).executeInstruction(instruction, signature);
    }

    /// @inheritdoc IGateway
    function safeExecuteInstruction(address target, InstructionLib.Instruction calldata instruction) external {
        // revert if the target is not delegated to OtimDelegate at runtime
        if (target.codehash != designatorHash) {
            revert TargetNotDelegated();
        }

        // execute the Instruction on the target account with no signature
        IOtimDelegate(target).executeInstruction(instruction, InstructionLib.Signature(0, 0, 0));
    }

    /// @inheritdoc IGateway
    function safeDeactivateInstruction(
        address target,
        InstructionLib.InstructionDeactivation calldata deactivation,
        InstructionLib.Signature calldata signature
    ) external {
        // revert if the target is not delegated to OtimDelegate at runtime
        if (target.codehash != designatorHash) {
            revert TargetNotDelegated();
        }

        // execute the Instruction on the target account
        IOtimDelegate(target).deactivateInstruction(deactivation, signature);
    }
}

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

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

import {IInstructionStorage} from "./interfaces/IInstructionStorage.sol";

/// @title InstructionStorage
/// @author Otim Labs, Inc.
/// @notice external storage contract for storing Instruction execution state
contract InstructionStorage is IInstructionStorage {
    //slither-disable-start too-many-digits

    /// @notice hash of the "delegation designator" i.e. keccak256(0xef0100 || delegate_address)
    bytes32 public immutable designatorHash;

    /// @notice reverts if the modified function is not called from within the code of a delegated EOA
    /// @dev if the EOA codehash matches `designator`, the EOA is delegated to some contract,
    ///      and if msg.sender is not equal to tx.origin, the EOA has not called the function directly
    modifier fromDelegateCodeOnly() {
        // IInstructionStorage.DataCorruptionAttempted.selector = 0xabdc7b7a

        bytes32 designatorHash_ = designatorHash;

        assembly {
            // revert if msg.sender == tx.origin OR msg.sender.codehash != delegateCodehash
            // from innermost to outermost:
            // 1. retrieve the codehash of the msg.sender
            // 2. load `delegateCodehash` from storage (slot 0 is the address of the `owner` and slot 1 is the `delegateCodehash`)
            // 3. compare the codehash of msg.sender to the `delegateCodehash`
            // 4. if they are not equal, revert
            // 5. compare msg.sender to tx.origin
            // 6. if they are equal, revert
            if or(eq(caller(), origin()), iszero(eq(extcodehash(caller()), designatorHash_))) {
                // store `IInstructionStorage.DataCorruptionAttempted.selector` in memory.
                // memory bytes [0, 27] are zero and bytes [28, 31] are the 4-byte-long selector
                mstore(0x0, 0xabdc7b7a)
                // decoding this revert statement: we revert starting at memory byte 28 with a length of 4
                // to return the selector as the reason for the revert
                revert(0x1c, 0x4)
            }
        }
        _;
    }

    constructor() {
        // construct the "delegation designator", then hash it.
        // OtimDelegate will deploy this contract so msg.sender will be the address of the delegate contract
        designatorHash = keccak256(abi.encodePacked(Constants.EIP7702_PREFIX, msg.sender));
    }

    /// @inheritdoc IInstructionStorage
    function incrementExecutionCounter(bytes32 instructionId) external fromDelegateCodeOnly {
        assembly {
            // store msg.sender in memory: bytes [0, 11] are 0, bytes [12, 31] are msg.sender address
            mstore(0x0, caller())
            // store `instructionId` in memory bytes [32, 63]
            mstore(0x20, instructionId)
            // compute the keccak256 hash of memory bytes [0, 63] to use as the storage `key`
            let key := keccak256(0x0, 0x40)
            // from innermost to outermost:
            // 1. load the storage value at `key`. This value is structured as follows:
            //    byte 0 is free,
            //    byte 1 is the `deactivated` boolean,
            //    bytes [2, 16] are the `counter`,
            //    bytes [17, 31] are the `lastExecuted` timestamp
            // 2. discard `lastExecuted` by masking out the last 15 bytes
            // 3. increment `counter` by 1 (add 1 left-shifted by 15 bytes to the retrieved storage value)
            // 4. set the last 15 bytes of the storage value to the current block.timestamp
            // 5. store the updated storage value at `key`
            /// @dev casting `block.timestamp` from uint256 to uint120 is safe because it will only overflow
            ///      2^120 seconds after epoch which is approximately 40 Octillion years from now... we'll have a v2 by then :)
            ///      Similarly, using a uint120 for the `counter` is safe because it will only overflow after
            ///      2^120 executions (approximately 1 Undecillion executions). Also, despite this being completely infeasible,
            ///      if `counter` were to overflow, it would simply set the `deactivated` boolean to true, making it
            ///      impossible to execute the Instruction again.
            sstore(
                key,
                or(
                    add(
                        and(sload(key), 0xffffffffffffffffffffffffffffffffff000000000000000000000000000000),
                        0x1000000000000000000000000000000
                    ),
                    timestamp()
                )
            )
        }
    }

    /// @inheritdoc IInstructionStorage
    function incrementAndDeactivate(bytes32 instructionId) external fromDelegateCodeOnly {
        assembly {
            // store msg.sender in memory: bytes [0, 11] are 0, bytes [12, 31] are msg.sender address
            mstore(0x0, caller())
            // store `instructionId` in memory bytes [32, 63]
            mstore(0x20, instructionId)
            // compute the keccak256 hash of memory bytes [0, 63] to use as the storage `key`
            let key := keccak256(0x0, 0x40)
            // from innermost to outermost:
            // 1. load the storage value at `key`. This value is structured as follows:
            //    byte 0 is free,
            //    byte 1 is the `deactivated` boolean,
            //    bytes [2, 16] are the `counter`,
            //    bytes [17, 31] are the `lastExecuted` timestamp
            // 2. discard `lastExecuted` by masking out the last 15 bytes
            // 3. increment `counter` by 1 (add 1 left-shifted by 15 bytes to the retrieved storage value)
            // 4. set the last 15 bytes of the storage value to the current block.timestamp
            // 5. set the `deactivated` boolean to true
            // 6. store the updated storage value at `key`
            sstore(
                key,
                or(
                    or(
                        add(
                            and(sload(key), 0xffffffffffffffffffffffffffffffffff000000000000000000000000000000),
                            0x1000000000000000000000000000000
                        ),
                        timestamp()
                    ),
                    0x1000000000000000000000000000000000000000000000000000000000000
                )
            )
        }
    }

    /// @inheritdoc IInstructionStorage
    function deactivateStorage(bytes32 instructionId) external fromDelegateCodeOnly {
        assembly {
            // store msg.sender in memory: bytes [0, 11] are 0, bytes [12, 31] are msg.sender address
            mstore(0x0, caller())
            // store `instructionId` in memory bytes [32, 63]
            mstore(0x20, instructionId)
            // compute the keccak256 hash of memory bytes [0, 63] to use as the storage `key`
            let key := keccak256(0x0, 0x40)
            // 1. load the storage value at `key`
            // 2. set the `deactivated` boolean to true
            // 3. store the updated storage value at `key`
            sstore(key, or(sload(key), 0x1000000000000000000000000000000000000000000000000000000000000))
        }
    }

    /// @inheritdoc IInstructionStorage
    function isDeactivated(bytes32 instructionId) external view returns (bool) {
        assembly {
            // store msg.sender in memory: bytes [0, 11] are 0, bytes [12, 31] are msg.sender address
            mstore(0x0, caller())
            // store `instructionId` in memory bytes [32, 63]
            mstore(0x20, instructionId)
            // compute the keccak256 hash of memory bytes [0, 63] to use as the storage `key`
            let key := keccak256(0x0, 0x40)
            // 1. load the storage value at `key`
            // 2. right-shift the loaded storage value by 30 bytes to get the `deactivated` boolean
            // 3. store the `deactivated` boolean in memory bytes [0, 31]
            mstore(0x0, shr(0xf0, sload(key)))
            // return the `deactivated` boolean (memory starting at 0 with a length of 32)
            return(0x0, 0x20)
        }
    }

    /// @inheritdoc IInstructionStorage
    function getExecutionState(bytes32 instructionId) external view returns (InstructionLib.ExecutionState memory) {
        assembly {
            // store msg.sender in memory: bytes [0, 11] are 0, bytes [12, 31] are msg.sender address
            mstore(0x0, caller())
            // store `instructionId` in memory bytes [32, 63]
            mstore(0x20, instructionId)
            // compute the keccak256 hash of memory bytes [0, 63] to use as the storage `key`
            let key := keccak256(0x0, 0x40)
            // load the storage value at `key` into `value`
            let value := sload(key)
            // load the 32-byte word at memory location 0x40 into `ptr`. This is the location of the next free slot in memory
            /// @dev we have to use free memory slots to store return values here because they are more than 64 bytes
            let ptr := mload(0x40)
            // 1. right-shift `value` by 30 bytes to get the `deactivated` boolean
            // 2. store this at memory location `ptr`
            mstore(ptr, shr(0xf0, value))
            // 1. right-shift `value` by 15 bytes to get rid of `lastExecuted`
            // 2. mask out the first 17 bytes of `value` to get `counter`
            // 3. store this at memory location `ptr` + 32 bytes
            mstore(add(ptr, 0x20), and(0xffffffffffffffffffffffffffffff, shr(0x78, value)))
            // 1. mask out the first 17 bytes of `value` to get `lastExecuted`
            // 2. store this at memory location `ptr` + 64 bytes
            mstore(add(ptr, 0x40), and(0xffffffffffffffffffffffffffffff, value))
            // return `deactivated`, `counter`, and `lastExecuted` as separate values
            // by returning memory starting at `ptr` with a length of 96 bytes
            return(ptr, 0x60)
        }
    }

    /// @notice returns the execution state of an Instruction for a particular user
    /// @param instructionId - unique identifier for an Instruction
    /// @param user - address of the EOA to return execution state for
    /// @return executionState - the current execution state of the Instruction
    function getExecutionState(address user, bytes32 instructionId)
        external
        view
        returns (InstructionLib.ExecutionState memory)
    {
        assembly {
            // store `user` in memory: bytes [0, 11] are 0, bytes [12, 31] are `user`
            mstore(0x0, user)
            // store `instructionId` in memory bytes [32, 63]
            mstore(0x20, instructionId)
            // compute the keccak256 hash of memory bytes [0, 63] to use as the storage `key`
            let key := keccak256(0x0, 0x40)
            // load the storage value at `key` into `value`
            let value := sload(key)
            // load the 32-byte word at memory location 0x40 into `ptr`. This is the location of the next free slot in memory
            let ptr := mload(0x40)
            // 1. right-shift `value` by 30 bytes to get the `deactivated` boolean
            // 2. store this at memory location `ptr`
            mstore(ptr, shr(0xf0, value))
            // 1. right-shift `value` by 15 bytes to get rid of `lastExecuted`
            // 2. mask out the first 17 bytes of `value` to get `counter`
            // 3. store this at memory location `ptr` + 32 bytes
            mstore(add(ptr, 0x20), and(0xffffffffffffffffffffffffffffff, shr(0x78, value)))
            // 1. mask out the first 17 bytes of `value` to get `lastExecuted`
            // 2. store this at memory location `ptr` + 64 bytes
            mstore(add(ptr, 0x40), and(0xffffffffffffffffffffffffffffff, value))
            // return `deactivated`, `counter`, and `lastExecuted` as separate values
            // by returning memory starting at `ptr` with a length of 96 bytes
            return(ptr, 0x60)
        }
    }
    //slither-disable-end too-many-digits
}

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

import {IActionManager} from "./interfaces/IActionManager.sol";
import {AccessControl} from "@openzeppelin-contracts/access/AccessControl.sol";

/// @title ActionManager
/// @author Otim Labs, Inc.
/// @notice an Otim-owned contract for managing Otim Actions
contract ActionManager is IActionManager, AccessControl {
    /// @notice global lock status
    bool private _globalLock;
    /// @notice mapping of available Actions
    mapping(address => bool) private _available;

    /// @notice AccessControl role for globally locking Actions
    bytes32 public constant KILL_SWITCH_ROLE = keccak256("KILL_SWITCH_ROLE");

    /// @dev `owner` is passed-in in the constructor so we don't need to use our deployer key for admin tasks
    /// @dev the KILL_SWITCH_ROLE is reserved for globally locking ActionManager in the event of an emergency.
    ///      `owner` is intended to be a multi-sig, while a `killSwitchOwner` (role granted after deployment) will be a less secure,
    ///      single-key wallet to allow Otim to take swift action in the event of an emergency. `owner` is also granted the
    ///      KILL_SWITCH_ROLE so that it can also globally lock ActionManager if necessary.
    constructor(address owner) {
        // add `owner` to the DEFAULT_ADMIN_ROLE
        _grantRole(DEFAULT_ADMIN_ROLE, owner);

        /// @dev allows accounts with DEFAULT_ADMIN_ROLE to call `grantRole` and `revokeRole` for KILL_SWITCH_ROLE, see AccessControl.sol
        ///      after deployment, `owner` will be able to grant the KILL_SWITCH_ROLE to a `killSwitchOwner` account
        _setRoleAdmin(KILL_SWITCH_ROLE, DEFAULT_ADMIN_ROLE);

        // grant `owner` the KILL_SWITCH_ROLE (so `owner` can also globally lock Actions)
        _grantRole(KILL_SWITCH_ROLE, owner);
    }

    /// @notice makes an Action available for use in Instructions
    /// @param action - the address of the Action
    function addAction(address action) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (_available[action]) revert AlreadyAdded();

        _available[action] = true;
        emit ActionAdded(action);
    }

    /// @notice removes an Action, making it unavailable for use in Instructions
    /// @param action - the address of the Action
    function removeAction(address action) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (!_available[action]) revert AlreadyRemoved();

        delete _available[action];
        emit ActionRemoved(action);
    }

    /// @notice locks all Actions
    function lockAllActions() external onlyRole(KILL_SWITCH_ROLE) {
        if (_globalLock) revert AlreadyLocked();

        _globalLock = true;
        emit ActionsGloballyLocked();
    }

    /// @notice unlocks all Actions
    /// @dev does NOT unlock Actions that have been individually locked
    function unlockAllActions() external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (!_globalLock) revert AlreadyUnlocked();

        _globalLock = false;
        emit ActionsGloballyUnlocked();
    }

    /// @inheritdoc IActionManager
    function isExecutable(address action) external view returns (bool) {
        return _available[action] && !_globalLock;
    }

    /// @notice returns true if global lock is engaged
    function isGloballyLocked() public view returns (bool) {
        return _globalLock;
    }
}

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

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;

/// @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 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 {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
// OpenZeppelin Contracts (last updated v5.3.0) (utils/TransientSlot.sol)
// This file was procedurally generated from scripts/generate/templates/TransientSlot.js.

pragma solidity ^0.8.24;

/**
 * @dev Library for reading and writing value-types to specific transient storage slots.
 *
 * Transient slots are often used to store temporary values that are removed after the current transaction.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 *  * Example reading and writing values using transient storage:
 * ```solidity
 * contract Lock {
 *     using TransientSlot for *;
 *
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542;
 *
 *     modifier locked() {
 *         require(!_LOCK_SLOT.asBoolean().tload());
 *
 *         _LOCK_SLOT.asBoolean().tstore(true);
 *         _;
 *         _LOCK_SLOT.asBoolean().tstore(false);
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library TransientSlot {
    /**
     * @dev UDVT that represents a slot holding an address.
     */
    type AddressSlot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a AddressSlot.
     */
    function asAddress(bytes32 slot) internal pure returns (AddressSlot) {
        return AddressSlot.wrap(slot);
    }

    /**
     * @dev UDVT that represents a slot holding a bool.
     */
    type BooleanSlot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a BooleanSlot.
     */
    function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {
        return BooleanSlot.wrap(slot);
    }

    /**
     * @dev UDVT that represents a slot holding a bytes32.
     */
    type Bytes32Slot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a Bytes32Slot.
     */
    function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) {
        return Bytes32Slot.wrap(slot);
    }

    /**
     * @dev UDVT that represents a slot holding a uint256.
     */
    type Uint256Slot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a Uint256Slot.
     */
    function asUint256(bytes32 slot) internal pure returns (Uint256Slot) {
        return Uint256Slot.wrap(slot);
    }

    /**
     * @dev UDVT that represents a slot holding a int256.
     */
    type Int256Slot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a Int256Slot.
     */
    function asInt256(bytes32 slot) internal pure returns (Int256Slot) {
        return Int256Slot.wrap(slot);
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(AddressSlot slot) internal view returns (address value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(AddressSlot slot, address value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(BooleanSlot slot) internal view returns (bool value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(BooleanSlot slot, bool value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(Bytes32Slot slot) internal view returns (bytes32 value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(Bytes32Slot slot, bytes32 value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(Uint256Slot slot) internal view returns (uint256 value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(Uint256Slot slot, uint256 value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(Int256Slot slot) internal view returns (int256 value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(Int256Slot slot, int256 value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }
}

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

pragma solidity ^0.8.20;

/**
 * @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.1.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.20;

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

File 19 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.3.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    mapping(bytes32 role => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        return _roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        if (!hasRole(role, account)) {
            _roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        if (hasRole(role, account)) {
            _roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC-165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted to signal this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

Settings
{
  "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

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bytes32","name":"instructionId","type":"bytes32"},{"internalType":"bytes","name":"result","type":"bytes"}],"name":"ActionExecutionFailed","type":"error"},{"inputs":[{"internalType":"bytes32","name":"instructionId","type":"bytes32"}],"name":"ActionNotExecutable","type":"error"},{"inputs":[{"internalType":"bytes32","name":"instructionId","type":"bytes32"}],"name":"ExecutionSameBlock","type":"error"},{"inputs":[{"internalType":"bytes32","name":"instructionId","type":"bytes32"}],"name":"InstructionAlreadyDeactivated","type":"error"},{"inputs":[{"internalType":"bytes32","name":"instructionId","type":"bytes32"}],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"instructionId","type":"bytes32"}],"name":"InstructionDeactivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"instructionId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"executionCount","type":"uint256"}],"name":"InstructionExecuted","type":"event"},{"inputs":[],"name":"actionManager","outputs":[{"internalType":"contract IActionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"instructionId","type":"bytes32"}],"internalType":"struct InstructionLib.InstructionDeactivation","name":"deactivation","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":"signature","type":"tuple"}],"name":"deactivateInstruction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","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":"signature","type":"tuple"}],"name":"executeInstruction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"gateway","outputs":[{"internalType":"contract IGateway","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"instructionStorage","outputs":[{"internalType":"contract IInstructionStorage","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"stateMutability":"payable","type":"receive"}]

610100604052348015610010575f80fd5b50604051612e2c380380612e2c83398101604081905261002f916101d0565b60405161003b906101a9565b604051809103905ff080158015610054573d5f803e3d5ffd5b506001600160a01b031660805260405161006d906101b6565b604051809103905ff080158015610086573d5f803e3d5ffd5b506001600160a01b031660a05260405181906100a1906101c3565b6001600160a01b039091168152602001604051809103905ff0801580156100ca573d5f803e3d5ffd5b506001600160a01b031660c0908152604080517fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647260208201527fd3e85cb2b99a4c00476c0e821e4e2f204b2a664b49b404a94cd18b7bd259e433918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a08201527f99e306735973eb18e995c471fb908bdc81d96084742bf77970b4065e146d172b9181019190915260e00160408051601f19818403018152919052805160209091012060e052506101fd565b6106358061195383390190565b61048780611f8883390190565b610a1d8061240f83390190565b5f602082840312156101e0575f80fd5b81516001600160a01b03811681146101f6575f80fd5b9392505050565b60805160a05160c05160e0516116e461026f5f395f81816102eb015281816104d3015261087801525f81816101b901526106f801525f8181610233015281816103e30152818161057f0152818161065e01528181610a7701528181610b5f0152610bf201525f61010b01526116e45ff3fe6080604052600436106100bb575f3560e01c8063bc197c8111610071578063ee264b7b1161004c578063ee264b7b14610276578063f23a6e6114610295578063f698da25146102da575f80fd5b8063bc197c81146101db578063ce0dafae14610222578063de9013ac14610255575f80fd5b8063150b7a02116100a1578063150b7a02146101455780631626ba7e1461018957806375d252a5146101a8575f80fd5b806301ffc9a7146100c6578063116191b6146100fa575f80fd5b366100c257005b5f80fd5b3480156100d1575f80fd5b506100e56100e0366004610fe5565b61031b565b60405190151581526020015b60405180910390f35b348015610105575f80fd5b5061012d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100f1565b348015610150575f80fd5b5061017061015f366004611073565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020016100f1565b348015610194575f80fd5b506101706101a3366004611122565b61037a565b3480156101b3575f80fd5b5061012d7f000000000000000000000000000000000000000000000000000000000000000081565b3480156101e6575f80fd5b506101706101f5366004611201565b7fbc197c810000000000000000000000000000000000000000000000000000000098975050505050505050565b34801561022d575f80fd5b5061012d7f000000000000000000000000000000000000000000000000000000000000000081565b348015610260575f80fd5b5061027461026f3660046112d6565b6103b2565b005b348015610281575f80fd5b5061027461029036600461130f565b610610565b3480156102a0575f80fd5b506101706102af366004611356565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b3480156102e5575f80fd5b5061030d7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016100f1565b5f61032582610ca7565b8061034057506001600160e01b03198216630b135d3f60e11b145b8061037457506001600160e01b031982167f9a08346a00000000000000000000000000000000000000000000000000000000145b92915050565b5f806103868484610d29565b50909150506001600160a01b03811630146103a1575f6103aa565b630b135d3f60e11b5b949350505050565b6040517fcb4cf15b000000000000000000000000000000000000000000000000000000008152823560048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063cb4cf15b90602401602060405180830381865afa158015610430573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061045491906113d8565b9050801561047d57604051631f50700560e21b8152833560048201526024015b60405180910390fd5b604080517f8fcc56aead4a3e76944dbb265abc2725a9a8915c4a0344b8794c8dd1ecb57c9360208083019190915285358284015282518083038401815260608301845280519082012061190160f01b60808401527f0000000000000000000000000000000000000000000000000000000000000000608284015260a2808401919091528351808403909101815260c290920190925280519101205f610538826105296020870187611401565b86602001358760400135610d72565b50909150506001600160a01b038116301461056957604051633335be5d60e11b815285356004820152602401610474565b604051638d5066a960e01b8152853560048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690638d5066a9906024015f604051808303815f87803b1580156105c8575f80fd5b505af11580156105da573d5f803e3d5ffd5b5050604051873592507f1082dc6fb1ba8d32f074a5e83864cf6cc4b447170a99e122100a5ed6107bd57491505f90a25050505050565b610618610e3a565b5f61062283610ec2565b6040517f49d8033e000000000000000000000000000000000000000000000000000000008152600481018290529091505f906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906349d8033e90602401606060405180830381865afa1580156106a3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106c79190611430565b8051909150156106ed57604051631f50700560e21b815260048101839052602401610474565b5f6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016636ede7aba61072d606088016040890161149c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561076f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061079391906113d8565b9050806107cf576040517f66ea9a0a00000000000000000000000000000000000000000000000000000000815260048101849052602401610474565b81602001516001600160781b03165f036108f7575f806107f5606088016040890161149c565b6001600160a01b0316639fcd91b361081060608a018a6114b5565b6040518363ffffffff1660e01b815260040161082d929190611520565b60408051808303815f875af1158015610848573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061086c9190611533565b90925090505f61089e887f00000000000000000000000000000000000000000000000000000000000000008585610ef1565b90505f6108c1826108b260208b018b611401565b8a602001358b60400135610d72565b50909150506001600160a01b03811630146108f257604051633335be5d60e11b815260048101889052602401610474565b505050505b81604001516001600160781b03164211610940576040517fde54f0a500000000000000000000000000000000000000000000000000000000815260048101849052602401610474565b5f80610952606088016040890161149c565b6001600160a01b03166369179de360e01b888887604051602401610978939291906115dc565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925290516109cb919061164a565b5f60405180830381855af49150503d805f8114610a03576040519150601f19603f3d011682016040523d82523d5f602084013e610a08565b606091505b509150915081610a485784816040517f9ec69530000000000000000000000000000000000000000000000000000000008152600401610474929190611660565b80806020019051810190610a5c91906113d8565b15610b0a57604051638d5066a960e01b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690638d5066a9906024015f604051808303815f87803b158015610ac0575f80fd5b505af1158015610ad2573d5f803e3d5ffd5b50506040518792507f1082dc6fb1ba8d32f074a5e83864cf6cc4b447170a99e122100a5ed6107bd57491505f90a25050505050610c9b565b8660200135846020018051610b1e9061169c565b6001600160781b03169081905203610bc3576040517f23fa8a4b000000000000000000000000000000000000000000000000000000008152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323fa8a4b906024015f604051808303815f87803b158015610ba8575f80fd5b505af1158015610bba573d5f803e3d5ffd5b50505050610c52565b6040517f3d71f9b9000000000000000000000000000000000000000000000000000000008152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690633d71f9b9906024015f604051808303815f87803b158015610c3b575f80fd5b505af1158015610c4d573d5f803e3d5ffd5b505050505b6020808501516040516001600160781b03909116815286917f78d5f8309f92656e13667c5828223f186cd8d06e258955ca71552b4ec400463b910160405180910390a250505050505b610ca3610fb4565b5050565b5f6001600160e01b031982167f01ffc9a7000000000000000000000000000000000000000000000000000000001480610cf057506001600160e01b03198216630a85bd0160e11b145b8061037457506001600160e01b031982167f4e2312e0000000000000000000000000000000000000000000000000000000001492915050565b5f805f8351604103610d60576020840151604085015160608601515f1a610d5288828585610d72565b955095509550505050610d6b565b505081515f91506002905b9250925092565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115610dab57505f91506003905082610e30565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610dfc573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b038116610e2757505f925060019150829050610e30565b92505f91508190505b9450945094915050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c15610e93576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ec060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b90610fde565b565b5f81604051602001610ed491906116d2565b604051602081830303815290604052805190602001209050919050565b5f61190160f01b848487356020890135610f1160608b0160408c0161149c565b60408051602081019590955284019290925260608301526001600160a01b0316608082015260a0810185905260c00160408051601f198184030181529082905280516020918201207fffff0000000000000000000000000000000000000000000000000000000000009094169082015260228101919091526042810191909152606201604051602081830303815290604052805190602001209050949350505050565b610ec05f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00610eba565b80825d5050565b5f60208284031215610ff5575f80fd5b81356001600160e01b03198116811461100c575f80fd5b9392505050565b80356001600160a01b0381168114611029575f80fd5b919050565b5f8083601f84011261103e575f80fd5b50813567ffffffffffffffff811115611055575f80fd5b60208301915083602082850101111561106c575f80fd5b9250929050565b5f805f805f60808688031215611087575f80fd5b61109086611013565b945061109e60208701611013565b935060408601359250606086013567ffffffffffffffff8111156110c0575f80fd5b6110cc8882890161102e565b969995985093965092949392505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561111a5761111a6110dd565b604052919050565b5f8060408385031215611133575f80fd5b82359150602083013567ffffffffffffffff811115611150575f80fd5b8301601f81018513611160575f80fd5b803567ffffffffffffffff81111561117a5761117a6110dd565b61118d601f8201601f19166020016110f1565b8181528660208385010111156111a1575f80fd5b816020840160208301375f602083830101528093505050509250929050565b5f8083601f8401126111d0575f80fd5b50813567ffffffffffffffff8111156111e7575f80fd5b6020830191508360208260051b850101111561106c575f80fd5b5f805f805f805f8060a0898b031215611218575f80fd5b61122189611013565b975061122f60208a01611013565b9650604089013567ffffffffffffffff81111561124a575f80fd5b6112568b828c016111c0565b909750955050606089013567ffffffffffffffff811115611275575f80fd5b6112818b828c016111c0565b909550935050608089013567ffffffffffffffff8111156112a0575f80fd5b6112ac8b828c0161102e565b999c989b5096995094979396929594505050565b5f606082840312156112d0575f80fd5b50919050565b5f8082840360808112156112e8575f80fd5b60208112156112f5575f80fd5b5082915061130684602085016112c0565b90509250929050565b5f8060808385031215611320575f80fd5b823567ffffffffffffffff811115611336575f80fd5b830160808186031215611347575f80fd5b915061130684602085016112c0565b5f805f805f8060a0878903121561136b575f80fd5b61137487611013565b955061138260208801611013565b94506040870135935060608701359250608087013567ffffffffffffffff8111156113ab575f80fd5b6113b789828a0161102e565b979a9699509497509295939492505050565b80518015158114611029575f80fd5b5f602082840312156113e8575f80fd5b61100c826113c9565b803560ff81168114611029575f80fd5b5f60208284031215611411575f80fd5b61100c826113f1565b80516001600160781b0381168114611029575f80fd5b5f6060828403128015611441575f80fd5b506040516060810167ffffffffffffffff81118282101715611465576114656110dd565b604052611471836113c9565b815261147f6020840161141a565b60208201526114906040840161141a565b60408201529392505050565b5f602082840312156114ac575f80fd5b61100c82611013565b5f808335601e198436030181126114ca575f80fd5b83018035915067ffffffffffffffff8211156114e4575f80fd5b60200191503681900382131561106c575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b602081525f6103aa6020830184866114f8565b5f8060408385031215611544575f80fd5b505080516020909101519092909150565b80358252602080820135908301525f6001600160a01b0361157860408401611013565b1660408401526060820135601e19833603018112611594575f80fd5b820160208101903567ffffffffffffffff8111156115b0575f80fd5b8036038213156115be575f80fd5b608060608601526115d36080860182846114f8565b95945050505050565b60e081525f6115ee60e0830186611555565b905060ff6115fb856113f1565b16602083810191909152848101356040808501919091529485013560608401528351151560808401528301516001600160781b0390811660a0840152929093015190911660c090910152919050565b5f82518060208501845e5f920191825250919050565b828152604060208201525f82518060408401528060208501606085015e5f606082850101526060601f19601f8301168401019150509392505050565b5f6001600160781b0382166001600160781b0381036116c957634e487b7160e01b5f52601160045260245ffd5b60010192915050565b602081525f61100c60208301846115555660a0604052348015600e575f80fd5b5060405161ef0160f01b60208201526001600160601b03193360601b16602382015260370160408051601f1981840301815291905280516020909101206080526080516105b56100805f395f818160aa0152818160fa0152818161012c015281816101ef01526102ae01526105b55ff3fe608060405234801561000f575f80fd5b5060043610610064575f3560e01c80633e28391d1161004d5780633e28391d14610090578063c7c8427e146100e2578063f208d989146100f5575f80fd5b80630e9b55f114610068578063287399ff1461007d575b5f80fd5b61007b610076366004610355565b61012a565b005b61007b61008b3660046103b1565b6101ed565b6100cd61009e3660046103fc565b6001600160a01b03163f7f00000000000000000000000000000000000000000000000000000000000000001490565b60405190151581526020015b60405180910390f35b61007b6100f036600461041c565b6102ac565b61011c7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016100d9565b7f0000000000000000000000000000000000000000000000000000000000000000836001600160a01b03163f146101745760405163a7e874f360e01b815260040160405180910390fd5b6040517fde9013ac0000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063de9013ac906101bb9085908590600401610497565b5f604051808303815f87803b1580156101d2575f80fd5b505af11580156101e4573d5f803e3d5ffd5b50505050505050565b7f0000000000000000000000000000000000000000000000000000000000000000826001600160a01b03163f146102375760405163a7e874f360e01b815260040160405180910390fd5b604080516060810182525f8082526020820181905281830152905163ee264b7b60e01b81526001600160a01b0384169163ee264b7b9161027b91859160040161055b565b5f604051808303815f87803b158015610292575f80fd5b505af11580156102a4573d5f803e3d5ffd5b505050505050565b7f0000000000000000000000000000000000000000000000000000000000000000836001600160a01b03163f146102f65760405163a7e874f360e01b815260040160405180910390fd5b60405163ee264b7b60e01b81526001600160a01b0384169063ee264b7b906101bb9085908590600401610594565b80356001600160a01b038116811461033a575f80fd5b919050565b5f6060828403121561034f575f80fd5b50919050565b5f805f83850360a0811215610368575f80fd5b61037185610324565b93506020601f1982011215610384575f80fd5b50602084019150610398856040860161033f565b90509250925092565b5f6080828403121561034f575f80fd5b5f80604083850312156103c2575f80fd5b6103cb83610324565b9150602083013567ffffffffffffffff8111156103e6575f80fd5b6103f2858286016103a1565b9150509250929050565b5f6020828403121561040c575f80fd5b61041582610324565b9392505050565b5f805f60a0848603121561042e575f80fd5b61043784610324565b9250602084013567ffffffffffffffff811115610452575f80fd5b61045e868287016103a1565b925050610398856040860161033f565b803560ff811680821461047f575f80fd5b83525060208181013590830152604090810135910152565b8235815260808101610415602083018461046e565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b80358252602080820135908301525f6001600160a01b036104f760408401610324565b1660408401526060820135601e19833603018112610513575f80fd5b820160208101903567ffffffffffffffff81111561052f575f80fd5b80360382131561053d575f80fd5b608060608601526105526080860182846104ac565b95945050505050565b608081525f61056d60808301856104d4565b905060ff835116602083015260208301516040830152604083015160608301529392505050565b608081525f6105a660808301856104d4565b9050610415602083018461046e5660a0604052348015600e575f80fd5b5060405161ef0160f01b60208201526001600160601b03193360601b16602382015260370160408051601f19818403018152919052805160209091012060805260805161040c61007b5f395f81816101490152818161017b015281816101f901526102db015261040c5ff3fe608060405234801561000f575f80fd5b506004361061007a575f3560e01c80638d5066a9116100585780638d5066a9146100fb578063cb4cf15b1461010e578063d300e03514610131578063f208d98914610144575f80fd5b806323fa8a4b1461007e5780633d71f9b91461009357806349d8033e146100a6575b5f80fd5b61009161008c3660046103b3565b610179565b005b6100916100a13660046103b3565b6101f7565b6100b96100b43660046103b3565b61026f565b604080518251151581526020808401516effffffffffffffffffffffffffffff9081169183019190915292820151909216908201526060015b60405180910390f35b6100916101093660046103b3565b6102d9565b61012161011c3660046103b3565b610331565b60405190151581526020016100f2565b6100b961013f3660046103ca565b610349565b61016b7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016100f2565b7f00000000000000000000000000000000000000000000000000000000000000003233908114903f82141517156101b75763abdc7b7a5f526004601cfd5b335f528160205260405f20600160f01b426f010000000000000000000000000000006effffffffffffffffffffffffffffff198454160117178155505050565b7f00000000000000000000000000000000000000000000000000000000000000003233908114903f82141517156102355763abdc7b7a5f526004601cfd5b335f528160205260405f20426f010000000000000000000000000000006effffffffffffffffffffffffffffff1983541601178155505050565b604080516060810182525f8082526020820181905291810191909152335f528160205260405f20805490506040518160f01c81528160781c6effffffffffffffffffffffffffffff166020820152816effffffffffffffffffffffffffffff166040820152606081f35b7f00000000000000000000000000000000000000000000000000000000000000003233908114903f82141517156103175763abdc7b7a5f526004601cfd5b335f528160205260405f20600160f01b8154178155505050565b5f335f528160205260405f20805460f01c5f5260205ff35b604080516060810182525f8082526020820181905291810191909152825f528160205260405f20805490506040518160f01c81528160781c6effffffffffffffffffffffffffffff166020820152816effffffffffffffffffffffffffffff166040820152606081f35b5f602082840312156103c3575f80fd5b5035919050565b5f80604083850312156103db575f80fd5b823573ffffffffffffffffffffffffffffffffffffffff811681146103fe575f80fd5b94602093909301359350505056608060405234801561000f575f80fd5b50604051610a1d380380610a1d83398101604081905261002e91610161565b6100385f8261006e565b506100505f805160206109fd8339815191525f610117565b6100675f805160206109fd8339815191528261006e565b505061018e565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1661010e575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556100c63390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610111565b505f5b92915050565b5f82815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b5f60208284031215610171575f80fd5b81516001600160a01b0381168114610187575f80fd5b9392505050565b6108628061019b5f395ff3fe608060405234801561000f575f80fd5b50600436106100e5575f3560e01c8063779f594f11610088578063978a0e7e11610063578063978a0e7e146101e8578063a217fddf146101f3578063c448318b146101fa578063d547741f14610221575f80fd5b8063779f594f146101a25780638fff65d2146101aa57806391d14854146101b2575f80fd5b80632a895d20116100c35780632a895d20146101565780632f2ff15d1461016957806336568abe1461017c5780636ede7aba1461018f575f80fd5b806301ffc9a7146100e957806323b9da8214610111578063248a9ca314610126575b5f80fd5b6100fc6100f73660046107a7565b610234565b60405190151581526020015b60405180910390f35b61012461011f366004610808565b6102cc565b005b610148610134366004610821565b5f9081526020819052604090206001015490565b604051908152602001610108565b610124610164366004610808565b610374565b610124610177366004610838565b610418565b61012461018a366004610838565b610442565b6100fc61019d366004610808565b610493565b6101246104c2565b61012461053d565b6100fc6101c0366004610838565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60015460ff166100fc565b6101485f81565b6101487fd464fd6cf08e6aa82ebe91345be699e75616020b78a7aea0275c11a6e848627881565b61012461022f366004610838565b6105db565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806102c657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b5f6102d6816105ff565b6001600160a01b0382165f9081526002602052604090205460ff1615610328576040517ff411c32700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382165f81815260026020526040808220805460ff19166001179055517fd2f292a835dd86c92c7a061331b493087fc429f1d3f1a88a2980f764caad7fc19190a25050565b5f61037e816105ff565b6001600160a01b0382165f9081526002602052604090205460ff166103cf576040517fab5bea8e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382165f81815260026020526040808220805460ff19169055517f7a758c91970762174b6a2c0063cddad708aaae66d419a1cf5aea62ec95af19319190a25050565b5f82815260208190526040902060010154610432816105ff565b61043c838361060c565b50505050565b6001600160a01b0381163314610484576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61048e82826106b3565b505050565b6001600160a01b0381165f9081526002602052604081205460ff1680156102c6575060015460ff161592915050565b5f6104cc816105ff565b60015460ff16610508576040517f5090d6c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805460ff191690556040517fd34261db910e61bfcbc3f85eef86045acdd949d69af861a65e3b27be0847cc62905f90a150565b7fd464fd6cf08e6aa82ebe91345be699e75616020b78a7aea0275c11a6e8486278610567816105ff565b60015460ff16156105a4576040517f5f0ccd7c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805460ff1916811790556040517f6bf144d9c21f7b63737c618fcd507eb87e3eed0ccb74f04251ece1b278c74174905f90a150565b5f828152602081905260409020600101546105f5816105ff565b61043c83836106b3565b6106098133610734565b50565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166106ac575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556106643390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016102c6565b505f6102c6565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16156106ac575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016102c6565b5f828152602081815260408083206001600160a01b038516845290915290205460ff166107a3576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024810183905260440160405180910390fd5b5050565b5f602082840312156107b7575f80fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146107e6575f80fd5b9392505050565b80356001600160a01b0381168114610803575f80fd5b919050565b5f60208284031215610818575f80fd5b6107e6826107ed565b5f60208284031215610831575f80fd5b5035919050565b5f8060408385031215610849575f80fd5b82359150610859602084016107ed565b9050925092905056d464fd6cf08e6aa82ebe91345be699e75616020b78a7aea0275c11a6e8486278000000000000000000000000065935e928c3cd5e1696970aeacb8c6885d49b0a

Deployed Bytecode

0x6080604052600436106100bb575f3560e01c8063bc197c8111610071578063ee264b7b1161004c578063ee264b7b14610276578063f23a6e6114610295578063f698da25146102da575f80fd5b8063bc197c81146101db578063ce0dafae14610222578063de9013ac14610255575f80fd5b8063150b7a02116100a1578063150b7a02146101455780631626ba7e1461018957806375d252a5146101a8575f80fd5b806301ffc9a7146100c6578063116191b6146100fa575f80fd5b366100c257005b5f80fd5b3480156100d1575f80fd5b506100e56100e0366004610fe5565b61031b565b60405190151581526020015b60405180910390f35b348015610105575f80fd5b5061012d7f00000000000000000000000030891995b7ad3d4d38d16e14ee91b57372c091d281565b6040516001600160a01b0390911681526020016100f1565b348015610150575f80fd5b5061017061015f366004611073565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020016100f1565b348015610194575f80fd5b506101706101a3366004611122565b61037a565b3480156101b3575f80fd5b5061012d7f000000000000000000000000e41dfd2706e3b35c230696f3107eda85ee73ce3e81565b3480156101e6575f80fd5b506101706101f5366004611201565b7fbc197c810000000000000000000000000000000000000000000000000000000098975050505050505050565b34801561022d575f80fd5b5061012d7f000000000000000000000000beb6f683a7a247de61b9d56885f65331d7f5503081565b348015610260575f80fd5b5061027461026f3660046112d6565b6103b2565b005b348015610281575f80fd5b5061027461029036600461130f565b610610565b3480156102a0575f80fd5b506101706102af366004611356565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b3480156102e5575f80fd5b5061030d7f4e2db44a2e5588e3e3d5b6f3637f3cecc1215cbde0869c6dd3c95e176085558b81565b6040519081526020016100f1565b5f61032582610ca7565b8061034057506001600160e01b03198216630b135d3f60e11b145b8061037457506001600160e01b031982167f9a08346a00000000000000000000000000000000000000000000000000000000145b92915050565b5f806103868484610d29565b50909150506001600160a01b03811630146103a1575f6103aa565b630b135d3f60e11b5b949350505050565b6040517fcb4cf15b000000000000000000000000000000000000000000000000000000008152823560048201525f907f000000000000000000000000beb6f683a7a247de61b9d56885f65331d7f550306001600160a01b03169063cb4cf15b90602401602060405180830381865afa158015610430573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061045491906113d8565b9050801561047d57604051631f50700560e21b8152833560048201526024015b60405180910390fd5b604080517f8fcc56aead4a3e76944dbb265abc2725a9a8915c4a0344b8794c8dd1ecb57c9360208083019190915285358284015282518083038401815260608301845280519082012061190160f01b60808401527f4e2db44a2e5588e3e3d5b6f3637f3cecc1215cbde0869c6dd3c95e176085558b608284015260a2808401919091528351808403909101815260c290920190925280519101205f610538826105296020870187611401565b86602001358760400135610d72565b50909150506001600160a01b038116301461056957604051633335be5d60e11b815285356004820152602401610474565b604051638d5066a960e01b8152853560048201527f000000000000000000000000beb6f683a7a247de61b9d56885f65331d7f550306001600160a01b031690638d5066a9906024015f604051808303815f87803b1580156105c8575f80fd5b505af11580156105da573d5f803e3d5ffd5b5050604051873592507f1082dc6fb1ba8d32f074a5e83864cf6cc4b447170a99e122100a5ed6107bd57491505f90a25050505050565b610618610e3a565b5f61062283610ec2565b6040517f49d8033e000000000000000000000000000000000000000000000000000000008152600481018290529091505f906001600160a01b037f000000000000000000000000beb6f683a7a247de61b9d56885f65331d7f5503016906349d8033e90602401606060405180830381865afa1580156106a3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106c79190611430565b8051909150156106ed57604051631f50700560e21b815260048101839052602401610474565b5f6001600160a01b037f000000000000000000000000e41dfd2706e3b35c230696f3107eda85ee73ce3e16636ede7aba61072d606088016040890161149c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561076f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061079391906113d8565b9050806107cf576040517f66ea9a0a00000000000000000000000000000000000000000000000000000000815260048101849052602401610474565b81602001516001600160781b03165f036108f7575f806107f5606088016040890161149c565b6001600160a01b0316639fcd91b361081060608a018a6114b5565b6040518363ffffffff1660e01b815260040161082d929190611520565b60408051808303815f875af1158015610848573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061086c9190611533565b90925090505f61089e887f4e2db44a2e5588e3e3d5b6f3637f3cecc1215cbde0869c6dd3c95e176085558b8585610ef1565b90505f6108c1826108b260208b018b611401565b8a602001358b60400135610d72565b50909150506001600160a01b03811630146108f257604051633335be5d60e11b815260048101889052602401610474565b505050505b81604001516001600160781b03164211610940576040517fde54f0a500000000000000000000000000000000000000000000000000000000815260048101849052602401610474565b5f80610952606088016040890161149c565b6001600160a01b03166369179de360e01b888887604051602401610978939291906115dc565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925290516109cb919061164a565b5f60405180830381855af49150503d805f8114610a03576040519150601f19603f3d011682016040523d82523d5f602084013e610a08565b606091505b509150915081610a485784816040517f9ec69530000000000000000000000000000000000000000000000000000000008152600401610474929190611660565b80806020019051810190610a5c91906113d8565b15610b0a57604051638d5066a960e01b8152600481018690527f000000000000000000000000beb6f683a7a247de61b9d56885f65331d7f550306001600160a01b031690638d5066a9906024015f604051808303815f87803b158015610ac0575f80fd5b505af1158015610ad2573d5f803e3d5ffd5b50506040518792507f1082dc6fb1ba8d32f074a5e83864cf6cc4b447170a99e122100a5ed6107bd57491505f90a25050505050610c9b565b8660200135846020018051610b1e9061169c565b6001600160781b03169081905203610bc3576040517f23fa8a4b000000000000000000000000000000000000000000000000000000008152600481018690527f000000000000000000000000beb6f683a7a247de61b9d56885f65331d7f550306001600160a01b0316906323fa8a4b906024015f604051808303815f87803b158015610ba8575f80fd5b505af1158015610bba573d5f803e3d5ffd5b50505050610c52565b6040517f3d71f9b9000000000000000000000000000000000000000000000000000000008152600481018690527f000000000000000000000000beb6f683a7a247de61b9d56885f65331d7f550306001600160a01b031690633d71f9b9906024015f604051808303815f87803b158015610c3b575f80fd5b505af1158015610c4d573d5f803e3d5ffd5b505050505b6020808501516040516001600160781b03909116815286917f78d5f8309f92656e13667c5828223f186cd8d06e258955ca71552b4ec400463b910160405180910390a250505050505b610ca3610fb4565b5050565b5f6001600160e01b031982167f01ffc9a7000000000000000000000000000000000000000000000000000000001480610cf057506001600160e01b03198216630a85bd0160e11b145b8061037457506001600160e01b031982167f4e2312e0000000000000000000000000000000000000000000000000000000001492915050565b5f805f8351604103610d60576020840151604085015160608601515f1a610d5288828585610d72565b955095509550505050610d6b565b505081515f91506002905b9250925092565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115610dab57505f91506003905082610e30565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610dfc573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b038116610e2757505f925060019150829050610e30565b92505f91508190505b9450945094915050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c15610e93576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ec060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b90610fde565b565b5f81604051602001610ed491906116d2565b604051602081830303815290604052805190602001209050919050565b5f61190160f01b848487356020890135610f1160608b0160408c0161149c565b60408051602081019590955284019290925260608301526001600160a01b0316608082015260a0810185905260c00160408051601f198184030181529082905280516020918201207fffff0000000000000000000000000000000000000000000000000000000000009094169082015260228101919091526042810191909152606201604051602081830303815290604052805190602001209050949350505050565b610ec05f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00610eba565b80825d5050565b5f60208284031215610ff5575f80fd5b81356001600160e01b03198116811461100c575f80fd5b9392505050565b80356001600160a01b0381168114611029575f80fd5b919050565b5f8083601f84011261103e575f80fd5b50813567ffffffffffffffff811115611055575f80fd5b60208301915083602082850101111561106c575f80fd5b9250929050565b5f805f805f60808688031215611087575f80fd5b61109086611013565b945061109e60208701611013565b935060408601359250606086013567ffffffffffffffff8111156110c0575f80fd5b6110cc8882890161102e565b969995985093965092949392505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561111a5761111a6110dd565b604052919050565b5f8060408385031215611133575f80fd5b82359150602083013567ffffffffffffffff811115611150575f80fd5b8301601f81018513611160575f80fd5b803567ffffffffffffffff81111561117a5761117a6110dd565b61118d601f8201601f19166020016110f1565b8181528660208385010111156111a1575f80fd5b816020840160208301375f602083830101528093505050509250929050565b5f8083601f8401126111d0575f80fd5b50813567ffffffffffffffff8111156111e7575f80fd5b6020830191508360208260051b850101111561106c575f80fd5b5f805f805f805f8060a0898b031215611218575f80fd5b61122189611013565b975061122f60208a01611013565b9650604089013567ffffffffffffffff81111561124a575f80fd5b6112568b828c016111c0565b909750955050606089013567ffffffffffffffff811115611275575f80fd5b6112818b828c016111c0565b909550935050608089013567ffffffffffffffff8111156112a0575f80fd5b6112ac8b828c0161102e565b999c989b5096995094979396929594505050565b5f606082840312156112d0575f80fd5b50919050565b5f8082840360808112156112e8575f80fd5b60208112156112f5575f80fd5b5082915061130684602085016112c0565b90509250929050565b5f8060808385031215611320575f80fd5b823567ffffffffffffffff811115611336575f80fd5b830160808186031215611347575f80fd5b915061130684602085016112c0565b5f805f805f8060a0878903121561136b575f80fd5b61137487611013565b955061138260208801611013565b94506040870135935060608701359250608087013567ffffffffffffffff8111156113ab575f80fd5b6113b789828a0161102e565b979a9699509497509295939492505050565b80518015158114611029575f80fd5b5f602082840312156113e8575f80fd5b61100c826113c9565b803560ff81168114611029575f80fd5b5f60208284031215611411575f80fd5b61100c826113f1565b80516001600160781b0381168114611029575f80fd5b5f6060828403128015611441575f80fd5b506040516060810167ffffffffffffffff81118282101715611465576114656110dd565b604052611471836113c9565b815261147f6020840161141a565b60208201526114906040840161141a565b60408201529392505050565b5f602082840312156114ac575f80fd5b61100c82611013565b5f808335601e198436030181126114ca575f80fd5b83018035915067ffffffffffffffff8211156114e4575f80fd5b60200191503681900382131561106c575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b602081525f6103aa6020830184866114f8565b5f8060408385031215611544575f80fd5b505080516020909101519092909150565b80358252602080820135908301525f6001600160a01b0361157860408401611013565b1660408401526060820135601e19833603018112611594575f80fd5b820160208101903567ffffffffffffffff8111156115b0575f80fd5b8036038213156115be575f80fd5b608060608601526115d36080860182846114f8565b95945050505050565b60e081525f6115ee60e0830186611555565b905060ff6115fb856113f1565b16602083810191909152848101356040808501919091529485013560608401528351151560808401528301516001600160781b0390811660a0840152929093015190911660c090910152919050565b5f82518060208501845e5f920191825250919050565b828152604060208201525f82518060408401528060208501606085015e5f606082850101526060601f19601f8301168401019150509392505050565b5f6001600160781b0382166001600160781b0381036116c957634e487b7160e01b5f52601160045260245ffd5b60010192915050565b602081525f61100c602083018461155556

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

000000000000000000000000065935e928c3cd5e1696970aeacb8c6885d49b0a

-----Decoded View---------------
Arg [0] : owner (address): 0x065935e928c3cd5E1696970aeaCB8C6885D49b0A

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000065935e928c3cd5e1696970aeacb8c6885d49b0a


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