ETH Price: $2,333.72 (+0.71%)

Contract

0xC2269E28e8b07Fd9a68D6084b6995315E2717C9b

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Execute Bundle4264172582026-01-29 9:55:314 days ago1769680531IN
0xC2269E28...5E2717C9b
0 ETH0.000004050.020022
Execute Bundle4253748522026-01-26 9:42:427 days ago1769420562IN
0xC2269E28...5E2717C9b
0 ETH0.000004040.02
Execute Bundle4244136592026-01-23 14:51:0910 days ago1769179869IN
0xC2269E28...5E2717C9b
0 ETH0.000004120.02017
Execute Bundle4243352522026-01-23 9:25:0910 days ago1769160309IN
0xC2269E28...5E2717C9b
0 ETH0.000004040.02
Execute Bundle4230300942026-01-19 14:49:5714 days ago1768834197IN
0xC2269E28...5E2717C9b
0 ETH0.000027760.02
Execute Bundle4212306322026-01-14 9:50:2419 days ago1768384224IN
0xC2269E28...5E2717C9b
0 ETH0.000004120.02003
Execute Bundle4205564922026-01-12 11:02:4921 days ago1768215769IN
0xC2269E28...5E2717C9b
0 ETH0.000006320.020004

Latest 1 internal transaction

Parent Transaction Hash Block From To
4191544262026-01-08 9:38:4125 days ago1767865121  Contract Creation0 ETH

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
EIP712TypedDataSafeModule

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;

import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {EIP712TypedDataLib} from "../libraries/EIP712TypedDataLib.sol";
import {Errors} from "../Errors.sol";
import {IAdminVault} from "../interfaces/IAdminVault.sol";
import {ISafe} from "../interfaces/safe/ISafe.sol";
import {IOwnerManager} from "../interfaces/safe/IOwnerManager.sol";
import {ISafeDeployment} from "../interfaces/ISafeDeployment.sol";
import {ITokenRegistry} from "../interfaces/ITokenRegistry.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IGasPriceAdaptor} from "../interfaces/IGasPriceAdaptor.sol";
import {Enum} from "../libraries/Enum.sol";
import {ActionBase} from "../actions/ActionBase.sol";
import {ISequenceExecutor} from "../interfaces/ISequenceExecutor.sol";
import {IEip712TypedDataSafeModule as ITyped} from "../interfaces/IEip712TypedDataSafeModule.sol";

/// @title EIP712TypedDataSafeModule
/// @notice Safe module that handles EIP-712 typed data signing for cross-chain bundle execution
/// @notice Verifies signatures against Safe owners and forwards validated sequences to the sequence executor
/// @notice Includes optional gas refund functionality with economic protections
/// @dev Designed for 1-of-1 Safes: this module verifies the signer is an owner but does not enforce Safe threshold
/// @notice Found a vulnerability? Please contact [email protected] - we appreciate responsible disclosure and reward ethical hackers
contract EIP712TypedDataSafeModule {
    using ECDSA for bytes32;
    using SafeERC20 for IERC20;

    // EIP-712 helpers are provided by a library to reduce bytecode size

    // Struct types provided by interface ITyped

    struct ExecutorSequence {
        string name;
        bytes[] callData;
        bytes4[] actionIds;
    }

    IAdminVault public ADMIN_VAULT;
    address public SEQUENCE_EXECUTOR_ADDR;
    ISafeDeployment public SAFE_DEPLOYMENT;
    ITokenRegistry public TOKEN_REGISTRY;
    address public FEE_RECIPIENT;
    address public usdcToken; // set post-deploy to preserve deterministic bytecode

    address public immutable CONFIG_SETTER;

    bytes4 public constant EXECUTE_SEQUENCE_SELECTOR = ISequenceExecutor.executeSequence.selector;

    string public domainName;
    string public domainVersion;

    bool public isInitialized;

    mapping(address => uint256) public sequenceNonces;

    // Gas/refund context is computed inline in executeBundle; no persistent storage required

    event BundleExecuted(address indexed safe, uint256 indexed expiry, uint256 indexed chainId, uint256 sequenceNonce);
    event GasRefundProcessed(address indexed safe, address indexed refundToken, uint256 refundAmount, address indexed recipient);
    // =============================
    // Gas refund config
    // =============================
    uint256 public gasRefundOverhead;
    address public gasPriceAdaptor;

    event SignatureVerified(address indexed safe, address indexed signer, bytes32 indexed bundleHash);
    event SafeDeployedForExecution(address indexed signer, address indexed safeAddress);
    event ConfigInitialized(
        address adminVault,
        address sequenceExecutor,
        address safeDeployment,
        address tokenRegistry,
        address feeRecipient,
        string name,
        string version
    );

    constructor(address _configSetter) {
        require(_configSetter != address(0), "Invalid input");
        CONFIG_SETTER = _configSetter;
    }

    /// @notice One-time initializer to set all external references and domain fields
    /// @dev Callable only once by CONFIG_SETTER for deterministic deployment across chains
    /// @param _gasRefundOverhead Gas consumed after measurement point (transfers, events, return path)
    function initializeConfig(
        address _adminVault,
        address _sequenceExecutor,
        address _safeDeployment,
        address _tokenRegistry,
        address _feeRecipient,
        address _usdcToken,
        address _gasPriceAdaptor,
        uint256 _gasRefundOverhead,
        string memory _domainName,
        string memory _domainVersion
    ) external {
        require(msg.sender == CONFIG_SETTER, "Unauthorized");
        require(!isInitialized, "Already initialized");
        require(
            _adminVault != address(0) &&
            _sequenceExecutor != address(0) &&
            _safeDeployment != address(0) &&
            _tokenRegistry != address(0) &&
            _feeRecipient != address(0) &&
            _usdcToken != address(0) &&
            _gasPriceAdaptor != address(0),
            "Invalid input"
        );

        ADMIN_VAULT = IAdminVault(_adminVault);
        SEQUENCE_EXECUTOR_ADDR = _sequenceExecutor;
        SAFE_DEPLOYMENT = ISafeDeployment(_safeDeployment);
        TOKEN_REGISTRY = ITokenRegistry(_tokenRegistry);
        FEE_RECIPIENT = _feeRecipient;
        usdcToken = _usdcToken;
        gasPriceAdaptor = _gasPriceAdaptor;
        gasRefundOverhead = _gasRefundOverhead;
        domainName = _domainName;
        domainVersion = _domainVersion;
        isInitialized = true;

        emit ConfigInitialized(
            _adminVault,
            _sequenceExecutor,
            _safeDeployment,
            _tokenRegistry,
            _feeRecipient,
            _domainName,
            _domainVersion
        );
    }

    /// @notice Executes a validated bundle for the current chain and nonce
    /// @dev This is the main entry point with explicit Safe address and controlled deployment
    /// @dev Expects single-owner Safes; verifies signer ownership but does not enforce Safe threshold
    /// @param _safeAddr The Safe address to execute on (used for domain verification)
    /// @param _bundle The bundle containing sequences for multiple chains
    /// @param _signature EIP-712 signature from a Safe owner
    function executeBundle(
        address _safeAddr,
        ITyped.Bundle calldata _bundle,
        bytes calldata _signature
    ) external payable {
        // Record gas and executor at entry
        uint256 gasStart = gasleft();

        // Guard: config set during initializeConfig(); a single check is enough
        require(address(ADMIN_VAULT) != address(0), "Config not initialized");

        // Verify bundle hasn't expired
        if (_bundle.expiry <= block.timestamp) {
            revert Errors.EIP712TypedDataSafeModule_BundleExpired();
        }

        // Verify EIP-712 signature using Safe address as verifying contract
        bytes32 digest = EIP712TypedDataLib.hashBundleForSigning(domainName, domainVersion, _safeAddr, _bundle);
        address signer = digest.recover(_signature);
        
        if (signer == address(0)) {
            revert Errors.EIP712TypedDataSafeModule_InvalidSignature();
        }
        
        emit SignatureVerified(_safeAddr, signer, digest);

        // Find the sequence for current chain and next nonce
        uint256 expectedSequenceNonce = sequenceNonces[_safeAddr];
        
        ITyped.ChainSequence memory targetSequence = _findChainSequence(
            _bundle.sequences,
            block.chainid,
            expectedSequenceNonce
        );
        
        // Handle Safe deployment if requested
        if (targetSequence.deploySafe) {
            // Validate that the provided Safe address matches predicted deployment address
            address predictedSafeAddr = SAFE_DEPLOYMENT.predictSafeAddress(signer);
            if (_safeAddr != predictedSafeAddr) {
                revert Errors.EIP712TypedDataSafeModule_SafeAddressMismatch(_safeAddr, predictedSafeAddr);
            }
            
            // Deploy Safe if it doesn't exist
            if (!SAFE_DEPLOYMENT.isSafeDeployed(signer)) {
                try SAFE_DEPLOYMENT.deploySafe(signer) returns (address deployedSafeAddr) {
                    emit SafeDeployedForExecution(signer, deployedSafeAddr);
                } catch {
                    revert Errors.EIP712TypedDataSafeModule_SafeDeploymentFailed();
                }
            }
        }
        
        // Verify signer is a Safe owner (after potential deployment)
        if (!IOwnerManager(_safeAddr).isOwner(signer)) {
            revert Errors.EIP712TypedDataSafeModule_SignerNotOwner(signer);
        }

        // Validate actions and detect if a gas refund action is present (reverse scan for gas efficiency)
        (bytes4[] memory actionIds, bool hasRefundAction) = _validateSequenceActionsAndDetectRefund(
            targetSequence.sequence,
            targetSequence.refundRecipient
        );

        // Enforce enableGasRefund flag consistency with presence of GasRefundAction
        if (targetSequence.enableGasRefund && !hasRefundAction) {
            revert Errors.EIP712TypedDataSafeModule_RefundActionRequired();
        }
        if (!targetSequence.enableGasRefund && hasRefundAction) {
            revert Errors.EIP712TypedDataSafeModule_RefundActionNotAllowed();
        }

        // Update sequence nonce
        sequenceNonces[_safeAddr] = expectedSequenceNonce + 1;

        // Execute the sequence via Safe module transaction
        bool ok = _execThroughSafe(
            _safeAddr,
            ExecutorSequence({
                name: targetSequence.sequence.name,
                callData: targetSequence.sequence.callData,
                actionIds: actionIds
            }),
            _bundle,
            _signature
        );
        if (!ok) {
            revert Errors.EIP712TypedDataSafeModule_ExecutionFailed();
        }

        // Perform gas refund within module scope if enabled
        if (targetSequence.enableGasRefund) {
            _executeGasRefund(
                _safeAddr,
                targetSequence.maxRefundAmount,
                targetSequence.refundRecipient,
                gasStart
            );
        }

        emit BundleExecuted(_safeAddr, _bundle.expiry, block.chainid, expectedSequenceNonce);
    }

    /// @dev Uses `bytes memory` for signature (not calldata) to support estimateBundleGas
    /// which passes an empty signature. Gas impact is negligible since abi.encodeWithSelector
    /// copies the data anyway.
    function _execThroughSafe(
        address safeAddr,
        ExecutorSequence memory execSeq,
        ITyped.Bundle calldata bundle,
        bytes memory signature
    ) private returns (bool) {
        return ISafe(safeAddr).execTransactionFromModule(
            SEQUENCE_EXECUTOR_ADDR,
            0,
            abi.encodeWithSelector(
                EXECUTE_SEQUENCE_SELECTOR,
                execSeq,
                bundle,
                signature,
                uint16(0)
            ),
            Enum.Operation.DelegateCall
        );
    }

    // Gas context is handled inline in executeBundle

    /// @notice Gets the next expected sequence nonce for a Safe
    /// @param _safeAddr Address of the Safe
    /// @return The next expected sequence nonce
    function getSequenceNonce(address _safeAddr) external view returns (uint256) {
        return sequenceNonces[_safeAddr];
    }

    /// @notice Gets the EIP-712 domain separator for a specific Safe address
    /// @param _safeAddr The Safe address to use as verifying contract
    /// @return The domain separator
    /// @dev Uses hardcoded chainID 1 for cross-chain compatibility as part of cross-chain domain design
    function getDomainSeparator(address _safeAddr) external view returns (bytes32) {
        return EIP712TypedDataLib.domainSeparator(domainName, domainVersion, _safeAddr);
    }

    /// @notice Computes the EIP-712 hash for a bundle (view function for external verification)
    /// @param _safeAddr The Safe address to use as verifying contract
    /// @param _bundle The bundle to hash
    /// @return The EIP-712 hash that should be signed
    function getBundleHash(address _safeAddr, ITyped.Bundle calldata _bundle) external view returns (bytes32) {
        return EIP712TypedDataLib.hashBundleForSigning(domainName, domainVersion, _safeAddr, _bundle);
    }

    /// @notice Computes the raw bundle hash (for testing purposes)
    /// @param _bundle The bundle to hash
    /// @return The raw bundle hash (before EIP-712 domain separator)
    function getRawBundleHash(ITyped.Bundle calldata _bundle) external pure returns (bytes32) {
        return EIP712TypedDataLib.hashBundle(_bundle);
    }

    // =============================
    // Internal: Gas refund
    // =============================
    function _executeGasRefund(
        address safe,
        uint256 maxRefundAmount,
        uint8 refundRecipient,
        uint256 gasStart
    ) internal {
        IERC20 token = IERC20(usdcToken);
        uint256 moduleDeposit = token.balanceOf(address(this));
        
        // If no deposit, nothing to do
        if (moduleDeposit == 0) return;
        
        // Calculate refund amount - use zero values if any step fails
        uint256 refundAmount = 0;
        address recipient = address(0);
        
        // Try to get gas pricing rate
        (uint256 ratePerGas, uint256 fixedFee) = _safeGetRefundRate();
        
        if (ratePerGas > 0) {
            // Measure gas consumption including overhead
            uint256 gasUsed = gasStart > gasleft() ? (gasStart - gasleft() + gasRefundOverhead) : 0;
            
            if (gasUsed > 0) {
                // Calculate refund amount in USDC
                refundAmount = (gasUsed * ratePerGas) / 1e18 + fixedFee;
                
                // Cap at max if specified
                if (maxRefundAmount > 0 && refundAmount > maxRefundAmount) {
                    refundAmount = maxRefundAmount;
                }
                
                // Determine recipient
                recipient = refundRecipient == 0 ? tx.origin : FEE_RECIPIENT;
            }
        }
        
        // Pay refund if we calculated a valid amount
        uint256 paidAmount = 0;
        if (refundAmount > 0 && recipient != address(0)) {
            uint256 payAmount = refundAmount <= moduleDeposit ? refundAmount : moduleDeposit;
            token.safeTransfer(recipient, payAmount);
            paidAmount = payAmount;
        }
        
        // ALWAYS return any remaining balance to the Safe
        uint256 remainder = token.balanceOf(address(this));
        if (remainder > 0) {
            token.safeTransfer(safe, remainder);
        }

        emit GasRefundProcessed(safe, usdcToken, paidAmount, recipient != address(0) ? recipient : safe);
    }

    /// @notice Safely get refund rate from gas price adaptor
    /// @dev Returns (0, 0) if the call fails instead of reverting
    function _safeGetRefundRate() internal view returns (uint256 ratePerGas, uint256 fixedFee) {
        try IGasPriceAdaptor(gasPriceAdaptor).getRefundRate(usdcToken, msg.data) 
            returns (uint256 rate, uint256 fee) 
        {
            return (rate, fee);
        } catch {
            return (0, 0);
        }
    }

    // Oracle math is implemented in the adaptor

    /// @notice Finds the chain sequence for the current chain and expected nonce
    /// @param _sequences Array of chain sequences
    /// @param _chainId Target chain ID
    /// @param _expectedNonce Expected sequence nonce
    /// @return The matching chain sequence
    function _findChainSequence(
        ITyped.ChainSequence[] memory _sequences,
        uint256 _chainId,
        uint256 _expectedNonce
    ) internal pure returns (ITyped.ChainSequence memory) {
        for (uint256 i = 0; i < _sequences.length; i++) {
            if (_sequences[i].chainId == _chainId && _sequences[i].sequenceNonce == _expectedNonce) {
                return _sequences[i];
            }
        }
        revert Errors.EIP712TypedDataSafeModule_ChainSequenceNotFound(_chainId, _expectedNonce);
    }

    /// @notice Validates action metadata, registration, and detects presence of GasRefundAction
    /// @param _sequence The sequence to validate
    /// @return actionIds Array of action IDs from the sequence
    /// @return hasRefundAction True if a GasRefundAction is present in the sequence
    function _validateSequenceActionsAndDetectRefund(ITyped.Sequence memory _sequence, uint8 _refundRecipient)
        internal
        view
        returns (bytes4[] memory actionIds, bool hasRefundAction)
    {
        if (_sequence.actions.length != _sequence.callData.length || 
            _sequence.actions.length != _sequence.actionIds.length) {
            revert Errors.EIP712TypedDataSafeModule_LengthMismatch();
        }
        
        actionIds = _sequence.actionIds;
        hasRefundAction = false;

        // Scan from last to first expecting refund action near the end
        for (uint256 i = _sequence.actions.length; i > 0; i--) {
            uint256 idx = i - 1;
            bytes4 actionId = _sequence.actionIds[idx];
            
            // Get the action contract address
            address actionAddr = ADMIN_VAULT.getActionAddress(actionId);
            if (actionAddr == address(0)) {
                revert Errors.EIP712TypedDataSafeModule_ActionNotFound(actionId);
            }
            
            // Verify protocol name and action type match
            ActionBase action = ActionBase(actionAddr);
            string memory actualProtocolName = action.protocolName();
            uint8 actualActionType = action.actionType();
            
            // Compare with expected values from typed data
            ITyped.ActionDefinition memory expectedAction = _sequence.actions[idx];
            
            if (
                keccak256(bytes(actualProtocolName)) != keccak256(bytes(expectedAction.protocolName)) ||
                actualActionType != expectedAction.actionType
            ) {
                revert Errors.EIP712TypedDataSafeModule_ActionMismatch(
                    idx,
                    expectedAction.protocolName,
                    expectedAction.actionType,
                    actualProtocolName,
                    actualActionType
                );
            }

            // Detect GasRefundAction via ActionType.FEE_ACTION
            if (!hasRefundAction && actualActionType == uint8(ActionBase.ActionType.FEE_ACTION)) {
                // Enforce valid refund recipient at module-level: 0=executor, 1=fee recipient
                if (!(_refundRecipient == 0 || _refundRecipient == 1)) {
                    revert Errors.EIP712TypedDataSafeModule_InvalidRefundRecipient(_refundRecipient);
                }
                hasRefundAction = true;
            }
        }
    }

    // Gas refunds are processed by this module when enabled; a fee action deposits the refund token before execution.


    // =============================================================
    //                    EIP-712 HASHING HELPERS
    // =============================================================

    /// @notice Hash an ActionDefinition following proven EIP-712 patterns
    // Hash helpers are implemented in the library

    // =============================================================
    //                    GAS ESTIMATION HELPER
    // =============================================================

    /// @notice Custom error used to signal successful gas estimation simulation
    /// @param gasUsed The estimated gas consumed by the bundle execution
    error SimulationComplete(uint256 gasUsed);

    /// @notice Estimates gas for a bundle without requiring a signature
    /// @dev This function ALWAYS reverts - it is designed for simulation only
    /// @dev Call this via eth_call or Tenderly simulation with `from` set to user address
    /// @dev State overrides should be used to:
    ///      - Set token balances on Safe (for CCTP destination chains)
    /// @param _safeAddr The Safe address to execute on (must match predicted address for msg.sender)
    /// @param _bundle The bundle containing sequences for multiple chains
    /// @dev The function uses msg.sender as the signer, so simulations should set `from` to the user's address
    function estimateBundleGas(
        address _safeAddr,
        ITyped.Bundle calldata _bundle
    ) external {
        // Record gas at entry for accurate measurement
        uint256 gasStart = gasleft();
        
        // Guard: config set during initializeConfig()
        require(address(ADMIN_VAULT) != address(0), "Config not initialized");

        // No expiry check for estimation - we want to estimate regardless of timing
        
        // Use msg.sender as the signer (simulation sets from=userAddress)
        address signer = msg.sender;

        // Find the sequence for current chain and next nonce
        uint256 expectedSequenceNonce = sequenceNonces[_safeAddr];
        
        ITyped.ChainSequence memory targetSequence = _findChainSequence(
            _bundle.sequences,
            block.chainid,
            expectedSequenceNonce
        );
        
        // Handle Safe deployment if requested (deploys with msg.sender as owner)
        if (targetSequence.deploySafe) {
            // Validate that the provided Safe address matches predicted deployment address
            address predictedSafeAddr = SAFE_DEPLOYMENT.predictSafeAddress(signer);
            if (_safeAddr != predictedSafeAddr) {
                revert Errors.EIP712TypedDataSafeModule_SafeAddressMismatch(_safeAddr, predictedSafeAddr);
            }
            
            // Deploy Safe if it doesn't exist
            if (!SAFE_DEPLOYMENT.isSafeDeployed(signer)) {
                try SAFE_DEPLOYMENT.deploySafe(signer) returns (address deployedSafeAddr) {
                    emit SafeDeployedForExecution(signer, deployedSafeAddr);
                } catch {
                    revert Errors.EIP712TypedDataSafeModule_SafeDeploymentFailed();
                }
            }
        }
        
        // Skip ownership verification - msg.sender may not be owner yet if Safe was just deployed
        // In real execution, the signature proves ownership. In simulation, we trust msg.sender.

        // Validate actions and detect if a gas refund action is present
        (bytes4[] memory actionIds, bool hasRefundAction) = _validateSequenceActionsAndDetectRefund(
            targetSequence.sequence,
            targetSequence.refundRecipient
        );

        // Enforce enableGasRefund flag consistency with presence of GasRefundAction
        if (targetSequence.enableGasRefund && !hasRefundAction) {
            revert Errors.EIP712TypedDataSafeModule_RefundActionRequired();
        }
        if (!targetSequence.enableGasRefund && hasRefundAction) {
            revert Errors.EIP712TypedDataSafeModule_RefundActionNotAllowed();
        }

        // Note: We don't update the nonce in simulation - this is estimation only

        // Execute the sequence via Safe module transaction
        // For estimation, we pass empty signature - actions should not validate it for gas estimation
        bool ok = _execThroughSafe(
            _safeAddr,
            ExecutorSequence({
                name: targetSequence.sequence.name,
                callData: targetSequence.sequence.callData,
                actionIds: actionIds
            }),
            _bundle,
            new bytes(0) // Empty signature - estimation only
        );
        if (!ok) {
            revert Errors.EIP712TypedDataSafeModule_ExecutionFailed();
        }

        // Calculate gas used
        uint256 gasUsed = gasStart - gasleft();

        // Add gas refund overhead estimate if enabled
        if (targetSequence.enableGasRefund) {
            gasUsed += gasRefundOverhead;
        }

        // Always revert with the gas estimate - this prevents any state changes
        // and allows the simulation to capture the gas used
        revert SimulationComplete(gasUsed);
    }
}

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

pragma solidity >=0.6.2;

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

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

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

pragma solidity >=0.4.16;

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

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

pragma solidity >=0.4.16;

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

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

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

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

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

// SPDX-License-Identifier: MIT
// 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
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IAdminVault} from "../interfaces/IAdminVault.sol";
import {ILogger} from "../interfaces/ILogger.sol";
import {Errors} from "../Errors.sol";

/// @title ActionBase - Base contract for all actions in the protocol
/// @notice Implements common functionality and interfaces for all actions
/// @dev This contract should be inherited by all specific action contracts
/// @notice Found a vulnerability? Please contact [email protected] - we appreciate responsible disclosure and reward ethical hackers
abstract contract ActionBase {
    using SafeERC20 for IERC20;

    /// @notice Interface for the admin vault
    IAdminVault public immutable ADMIN_VAULT;

    /// @notice Interface for the logger
    ILogger public immutable LOGGER;

    /// @notice Basis points for fee calculations (100% = 10000)
    uint256 public constant FEE_BASIS_POINTS = 10000;

    /// @notice Duration of a fee period (1 year)
    uint256 public constant FEE_PERIOD = 365 days;

    /// @notice Enum representing different types of actions
    enum ActionType {
        DEPOSIT_ACTION,
        WITHDRAW_ACTION,
        SWAP_ACTION,
        COVER_ACTION,
        FEE_ACTION,
        TRANSFER_ACTION,
        CUSTOM_ACTION
    }

    /// @notice Enum representing different types of logs
    // List of log types, this list should be updated with each new log type added to the system.
    //   Existing values should not be changed/removed, as they may be already in use by a deployed action.
    //   UNUSED keeps the enum starting at index 1 for off-chain processing.
    enum LogType {
        UNUSED,
        BALANCE_UPDATE,
        BUY_COVER,
        CURVE_3POOL_SWAP,
        SEND_TOKEN,
        PULL_TOKEN,
        PARASWAP_SWAP,
        UPGRADE_ACTION,
        WITHDRAWAL_REQUEST,
        BUY_COVER_WITH_PREMIUM,
        ZERO_EX_SWAP,
        GAS_REFUND,
        CCTP_BRIDGE_SEND
    }

    /// @notice Initializes the ActionBase contract
    /// @param _adminVault Address of the admin vault
    /// @param _logger Address of the logger contract
    constructor(address _adminVault, address _logger) {
        ADMIN_VAULT = IAdminVault(_adminVault);
        LOGGER = ILogger(_logger);
    }

    /// @notice Executes the implemented action
    /// @dev This function should be overridden by inheriting contracts
    /// @param _callData Encoded input data for the action
    /// @param _strategyId The ID of the strategy executing this action (for logging use only)
    function executeAction(bytes memory _callData, uint16 _strategyId) public payable virtual;

    /// @notice Returns the type of action being implemented
    /// @return uint8 The action type as defined in the ActionType enum
    function actionType() public pure virtual returns (uint8);

    /// @notice Processes the fee taking, figures out if it's a supply and we need to initialize the fee timestamp
    /// @param _pool Address of the pool
    /// @param _feePercentage Fee percentage in basis points
    /// @param _feeToken Address of the fee token
    /// @return feeInTokens The amount of fee taken
    /// @dev it's rare but in some cases the _pool does differ from the _feeToken
    function _processFee(
        address _pool,
        uint256 _feePercentage,
        address _feeToken
    ) internal returns (uint256 feeInTokens) {
        uint256 lastFeeTimestamp = ADMIN_VAULT.getLastFeeTimestamp(_pool);

        // Initialize timestamp if not set, this will be the users first interaction with the pool
        if (lastFeeTimestamp == 0) {
            ADMIN_VAULT.setFeeTimestamp(_pool);
            return 0;
        }

        uint256 currentTimestamp = block.timestamp;
        if (lastFeeTimestamp == currentTimestamp) {
            return 0; // Don't take fees twice in the same block
        }

        IERC20 vault = IERC20(_feeToken);
        uint256 balance = vault.balanceOf(address(this));
        uint256 fee = _calculateFee(balance, _feePercentage, lastFeeTimestamp, currentTimestamp);
        if (fee > 0) {
            vault.safeTransfer(ADMIN_VAULT.feeConfig().recipient, fee);
        }
        ADMIN_VAULT.setFeeTimestamp(_pool);
        return fee;
    }

    /// @notice Calculates the fee due from the vault
    /// @param _totalDeposit Total amount deposited in the vault
    /// @param _feePercentage Fee percentage in basis points
    /// @param _lastFeeTimestamp Timestamp of the last fee collection
    /// @param _currentTimestamp Current timestamp
    /// @return uint256 The calculated fee amount
    function _calculateFee(
        uint256 _totalDeposit,
        uint256 _feePercentage,
        uint256 _lastFeeTimestamp,
        uint256 _currentTimestamp
    ) internal pure returns (uint256) {
        uint256 secondsPassed = _currentTimestamp - _lastFeeTimestamp;
        uint256 annualFee = (_totalDeposit * _feePercentage) / FEE_BASIS_POINTS;
        uint256 feeForPeriod = (annualFee * secondsPassed) / FEE_PERIOD;
        return feeForPeriod;
    }

    /// @notice Generates a pool ID from an address
    /// @param _addr Address to generate the pool ID from
    /// @return bytes4 The generated pool ID
    function _poolIdFromAddress(address _addr) internal pure returns (bytes4) {
        return bytes4(keccak256(abi.encodePacked(_addr)));
    }

    /// @notice Encodes balance update information
    /// @param _strategyId ID of the strategy
    /// @param _poolId ID of the pool
    /// @param _balanceBefore Balance before the action
    /// @param _balanceAfter Balance after the action
    /// @param _feeInTokens Amount of fee taken in tokens
    /// @return bytes Encoded balance update information
    function _encodeBalanceUpdate(
        uint16 _strategyId,
        bytes4 _poolId,
        uint256 _balanceBefore,
        uint256 _balanceAfter,
        uint256 _feeInTokens
    ) internal pure returns (bytes memory) {
        return abi.encode(_strategyId, _poolId, _balanceBefore, _balanceAfter, _feeInTokens);
    }

    function _checkFeesTaken(address _token) internal view {
        uint256 feeTimestamp = ADMIN_VAULT.getLastFeeTimestamp(_token);
        require(feeTimestamp == 0 || feeTimestamp >= block.timestamp, Errors.Action_FeesNotPaid(protocolName(), actionType(), _token));
    }

    /// @notice Returns the name of the protocol
    /// @return string The name of the protocol
    function protocolName() public pure virtual returns (string memory);

    /// @notice Reads a chain-specific configuration address for this action from AdminVault
    /// @return configAddress The configured on-chain address for this action on the current chain
    /// @notice Reads this action's chain-specific configuration address from AdminVault
    function _configAddress() internal view returns (address configAddress) {
        configAddress = ADMIN_VAULT.getActionConfig(protocolName(), actionType());
        require(configAddress != address(0), Errors.InvalidInput(protocolName(), "config"));
    }
}

File 10 of 24 : Errors.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;

/// @title Errors
/// @notice This contract contains all custom errors used across the protocol
/// @notice Found a vulnerability? Please contact [email protected] - we appreciate responsible disclosure and reward ethical hackers
contract Errors {
    // Generic errors
    error InvalidInput(string _contract, string _function);

    // AccessControlDelayed errors
    error AccessControlDelayed_InvalidDelay();
    error AccessControlDelayed_MustHaveAdminRole(address account, bytes32 role);
    error AccessControlDelayed_CannotGrantOwnerRole();
    error AccessControlDelayed_MustHaveRoleManagerOrOwner(address account);

    // AdminVault errors
    error AdminVault_InvalidInput();
    error AdminVault_FeePercentageOutOfRange(uint256 _providedPercentage, uint256 _minAllowed, uint256 _maxAllowed);
    error AdminVault_InvalidFeeRange(uint256 _minFee, uint256 _maxFee);
    error AdminVault_DelayNotPassed(uint256 _currentTime, uint256 _requiredTime);
    error AdminVault_PoolNotFound(bytes4 _poolId);
    error AdminVault_ActionNotFound(bytes4 _actionId);
    error AdminVault_ConfigNotFound(bytes4 _configId);
    error AdminVault_NotProposed();
    error AdminVault_AlreadyProposed();
    error AdminVault_AlreadyAdded();
    error AdminVault_NotPool(address _pool);
    error AdminVault_AlreadyGranted();
    error AdminVault_NotGranted();
    error AdminVault_TransactionNotProposed();
    error AdminVault_TransactionAlreadyApproved();
    error AdminVault_MissingRole(bytes32 role, address account);

    // FeeTakeSafeModule errors
    error FeeTakeSafeModule_SenderNotFeeTaker(address _sender);
    error FeeTakeSafeModule_InvalidActionType(bytes4 _actionId);
    error FeeTakeSafeModule_ExecutionFailed();
    error FeeTakeSafeModule_LengthMismatch();

    // Generic Action errors
    error Action_ZeroAmount(string _protocolName, uint8 _actionType);
    error Action_InsufficientSharesReceived(
        string _protocolName,
        uint8 _actionType,
        uint256 _sharesReceived,
        uint256 _minSharesReceived
    );
    error Action_MaxSharesBurnedExceeded(
        string _protocolName,
        uint8 _actionType,
        uint256 _sharesBurned,
        uint256 _maxAllowed
    );
    
    error Action_UnderlyingReceivedLessThanExpected(uint256 _underlyingReceived, uint256 _expected);
    error Action_FeesNotPaid(string _protocolName, uint8 _actionType, address _token);

    // CompoundV2Supply errors
    error Action_CompoundError(string _protocolName, uint8 _actionType, uint256 _errorCode);

    // Curve3PoolSwap errors
    error Curve3Pool__InvalidTokenIndices(int128 _fromToken, int128 _toToken);

    // ParaswapSwap errors
    error Paraswap__SwapFailed();
    error Paraswap__InsufficientOutput(uint256 _amountReceived, uint256 _minToAmount);
    error Paraswap__TokenNotApproved(address token);
    error Paraswap__TokenMismatch(address expected, address actual);
    error Paraswap__InvalidCalldata();
    error Paraswap__UnsupportedSelector(bytes4 selector);

    // 0x errors
    error ZeroEx__SwapFailed();
    error ZeroEx__InsufficientOutput(uint256 _amountReceived, uint256 _minToAmount);
    error ZeroEx__InvalidSwapTarget(address provided, address expected);
    error ZeroEx__TokenNotApproved(address token);

    // SendToken errors
    error Action_InvalidRecipient(string _protocolName, uint8 _actionType);

    // UpgradeAction errors

    // EIP712TypedDataSafeModule errors
    error EIP712TypedDataSafeModule_InvalidSignature();
    error EIP712TypedDataSafeModule_BundleExpired();
    error EIP712TypedDataSafeModule_ChainSequenceNotFound(uint256 chainId, uint256 expectedNonce);
    error EIP712TypedDataSafeModule_ActionMismatch(uint256 actionIndex, string expectedProtocol, uint8 expectedType, string actualProtocol, uint8 actualType);
    error EIP712TypedDataSafeModule_ExecutionFailed();
    error EIP712TypedDataSafeModule_SignerNotOwner(address signer);
    error EIP712TypedDataSafeModule_LengthMismatch();
    error EIP712TypedDataSafeModule_SafeDeploymentFailed();
    error EIP712TypedDataSafeModule_SafeAddressMismatch(address provided, address predicted);
    error EIP712TypedDataSafeModule_ActionNotFound(bytes4 actionId);
    // Gas refund errors
    error EIP712TypedDataSafeModule_InvalidRefundRecipient(uint8 refundTo);
    error EIP712TypedDataSafeModule_RefundActionRequired();
    error EIP712TypedDataSafeModule_RefundActionNotAllowed();

    // SafeDeployment errors
    error SafeDeployment_SafeAlreadyDeployed();
    error SafeDeployment_SafeDeploymentFailed();
    error SafeDeployment_SafeInitializationFailed();

    // TokenRegistry errors
    error TokenRegistry_TokenNotApproved();

    // CCTPBundleReceiver errors
    error CCTPReceiver_BadMessage();
    error CCTPReceiver_BadVersion(uint32 provided);
    error CCTPReceiver_RelayFailed();
    error CCTPReceiver_ShortHook();
    error CCTPReceiver_OutOfBounds();

    // CCTPBridgeSend errors
    error CCTPBridgeSend_InsufficientBalance(uint256 balance, uint256 amount);
    error CCTPBridgeSend_DepositFailed();
    error CCTPBridgeSend_BalanceMismatch(uint256 beforeBalance, uint256 afterBalance, uint256 expectedDelta);
    error CCTPBridgeSend_BundleContextRequired();
}

File 11 of 24 : IAdminVault.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;

interface IAdminVault {
    // Errors
    error SenderNotAdmin();
    error SenderNotOwner();
    error FeeTimestampNotInitialized();
    error FeeTimestampAlreadyInitialized();
    error FeePercentageOutOfRange();
    error InvalidRange();
    error InvalidRecipient();
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
    error AccessControlBadConfirmation();

    // Structs
    struct FeeConfig {
        address recipient;
        uint256 minBasis;
        uint256 maxBasis;
        uint256 proposalTime;
    }

    // View Functions
    // solhint-disable-next-line func-name-mixedcase
    function LOGGER() external view returns (address);
    // solhint-disable-next-line func-name-mixedcase
    function OWNER_ROLE() external view returns (bytes32);
    // solhint-disable-next-line func-name-mixedcase
    function ADMIN_ROLE() external view returns (bytes32);
    function feeConfig() external view returns (FeeConfig memory);
    function pendingFeeConfig() external view returns (FeeConfig memory);
    function lastFeeTimestamp(address, address) external view returns (uint256);
    function protocolPools(uint256 protocolId, bytes4 poolId) external view returns (address);
    function actionAddresses(bytes4 actionId) external view returns (address);
    function getPoolAddress(string calldata _protocolName, bytes4 _poolId) external view returns (address);
    function getActionAddress(bytes4 _actionId) external view returns (address);
    function getActionConfig(string calldata _protocolName, uint8 _actionType) external view returns (address);
    function getLastFeeTimestamp(address _vault) external view returns (uint256);
    function checkFeeBasis(uint256 _feeBasis) external view;
    function getPoolProposalTime(string calldata protocolName, address poolAddress) external view returns (uint256);
    function getActionProposalTime(bytes4 actionId, address actionAddress) external view returns (uint256);
    function setActionConfig(string calldata _protocolName, uint8 _actionType, address _configAddress) external;

    // Role Management Functions
    function hasRole(bytes32 role, address account) external view returns (bool);
    function getRoleAdmin(bytes32 role) external view returns (bytes32);
    function grantRole(bytes32 role, address account) external;
    function revokeRole(bytes32 role, address account) external;
    function renounceRole(bytes32 role, address callerConfirmation) external;

    // Fee Management Functions
    function proposeFeeConfig(address recipient, uint256 min, uint256 max) external;
    function cancelFeeConfigProposal() external;
    function setFeeConfig() external;
    function setFeeTimestamp(address _vault) external;

    // Pool Management Functions
    function proposePool(string calldata protocolName, address poolAddress) external;
    function cancelPoolProposal(string calldata protocolName, address poolAddress) external;
    function addPool(string calldata protocolName, address poolAddress) external;
    function removePool(string calldata protocolName, address poolAddress) external;

    // Action Management Functions
    function proposeAction(bytes4 actionId, address actionAddress) external;
    function cancelActionProposal(bytes4 actionId, address actionAddress) external;
    function addAction(bytes4 actionId, address actionAddress) external;
    function removeAction(bytes4 actionId) external;

    // Transaction Management Functions
    function proposeTransaction(bytes32 txHash) external;
    function cancelTransactionProposal(bytes32 txHash) external;
    function approveTransaction(bytes32 txHash) external;
    function revokeTransaction(bytes32 txHash) external;
    function isApprovedTransaction(bytes32 txHash) external view returns (bool);

    // Delay Management Functions
    function getDelayTimestamp() external returns (uint256);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;

/// @title IEip712TypedDataSafeModule
/// @notice Interface for EIP712TypedDataSafeModule contract to enable Bundle execution
/// @notice Found a vulnerability? Please contact [email protected] - we appreciate responsible disclosure and reward ethical hackers
interface IEip712TypedDataSafeModule {

    /// @notice Action definition structure
    struct ActionDefinition {
        string protocolName;
        uint8 actionType;
    }

    /// @notice Sequence structure containing actions and calldata
    struct Sequence {
        string name;
        ActionDefinition[] actions;
        bytes4[] actionIds;
        bytes[] callData;
    }

    /// @notice Chain sequence structure for multi-chain operations
    struct ChainSequence {
        uint256 chainId;
        uint256 sequenceNonce;
        bool deploySafe;
        bool enableGasRefund;
        uint256 maxRefundAmount;
        uint8 refundRecipient; // 0=executor, 1=fee recipient
        Sequence sequence;
    }

    /// @notice Bundle structure containing multiple chain sequences
    struct Bundle {
        uint256 expiry;
        ChainSequence[] sequences;
    }

    /// @notice Executes a validated bundle for the current chain and nonce
    /// @param _safeAddr The Safe address to execute on
    /// @param _bundle The bundle containing sequences for multiple chains
    /// @param _signature EIP-712 signature from a Safe owner
    function executeBundle(
        address _safeAddr,
        Bundle calldata _bundle,
        bytes calldata _signature
    ) external payable;

    /// @notice Gets the next expected sequence nonce for a Safe
    /// @param _safeAddr Address of the Safe
    /// @return The next expected sequence nonce
    function getSequenceNonce(address _safeAddr) external view returns (uint256);

    /// @notice Gets the EIP-712 domain separator for a specific Safe address
    /// @param _safeAddr The Safe address to use as verifying contract
    /// @return The domain separator
    function getDomainSeparator(address _safeAddr) external view returns (bytes32);

    /// @notice Computes the EIP-712 hash for a bundle
    /// @param _safeAddr The Safe address to use as verifying contract
    /// @param _bundle The bundle to hash
    /// @return The EIP-712 hash that should be signed
    function getBundleHash(address _safeAddr, Bundle calldata _bundle) external view returns (bytes32);

    /// @notice Events emitted by the module
    event BundleExecuted(address indexed safe, uint256 indexed expiry, uint256 indexed chainId, uint256 sequenceNonce);
    event SignatureVerified(address indexed safe, address indexed signer, bytes32 indexed bundleHash);
    event SafeDeployedForExecution(address indexed signer, address indexed safeAddress);
    event ConfigInitialized(
        address adminVault,
        address sequenceExecutor,
        address safeDeployment,
        address tokenRegistry,
        address feeRecipient,
        string name,
        string version
    );
    event GasRefundProcessed(address indexed safe, address indexed refundToken, uint256 refundAmount, address indexed recipient);
}

File 13 of 24 : IGasPriceAdaptor.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;

/// @title IGasPriceAdaptor
/// @notice Chain-specific adaptor interface for pricing gas usage
/// @dev Provides gas pricing rate that allows caller to measure gas consumption accurately
interface IGasPriceAdaptor {
    /// @notice Get the refund rate per gas unit in token terms
    /// @dev Rate is scaled by 1e18 for precision: actualRefund = (gasUsed * ratePerGas) / 1e18 + fixedFee
    /// @dev Caller measures gas after obtaining rate to ensure accurate measurement
    /// @param refundToken Token to calculate rate for (e.g., USDC)
    /// @param outerTxCalldata The calldata of the outer transaction (for L1 fee estimation on L2s)
    /// @return ratePerGas Token units per gas (scaled by 1e18)
    /// @return fixedFee Fixed cost component in token units (e.g., L1 data fee on OP Stack)
    function getRefundRate(
        address refundToken,
        bytes calldata outerTxCalldata
    ) external view returns (uint256 ratePerGas, uint256 fixedFee);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;

import {ActionBase} from "../actions/ActionBase.sol";

interface ILogger {
    event ActionEvent(address caller, ActionBase.LogType logId, bytes data);
    event AdminVaultEvent(uint256 logId, bytes data);

    function logActionEvent(ActionBase.LogType _logType, bytes memory _data) external;
    function logAdminVaultEvent(uint256 _logId, bytes memory _data) external;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;

/// @title ISafeDeployment
/// @notice Interface for deploying Safe accounts with current configuration from registry
/// @notice Found a vulnerability? Please contact [email protected] - we appreciate responsible disclosure and reward ethical hackers
/// @author BravaLabs.xyz
interface ISafeDeployment {
    /// @notice Emitted when a Safe is successfully deployed and configured
    event SafeDeployed(
        address indexed userAddress,
        address indexed safeAddress
    );

    /// @notice Deploys a Safe with the current configuration from the registry
    /// @param _userAddress The address that will own the Safe
    /// @return safeAddress The address of the deployed Safe
    function deploySafe(address _userAddress) external returns (address safeAddress);

    /// @notice Predicts the address of a Safe before deployment
    /// @param _userAddress The address that will own the Safe
    /// @return safeAddress The predicted Safe address
    function predictSafeAddress(address _userAddress) external view returns (address safeAddress);

    /// @notice Checks if a Safe is already deployed at the predicted address
    /// @param _userAddress The address that will own the Safe
    /// @return bool True if Safe is already deployed, false otherwise
    function isSafeDeployed(address _userAddress) external view returns (bool);

    /// @notice Gets the Safe singleton address used for deployments
    /// @return address The Safe singleton address
    function getSafeSingleton() external view returns (address);

    /// @notice Gets the setup registry address
    /// @return address The setup registry address
    function getSetupRegistry() external view returns (address);
}

File 16 of 24 : ISequenceExecutor.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;

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

interface ISequenceExecutor {
    struct Sequence {
        string name;
        bytes[] callData;
        bytes4[] actionIds;
    }

    function executeSequence(
        Sequence calldata _currSequence,
        IEip712TypedDataSafeModule.Bundle calldata _bundle,
        bytes calldata _signature,
        uint16 _strategyId
    ) external payable;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;

/// @title ITokenRegistry Interface
/// @notice Interface for the TokenRegistry contract that manages token approvals
interface ITokenRegistry {
    /// @notice Proposes a new token for approval
    /// @param _token The address of the token contract to propose
    function proposeToken(address _token) external;

    /// @notice Cancels a token proposal
    /// @param _token The address of the token contract to cancel
    function cancelTokenProposal(address _token) external;

    /// @notice Approves a proposed token
    /// @param _token The address of the token contract to approve
    function approveToken(address _token) external;

    /// @notice Revokes approval for a token
    /// @param _token The address of the token contract to revoke
    function revokeToken(address _token) external;

    /// @notice Checks if a token is approved
    /// @param _token The address of the token contract to check
    /// @return bool True if the token is approved, false otherwise
    function isApprovedToken(address _token) external view returns (bool);

    /// @notice Canonical gas refund token used by GasRefundAction
    function gasRefundToken() external view returns (address);
    /// @notice Set the canonical gas refund token (OWNER_ROLE only)
    function setGasRefundToken(address _token) external;
}

// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.0;

/**
 * @title IFallbackManager - A contract interface managing fallback calls made to this contract.
 * @author @safe-global/safe-protocol
 */
interface IFallbackManager {
    event ChangedFallbackHandler(address indexed handler);

    /**
     * @notice Set Fallback Handler to `handler` for the Safe.
     * @dev Only fallback calls without value and with data will be forwarded.
     *      This can only be done via a Safe transaction.
     *      Cannot be set to the Safe itself.
     * @param handler contract to handle fallback calls.
     */
    function setFallbackHandler(address handler) external;
}

// SPDX-License-Identifier: LGPL-3.0-only
/* solhint-disable one-contract-per-file */
pragma solidity ^0.8.0;

/**
 * @title IGuardManager - A contract interface managing transaction guards which perform pre and post-checks on Safe transactions.
 * @author @safe-global/safe-protocol
 */
interface IGuardManager {
    event ChangedGuard(address indexed guard);

    /**
     * @dev Set a guard that checks transactions before execution
     *      This can only be done via a Safe transaction.
     *      ⚠️ IMPORTANT: Since a guard has full power to block Safe transaction execution,
     *        a broken guard can cause a denial of service for the Safe. Make sure to carefully
     *        audit the guard code and design recovery mechanisms.
     * @notice Set Transaction Guard `guard` for the Safe. Make sure you trust the guard.
     * @param guard The address of the guard to be used or the 0 address to disable the guard
     */
    function setGuard(address guard) external;
}

// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.0;
import {Enum} from "../../libraries/Enum.sol";

/**
 * @title IModuleManager - An interface of contract managing Safe modules
 * @notice Modules are extensions with unlimited access to a Safe that can be added to a Safe by its owners.
           ⚠️ WARNING: Modules are a security risk since they can execute arbitrary transactions, 
           so only trusted and audited modules should be added to a Safe. A malicious module can
           completely takeover a Safe.
 * @author @safe-global/safe-protocol
 */
interface IModuleManager {
    event EnabledModule(address indexed module);
    event DisabledModule(address indexed module);
    event ExecutionFromModuleSuccess(address indexed module);
    event ExecutionFromModuleFailure(address indexed module);
    event ChangedModuleGuard(address indexed moduleGuard);

    /**
     * @notice Enables the module `module` for the Safe.
     * @dev This can only be done via a Safe transaction.
     * @param module Module to be whitelisted.
     */
    function enableModule(address module) external;

    /**
     * @notice Disables the module `module` for the Safe.
     * @dev This can only be done via a Safe transaction.
     * @param prevModule Previous module in the modules linked list.
     * @param module Module to be removed.
     */
    function disableModule(address prevModule, address module) external;

    /**
     * @notice Execute `operation` (0: Call, 1: DelegateCall) to `to` with `value` (Native Token)
     * @dev Function is virtual to allow overriding for L2 singleton to emit an event for indexing.
     * @param to Destination address of module transaction.
     * @param value Ether value of module transaction.
     * @param data Data payload of module transaction.
     * @param operation Operation type of module transaction.
     * @return success Boolean flag indicating if the call succeeded.
     */
    function execTransactionFromModule(
        address to,
        uint256 value,
        bytes memory data,
        Enum.Operation operation
    ) external returns (bool success);

    /**
     * @notice Execute `operation` (0: Call, 1: DelegateCall) to `to` with `value` (Native Token) and return data
     * @param to Destination address of module transaction.
     * @param value Ether value of module transaction.
     * @param data Data payload of module transaction.
     * @param operation Operation type of module transaction.
     * @return success Boolean flag indicating if the call succeeded.
     * @return returnData Data returned by the call.
     */
    function execTransactionFromModuleReturnData(
        address to,
        uint256 value,
        bytes memory data,
        Enum.Operation operation
    ) external returns (bool success, bytes memory returnData);

    /**
     * @notice Returns if an module is enabled
     * @return True if the module is enabled
     */
    function isModuleEnabled(address module) external view returns (bool);

    /**
     * @notice Returns an array of modules.
     *         If all entries fit into a single page, the next pointer will be 0x1.
     *         If another page is present, next will be the last element of the returned array.
     * @param start Start of the page. Has to be a module or start pointer (0x1 address)
     * @param pageSize Maximum number of modules that should be returned. Has to be > 0
     * @return array Array of modules.
     * @return next Start of the next page.
     */
    function getModulesPaginated(
        address start,
        uint256 pageSize
    ) external view returns (address[] memory array, address next);

    /**
     * @dev Set a module guard that checks transactions initiated by the module before execution
     *      This can only be done via a Safe transaction.
     *      ⚠️ IMPORTANT: Since a module guard has full power to block Safe transaction execution initiatied via a module,
     *        a broken module guard can cause a denial of service for the Safe modules. Make sure to carefully
     *        audit the module guard code and design recovery mechanisms.
     * @notice Set Module Guard `moduleGuard` for the Safe. Make sure you trust the module guard.
     * @param moduleGuard The address of the module guard to be used or the zero address to disable the module guard.
     */
    function setModuleGuard(address moduleGuard) external;
}

// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.0;

/**
 * @title IOwnerManager - Interface for contract which manages Safe owners and a threshold to authorize transactions.
 * @author @safe-global/safe-protocol
 */
interface IOwnerManager {
    event AddedOwner(address indexed owner);
    event RemovedOwner(address indexed owner);
    event ChangedThreshold(uint256 threshold);

    /**
     * @notice Adds the owner `owner` to the Safe and updates the threshold to `_threshold`.
     * @dev This can only be done via a Safe transaction.
     * @param owner New owner address.
     * @param _threshold New threshold.
     */
    function addOwnerWithThreshold(address owner, uint256 _threshold) external;

    /**
     * @notice Removes the owner `owner` from the Safe and updates the threshold to `_threshold`.
     * @dev This can only be done via a Safe transaction.
     * @param prevOwner Owner that pointed to the owner to be removed in the linked list
     * @param owner Owner address to be removed.
     * @param _threshold New threshold.
     */
    function removeOwner(address prevOwner, address owner, uint256 _threshold) external;

    /**
     * @notice Replaces the owner `oldOwner` in the Safe with `newOwner`.
     * @dev This can only be done via a Safe transaction.
     * @param prevOwner Owner that pointed to the owner to be replaced in the linked list
     * @param oldOwner Owner address to be replaced.
     * @param newOwner New owner address.
     */
    function swapOwner(address prevOwner, address oldOwner, address newOwner) external;

    /**
     * @notice Changes the threshold of the Safe to `_threshold`.
     * @dev This can only be done via a Safe transaction.
     * @param _threshold New threshold.
     */
    function changeThreshold(uint256 _threshold) external;

    /**
     * @notice Returns the number of required confirmations for a Safe transaction aka the threshold.
     * @return Threshold number.
     */
    function getThreshold() external view returns (uint256);

    /**
     * @notice Returns if `owner` is an owner of the Safe.
     * @return Boolean if owner is an owner of the Safe.
     */
    function isOwner(address owner) external view returns (bool);

    /**
     * @notice Returns a list of Safe owners.
     * @return Array of Safe owners.
     */
    function getOwners() external view returns (address[] memory);
}

// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.0;

import {Enum} from "../../libraries/Enum.sol";
import {IModuleManager} from "./IModuleManager.sol";
import {IOwnerManager} from "./IOwnerManager.sol";
import {IFallbackManager} from "./IFallbackManager.sol";
import {IGuardManager} from "./IGuardManager.sol";

/**
 * @title ISafe - A multisignature wallet interface with support for confirmations using signed messages based on EIP-712.
 * @author @safe-global/safe-protocol
 */
interface ISafe is IModuleManager, IGuardManager, IOwnerManager, IFallbackManager {
    event SafeSetup(
        address indexed initiator,
        address[] owners,
        uint256 threshold,
        address initializer,
        address fallbackHandler
    );
    event ApproveHash(bytes32 indexed approvedHash, address indexed owner);
    event SignMsg(bytes32 indexed msgHash);
    event ExecutionFailure(bytes32 indexed txHash, uint256 payment);
    event ExecutionSuccess(bytes32 indexed txHash, uint256 payment);

    /**
     * @notice Sets an initial storage of the Safe contract.
     * @dev This method can only be called once.
     *      If a proxy was created without setting up, anyone can call setup and claim the proxy.
     * @param _owners List of Safe owners.
     * @param _threshold Number of required confirmations for a Safe transaction.
     * @param to Contract address for optional delegate call.
     * @param data Data payload for optional delegate call.
     * @param fallbackHandler Handler for fallback calls to this contract
     * @param paymentToken Token that should be used for the payment (0 is ETH)
     * @param payment Value that should be paid
     * @param paymentReceiver Address that should receive the payment (or 0 if tx.origin)
     */
    function setup(
        address[] calldata _owners,
        uint256 _threshold,
        address to,
        bytes calldata data,
        address fallbackHandler,
        address paymentToken,
        uint256 payment,
        address payable paymentReceiver
    ) external;

    /** @notice Executes a `operation` {0: Call, 1: DelegateCall}} transaction to `to` with `value` (Native Currency)
     *          and pays `gasPrice` * `gasLimit` in `gasToken` token to `refundReceiver`.
     * @dev The fees are always transferred, even if the user transaction fails.
     *      This method doesn't perform any sanity check of the transaction, such as:
     *      - if the contract at `to` address has code or not
     *      - if the `gasToken` is a contract or not
     *      It is the responsibility of the caller to perform such checks.
     * @param to Destination address of Safe transaction.
     * @param value Ether value of Safe transaction.
     * @param data Data payload of Safe transaction.
     * @param operation Operation type of Safe transaction.
     * @param safeTxGas Gas that should be used for the Safe transaction.
     * @param baseGas Gas costs that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
     * @param gasPrice Gas price that should be used for the payment calculation.
     * @param gasToken Token address (or 0 if ETH) that is used for the payment.
     * @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
     * @param signatures Signature data that should be verified.
     *                   Can be packed ECDSA signature ({bytes32 r}{bytes32 s}{uint8 v}), contract signature (EIP-1271) or approved hash.
     * @return success Boolean indicating transaction's success.
     */
    function execTransaction(
        address to,
        uint256 value,
        bytes calldata data,
        Enum.Operation operation,
        uint256 safeTxGas,
        uint256 baseGas,
        uint256 gasPrice,
        address gasToken,
        address payable refundReceiver,
        bytes memory signatures
    ) external payable returns (bool success);

    /**
     * @notice Checks whether the signature provided is valid for the provided data and hash. Reverts otherwise.
     * @param dataHash Hash of the data (could be either a message hash or transaction hash)
     * @param signatures Signature data that should be verified.
     *                   Can be packed ECDSA signature ({bytes32 r}{bytes32 s}{uint8 v}), contract signature (EIP-1271) or approved hash.
     */
    function checkSignatures(bytes32 dataHash, bytes memory signatures) external view;

    /**
     * @notice Checks whether the signature provided is valid for the provided data and hash. Reverts otherwise.
     * @dev Since the EIP-1271 does an external call, be mindful of reentrancy attacks.
     * @param executor Address that executing the transaction.
     *        ⚠️⚠️⚠️ Make sure that the executor address is a legitmate executor.
     *        Incorrectly passed the executor might reduce the threshold by 1 signature. ⚠️⚠️⚠️
     * @param dataHash Hash of the data (could be either a message hash or transaction hash)
     * @param signatures Signature data that should be verified.
     *                   Can be packed ECDSA signature ({bytes32 r}{bytes32 s}{uint8 v}), contract signature (EIP-1271) or approved hash.
     * @param requiredSignatures Amount of required valid signatures.
     */
    function checkNSignatures(
        address executor,
        bytes32 dataHash,
        bytes memory signatures,
        uint256 requiredSignatures
    ) external view;

    /**
     * @notice Marks hash `hashToApprove` as approved.
     * @dev This can be used with a pre-approved hash transaction signature.
     *      IMPORTANT: The approved hash stays approved forever. There's no revocation mechanism, so it behaves similarly to ECDSA signatures
     * @param hashToApprove The hash to mark as approved for signatures that are verified by this contract.
     */
    function approveHash(bytes32 hashToApprove) external;

    /**
     * @dev Returns the domain separator for this contract, as defined in the EIP-712 standard.
     * @return bytes32 The domain separator hash.
     */
    function domainSeparator() external view returns (bytes32);

    /**
     * @notice Returns transaction hash to be signed by owners.
     * @param to Destination address.
     * @param value Ether value.
     * @param data Data payload.
     * @param operation Operation type.
     * @param safeTxGas Gas that should be used for the safe transaction.
     * @param baseGas Gas costs for data used to trigger the safe transaction.
     * @param gasPrice Maximum gas price that should be used for this transaction.
     * @param gasToken Token address (or 0 if ETH) that is used for the payment.
     * @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
     * @param _nonce Transaction nonce.
     * @return Transaction hash.
     */
    function getTransactionHash(
        address to,
        uint256 value,
        bytes calldata data,
        Enum.Operation operation,
        uint256 safeTxGas,
        uint256 baseGas,
        uint256 gasPrice,
        address gasToken,
        address refundReceiver,
        uint256 _nonce
    ) external view returns (bytes32);

    /**
     * External getter function for state variables.
     */

    /**
     * @notice Returns the version of the Safe contract.
     * @return Version string.
     */
    // solhint-disable-next-line
    function VERSION() external view returns (string memory);

    /**
     * @notice Returns the nonce of the Safe contract.
     * @return Nonce.
     */
    function nonce() external view returns (uint256);

    /**
     * @notice Returns a uint if the messageHash is signed by the owner.
     * @param messageHash Hash of message that should be checked.
     * @return Number denoting if an owner signed the hash.
     */
    function signedMessages(bytes32 messageHash) external view returns (uint256);

    /**
     * @notice Returns a uint if the messageHash is approved by the owner.
     * @param owner Owner address that should be checked.
     * @param messageHash Hash of message that should be checked.
     * @return Number denoting if an owner approved the hash.
     */
    function approvedHashes(address owner, bytes32 messageHash) external view returns (uint256);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;

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

/// @title EIP712TypedDataLib
/// @notice External library for EIP-712 type strings, type hashes, and hashing helpers to keep module bytecode small
library EIP712TypedDataLib {
    // EIP-712 type strings
    string private constant ACTION_DEFINITION_TYPE = "ActionDefinition(string protocolName,uint8 actionType)";
    string private constant SEQUENCE_TYPE = "Sequence(string name,ActionDefinition[] actions,bytes4[] actionIds,bytes[] callData)ActionDefinition(string protocolName,uint8 actionType)";
    string private constant CHAIN_SEQUENCE_TYPE = "ChainSequence(uint256 chainId,uint256 sequenceNonce,bool deploySafe,bool enableGasRefund,uint256 maxRefundAmount,uint8 refundRecipient,Sequence sequence)ActionDefinition(string protocolName,uint8 actionType)Sequence(string name,ActionDefinition[] actions,bytes4[] actionIds,bytes[] callData)";
    string private constant BUNDLE_TYPE = "Bundle(uint256 expiry,ChainSequence[] sequences)ActionDefinition(string protocolName,uint8 actionType)ChainSequence(uint256 chainId,uint256 sequenceNonce,bool deploySafe,bool enableGasRefund,uint256 maxRefundAmount,uint8 refundRecipient,Sequence sequence)Sequence(string name,ActionDefinition[] actions,bytes4[] actionIds,bytes[] callData)";
    string private constant DOMAIN_TYPE = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)";

    // Precomputed type hashes
    bytes32 private constant ACTION_DEFINITION_TYPEHASH = keccak256(abi.encodePacked(ACTION_DEFINITION_TYPE));
    bytes32 private constant SEQUENCE_TYPEHASH = keccak256(abi.encodePacked(SEQUENCE_TYPE));
    bytes32 private constant CHAIN_SEQUENCE_TYPEHASH = keccak256(abi.encodePacked(CHAIN_SEQUENCE_TYPE));
    bytes32 private constant BUNDLE_TYPEHASH = keccak256(abi.encodePacked(BUNDLE_TYPE));
    bytes32 private constant DOMAIN_TYPEHASH = keccak256(abi.encodePacked(DOMAIN_TYPE));

    function hashActionDefinition(IEip712TypedDataSafeModule.ActionDefinition memory action) public pure returns (bytes32) {
        return keccak256(abi.encode(
            ACTION_DEFINITION_TYPEHASH,
            keccak256(bytes(action.protocolName)),
            action.actionType
        ));
    }

    function hashSequence(IEip712TypedDataSafeModule.Sequence memory sequence) public pure returns (bytes32) {
        bytes32[] memory actionHashes = new bytes32[](sequence.actions.length);
        for (uint256 i = 0; i < sequence.actions.length; i++) {
            actionHashes[i] = hashActionDefinition(sequence.actions[i]);
        }

        bytes32[] memory callDataHashes = new bytes32[](sequence.callData.length);
        for (uint256 i = 0; i < sequence.callData.length; i++) {
            callDataHashes[i] = keccak256(sequence.callData[i]);
        }

        bytes32[] memory actionIdWords = new bytes32[](sequence.actionIds.length);
        for (uint256 i = 0; i < sequence.actionIds.length; i++) {
            actionIdWords[i] = bytes32(sequence.actionIds[i]);
        }

        return keccak256(abi.encode(
            SEQUENCE_TYPEHASH,
            keccak256(bytes(sequence.name)),
            keccak256(abi.encodePacked(actionHashes)),
            keccak256(abi.encodePacked(actionIdWords)),
            keccak256(abi.encodePacked(callDataHashes))
        ));
    }

    function hashChainSequence(IEip712TypedDataSafeModule.ChainSequence memory chainSequence) public pure returns (bytes32) {
        return keccak256(abi.encode(
            CHAIN_SEQUENCE_TYPEHASH,
            chainSequence.chainId,
            chainSequence.sequenceNonce,
            chainSequence.deploySafe,
            chainSequence.enableGasRefund,
            chainSequence.maxRefundAmount,
            chainSequence.refundRecipient,
            hashSequence(chainSequence.sequence)
        ));
    }

    function hashBundle(IEip712TypedDataSafeModule.Bundle memory bundle) public pure returns (bytes32) {
        bytes32[] memory chainSequenceHashes = new bytes32[](bundle.sequences.length);
        for (uint256 i = 0; i < bundle.sequences.length; i++) {
            chainSequenceHashes[i] = hashChainSequence(bundle.sequences[i]);
        }

        return keccak256(abi.encode(
            BUNDLE_TYPEHASH,
            bundle.expiry,
            keccak256(abi.encodePacked(chainSequenceHashes))
        ));
    }

    function domainSeparator(string memory name, string memory version, address verifyingContract) public pure returns (bytes32) {
        return keccak256(abi.encode(
            DOMAIN_TYPEHASH,
            keccak256(bytes(name)),
            keccak256(bytes(version)),
            1, // hardcoded chainID 1
            verifyingContract,
            keccak256("BravaSafe")
        ));
    }

    function hashBundleForSigning(
        string memory name,
        string memory version,
        address verifyingContract,
        IEip712TypedDataSafeModule.Bundle calldata bundle
    ) public pure returns (bytes32) {
        bytes32 ds = domainSeparator(name, version, verifyingContract);
        return keccak256(abi.encodePacked("\x19\x01", ds, hashBundle(bundle)));
    }
}

File 24 of 24 : Enum.sol
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.0;

/**
 * @title Enum - Collection of enums used in Safe Smart Account contracts.
 * @author @safe-global/safe-protocol
 */
library Enum {
    enum Operation {
        Call,
        DelegateCall
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {
    "contracts/auth/EIP712TypedDataSafeModule.sol": {
      "EIP712TypedDataLib": "0x8c77694629c2b2916b10d952a58657d3fe4c6d89"
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_configSetter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[{"internalType":"uint256","name":"actionIndex","type":"uint256"},{"internalType":"string","name":"expectedProtocol","type":"string"},{"internalType":"uint8","name":"expectedType","type":"uint8"},{"internalType":"string","name":"actualProtocol","type":"string"},{"internalType":"uint8","name":"actualType","type":"uint8"}],"name":"EIP712TypedDataSafeModule_ActionMismatch","type":"error"},{"inputs":[{"internalType":"bytes4","name":"actionId","type":"bytes4"}],"name":"EIP712TypedDataSafeModule_ActionNotFound","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_BundleExpired","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"expectedNonce","type":"uint256"}],"name":"EIP712TypedDataSafeModule_ChainSequenceNotFound","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_ExecutionFailed","type":"error"},{"inputs":[{"internalType":"uint8","name":"refundTo","type":"uint8"}],"name":"EIP712TypedDataSafeModule_InvalidRefundRecipient","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_InvalidSignature","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_LengthMismatch","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_RefundActionNotAllowed","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_RefundActionRequired","type":"error"},{"inputs":[{"internalType":"address","name":"provided","type":"address"},{"internalType":"address","name":"predicted","type":"address"}],"name":"EIP712TypedDataSafeModule_SafeAddressMismatch","type":"error"},{"inputs":[],"name":"EIP712TypedDataSafeModule_SafeDeploymentFailed","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"EIP712TypedDataSafeModule_SignerNotOwner","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"name":"SimulationComplete","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safe","type":"address"},{"indexed":true,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sequenceNonce","type":"uint256"}],"name":"BundleExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"adminVault","type":"address"},{"indexed":false,"internalType":"address","name":"sequenceExecutor","type":"address"},{"indexed":false,"internalType":"address","name":"safeDeployment","type":"address"},{"indexed":false,"internalType":"address","name":"tokenRegistry","type":"address"},{"indexed":false,"internalType":"address","name":"feeRecipient","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"version","type":"string"}],"name":"ConfigInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safe","type":"address"},{"indexed":true,"internalType":"address","name":"refundToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"refundAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"GasRefundProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"signer","type":"address"},{"indexed":true,"internalType":"address","name":"safeAddress","type":"address"}],"name":"SafeDeployedForExecution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"safe","type":"address"},{"indexed":true,"internalType":"address","name":"signer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"bundleHash","type":"bytes32"}],"name":"SignatureVerified","type":"event"},{"inputs":[],"name":"ADMIN_VAULT","outputs":[{"internalType":"contract IAdminVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONFIG_SETTER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXECUTE_SEQUENCE_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RECIPIENT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SAFE_DEPLOYMENT","outputs":[{"internalType":"contract ISafeDeployment","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SEQUENCE_EXECUTOR_ADDR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_REGISTRY","outputs":[{"internalType":"contract ITokenRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_safeAddr","type":"address"},{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"sequenceNonce","type":"uint256"},{"internalType":"bool","name":"deploySafe","type":"bool"},{"internalType":"bool","name":"enableGasRefund","type":"bool"},{"internalType":"uint256","name":"maxRefundAmount","type":"uint256"},{"internalType":"uint8","name":"refundRecipient","type":"uint8"},{"components":[{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"string","name":"protocolName","type":"string"},{"internalType":"uint8","name":"actionType","type":"uint8"}],"internalType":"struct IEip712TypedDataSafeModule.ActionDefinition[]","name":"actions","type":"tuple[]"},{"internalType":"bytes4[]","name":"actionIds","type":"bytes4[]"},{"internalType":"bytes[]","name":"callData","type":"bytes[]"}],"internalType":"struct IEip712TypedDataSafeModule.Sequence","name":"sequence","type":"tuple"}],"internalType":"struct IEip712TypedDataSafeModule.ChainSequence[]","name":"sequences","type":"tuple[]"}],"internalType":"struct IEip712TypedDataSafeModule.Bundle","name":"_bundle","type":"tuple"}],"name":"estimateBundleGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_safeAddr","type":"address"},{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"sequenceNonce","type":"uint256"},{"internalType":"bool","name":"deploySafe","type":"bool"},{"internalType":"bool","name":"enableGasRefund","type":"bool"},{"internalType":"uint256","name":"maxRefundAmount","type":"uint256"},{"internalType":"uint8","name":"refundRecipient","type":"uint8"},{"components":[{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"string","name":"protocolName","type":"string"},{"internalType":"uint8","name":"actionType","type":"uint8"}],"internalType":"struct IEip712TypedDataSafeModule.ActionDefinition[]","name":"actions","type":"tuple[]"},{"internalType":"bytes4[]","name":"actionIds","type":"bytes4[]"},{"internalType":"bytes[]","name":"callData","type":"bytes[]"}],"internalType":"struct IEip712TypedDataSafeModule.Sequence","name":"sequence","type":"tuple"}],"internalType":"struct IEip712TypedDataSafeModule.ChainSequence[]","name":"sequences","type":"tuple[]"}],"internalType":"struct IEip712TypedDataSafeModule.Bundle","name":"_bundle","type":"tuple"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"executeBundle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gasPriceAdaptor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasRefundOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_safeAddr","type":"address"},{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"sequenceNonce","type":"uint256"},{"internalType":"bool","name":"deploySafe","type":"bool"},{"internalType":"bool","name":"enableGasRefund","type":"bool"},{"internalType":"uint256","name":"maxRefundAmount","type":"uint256"},{"internalType":"uint8","name":"refundRecipient","type":"uint8"},{"components":[{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"string","name":"protocolName","type":"string"},{"internalType":"uint8","name":"actionType","type":"uint8"}],"internalType":"struct IEip712TypedDataSafeModule.ActionDefinition[]","name":"actions","type":"tuple[]"},{"internalType":"bytes4[]","name":"actionIds","type":"bytes4[]"},{"internalType":"bytes[]","name":"callData","type":"bytes[]"}],"internalType":"struct IEip712TypedDataSafeModule.Sequence","name":"sequence","type":"tuple"}],"internalType":"struct IEip712TypedDataSafeModule.ChainSequence[]","name":"sequences","type":"tuple[]"}],"internalType":"struct IEip712TypedDataSafeModule.Bundle","name":"_bundle","type":"tuple"}],"name":"getBundleHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_safeAddr","type":"address"}],"name":"getDomainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint256","name":"sequenceNonce","type":"uint256"},{"internalType":"bool","name":"deploySafe","type":"bool"},{"internalType":"bool","name":"enableGasRefund","type":"bool"},{"internalType":"uint256","name":"maxRefundAmount","type":"uint256"},{"internalType":"uint8","name":"refundRecipient","type":"uint8"},{"components":[{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"string","name":"protocolName","type":"string"},{"internalType":"uint8","name":"actionType","type":"uint8"}],"internalType":"struct IEip712TypedDataSafeModule.ActionDefinition[]","name":"actions","type":"tuple[]"},{"internalType":"bytes4[]","name":"actionIds","type":"bytes4[]"},{"internalType":"bytes[]","name":"callData","type":"bytes[]"}],"internalType":"struct IEip712TypedDataSafeModule.Sequence","name":"sequence","type":"tuple"}],"internalType":"struct IEip712TypedDataSafeModule.ChainSequence[]","name":"sequences","type":"tuple[]"}],"internalType":"struct IEip712TypedDataSafeModule.Bundle","name":"_bundle","type":"tuple"}],"name":"getRawBundleHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_safeAddr","type":"address"}],"name":"getSequenceNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_adminVault","type":"address"},{"internalType":"address","name":"_sequenceExecutor","type":"address"},{"internalType":"address","name":"_safeDeployment","type":"address"},{"internalType":"address","name":"_tokenRegistry","type":"address"},{"internalType":"address","name":"_feeRecipient","type":"address"},{"internalType":"address","name":"_usdcToken","type":"address"},{"internalType":"address","name":"_gasPriceAdaptor","type":"address"},{"internalType":"uint256","name":"_gasRefundOverhead","type":"uint256"},{"internalType":"string","name":"_domainName","type":"string"},{"internalType":"string","name":"_domainVersion","type":"string"}],"name":"initializeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"sequenceNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdcToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60a060405234801561001057600080fd5b50604051613f21380380613f2183398101604081905261002f9161008a565b6001600160a01b0381166100795760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081a5b9c1d5d609a1b604482015260640160405180910390fd5b6001600160a01b03166080526100ba565b60006020828403121561009c57600080fd5b81516001600160a01b03811681146100b357600080fd5b9392505050565b608051613e456100dc6000396000818161030501526105bd0152613e456000f3fe60806040526004361061016a5760003560e01c80638a5b1d7a116100cb578063a607945b1161007f578063c7d8390611610059578063c7d839061461049d578063ebd09054146104ca578063f3dde61c146104f757600080fd5b8063a607945b14610417578063a8eb416c1461045a578063bd05a6b11461048757600080fd5b806395d7a060116100b057806395d7a060146103b75780639950d05c146103ca5780639eef8255146103ea57600080fd5b80638a5b1d7a1461036a5780638a8aec311461039757600080fd5b8063392e53cd116101225780633da67cd6116101075780633da67cd6146102f357806374beaed614610327578063895d73861461035557600080fd5b8063392e53cd146102645780633b0891811461028e57600080fd5b80631d43e1c0116101535780631d43e1c0146101f357806324568b5e1461021557806328480f321461023757600080fd5b806311eac8551461016f578063132620fd146101c6575b600080fd5b34801561017b57600080fd5b5060055461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101d257600080fd5b5060005461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156101ff57600080fd5b50610208610517565b6040516101bd91906126d3565b34801561022157600080fd5b506102356102303660046128ac565b6105a5565b005b34801561024357600080fd5b5060015461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561027057600080fd5b5060085461027e9060ff1681565b60405190151581526020016101bd565b34801561029a57600080fd5b506102c27f3d423fd40000000000000000000000000000000000000000000000000000000081565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016101bd565b3480156102ff57600080fd5b5061019c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561033357600080fd5b506103476103423660046129ad565b610928565b6040519081526020016101bd565b34801561036157600080fd5b506102086109cd565b34801561037657600080fd5b5060035461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103a357600080fd5b506102356103b23660046129ad565b6109da565b6102356103c53660046129fd565b610f28565b3480156103d657600080fd5b506103476103e5366004612aab565b611782565b3480156103f657600080fd5b50600b5461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561042357600080fd5b50610347610432366004612aab565b73ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604090205490565b34801561046657600080fd5b50610347610475366004612aab565b60096020526000908152604090205481565b34801561049357600080fd5b50610347600a5481565b3480156104a957600080fd5b5060025461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104d657600080fd5b5060045461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561050357600080fd5b50610347610512366004612ac8565b61181c565b6007805461052490612b05565b80601f016020809104026020016040519081016040528092919081815260200182805461055090612b05565b801561059d5780601f106105725761010080835404028352916020019161059d565b820191906000526020600020905b81548152906001019060200180831161058057829003601f168201915b505050505081565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f556e617574686f72697a6564000000000000000000000000000000000000000060448201526064015b60405180910390fd5b60085460ff16156106b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610640565b73ffffffffffffffffffffffffffffffffffffffff8a16158015906106f0575073ffffffffffffffffffffffffffffffffffffffff891615155b8015610711575073ffffffffffffffffffffffffffffffffffffffff881615155b8015610732575073ffffffffffffffffffffffffffffffffffffffff871615155b8015610753575073ffffffffffffffffffffffffffffffffffffffff861615155b8015610774575073ffffffffffffffffffffffffffffffffffffffff851615155b8015610795575073ffffffffffffffffffffffffffffffffffffffff841615155b6107fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c696420696e707574000000000000000000000000000000000000006044820152606401610640565b600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff8d8116919091179092556001805482168c84161790556002805482168b84161790556003805482168a8416179055600480548216898416179055600580548216888416179055600b8054909116918616919091179055600a839055600661089f8382612ba0565b5060076108ac8282612ba0565b50600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517f523f84e41556c5af02ae8009aa221886547803e16e52abbcf3194bc52642b94290610914908c908c908c908c908c9089908990612cb9565b60405180910390a150505050505050505050565b6040517fd54decb3000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d899063d54decb3906109839060069060079088908890600401613353565b602060405180830381865af41580156109a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c491906133b3565b90505b92915050565b6006805461052490612b05565b60005a60005490915073ffffffffffffffffffffffffffffffffffffffff16610a5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f436f6e666967206e6f7420696e697469616c697a6564000000000000000000006044820152606401610640565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260096020908152604082205433929091610aab90610a9b908701876133cc565b610aa49161371c565b468461186f565b9050806040015115610dab576002546040517f9ee0ce2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000921690639ee0ce2790602401602060405180830381865afa158015610b28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4c9190613813565b90508073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610bd3576040517f7e4f98c200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808916600483015282166024820152604401610640565b6002546040517f774b063000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063774b063090602401602060405180830381865afa158015610c43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c679190613830565b610da9576002546040517fc97bec9b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063c97bec9b906024016020604051808303816000875af1925050508015610d17575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252610d1491810190613813565b60015b610d4d576040517f392988ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f6ca1846810704866184e21ded7d0e974366aaf77e174853b411b80aed5a2960f60405160405180910390a3505b505b600080610dc08360c001518460a0015161193e565b9150915082606001518015610dd3575080155b15610e0a576040517fa93ba8ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260600151158015610e195750805b15610e50576040517f0fb25ce900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516060808201835260c0860180515183525101516020808301919091528183018590528251600080825291810190935291610e91918b918b90611d3d565b905080610eca576040517f847d43ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a610ed7908961387c565b9050846060015115610ef357600a54610ef0908261388f565b90505b6040517fa9ea822800000000000000000000000000000000000000000000000000000000815260048101829052602401610640565b60005a60005490915073ffffffffffffffffffffffffffffffffffffffff16610fad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f436f6e666967206e6f7420696e697469616c697a6564000000000000000000006044820152606401610640565b42843511610fe7576040517fb51df0ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd54decb3000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d899063d54decb390611042906006906007908b908b90600401613353565b602060405180830381865af415801561105f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108391906133b3565b905060006110c985858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611e829050565b905073ffffffffffffffffffffffffffffffffffffffff8116611118576040517f165dfe4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818173ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fcd182b7b23d2cf25e3288287cb62a2c6f0ba73d649eea19849d24c1e7d896a5f60405160405180910390a473ffffffffffffffffffffffffffffffffffffffff8716600090815260096020908152604082205491906111ad90610a9b908a018a6133cc565b90508060400151156114ad576002546040517f9ee0ce2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000921690639ee0ce2790602401602060405180830381865afa15801561122a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124e9190613813565b90508073ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff16146112d5576040517f7e4f98c200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808c16600483015282166024820152604401610640565b6002546040517f774b063000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063774b063090602401602060405180830381865afa158015611345573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113699190613830565b6114ab576002546040517fc97bec9b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063c97bec9b906024016020604051808303816000875af1925050508015611419575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261141691810190613813565b60015b61144f576040517f392988ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f6ca1846810704866184e21ded7d0e974366aaf77e174853b411b80aed5a2960f60405160405180910390a3505b505b6040517f2f54bf6e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301528a1690632f54bf6e90602401602060405180830381865afa158015611519573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153d9190613830565b61158b576040517f2132375600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000806115a08360c001518460a0015161193e565b91509150826060015180156115b3575080155b156115ea576040517fa93ba8ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82606001511580156115f95750805b15611630576040517f0fb25ce900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61163b84600161388f565b73ffffffffffffffffffffffffffffffffffffffff8c1660009081526009602090815260408083209390935582516060808201855260c088018051518352510151818301528084018690528351601f8d018390048302810183019094528b845291926116c7928f9290918f918f908f9081908401838280828437600092019190915250611d3d92505050565b905080611700576040517f847d43ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83606001511561171e5761171e8c85608001518660a001518b611eac565b468b600001358d73ffffffffffffffffffffffffffffffffffffffff167f2833eb2894ed7a554675d7668327a96a61008f575828de8a2694d7648d46ff448860405161176c91815260200190565b60405180910390a4505050505050505050505050565b6040517f7efa81c1000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d8990637efa81c1906117db9060069060079087906004016138a2565b602060405180830381865af41580156117f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c791906133b3565b6040517f4a4dc2e1000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d8990634a4dc2e1906117db9085906004016138ee565b6118776125f9565b60005b84518110156118fa578385828151811061189657611896613901565b6020026020010151600001511480156118cb5750828582815181106118bd576118bd613901565b602002602001015160200151145b156118f2578481815181106118e2576118e2613901565b6020026020010151915050611937565b60010161187a565b506040517feb0c4da10000000000000000000000000000000000000000000000000000000081526004810184905260248101839052604401610640565b9392505050565b60606000836060015151846020015151141580611965575083604001515184602001515114155b1561199c576040517f4d200e6700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060408201516020830151516000905b8015611d355760006119c060018361387c565b90506000866040015182815181106119da576119da613901565b6020908102919091010151600080546040517f1977ddee0000000000000000000000000000000000000000000000000000000081527fffffffff0000000000000000000000000000000000000000000000000000000084166004820152929350909173ffffffffffffffffffffffffffffffffffffffff90911690631977ddee90602401602060405180830381865afa158015611a7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9f9190613813565b905073ffffffffffffffffffffffffffffffffffffffff8116611b12576040517ff1a321d40000000000000000000000000000000000000000000000000000000081527fffffffff0000000000000000000000000000000000000000000000000000000083166004820152602401610640565b600081905060008173ffffffffffffffffffffffffffffffffffffffff1663e567e8696040518163ffffffff1660e01b8152600401600060405180830381865afa158015611b64573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611baa9190810190613930565b905060008273ffffffffffffffffffffffffffffffffffffffff1663247492f86040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1d919061399e565b905060008b602001518781518110611c3757611c37613901565b602002602001015190508060000151805190602001208380519060200120141580611c6c5750806020015160ff168260ff1614155b15611cb257805160208201516040517f6871f291000000000000000000000000000000000000000000000000000000008152610640928a929091879087906004016139bb565b88158015611cc3575060ff82166004145b15611d1b5760ff8b161580611cdb57508a60ff166001145b611d16576040517fc95d9f7900000000000000000000000000000000000000000000000000000000815260ff8c166004820152602401610640565b600198505b505050505050508080611d2d90613a34565b9150506119ad565b509250929050565b60015460405160009173ffffffffffffffffffffffffffffffffffffffff8088169263468721a7929091169084907f3d423fd40000000000000000000000000000000000000000000000000000000090611da1908a908a908a908690602401613bbc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009485161790525160e086901b9092168252611e36939291600190600401613cec565b6020604051808303816000875af1158015611e55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e799190613830565b95945050505050565b600080600080611e9286866121a6565b925092509250611ea282826121f3565b5090949350505050565b6005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169060009082906370a0823190602401602060405180830381865afa158015611f1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4391906133b3565b905080600003611f545750506121a0565b600080600080611f626122fb565b9092509050811561200d5760005a8811611f7d576000611f95565b600a545a611f8b908a61387c565b611f95919061388f565b9050801561200b5781670de0b6b3a7640000611fb18584613d69565b611fbb9190613d80565b611fc5919061388f565b945060008a118015611fd657508985115b15611fdf578994505b60ff8916156120065760045473ffffffffffffffffffffffffffffffffffffffff16612008565b325b93505b505b60008085118015612033575073ffffffffffffffffffffffffffffffffffffffff841615155b1561207057600086861115612048578661204a565b855b905061206d73ffffffffffffffffffffffffffffffffffffffff891686836123c9565b90505b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8916906370a0823190602401602060405180830381865afa1580156120dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210191906133b3565b9050801561212a5761212a73ffffffffffffffffffffffffffffffffffffffff89168d836123c9565b73ffffffffffffffffffffffffffffffffffffffff851661214b578b61214d565b845b60055460405184815273ffffffffffffffffffffffffffffffffffffffff92831692918216918f16907f4491aef93914fa4c0b351f507d27ab20ff9bf264d92d730c356332786acfc1c09060200161176c565b50505050565b600080600083516041036121e05760208401516040850151606086015160001a6121d28882858561245b565b9550955095505050506121ec565b50508151600091506002905b9250925092565b600082600381111561220757612207613a05565b03612210575050565b600182600381111561222457612224613a05565b0361225b576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600282600381111561226f5761226f613a05565b036122a9576040517ffce698f700000000000000000000000000000000000000000000000000000000815260048101829052602401610640565b60038260038111156122bd576122bd613a05565b036122f7576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401610640565b5050565b600b546005546040517f1339293a000000000000000000000000000000000000000000000000000000008152600092839273ffffffffffffffffffffffffffffffffffffffff91821692631339293a9261235d92169085903690600401613dbb565b6040805180830381865afa9250505080156123b3575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526123b091810190613deb565b60015b6123c05750600091829150565b90939092509050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052612456908490612555565b505050565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115612496575060009150600390508261254b565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156124ea573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166125415750600092506001915082905061254b565b9250600091508190505b9450945094915050565b600080602060008451602086016000885af180612578576040513d6000823e3d81fd5b50506000513d915081156125905780600114156125aa565b73ffffffffffffffffffffffffffffffffffffffff84163b155b156121a0576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b6040518060e00160405280600081526020016000815260200160001515815260200160001515815260200160008152602001600060ff1681526020016126606040518060800160405280606081526020016060815260200160608152602001606081525090565b905290565b60005b83811015612680578181015183820152602001612668565b50506000910152565b600081518084526126a1816020860160208601612665565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109c46020830184612689565b73ffffffffffffffffffffffffffffffffffffffff8116811461270857600080fd5b50565b8035612716816126e6565b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561276d5761276d61271b565b60405290565b6040516080810167ffffffffffffffff8111828210171561276d5761276d61271b565b60405160e0810167ffffffffffffffff8111828210171561276d5761276d61271b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156128005761280061271b565b604052919050565b600067ffffffffffffffff8211156128225761282261271b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600061286161285c84612808565b6127b9565b905082815283838301111561287557600080fd5b828260208301376000602084830101529392505050565b600082601f83011261289d57600080fd5b6109c48383356020850161284e565b6000806000806000806000806000806101408b8d0312156128cc57600080fd5b6128d58b61270b565b99506128e360208c0161270b565b98506128f160408c0161270b565b97506128ff60608c0161270b565b965061290d60808c0161270b565b955061291b60a08c0161270b565b945061292960c08c0161270b565b935060e08b013592506101008b013567ffffffffffffffff81111561294d57600080fd5b6129598d828e0161288c565b9250506101208b013567ffffffffffffffff81111561297757600080fd5b6129838d828e0161288c565b9150509295989b9194979a5092959850565b6000604082840312156129a757600080fd5b50919050565b600080604083850312156129c057600080fd5b82356129cb816126e6565b9150602083013567ffffffffffffffff8111156129e757600080fd5b6129f385828601612995565b9150509250929050565b60008060008060608587031215612a1357600080fd5b8435612a1e816126e6565b9350602085013567ffffffffffffffff811115612a3a57600080fd5b612a4687828801612995565b935050604085013567ffffffffffffffff811115612a6357600080fd5b8501601f81018713612a7457600080fd5b803567ffffffffffffffff811115612a8b57600080fd5b876020828401011115612a9d57600080fd5b949793965060200194505050565b600060208284031215612abd57600080fd5b8135611937816126e6565b600060208284031215612ada57600080fd5b813567ffffffffffffffff811115612af157600080fd5b612afd84828501612995565b949350505050565b600181811c90821680612b1957607f821691505b6020821081036129a7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f82111561245657806000526020600020601f840160051c81016020851015612b795750805b601f840160051c820191505b81811015612b995760008155600101612b85565b5050505050565b815167ffffffffffffffff811115612bba57612bba61271b565b612bce81612bc88454612b05565b84612b52565b6020601f821160018114612c205760008315612bea5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455612b99565b6000848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b82811015612c6e5787850151825560209485019460019092019101612c4e565b5084821015612caa57868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b73ffffffffffffffffffffffffffffffffffffffff8816815273ffffffffffffffffffffffffffffffffffffffff8716602082015273ffffffffffffffffffffffffffffffffffffffff8616604082015273ffffffffffffffffffffffffffffffffffffffff8516606082015273ffffffffffffffffffffffffffffffffffffffff8416608082015260e060a08201526000612d5860e0830185612689565b82810360c0840152612d6a8185612689565b9a9950505050505050505050565b60008154612d8581612b05565b808552600182168015612d9f5760018114612dd957612e10565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083166020870152602082151560051b8701019350612e10565b84600052602060002060005b83811015612e075781546020828a010152600182019150602081019050612de5565b87016020019450505b50505092915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612e4e57600080fd5b830160208101925035905067ffffffffffffffff811115612e6e57600080fd5b8060051b3603821315612e8057600080fd5b9250929050565b801515811461270857600080fd5b803561271681612e87565b60ff8116811461270857600080fd5b803561271681612ea0565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112612eee57600080fd5b90910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612f2c57600080fd5b830160208101925035905067ffffffffffffffff811115612f4c57600080fd5b803603821315612e8057600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112612eee57600080fd5b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461271657600080fd5b81835260208301925060008160005b8481101561305f577fffffffff0000000000000000000000000000000000000000000000000000000061304983612fd8565b1686526020958601959190910190600101613017565b5093949350505050565b60008383855260208501945060208460051b8201018360005b868110156130de577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08484030188526130bb8287612ef7565b6130c6858284612f5b565b60209a8b019a90955093909301925050600101613082565b50909695505050505050565b60006130f68283612ef7565b60808552613108608086018284612f5b565b9150506131186020840184612e19565b85830360208701528281845260208401905060208260051b8501018360005b848110156131bd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030184526131708287612fa4565b61317a8182612ef7565b6040865261318c604087018284612f5b565b9150506020820135915061319f82612ea0565b60ff9190911660209485015293830193929190910190600101613137565b50506131cc6040880188612e19565b9550935087810360408901526131e3818686613008565b9450505050506131f66060840184612e19565b8583036060870152613209838284613069565b9695505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff21833603018112612eee57600080fd5b8035825260006040830161325e6020840184612e19565b604060208701528281845260608701905060608260051b88010193508260005b83811015613346577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08987030183526132b78286613213565b803587526020808201359088015260408101356132d381612e87565b1515604088015260608101356132e881612e87565b151560608801526080818101359088015261330560a08201612eaf565b60ff1660a088015261331a60c0820182612eba565b905060e060c088015261333060e08801826130ea565b965050602092830192919091019060010161327e565b5093979650505050505050565b6080815260006133666080830187612d78565b82810360208401526133788187612d78565b905073ffffffffffffffffffffffffffffffffffffffff8516604084015282810360608401526133a88185613247565b979650505050505050565b6000602082840312156133c557600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261340157600080fd5b83018035915067ffffffffffffffff82111561341c57600080fd5b6020019150600581901b3603821315612e8057600080fd5b600067ffffffffffffffff82111561344e5761344e61271b565b5060051b60200190565b600082601f83011261346957600080fd5b813561347761285c82613434565b8082825260208201915060208360051b86010192508583111561349957600080fd5b602085015b8381101561354a57803567ffffffffffffffff8111156134bd57600080fd5b860160408189037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156134f157600080fd5b6134f961274a565b602082013567ffffffffffffffff81111561351357600080fd5b6135228a60208386010161288c565b8252506040820135915061353582612ea0565b6020818101929092528452928301920161349e565b5095945050505050565b600082601f83011261356557600080fd5b813561357361285c82613434565b8082825260208201915060208360051b86010192508583111561359557600080fd5b602085015b8381101561354a576135ab81612fd8565b83526020928301920161359a565b600082601f8301126135ca57600080fd5b81356135d861285c82613434565b8082825260208201915060208360051b8601019250858311156135fa57600080fd5b602085015b8381101561354a57803567ffffffffffffffff81111561361e57600080fd5b8601603f8101881361362f57600080fd5b6136418860208301356040840161284e565b845250602092830192016135ff565b60006080828403121561366257600080fd5b61366a612773565b9050813567ffffffffffffffff81111561368357600080fd5b61368f8482850161288c565b825250602082013567ffffffffffffffff8111156136ac57600080fd5b6136b884828501613458565b602083015250604082013567ffffffffffffffff8111156136d857600080fd5b6136e484828501613554565b604083015250606082013567ffffffffffffffff81111561370457600080fd5b613710848285016135b9565b60608301525092915050565b600061372a61285c84613434565b8381526020810190600585901b84013681111561374657600080fd5b845b8181101561380857803567ffffffffffffffff81111561376757600080fd5b860160e036829003121561377a57600080fd5b613782612796565b813581526020808301359082015261379c60408301612e95565b60408201526137ad60608301612e95565b6060820152608082810135908201526137c860a08301612eaf565b60a082015260c082013567ffffffffffffffff8111156137e757600080fd5b6137f336828501613650565b60c08301525085525060209384019301613748565b509095945050505050565b60006020828403121561382557600080fd5b8151611937816126e6565b60006020828403121561384257600080fd5b815161193781612e87565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156109c7576109c761384d565b808201808211156109c7576109c761384d565b6060815260006138b56060830186612d78565b82810360208401526138c78186612d78565b91505073ffffffffffffffffffffffffffffffffffffffff83166040830152949350505050565b6020815260006109c46020830184613247565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561394257600080fd5b815167ffffffffffffffff81111561395957600080fd5b8201601f8101841361396a57600080fd5b805161397861285c82612808565b81815285602083850101111561398d57600080fd5b611e79826020830160208601612665565b6000602082840312156139b057600080fd5b815161193781612ea0565b85815260a0602082015260006139d460a0830187612689565b60ff8616604084015282810360608401526139ef8186612689565b91505060ff831660808301529695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600081613a4357613a4361384d565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b600081518084526020840193506020830160005b8281101561305f5781517fffffffff0000000000000000000000000000000000000000000000000000000016865260209586019590910190600101613a7d565b80358252600060408301613ad46020840184612e19565b604060208701528281845260608701905060608260051b88010193508260005b83811015613346577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0898703018352613b2d8286613213565b80358752602080820135908801526040810135613b4981612e87565b151560408801526060810135613b5e81612e87565b1515606088015260808181013590880152613b7b60a08201612eaf565b60ff1660a0880152613b9060c0820182612eba565b905060e060c0880152613ba660e08801826130ea565b9650506020928301929190910190600101613af4565b608081526000855160606080840152613bd860e0840182612689565b6020888101518583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800160a0870152805180845292935081019181840191600582901b85010160005b82811015613c71577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868303018452613c5c828651612689565b60209586019594909401939150600101613c22565b5060408b015194507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808782030160c0880152613cad8186613a69565b9450505050508281036020840152613cc58187613abd565b90508281036040840152613cd98186612689565b915050611e79606083018461ffff169052565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152608060408201526000613d216080830185612689565b905060028310613d5a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b82606083015295945050505050565b80820281158282048414176109c7576109c761384d565b600082613db6577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000611e79604083018486612f5b565b60008060408385031215613dfe57600080fd5b50508051602090910151909290915056fea2646970667358221220cfb2980bf92440be29875dabaf6765125162ac6e89a62ddcd9715c2f7d6511ae64736f6c634300081c0033000000000000000000000000237e5d6caf1abc06b9a1a625ff04f8bc1b7f7e2c

Deployed Bytecode

0x60806040526004361061016a5760003560e01c80638a5b1d7a116100cb578063a607945b1161007f578063c7d8390611610059578063c7d839061461049d578063ebd09054146104ca578063f3dde61c146104f757600080fd5b8063a607945b14610417578063a8eb416c1461045a578063bd05a6b11461048757600080fd5b806395d7a060116100b057806395d7a060146103b75780639950d05c146103ca5780639eef8255146103ea57600080fd5b80638a5b1d7a1461036a5780638a8aec311461039757600080fd5b8063392e53cd116101225780633da67cd6116101075780633da67cd6146102f357806374beaed614610327578063895d73861461035557600080fd5b8063392e53cd146102645780633b0891811461028e57600080fd5b80631d43e1c0116101535780631d43e1c0146101f357806324568b5e1461021557806328480f321461023757600080fd5b806311eac8551461016f578063132620fd146101c6575b600080fd5b34801561017b57600080fd5b5060055461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101d257600080fd5b5060005461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156101ff57600080fd5b50610208610517565b6040516101bd91906126d3565b34801561022157600080fd5b506102356102303660046128ac565b6105a5565b005b34801561024357600080fd5b5060015461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561027057600080fd5b5060085461027e9060ff1681565b60405190151581526020016101bd565b34801561029a57600080fd5b506102c27f3d423fd40000000000000000000000000000000000000000000000000000000081565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016101bd565b3480156102ff57600080fd5b5061019c7f000000000000000000000000237e5d6caf1abc06b9a1a625ff04f8bc1b7f7e2c81565b34801561033357600080fd5b506103476103423660046129ad565b610928565b6040519081526020016101bd565b34801561036157600080fd5b506102086109cd565b34801561037657600080fd5b5060035461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103a357600080fd5b506102356103b23660046129ad565b6109da565b6102356103c53660046129fd565b610f28565b3480156103d657600080fd5b506103476103e5366004612aab565b611782565b3480156103f657600080fd5b50600b5461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561042357600080fd5b50610347610432366004612aab565b73ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604090205490565b34801561046657600080fd5b50610347610475366004612aab565b60096020526000908152604090205481565b34801561049357600080fd5b50610347600a5481565b3480156104a957600080fd5b5060025461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104d657600080fd5b5060045461019c9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561050357600080fd5b50610347610512366004612ac8565b61181c565b6007805461052490612b05565b80601f016020809104026020016040519081016040528092919081815260200182805461055090612b05565b801561059d5780601f106105725761010080835404028352916020019161059d565b820191906000526020600020905b81548152906001019060200180831161058057829003601f168201915b505050505081565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000237e5d6caf1abc06b9a1a625ff04f8bc1b7f7e2c1614610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f556e617574686f72697a6564000000000000000000000000000000000000000060448201526064015b60405180910390fd5b60085460ff16156106b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610640565b73ffffffffffffffffffffffffffffffffffffffff8a16158015906106f0575073ffffffffffffffffffffffffffffffffffffffff891615155b8015610711575073ffffffffffffffffffffffffffffffffffffffff881615155b8015610732575073ffffffffffffffffffffffffffffffffffffffff871615155b8015610753575073ffffffffffffffffffffffffffffffffffffffff861615155b8015610774575073ffffffffffffffffffffffffffffffffffffffff851615155b8015610795575073ffffffffffffffffffffffffffffffffffffffff841615155b6107fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c696420696e707574000000000000000000000000000000000000006044820152606401610640565b600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff8d8116919091179092556001805482168c84161790556002805482168b84161790556003805482168a8416179055600480548216898416179055600580548216888416179055600b8054909116918616919091179055600a839055600661089f8382612ba0565b5060076108ac8282612ba0565b50600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517f523f84e41556c5af02ae8009aa221886547803e16e52abbcf3194bc52642b94290610914908c908c908c908c908c9089908990612cb9565b60405180910390a150505050505050505050565b6040517fd54decb3000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d899063d54decb3906109839060069060079088908890600401613353565b602060405180830381865af41580156109a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c491906133b3565b90505b92915050565b6006805461052490612b05565b60005a60005490915073ffffffffffffffffffffffffffffffffffffffff16610a5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f436f6e666967206e6f7420696e697469616c697a6564000000000000000000006044820152606401610640565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260096020908152604082205433929091610aab90610a9b908701876133cc565b610aa49161371c565b468461186f565b9050806040015115610dab576002546040517f9ee0ce2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000921690639ee0ce2790602401602060405180830381865afa158015610b28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4c9190613813565b90508073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610bd3576040517f7e4f98c200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808916600483015282166024820152604401610640565b6002546040517f774b063000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063774b063090602401602060405180830381865afa158015610c43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c679190613830565b610da9576002546040517fc97bec9b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063c97bec9b906024016020604051808303816000875af1925050508015610d17575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252610d1491810190613813565b60015b610d4d576040517f392988ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f6ca1846810704866184e21ded7d0e974366aaf77e174853b411b80aed5a2960f60405160405180910390a3505b505b600080610dc08360c001518460a0015161193e565b9150915082606001518015610dd3575080155b15610e0a576040517fa93ba8ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260600151158015610e195750805b15610e50576040517f0fb25ce900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516060808201835260c0860180515183525101516020808301919091528183018590528251600080825291810190935291610e91918b918b90611d3d565b905080610eca576040517f847d43ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a610ed7908961387c565b9050846060015115610ef357600a54610ef0908261388f565b90505b6040517fa9ea822800000000000000000000000000000000000000000000000000000000815260048101829052602401610640565b60005a60005490915073ffffffffffffffffffffffffffffffffffffffff16610fad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f436f6e666967206e6f7420696e697469616c697a6564000000000000000000006044820152606401610640565b42843511610fe7576040517fb51df0ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd54decb3000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d899063d54decb390611042906006906007908b908b90600401613353565b602060405180830381865af415801561105f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108391906133b3565b905060006110c985858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050611e829050565b905073ffffffffffffffffffffffffffffffffffffffff8116611118576040517f165dfe4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818173ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fcd182b7b23d2cf25e3288287cb62a2c6f0ba73d649eea19849d24c1e7d896a5f60405160405180910390a473ffffffffffffffffffffffffffffffffffffffff8716600090815260096020908152604082205491906111ad90610a9b908a018a6133cc565b90508060400151156114ad576002546040517f9ee0ce2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526000921690639ee0ce2790602401602060405180830381865afa15801561122a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124e9190613813565b90508073ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff16146112d5576040517f7e4f98c200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808c16600483015282166024820152604401610640565b6002546040517f774b063000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063774b063090602401602060405180830381865afa158015611345573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113699190613830565b6114ab576002546040517fc97bec9b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86811660048301529091169063c97bec9b906024016020604051808303816000875af1925050508015611419575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261141691810190613813565b60015b61144f576040517f392988ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f6ca1846810704866184e21ded7d0e974366aaf77e174853b411b80aed5a2960f60405160405180910390a3505b505b6040517f2f54bf6e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301528a1690632f54bf6e90602401602060405180830381865afa158015611519573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153d9190613830565b61158b576040517f2132375600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000806115a08360c001518460a0015161193e565b91509150826060015180156115b3575080155b156115ea576040517fa93ba8ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82606001511580156115f95750805b15611630576040517f0fb25ce900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61163b84600161388f565b73ffffffffffffffffffffffffffffffffffffffff8c1660009081526009602090815260408083209390935582516060808201855260c088018051518352510151818301528084018690528351601f8d018390048302810183019094528b845291926116c7928f9290918f918f908f9081908401838280828437600092019190915250611d3d92505050565b905080611700576040517f847d43ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83606001511561171e5761171e8c85608001518660a001518b611eac565b468b600001358d73ffffffffffffffffffffffffffffffffffffffff167f2833eb2894ed7a554675d7668327a96a61008f575828de8a2694d7648d46ff448860405161176c91815260200190565b60405180910390a4505050505050505050505050565b6040517f7efa81c1000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d8990637efa81c1906117db9060069060079087906004016138a2565b602060405180830381865af41580156117f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c791906133b3565b6040517f4a4dc2e1000000000000000000000000000000000000000000000000000000008152600090738c77694629c2b2916b10d952a58657d3fe4c6d8990634a4dc2e1906117db9085906004016138ee565b6118776125f9565b60005b84518110156118fa578385828151811061189657611896613901565b6020026020010151600001511480156118cb5750828582815181106118bd576118bd613901565b602002602001015160200151145b156118f2578481815181106118e2576118e2613901565b6020026020010151915050611937565b60010161187a565b506040517feb0c4da10000000000000000000000000000000000000000000000000000000081526004810184905260248101839052604401610640565b9392505050565b60606000836060015151846020015151141580611965575083604001515184602001515114155b1561199c576040517f4d200e6700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060408201516020830151516000905b8015611d355760006119c060018361387c565b90506000866040015182815181106119da576119da613901565b6020908102919091010151600080546040517f1977ddee0000000000000000000000000000000000000000000000000000000081527fffffffff0000000000000000000000000000000000000000000000000000000084166004820152929350909173ffffffffffffffffffffffffffffffffffffffff90911690631977ddee90602401602060405180830381865afa158015611a7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9f9190613813565b905073ffffffffffffffffffffffffffffffffffffffff8116611b12576040517ff1a321d40000000000000000000000000000000000000000000000000000000081527fffffffff0000000000000000000000000000000000000000000000000000000083166004820152602401610640565b600081905060008173ffffffffffffffffffffffffffffffffffffffff1663e567e8696040518163ffffffff1660e01b8152600401600060405180830381865afa158015611b64573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611baa9190810190613930565b905060008273ffffffffffffffffffffffffffffffffffffffff1663247492f86040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1d919061399e565b905060008b602001518781518110611c3757611c37613901565b602002602001015190508060000151805190602001208380519060200120141580611c6c5750806020015160ff168260ff1614155b15611cb257805160208201516040517f6871f291000000000000000000000000000000000000000000000000000000008152610640928a929091879087906004016139bb565b88158015611cc3575060ff82166004145b15611d1b5760ff8b161580611cdb57508a60ff166001145b611d16576040517fc95d9f7900000000000000000000000000000000000000000000000000000000815260ff8c166004820152602401610640565b600198505b505050505050508080611d2d90613a34565b9150506119ad565b509250929050565b60015460405160009173ffffffffffffffffffffffffffffffffffffffff8088169263468721a7929091169084907f3d423fd40000000000000000000000000000000000000000000000000000000090611da1908a908a908a908690602401613bbc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009485161790525160e086901b9092168252611e36939291600190600401613cec565b6020604051808303816000875af1158015611e55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e799190613830565b95945050505050565b600080600080611e9286866121a6565b925092509250611ea282826121f3565b5090949350505050565b6005546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169060009082906370a0823190602401602060405180830381865afa158015611f1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4391906133b3565b905080600003611f545750506121a0565b600080600080611f626122fb565b9092509050811561200d5760005a8811611f7d576000611f95565b600a545a611f8b908a61387c565b611f95919061388f565b9050801561200b5781670de0b6b3a7640000611fb18584613d69565b611fbb9190613d80565b611fc5919061388f565b945060008a118015611fd657508985115b15611fdf578994505b60ff8916156120065760045473ffffffffffffffffffffffffffffffffffffffff16612008565b325b93505b505b60008085118015612033575073ffffffffffffffffffffffffffffffffffffffff841615155b1561207057600086861115612048578661204a565b855b905061206d73ffffffffffffffffffffffffffffffffffffffff891686836123c9565b90505b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8916906370a0823190602401602060405180830381865afa1580156120dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210191906133b3565b9050801561212a5761212a73ffffffffffffffffffffffffffffffffffffffff89168d836123c9565b73ffffffffffffffffffffffffffffffffffffffff851661214b578b61214d565b845b60055460405184815273ffffffffffffffffffffffffffffffffffffffff92831692918216918f16907f4491aef93914fa4c0b351f507d27ab20ff9bf264d92d730c356332786acfc1c09060200161176c565b50505050565b600080600083516041036121e05760208401516040850151606086015160001a6121d28882858561245b565b9550955095505050506121ec565b50508151600091506002905b9250925092565b600082600381111561220757612207613a05565b03612210575050565b600182600381111561222457612224613a05565b0361225b576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600282600381111561226f5761226f613a05565b036122a9576040517ffce698f700000000000000000000000000000000000000000000000000000000815260048101829052602401610640565b60038260038111156122bd576122bd613a05565b036122f7576040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260048101829052602401610640565b5050565b600b546005546040517f1339293a000000000000000000000000000000000000000000000000000000008152600092839273ffffffffffffffffffffffffffffffffffffffff91821692631339293a9261235d92169085903690600401613dbb565b6040805180830381865afa9250505080156123b3575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526123b091810190613deb565b60015b6123c05750600091829150565b90939092509050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052612456908490612555565b505050565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115612496575060009150600390508261254b565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156124ea573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166125415750600092506001915082905061254b565b9250600091508190505b9450945094915050565b600080602060008451602086016000885af180612578576040513d6000823e3d81fd5b50506000513d915081156125905780600114156125aa565b73ffffffffffffffffffffffffffffffffffffffff84163b155b156121a0576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b6040518060e00160405280600081526020016000815260200160001515815260200160001515815260200160008152602001600060ff1681526020016126606040518060800160405280606081526020016060815260200160608152602001606081525090565b905290565b60005b83811015612680578181015183820152602001612668565b50506000910152565b600081518084526126a1816020860160208601612665565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006109c46020830184612689565b73ffffffffffffffffffffffffffffffffffffffff8116811461270857600080fd5b50565b8035612716816126e6565b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561276d5761276d61271b565b60405290565b6040516080810167ffffffffffffffff8111828210171561276d5761276d61271b565b60405160e0810167ffffffffffffffff8111828210171561276d5761276d61271b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156128005761280061271b565b604052919050565b600067ffffffffffffffff8211156128225761282261271b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600061286161285c84612808565b6127b9565b905082815283838301111561287557600080fd5b828260208301376000602084830101529392505050565b600082601f83011261289d57600080fd5b6109c48383356020850161284e565b6000806000806000806000806000806101408b8d0312156128cc57600080fd5b6128d58b61270b565b99506128e360208c0161270b565b98506128f160408c0161270b565b97506128ff60608c0161270b565b965061290d60808c0161270b565b955061291b60a08c0161270b565b945061292960c08c0161270b565b935060e08b013592506101008b013567ffffffffffffffff81111561294d57600080fd5b6129598d828e0161288c565b9250506101208b013567ffffffffffffffff81111561297757600080fd5b6129838d828e0161288c565b9150509295989b9194979a5092959850565b6000604082840312156129a757600080fd5b50919050565b600080604083850312156129c057600080fd5b82356129cb816126e6565b9150602083013567ffffffffffffffff8111156129e757600080fd5b6129f385828601612995565b9150509250929050565b60008060008060608587031215612a1357600080fd5b8435612a1e816126e6565b9350602085013567ffffffffffffffff811115612a3a57600080fd5b612a4687828801612995565b935050604085013567ffffffffffffffff811115612a6357600080fd5b8501601f81018713612a7457600080fd5b803567ffffffffffffffff811115612a8b57600080fd5b876020828401011115612a9d57600080fd5b949793965060200194505050565b600060208284031215612abd57600080fd5b8135611937816126e6565b600060208284031215612ada57600080fd5b813567ffffffffffffffff811115612af157600080fd5b612afd84828501612995565b949350505050565b600181811c90821680612b1957607f821691505b6020821081036129a7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f82111561245657806000526020600020601f840160051c81016020851015612b795750805b601f840160051c820191505b81811015612b995760008155600101612b85565b5050505050565b815167ffffffffffffffff811115612bba57612bba61271b565b612bce81612bc88454612b05565b84612b52565b6020601f821160018114612c205760008315612bea5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455612b99565b6000848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b82811015612c6e5787850151825560209485019460019092019101612c4e565b5084821015612caa57868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b73ffffffffffffffffffffffffffffffffffffffff8816815273ffffffffffffffffffffffffffffffffffffffff8716602082015273ffffffffffffffffffffffffffffffffffffffff8616604082015273ffffffffffffffffffffffffffffffffffffffff8516606082015273ffffffffffffffffffffffffffffffffffffffff8416608082015260e060a08201526000612d5860e0830185612689565b82810360c0840152612d6a8185612689565b9a9950505050505050505050565b60008154612d8581612b05565b808552600182168015612d9f5760018114612dd957612e10565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083166020870152602082151560051b8701019350612e10565b84600052602060002060005b83811015612e075781546020828a010152600182019150602081019050612de5565b87016020019450505b50505092915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612e4e57600080fd5b830160208101925035905067ffffffffffffffff811115612e6e57600080fd5b8060051b3603821315612e8057600080fd5b9250929050565b801515811461270857600080fd5b803561271681612e87565b60ff8116811461270857600080fd5b803561271681612ea0565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112612eee57600080fd5b90910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612f2c57600080fd5b830160208101925035905067ffffffffffffffff811115612f4c57600080fd5b803603821315612e8057600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112612eee57600080fd5b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461271657600080fd5b81835260208301925060008160005b8481101561305f577fffffffff0000000000000000000000000000000000000000000000000000000061304983612fd8565b1686526020958601959190910190600101613017565b5093949350505050565b60008383855260208501945060208460051b8201018360005b868110156130de577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08484030188526130bb8287612ef7565b6130c6858284612f5b565b60209a8b019a90955093909301925050600101613082565b50909695505050505050565b60006130f68283612ef7565b60808552613108608086018284612f5b565b9150506131186020840184612e19565b85830360208701528281845260208401905060208260051b8501018360005b848110156131bd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030184526131708287612fa4565b61317a8182612ef7565b6040865261318c604087018284612f5b565b9150506020820135915061319f82612ea0565b60ff9190911660209485015293830193929190910190600101613137565b50506131cc6040880188612e19565b9550935087810360408901526131e3818686613008565b9450505050506131f66060840184612e19565b8583036060870152613209838284613069565b9695505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff21833603018112612eee57600080fd5b8035825260006040830161325e6020840184612e19565b604060208701528281845260608701905060608260051b88010193508260005b83811015613346577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08987030183526132b78286613213565b803587526020808201359088015260408101356132d381612e87565b1515604088015260608101356132e881612e87565b151560608801526080818101359088015261330560a08201612eaf565b60ff1660a088015261331a60c0820182612eba565b905060e060c088015261333060e08801826130ea565b965050602092830192919091019060010161327e565b5093979650505050505050565b6080815260006133666080830187612d78565b82810360208401526133788187612d78565b905073ffffffffffffffffffffffffffffffffffffffff8516604084015282810360608401526133a88185613247565b979650505050505050565b6000602082840312156133c557600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261340157600080fd5b83018035915067ffffffffffffffff82111561341c57600080fd5b6020019150600581901b3603821315612e8057600080fd5b600067ffffffffffffffff82111561344e5761344e61271b565b5060051b60200190565b600082601f83011261346957600080fd5b813561347761285c82613434565b8082825260208201915060208360051b86010192508583111561349957600080fd5b602085015b8381101561354a57803567ffffffffffffffff8111156134bd57600080fd5b860160408189037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156134f157600080fd5b6134f961274a565b602082013567ffffffffffffffff81111561351357600080fd5b6135228a60208386010161288c565b8252506040820135915061353582612ea0565b6020818101929092528452928301920161349e565b5095945050505050565b600082601f83011261356557600080fd5b813561357361285c82613434565b8082825260208201915060208360051b86010192508583111561359557600080fd5b602085015b8381101561354a576135ab81612fd8565b83526020928301920161359a565b600082601f8301126135ca57600080fd5b81356135d861285c82613434565b8082825260208201915060208360051b8601019250858311156135fa57600080fd5b602085015b8381101561354a57803567ffffffffffffffff81111561361e57600080fd5b8601603f8101881361362f57600080fd5b6136418860208301356040840161284e565b845250602092830192016135ff565b60006080828403121561366257600080fd5b61366a612773565b9050813567ffffffffffffffff81111561368357600080fd5b61368f8482850161288c565b825250602082013567ffffffffffffffff8111156136ac57600080fd5b6136b884828501613458565b602083015250604082013567ffffffffffffffff8111156136d857600080fd5b6136e484828501613554565b604083015250606082013567ffffffffffffffff81111561370457600080fd5b613710848285016135b9565b60608301525092915050565b600061372a61285c84613434565b8381526020810190600585901b84013681111561374657600080fd5b845b8181101561380857803567ffffffffffffffff81111561376757600080fd5b860160e036829003121561377a57600080fd5b613782612796565b813581526020808301359082015261379c60408301612e95565b60408201526137ad60608301612e95565b6060820152608082810135908201526137c860a08301612eaf565b60a082015260c082013567ffffffffffffffff8111156137e757600080fd5b6137f336828501613650565b60c08301525085525060209384019301613748565b509095945050505050565b60006020828403121561382557600080fd5b8151611937816126e6565b60006020828403121561384257600080fd5b815161193781612e87565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156109c7576109c761384d565b808201808211156109c7576109c761384d565b6060815260006138b56060830186612d78565b82810360208401526138c78186612d78565b91505073ffffffffffffffffffffffffffffffffffffffff83166040830152949350505050565b6020815260006109c46020830184613247565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561394257600080fd5b815167ffffffffffffffff81111561395957600080fd5b8201601f8101841361396a57600080fd5b805161397861285c82612808565b81815285602083850101111561398d57600080fd5b611e79826020830160208601612665565b6000602082840312156139b057600080fd5b815161193781612ea0565b85815260a0602082015260006139d460a0830187612689565b60ff8616604084015282810360608401526139ef8186612689565b91505060ff831660808301529695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600081613a4357613a4361384d565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b600081518084526020840193506020830160005b8281101561305f5781517fffffffff0000000000000000000000000000000000000000000000000000000016865260209586019590910190600101613a7d565b80358252600060408301613ad46020840184612e19565b604060208701528281845260608701905060608260051b88010193508260005b83811015613346577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0898703018352613b2d8286613213565b80358752602080820135908801526040810135613b4981612e87565b151560408801526060810135613b5e81612e87565b1515606088015260808181013590880152613b7b60a08201612eaf565b60ff1660a0880152613b9060c0820182612eba565b905060e060c0880152613ba660e08801826130ea565b9650506020928301929190910190600101613af4565b608081526000855160606080840152613bd860e0840182612689565b6020888101518583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800160a0870152805180845292935081019181840191600582901b85010160005b82811015613c71577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868303018452613c5c828651612689565b60209586019594909401939150600101613c22565b5060408b015194507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808782030160c0880152613cad8186613a69565b9450505050508281036020840152613cc58187613abd565b90508281036040840152613cd98186612689565b915050611e79606083018461ffff169052565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152608060408201526000613d216080830185612689565b905060028310613d5a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b82606083015295945050505050565b80820281158282048414176109c7576109c761384d565b600082613db6577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000611e79604083018486612f5b565b60008060408385031215613dfe57600080fd5b50508051602090910151909290915056fea2646970667358221220cfb2980bf92440be29875dabaf6765125162ac6e89a62ddcd9715c2f7d6511ae64736f6c634300081c0033

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

000000000000000000000000237e5d6caf1abc06b9a1a625ff04f8bc1b7f7e2c

-----Decoded View---------------
Arg [0] : _configSetter (address): 0x237E5d6CAf1ABc06B9A1a625FF04f8BC1b7F7e2c

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000237e5d6caf1abc06b9a1a625ff04f8bc1b7f7e2c


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ 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.