ETH Price: $2,803.04 (-0.38%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Claim Withdraw238689582025-11-24 13:17:231 hr ago1763990243IN
0x504392F0...EBe28b30a
0 ETH0.000175481.28340793
Claim Withdraw238689582025-11-24 13:17:231 hr ago1763990243IN
0x504392F0...EBe28b30a
0 ETH0.00017551.28340793
Claim Withdraw238689582025-11-24 13:17:231 hr ago1763990243IN
0x504392F0...EBe28b30a
0 ETH0.000175481.28340793
Claim Withdraw238689022025-11-24 13:05:591 hr ago1763989559IN
0x504392F0...EBe28b30a
0 ETH0.000169721.24130043
Claim Withdraw238689022025-11-24 13:05:591 hr ago1763989559IN
0x504392F0...EBe28b30a
0 ETH0.000169721.24130043
Claim Withdraw238689022025-11-24 13:05:591 hr ago1763989559IN
0x504392F0...EBe28b30a
0 ETH0.000169721.24130043
Claim Withdraw238689022025-11-24 13:05:591 hr ago1763989559IN
0x504392F0...EBe28b30a
0 ETH0.000169741.24130043
Claim Withdraw238689022025-11-24 13:05:591 hr ago1763989559IN
0x504392F0...EBe28b30a
0 ETH0.000169741.24130043
Claim Withdraw238689022025-11-24 13:05:591 hr ago1763989559IN
0x504392F0...EBe28b30a
0 ETH0.000169741.24130043
Claim Withdraw238689022025-11-24 13:05:591 hr ago1763989559IN
0x504392F0...EBe28b30a
0 ETH0.000169741.24130043
Claim Withdraw238689022025-11-24 13:05:591 hr ago1763989559IN
0x504392F0...EBe28b30a
0 ETH0.000169741.24130043
Claim Withdraw238689022025-11-24 13:05:591 hr ago1763989559IN
0x504392F0...EBe28b30a
0 ETH0.000169741.24130043
Claim Withdraw238688422025-11-24 12:53:471 hr ago1763988827IN
0x504392F0...EBe28b30a
0 ETH0.000096460.7055211
Claim Withdraw238688422025-11-24 12:53:471 hr ago1763988827IN
0x504392F0...EBe28b30a
0 ETH0.000096460.7055211
Claim Withdraw238688422025-11-24 12:53:471 hr ago1763988827IN
0x504392F0...EBe28b30a
0 ETH0.000096470.7055211
Claim Withdraw238688422025-11-24 12:53:471 hr ago1763988827IN
0x504392F0...EBe28b30a
0 ETH0.000096470.7055211
Claim Withdraw238688422025-11-24 12:53:471 hr ago1763988827IN
0x504392F0...EBe28b30a
0 ETH0.000096470.7055211
Claim Withdraw238688422025-11-24 12:53:471 hr ago1763988827IN
0x504392F0...EBe28b30a
0 ETH0.000096470.7055211
Claim Withdraw238688422025-11-24 12:53:471 hr ago1763988827IN
0x504392F0...EBe28b30a
0 ETH0.000096470.7055211
Claim Withdraw238688422025-11-24 12:53:471 hr ago1763988827IN
0x504392F0...EBe28b30a
0 ETH0.000096470.7055211
Claim Withdraw238688422025-11-24 12:53:471 hr ago1763988827IN
0x504392F0...EBe28b30a
0 ETH0.000096470.7055211
Claim Withdraw238685822025-11-24 12:00:472 hrs ago1763985647IN
0x504392F0...EBe28b30a
0 ETH0.000149171.09085606
Claim Withdraw238685802025-11-24 12:00:232 hrs ago1763985623IN
0x504392F0...EBe28b30a
0 ETH0.000274572.00810423
Claim Withdraw238685792025-11-24 12:00:112 hrs ago1763985611IN
0x504392F0...EBe28b30a
0 ETH0.000273241.99834647
Claim Withdraw238685792025-11-24 12:00:112 hrs ago1763985611IN
0x504392F0...EBe28b30a
0 ETH0.000273261.99834647
View all transactions

Latest 15 internal transactions

Advanced mode:
Parent Transaction Hash Method Block
From
To
Deposit Eth238674462025-11-24 8:11:116 hrs ago1763971871
0x504392F0...EBe28b30a
0.002 ETH
Deposit Eth238672042025-11-24 7:22:116 hrs ago1763968931
0x504392F0...EBe28b30a
0.01 ETH
Deposit Eth238638492025-11-23 20:03:4718 hrs ago1763928227
0x504392F0...EBe28b30a
0.0078 ETH
Deposit Eth238610512025-11-23 10:39:5927 hrs ago1763894399
0x504392F0...EBe28b30a
0.00348 ETH
Deposit Eth238582962025-11-23 1:21:4736 hrs ago1763860907
0x504392F0...EBe28b30a
0.002 ETH
Deposit Eth238349142025-11-19 18:30:474 days ago1763577047
0x504392F0...EBe28b30a
2.101 ETH
Deposit Eth238181442025-11-17 9:57:237 days ago1763373443
0x504392F0...EBe28b30a
0.01 ETH
Deposit Eth238131502025-11-16 17:10:477 days ago1763313047
0x504392F0...EBe28b30a
0.002 ETH
Deposit Eth238125302025-11-16 15:05:357 days ago1763305535
0x504392F0...EBe28b30a
0.0028 ETH
Deposit Eth238117982025-11-16 12:38:238 days ago1763296703
0x504392F0...EBe28b30a
0.005 ETH
Deposit Eth238072252025-11-15 21:18:598 days ago1763241539
0x504392F0...EBe28b30a
0.019 ETH
Deposit Eth238071912025-11-15 21:12:118 days ago1763241131
0x504392F0...EBe28b30a
0.05 ETH
Deposit Eth238067282025-11-15 19:39:238 days ago1763235563
0x504392F0...EBe28b30a
0.0025 ETH
Deposit Eth238011002025-11-15 0:46:119 days ago1763167571
0x504392F0...EBe28b30a
0.002 ETH
Deposit Eth237981292025-11-14 14:49:119 days ago1763131751
0x504392F0...EBe28b30a
0.02 ETH
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

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

Contract Source Code Verified (Exact Match)

Contract Name:
CanonicalBridgeV3

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 1000 runs

Other Settings:
shanghai EvmVersion
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;

import {AccessControl, IAccessControl} from "openzeppelin-contracts/contracts/access/AccessControl.sol";
import {ReentrancyGuard} from "openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import {Pausable} from "openzeppelin-contracts/contracts/utils/Pausable.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {ICanonicalBridge} from "../v1/interfaces/ICanonicalBridge.sol";
import {ITreasury} from "../v1/interfaces/ITreasury.sol";
import {ISemVer} from "../v1/interfaces/ISemVer.sol";

/// @title CanonicalBridge
/// @dev A bridge contract for depositing and withdrawing ether to and from the Eclipse rollup.
contract CanonicalBridgeV3 is ICanonicalBridge, ISemVer, AccessControl, Pausable, ReentrancyGuard {
    address private constant NULL_ADDRESS = address(0);
    bytes32 private constant NULL_BYTES32 = bytes32(0);
    uint256 private constant NEVER = type(uint256).max;
    uint256 private constant MIN_DEPOSIT_LAMPORTS = 2_000_000;
    uint256 private constant WEI_PER_LAMPORT = 1_000_000_000;
    uint256 private constant MIN_FRAUD_WINDOW_DURATION = 1 days;
    uint256 private constant FEE_WEI_GAS_ALLOWANCE = 200_000;
    uint256 private constant FEE_WEI_MAX_ALLOWANCE = 0.2 ether;
    uint8 private constant MAJOR_VERSION = 3;
    uint8 private constant MINOR_VERSION = 0;
    uint8 private constant PATCH_VERSION = 0;

    address private immutable CANONICAL_BRIDGE_V1;
    address private immutable CANONICAL_BRIDGE_V2;

    bytes32 public constant override PAUSER_ROLE = keccak256("Pauser");
    bytes32 public constant override STARTER_ROLE = keccak256("Starter");
    bytes32 public constant override WITHDRAW_AUTHORITY_ROLE = keccak256("WithdrawAuthority");
    bytes32 public constant override CLAIM_AUTHORITY_ROLE = keccak256("ClaimAuthority");
    bytes32 public constant override WITHDRAW_CANCELLER_ROLE = keccak256("WithdrawCanceller");
    bytes32 public constant override FRAUD_WINDOW_SETTER_ROLE = keccak256("FraudWindowSetter");
    uint256 public constant override MIN_DEPOSIT = MIN_DEPOSIT_LAMPORTS * WEI_PER_LAMPORT;
    address public immutable override TREASURY;

    uint256 public override fraudWindowDuration = 7 days;
    uint64 public depositIndex = 0;

    mapping(bytes32 withdrawMessageHash => uint256 startTime) public override startTime;
    mapping(uint64 withdrawMessageId => uint256 blockNumber) public override withdrawMsgIdProcessed;

    /// @notice Emitted from the contract constructor.
    /// @param deployer The deployer address.
    /// @param canonicalBridgeV1 The address of CanonicalBridgeV1.
    event CanonicalBridgeV1(address indexed deployer, address canonicalBridgeV1);

    /// @notice Emitted from the contract constructor.
    /// @param deployer The deployer address.
    /// @param canonicalBridgeV2 The address of CanonicalBridgeV2.
    event CanonicalBridgeV2(address indexed deployer, address canonicalBridgeV2);

    /// @notice Emitted when a pending claim on another bridge is claimed on this bridge
    /// @param canonicalBridge the address of the bridge on which the withdraw was pending
    /// @param messageHash The messageHash that was settled
    /// @param message The message that was settled
    event WithdrawSettled(address indexed canonicalBridge, bytes32 indexed messageHash, WithdrawMessage message);

    /// @notice Emitted when a withdraw fee is settled.
    /// @param receiver The recipient of the funds who is also the requester.
    /// @param message The withdraw message includes details such as origin and amount.
    /// @param messageHash The hash of the withdrawMessage.
    event WithdrawFeeSettled(
        address indexed receiver, bytes32 indexed remoteSender, bytes32 indexed messageHash, WithdrawMessage message
    );

    /// @notice Emitted on a successful deposit.
    /// @param sender The address of the user who made the deposit.
    /// @param recipient The recipient account on the target chain.
    /// @param amountWei The amount in wei deposited.
    /// @param amountLamports the amount in lamports deposited.
    /// @param depositId the pseudo-random depositId of the deposit.
    event DepositedWithId(
        address indexed sender, bytes32 indexed recipient, uint256 amountWei, uint256 amountLamports, uint64 depositId
    );

    /// @notice Emitted when attempting to initialize the contract with a null address
    error NullAddress();

    /// @notice Ensures that the provided bytes32 data is not empty.
    /// @dev This modifier checks if the input is equal to NULL_BYTES32 (0x0).
    ///      If the input is empty, the transaction will revert with an appropriate error message.
    modifier bytes32Initialized(bytes32 _data) {
        if (_data == NULL_BYTES32) revert EmptyBytes32();
        _;
    }

    /// @dev Ensures the deposit amount and msg.value are valid, equal and they are >= to the min deposit amount.
    /// @param amountWei The amount to be deposited.
    modifier validDepositAmount(uint256 amountWei) {
        if (msg.value != amountWei) revert CanonicalBridgeTransactionRejected(0, "Deposit amount mismatch");
        if (msg.value % WEI_PER_LAMPORT != 0) {
            revert CanonicalBridgeTransactionRejected(0, "Fractional value not allowed");
        }
        if (msg.value < MIN_DEPOSIT) revert CanonicalBridgeTransactionRejected(0, "Deposit less than minimum");
        _;
    }

    /// @dev Ensure that withdraw messages are complete.
    modifier validWithdrawMessage(WithdrawMessage memory message) {
        /// @dev message field checks
        if (message.from == NULL_BYTES32) {
            revert CanonicalBridgeTransactionRejected(message.withdrawId, "Null message.from");
        }
        if (message.destination == NULL_ADDRESS) {
            revert CanonicalBridgeTransactionRejected(message.withdrawId, "Null message.destination");
        }
        if (message.amountWei == 0) {
            revert CanonicalBridgeTransactionRejected(message.withdrawId, "message.amountWei is 0");
        }
        if (message.withdrawId == 0) {
            revert CanonicalBridgeTransactionRejected(message.withdrawId, "message.withdrawId is 0");
        }
        if (message.feeWei > message.amountWei) {
            revert CanonicalBridgeTransactionRejected(message.withdrawId, "message.fee exceeds message.amount");
        }
        if (message.feeReceiver == NULL_ADDRESS) {
            revert CanonicalBridgeTransactionRejected(message.withdrawId, "Null message.feeReceiver");
        }

        /// @dev explicit gas allowance check for authorizeWithdraw
        uint256 maxGasAllowance = FEE_WEI_GAS_ALLOWANCE * tx.gasprice;
        if (message.feeWei > maxGasAllowance || message.feeWei > FEE_WEI_MAX_ALLOWANCE) {
            revert CanonicalBridgeTransactionRejected(
                message.withdrawId,
                string(
                    abi.encodePacked(
                        "Fee exceeds max allowance: ",
                        Strings.toString(message.feeWei),
                        " > ",
                        Strings.toString(maxGasAllowance)
                    )
                )
            );
        }

        _;
    }

    /// @dev Constructor that initializes the contract.
    constructor(address owner, address treasuryAddress, address canonicalBridgeV1, address canonicalBridgeV2) {
        /// @dev check that all addresses are properly initialized
        if (owner == NULL_ADDRESS) revert NullAddress();
        if (treasuryAddress == NULL_ADDRESS) revert NullAddress();
        if (canonicalBridgeV1 == NULL_ADDRESS) revert NullAddress();
        if (canonicalBridgeV2 == NULL_ADDRESS) revert NullAddress();

        /// @dev The owner receives default ACL-admin role that controls access to the
        /// operational roles that follow.
        _grantRole(DEFAULT_ADMIN_ROLE, owner);
        /// @dev These assignments are conveniences, since the owner now has user admin authority.
        _grantRole(PAUSER_ROLE, owner);
        _grantRole(STARTER_ROLE, owner);
        _grantRole(WITHDRAW_AUTHORITY_ROLE, owner);
        _grantRole(CLAIM_AUTHORITY_ROLE, owner);
        _grantRole(WITHDRAW_CANCELLER_ROLE, owner);
        _grantRole(FRAUD_WINDOW_SETTER_ROLE, owner);

        TREASURY = treasuryAddress;
        CANONICAL_BRIDGE_V1 = canonicalBridgeV1;
        CANONICAL_BRIDGE_V2 = canonicalBridgeV2;

        emit Deployed(msg.sender, owner, treasuryAddress);
        emit CanonicalBridgeV1(msg.sender, canonicalBridgeV1);
        emit CanonicalBridgeV2(msg.sender, canonicalBridgeV2);
    }

    /// @inheritdoc ICanonicalBridge
    function withdrawMessageStatus(WithdrawMessage calldata message) external view override returns (WithdrawStatus) {
        return withdrawMessageStatus(withdrawMessageHash(message));
    }

    /// @inheritdoc ICanonicalBridge
    function withdrawMessageStatus(bytes32 messageHash) public view override returns (WithdrawStatus) {
        uint256 startTime_ = startTime[messageHash];
        if (startTime_ == 0) return WithdrawStatus.UNKNOWN;
        if (startTime_ == NEVER) return WithdrawStatus.CLOSED;
        if (startTime_ > block.timestamp) return WithdrawStatus.PROCESSING;
        return WithdrawStatus.PENDING;
    }

    /// @inheritdoc ICanonicalBridge
    function withdrawMessageHash(WithdrawMessage memory message) public pure override returns (bytes32) {
        return keccak256(abi.encode(message));
    }

    /// @inheritdoc ISemVer
    /// @dev Retrieves the constant version details of the smart contract.
    function getVersionComponents() external pure override returns (Version memory) {
        return Version(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION);
    }

    // Operations

    /// @inheritdoc ICanonicalBridge
    /// @dev Access controlled, pausible
    function deposit(bytes32 recipient, uint256 amountWei)
        external
        payable
        virtual
        override
        whenNotPaused
        bytes32Initialized(recipient)
        validDepositAmount(amountWei)
        nonReentrant
    {
        ITreasury(TREASURY).depositEth{value: amountWei}();

        // Calculate the depositId for the deposit and increment depositIndex
        uint64 depositId = uint64(uint256(keccak256(abi.encodePacked(depositIndex++))));

        // Calculate amountLamports for target chain
        uint256 amountLamports = amountWei / WEI_PER_LAMPORT;

        // Emit both new and legacy events for deposit
        emit Deposited(msg.sender, recipient, amountWei, amountLamports);
        emit DepositedWithId(msg.sender, recipient, amountWei, amountLamports, depositId);
    }

    /// @inheritdoc ICanonicalBridge
    /// @dev Access controlled, pausable
    function authorizeWithdraws(WithdrawMessage[] calldata messages)
        external
        override
        whenNotPaused
        onlyRole(WITHDRAW_AUTHORITY_ROLE)
    {
        for (uint256 i = 0; i < messages.length; i++) {
            _authorizeWithdraw(messages[i]);
        }
    }

    /// @inheritdoc ICanonicalBridge
    /// @dev Access controlled, pausable
    function authorizeWithdraw(WithdrawMessage calldata message)
        external
        override
        whenNotPaused
        onlyRole(WITHDRAW_AUTHORITY_ROLE)
    {
        _authorizeWithdraw(message);
    }

    /// @notice Inserts a withdraw authorization with a start time after the fraud window.
    /// @param message The message to record.
    /// @dev Message must pass validation rules.
    function _authorizeWithdraw(WithdrawMessage memory message) private validWithdrawMessage(message) {
        /// @dev compute hash and fraud window
        bytes32 messageHash = withdrawMessageHash(message);
        uint256 messageStartTime = block.timestamp + fraudWindowDuration;

        /// @dev CanonicalBridgeV1 replay protection.
        if ((ICanonicalBridge(CANONICAL_BRIDGE_V1).withdrawMsgIdProcessed(message.withdrawId) != 0)) {
            revert CanonicalBridgeTransactionRejected(message.withdrawId, "Message replay protection v1");
        }

        /// @dev CanonicalBridgeV2 replay protection.
        if ((ICanonicalBridge(CANONICAL_BRIDGE_V2).withdrawMsgIdProcessed(message.withdrawId) != 0)) {
            revert CanonicalBridgeTransactionRejected(message.withdrawId, "Message replay protection v2");
        }

        /// @dev This would occur if the relayer passed the same message twice.
        if (withdrawMessageStatus(messageHash) != WithdrawStatus.UNKNOWN) {
            revert CanonicalBridgeTransactionRejected(message.withdrawId, "Message already exists");
        }

        /// @dev This would only occur if the same withdrawId was used for two different messages.
        if (withdrawMsgIdProcessed[message.withdrawId] != 0) {
            revert CanonicalBridgeTransactionRejected(message.withdrawId, "Message Id already exists");
        }

        startTime[messageHash] = messageStartTime;
        withdrawMsgIdProcessed[message.withdrawId] = block.number;

        emit WithdrawAuthorized(msg.sender, message, messageHash, messageStartTime);
    }

    /// @inheritdoc ICanonicalBridge
    /// @dev Pausable
    function claimWithdraw(WithdrawMessage calldata message) external override whenNotPaused nonReentrant {
        bool authorizedWithdrawer = (msg.sender == message.destination || hasRole(CLAIM_AUTHORITY_ROLE, msg.sender));
        if (!authorizedWithdrawer) {
            revert IAccessControl.AccessControlUnauthorizedAccount(msg.sender, CLAIM_AUTHORITY_ROLE);
        }

        bytes32 messageHash = withdrawMessageHash(message);

        // Check the v3 status first and revert if alerady processed
        bool isClosedV3 = withdrawMessageStatus(messageHash) == WithdrawStatus.CLOSED;
        if (isClosedV3) {
            revert WithdrawUnauthorized();
        }

        // settle claim on earlier versions if possible
        bool isPendingV1 =
            ICanonicalBridge(CANONICAL_BRIDGE_V1).withdrawMessageStatus(messageHash) == WithdrawStatus.PENDING;
        bool isPendingV2 =
            ICanonicalBridge(CANONICAL_BRIDGE_V2).withdrawMessageStatus(messageHash) == WithdrawStatus.PENDING;
        bool isPendingV3 = withdrawMessageStatus(messageHash) == WithdrawStatus.PENDING;

        // Revert only if not claimable on any bridge
        if (!isPendingV1 && !isPendingV2 && !isPendingV3) {
            revert WithdrawUnauthorized();
        }

        // If the message is pending on v1, record in v3 and nullify on v1
        if (isPendingV1) {
            uint256 blockNumber = ICanonicalBridge(CANONICAL_BRIDGE_V1).withdrawMsgIdProcessed(message.withdrawId);
            withdrawMsgIdProcessed[message.withdrawId] = blockNumber;
            startTime[messageHash] = NEVER;

            emit WithdrawSettled(CANONICAL_BRIDGE_V1, messageHash, message);
            _claimWithdraw(message, messageHash);
        }
        // If the message is pending on v2, record in v3 and nullify on v2
        else if (isPendingV2) {
            uint256 blockNumber = ICanonicalBridge(CANONICAL_BRIDGE_V2).withdrawMsgIdProcessed(message.withdrawId);
            withdrawMsgIdProcessed[message.withdrawId] = blockNumber;
            startTime[messageHash] = NEVER;

            emit WithdrawSettled(CANONICAL_BRIDGE_V2, messageHash, message);
            _claimWithdraw(message, messageHash);
            _settleWithdrawFee(message, messageHash);
        }
        // If the message is pending on any version flag as never on this version
        else {
            startTime[messageHash] = NEVER;
            _claimWithdraw(message, messageHash);
            _settleWithdrawFee(message, messageHash);
        }
    }

    function _claimWithdraw(WithdrawMessage memory message, bytes32 messageHash) private {
        bool success;

        /// @dev Transfer amountWei - feeWei to recipient.
        success = ITreasury(TREASURY).withdrawEth(message.destination, message.amountWei - message.feeWei);

        /// @dev The following condition should never occur and the error should be unreachable code.
        if (!success) revert WithdrawFailed();

        emit WithdrawClaimed(message.destination, message.from, messageHash, message);
    }

    function _settleWithdrawFee(WithdrawMessage memory message, bytes32 messageHash) private {
        bool success;

        /// @dev Transfer feeWei to fee receiver.
        success = ITreasury(TREASURY).withdrawEth(message.feeReceiver, message.feeWei);

        /// @dev The following condition should never occur and the error should be unreachable code.
        if (!success) revert WithdrawFailed();

        emit WithdrawFeeSettled(message.destination, message.from, messageHash, message);
    }

    // Admin

    /// @inheritdoc ICanonicalBridge
    /// @dev Access controlled
    function deleteWithdrawMessage(WithdrawMessage calldata message)
        external
        override
        onlyRole(WITHDRAW_CANCELLER_ROLE)
    {
        bytes32 messageHash = withdrawMessageHash(message);
        WithdrawStatus status = withdrawMessageStatus(messageHash);
        if (status != WithdrawStatus.PENDING && status != WithdrawStatus.PROCESSING) {
            revert CannotCancel();
        }
        startTime[messageHash] = 0;
        withdrawMsgIdProcessed[message.withdrawId] = 0;
        emit WithdrawMessageDeleted(msg.sender, message);
    }

    /// @inheritdoc ICanonicalBridge
    /// @dev Access controlled
    function setFraudWindowDuration(uint256 durationSeconds) external onlyRole(FRAUD_WINDOW_SETTER_ROLE) {
        if (durationSeconds < MIN_FRAUD_WINDOW_DURATION) revert DurationTooShort();
        _setFraudWindowDuration(durationSeconds);
    }

    function _setFraudWindowDuration(uint256 durationSeconds) internal {
        fraudWindowDuration = durationSeconds;
        emit FraudWindowSet(msg.sender, durationSeconds);
    }

    /// @dev Pause deposits
    /// @dev Access controlled
    function pause() external virtual onlyRole(PAUSER_ROLE) {
        _pause();
    }

    /// @dev Unpause deposits
    /// @dev Access controlled
    function unpause() external virtual onlyRole(STARTER_ROLE) {
        _unpause();
    }
}

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

pragma solidity ^0.8.20;

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

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

    mapping(bytes32 role => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

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

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

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

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

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

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

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

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

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

        _revokeRole(role, callerConfirmation);
    }

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

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

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

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

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

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

    constructor() {
        _status = NOT_ENTERED;
    }

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

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

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

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

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    bool private _paused;

    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

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

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = HEX_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;

/// @title ICanonicalBridge
/// @notice Interface for a bridge contract that handles ether transfers to and from an
/// SVM compatible network.
interface ICanonicalBridge {
    /// @notice Contains deposit details sent to the target rollup chain.
    /// @param sender The address which provided the ether to deposit.
    /// @param recipient Abi packed bytes32 of a base58-encoded Solana address on the target chain.
    /// @param amountGwei The amount deposited in Gwei.
    struct DepositMessage {
        address sender;
        bytes32 recipient;
        uint256 amountGwei;
    }

    /// @notice Contains withdraw details sent by an authoritative state updater.
    /// @param from Public key of the primary txn signer.
    /// @param destination Receiver who can claim the withdraw.
    /// @param amountWei Amount of wei that can be withdrawn.
    /// @param withdrawId Unique identifier can be used once.
    /// @param feeReceiver The address that will receive the transaction fee.
    /// @param feeWei The amount of fee to deduct from the amountWei.
    struct WithdrawMessage {
        bytes32 from;
        address destination;
        uint256 amountWei;
        uint64 withdrawId;
        address feeReceiver;
        uint256 feeWei;
    }

    enum WithdrawStatus {
        UNKNOWN,
        PROCESSING,
        PENDING,
        CLOSED
    }

    /// @notice Emitted from the contract constructor.
    /// @param deployer The deployer address.
    /// @param owner The address that received the default permissions.
    /// @param treasuryAddress The address that will hold received funds.
    event Deployed(address indexed deployer, address owner, address treasuryAddress);

    /// @notice Emitted when the fraud window is set.
    /// @param sender The authority that updated the fraud window.
    /// @param durationSeconds The new fraud window.
    event FraudWindowSet(address indexed sender, uint256 durationSeconds);

    /// @notice Emitted on a successful deposit.
    /// @param sender The address of the user who made the deposit.
    /// @param recipient The recipient account on the target chain.
    /// @param amountWei The amount in wei deposited.
    /// @param amountLamports the amount in lamports deposited.
    event Deposited(address indexed sender, bytes32 indexed recipient, uint256 amountWei, uint256 amountLamports);

    /// @notice Emitted when a withdraw message is accepted.
    /// @param sender The address of the withdraw authority that forwarded the message.
    /// @param message The withdraw message accepted.
    /// @param messageHash The hash of the withdrawMessage.
    /// @param startTime The earliest timestamp when the withdraw can be executed.
    event WithdrawAuthorized(
        address indexed sender, WithdrawMessage message, bytes32 indexed messageHash, uint256 startTime
    );

    /// @notice Emitted when a withdraw is claimed and executed.
    /// @param receiver The recipient of the funds who is also the requester.
    /// @param remoteSender The address which originated the withdraw converted to bytes32.
    /// @param message The withdraw message includes details such as origin and amount.
    /// @param messageHash The hash of the withdrawMessage.
    event WithdrawClaimed(
        address indexed receiver, bytes32 indexed remoteSender, bytes32 indexed messageHash, WithdrawMessage message
    );

    /// @notice Emitted when an authorized withdraw is cancelled, by pre-image.
    /// @param authority The sender to authorized the cancellation.
    /// @param message The withdraw message that was cancelled.
    event WithdrawMessageDeleted(address authority, WithdrawMessage message);

    /// @notice Emitted when an authorized withdraw is cancelled, by hash.
    /// @param authority The sender to authorized the cancellation.
    /// @param messageHash The withdraw message hash that was cancelled.
    event WithdrawMessageHashDeleted(address indexed authority, bytes32 indexed messageHash);

    /// @notice Emitted when a withdraw authorization is cancelled.
    /// @param sender The authority that cancelled with the withdraw.
    /// @param messageHash The hash of the withdraw message that was cancelled.
    event WithdrawCancelled(address indexed sender, bytes32 indexed messageHash);

    /// @notice Emitted when the withdraw authorization is rejected.
    /// @param withdrawId The transactionId that was rejected.
    /// @dev withdrawId is 0 if deposit transaction. It is meaningful if a withdraw transaction or batch.
    error CanonicalBridgeTransactionRejected(uint64 withdrawId, string reason);

    /// @notice Emitted when the requested fraud window is less than the hard-code minimum.
    error DurationTooShort();

    /// @notice Emitted when the Treasury fails to withdraw funds as instructed.
    error WithdrawFailed();

    /// @notice Emitted when an attempted withdraw is unauthorized.
    error WithdrawUnauthorized();

    /// @notice Emitted when an unable to cancel an authorized withdraw.
    /// @dev The authorized withdraw must be in the PENDING state or it cannot be cancelled.
    error CannotCancel();

    /// @notice Emitted when a bytes32 input is empty.
    error EmptyBytes32();

    /// @notice Returns the pauser role id.
    /// @return roleId The bytes32 value representing the pauser role identifier.
    function PAUSER_ROLE() external view returns (bytes32 roleId);

    /// @notice Returns the starter role id.
    /// @return roleId The bytes32 value representing the starter role identifier.
    function STARTER_ROLE() external view returns (bytes32 roleId);

    /// @notice Returns the withdraw authority role id.
    /// @return roleId The bytes32 value representing the withdraw authority role identifier.
    function WITHDRAW_AUTHORITY_ROLE() external view returns (bytes32 roleId);

    /// @notice Returns the claim authority role id.
    /// @return roleId The bytes32 value representing the claim authority role identifier.
    function CLAIM_AUTHORITY_ROLE() external view returns (bytes32 roleId);

    /// @notice Returns the withdraw canceller role id.
    /// @return roleId The bytes32 value representing the withdraw canceller role identifier.
    function WITHDRAW_CANCELLER_ROLE() external view returns (bytes32 roleId);

    /// @notice Returns the fraud window duration setter role id.
    /// @return roleId The bytes32 value representing the fraud window setter role identifier.
    function FRAUD_WINDOW_SETTER_ROLE() external view returns (bytes32 roleId);

    /// @notice Returns the minimum wei required to acquire a single lamport.
    /// @return amountWei The minimum deposit expressed in wei.
    function MIN_DEPOSIT() external view returns (uint256 amountWei);

    /// @notice Returns the address of the treasury that will receive locked funds.
    /// @return treasuryAddress The address of the treasury contract.
    function TREASURY() external view returns (address treasuryAddress);

    /// @notice Returns the fraud window duration that governs withdraw eligibility.
    /// @return fraudWindowDuration the fraud window duration in seconds.
    function fraudWindowDuration() external view returns (uint256 fraudWindowDuration);

    /// @notice Returns the startTime of withdraw eligibility for a withdraw message hash.
    /// @param withdrawMessageHash A hash of a withdraw message.
    /// @dev Eth timestamp format is in seconds. zero is not possible for a withdraw message
    /// with a non-zero amount. 2^^256 means the withdraw has been claimed and can never
    /// be executed again.
    /// @return startTime The unix time after which the withdraw becomes claimable.
    function startTime(bytes32 withdrawMessageHash) external view returns (uint256 startTime);

    /// @notice Returns the status of the withdraw message.
    /// @param message The message to check.
    /// @return status The status of the withdraw message.
    function withdrawMessageStatus(WithdrawMessage calldata message) external view returns (WithdrawStatus status);

    /// @notice Returns the status of the withdraw message.
    /// @param messageHash The message to check.
    /// @return status The status of the withdraw message.
    function withdrawMessageStatus(bytes32 messageHash) external view returns (WithdrawStatus status);

    /// @notice Set the duration to delay withdraw eligibility.
    /// @param durationSeconds The delay duration when withdraw messages are accepted.
    function setFraudWindowDuration(uint256 durationSeconds) external;

    /// @notice Allows users to deposit ether to the target chain.
    /// @dev Accepts Ether along with the deposit message. Emits the `Deposited` event upon success.
    /// @param recipient The recipient account on target chain.
    /// @param amountWei The amount in wei to deposit.
    function deposit(bytes32 recipient, uint256 amountWei) external payable;

    /// @notice Establishes permission to withdraw funds after the fraud window passes.
    /// @param messages abi.encoded array of Withdraw messages to authorize.
    function authorizeWithdraws(WithdrawMessage[] calldata messages) external;

    /// @notice Establishes permission to withdraw funds after the fraud window passes.
    /// @param message abi.encoded Withdraw message to authorize.
    function authorizeWithdraw(WithdrawMessage calldata message) external;

    /// @notice Allows the receiver to claim an authorized withdraw.
    /// @param message The message to execute.
    function claimWithdraw(WithdrawMessage calldata message) external;

    /// @notice Allows the fraud authority to cancel a pending withdraw.
    /// @param message The authorized withdraw message to cancel.
    function deleteWithdrawMessage(WithdrawMessage calldata message) external;

    /// @notice Returns the hash of a withdraw message.
    /// @param message The message to hash
    /// @return messageHash The computed message hash of the withdraw message.
    function withdrawMessageHash(WithdrawMessage calldata message) external pure returns (bytes32 messageHash);

    /// @notice Returns the block number if the withdraw message id has been observed and recorded.
    /// @param withdrawMsgId The message id to inspect.
    /// @return blockNumber The block number on which the withdraw authorization was submitted.
    function withdrawMsgIdProcessed(uint64 withdrawMsgId) external view returns (uint256 blockNumber);
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;

/// @title ITreasury
/// @notice Interface for a treasury contract stores ether.
/// @dev This interface assumes the implementation will provide a fallback function to receive ether.
interface ITreasury {
    /// @notice Emitted when the treasury is re-initialized.
    /// @param admin Address that initiated the re-initialization.
    /// @param oldOwner Address that was granted various permissions.
    event TreasuryReinitialized(address admin, address oldOwner);

    /// @notice Emitted when ether is deposited into the treasury.
    /// @param from The address of the sender who deposited ether.
    /// @param amountWei The amount of ether deposited.
    event TreasuryDeposit(address indexed from, uint256 amountWei);

    /// @notice Emitted when ether is withdrawn from the treasury.
    /// @param authority The sender of the withdraw instruction.
    /// @param to The address of the sender who received ether.
    /// @param amountWei The amount of ether withdrawn.
    event TreasuryWithdraw(address authority, address indexed to, uint256 amountWei);

    /// @notice Emitted when ether is withdrawn from the treasury during an emergency withdraw.
    /// @param to The address to which ether was sent.
    /// @param amountWei The amount of ether withdrawn.
    event EmergencyTreasuryWithdraw(address indexed to, uint256 amountWei);

    /// @notice Emitted when withdraws couldn't be sent to the receiver.
    error TreasuryTransferFailed();

    /// @notice Emitted when withdraw amount exceeds funds on hand.
    error InsufficientFunds();

    /// @notice Emitted when an input address is a prohibited address(0).
    error ZeroAddress();

    /// @notice Returns the depositor role id.
    function DEPOSITOR_ROLE() external view returns (bytes32);

    /// @notice Returns the withdraw authority role id.
    function WITHDRAW_AUTHORITY_ROLE() external view returns (bytes32);

    /// @notice Returns the pauser role id.
    function PAUSER_ROLE() external view returns (bytes32);

    /// @notice Returns the starter role id.
    function STARTER_ROLE() external view returns (bytes32);

    /// @notice Returns the upgrader role id.
    function UPGRADER_ROLE() external view returns (bytes32);

    /// @notice Returns the emergency authority role id.
    function EMERGENCY_ROLE() external view returns (bytes32);

    /// @notice Reinitializes the Treasury. Grants roles to the owner.
    function reinitialize() external;

    /// @notice Accepts eth deposits.
    function depositEth() external payable;

    /// @notice Withdraws Eth from the Treasury.
    /// @param to The receiver of the withdrawn Eth.
    /// @param amountWei The gross amount of Eth to withdraw.
    /// @return success True if the withdraw was succesful.
    function withdrawEth(address to, uint256 amountWei) external returns (bool success);

    /// @notice Stops deposits. Requires the PAUSER_ROLE.
    function pause() external;

    /// @notice Starts deposits. Requires the STARTER_ROLE.
    function unpause() external;

    /// @notice Withdraws an 'amount' of ether during emergencies.
    /// @param amountWei The amount of ether to be sent.
    function emergencyWithdraw(uint256 amountWei) external;
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;

/**
 * @title ISemVer
 * @dev Interface for SemVer versioning within smart contracts.
 */
interface ISemVer {
    /// @dev Struct to hold the version components.
    /// @param major The major version component, incremented for incompatible API changes.
    /// @param minor The minor version component, incremented for added functionality in a backwards-compatible manner.
    /// @param patch The patch version component, incremented for backwards-compatible bug fixes.
    struct Version {
        uint8 major;
        uint8 minor;
        uint8 patch;
    }

    /// @dev Returns the major, minor, and patch components of the version as a struct.
    /// @return Version memory Returns the version details encapsulated in a Version struct.
    function getVersionComponents() external pure returns (Version memory);
}

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

pragma solidity ^0.8.20;

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

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

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

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

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

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

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

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

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

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

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

pragma solidity ^0.8.20;

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

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

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

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

pragma solidity ^0.8.20;

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

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

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * 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[EIP 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);
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "lib/forge-std:ds-test/=lib/forge-std/lib/ds-test/src/",
    "lib/openzeppelin-contracts:@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "lib/openzeppelin-contracts:ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
    "lib/openzeppelin-contracts:erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "lib/openzeppelin-contracts:forge-std/=lib/openzeppelin-contracts/lib/forge-std/src/",
    "lib/openzeppelin-contracts-upgradeable:@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "lib/openzeppelin-contracts-upgradeable:@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
    "lib/openzeppelin-contracts-upgradeable:ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
    "lib/openzeppelin-contracts-upgradeable:erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "lib/openzeppelin-contracts-upgradeable:forge-std/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/src/",
    "lib/openzeppelin-contracts-upgradeable:openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "@openzeppelin-upgradeable/=lib/@penzeppelin-contracts-upgradeable/contracts/",
    "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
    "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "shanghai",
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"treasuryAddress","type":"address"},{"internalType":"address","name":"canonicalBridgeV1","type":"address"},{"internalType":"address","name":"canonicalBridgeV2","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"CannotCancel","type":"error"},{"inputs":[{"internalType":"uint64","name":"withdrawId","type":"uint64"},{"internalType":"string","name":"reason","type":"string"}],"name":"CanonicalBridgeTransactionRejected","type":"error"},{"inputs":[],"name":"DurationTooShort","type":"error"},{"inputs":[],"name":"EmptyBytes32","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"NullAddress","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"WithdrawFailed","type":"error"},{"inputs":[],"name":"WithdrawUnauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"deployer","type":"address"},{"indexed":false,"internalType":"address","name":"canonicalBridgeV1","type":"address"}],"name":"CanonicalBridgeV1","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"deployer","type":"address"},{"indexed":false,"internalType":"address","name":"canonicalBridgeV2","type":"address"}],"name":"CanonicalBridgeV2","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"deployer","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"address","name":"treasuryAddress","type":"address"}],"name":"Deployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"bytes32","name":"recipient","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amountWei","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountLamports","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"bytes32","name":"recipient","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amountWei","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountLamports","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"depositId","type":"uint64"}],"name":"DepositedWithId","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"durationSeconds","type":"uint256"}],"name":"FraudWindowSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amountWei","type":"uint256"},{"internalType":"uint64","name":"withdrawId","type":"uint64"},{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"feeWei","type":"uint256"}],"indexed":false,"internalType":"struct ICanonicalBridge.WithdrawMessage","name":"message","type":"tuple"},{"indexed":true,"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"}],"name":"WithdrawAuthorized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"bytes32","name":"messageHash","type":"bytes32"}],"name":"WithdrawCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"bytes32","name":"remoteSender","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amountWei","type":"uint256"},{"internalType":"uint64","name":"withdrawId","type":"uint64"},{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"feeWei","type":"uint256"}],"indexed":false,"internalType":"struct ICanonicalBridge.WithdrawMessage","name":"message","type":"tuple"}],"name":"WithdrawClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"bytes32","name":"remoteSender","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amountWei","type":"uint256"},{"internalType":"uint64","name":"withdrawId","type":"uint64"},{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"feeWei","type":"uint256"}],"indexed":false,"internalType":"struct ICanonicalBridge.WithdrawMessage","name":"message","type":"tuple"}],"name":"WithdrawFeeSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"authority","type":"address"},{"components":[{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amountWei","type":"uint256"},{"internalType":"uint64","name":"withdrawId","type":"uint64"},{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"feeWei","type":"uint256"}],"indexed":false,"internalType":"struct ICanonicalBridge.WithdrawMessage","name":"message","type":"tuple"}],"name":"WithdrawMessageDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authority","type":"address"},{"indexed":true,"internalType":"bytes32","name":"messageHash","type":"bytes32"}],"name":"WithdrawMessageHashDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"canonicalBridge","type":"address"},{"indexed":true,"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amountWei","type":"uint256"},{"internalType":"uint64","name":"withdrawId","type":"uint64"},{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"feeWei","type":"uint256"}],"indexed":false,"internalType":"struct ICanonicalBridge.WithdrawMessage","name":"message","type":"tuple"}],"name":"WithdrawSettled","type":"event"},{"inputs":[],"name":"CLAIM_AUTHORITY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FRAUD_WINDOW_SETTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEPOSIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STARTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TREASURY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WITHDRAW_AUTHORITY_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WITHDRAW_CANCELLER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amountWei","type":"uint256"},{"internalType":"uint64","name":"withdrawId","type":"uint64"},{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"feeWei","type":"uint256"}],"internalType":"struct ICanonicalBridge.WithdrawMessage","name":"message","type":"tuple"}],"name":"authorizeWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amountWei","type":"uint256"},{"internalType":"uint64","name":"withdrawId","type":"uint64"},{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"feeWei","type":"uint256"}],"internalType":"struct ICanonicalBridge.WithdrawMessage[]","name":"messages","type":"tuple[]"}],"name":"authorizeWithdraws","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amountWei","type":"uint256"},{"internalType":"uint64","name":"withdrawId","type":"uint64"},{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"feeWei","type":"uint256"}],"internalType":"struct ICanonicalBridge.WithdrawMessage","name":"message","type":"tuple"}],"name":"claimWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amountWei","type":"uint256"},{"internalType":"uint64","name":"withdrawId","type":"uint64"},{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"feeWei","type":"uint256"}],"internalType":"struct ICanonicalBridge.WithdrawMessage","name":"message","type":"tuple"}],"name":"deleteWithdrawMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint256","name":"amountWei","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"depositIndex","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fraudWindowDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVersionComponents","outputs":[{"components":[{"internalType":"uint8","name":"major","type":"uint8"},{"internalType":"uint8","name":"minor","type":"uint8"},{"internalType":"uint8","name":"patch","type":"uint8"}],"internalType":"struct ISemVer.Version","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"durationSeconds","type":"uint256"}],"name":"setFraudWindowDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"withdrawMessageHash","type":"bytes32"}],"name":"startTime","outputs":[{"internalType":"uint256","name":"startTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amountWei","type":"uint256"},{"internalType":"uint64","name":"withdrawId","type":"uint64"},{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"feeWei","type":"uint256"}],"internalType":"struct ICanonicalBridge.WithdrawMessage","name":"message","type":"tuple"}],"name":"withdrawMessageHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"messageHash","type":"bytes32"}],"name":"withdrawMessageStatus","outputs":[{"internalType":"enum ICanonicalBridge.WithdrawStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amountWei","type":"uint256"},{"internalType":"uint64","name":"withdrawId","type":"uint64"},{"internalType":"address","name":"feeReceiver","type":"address"},{"internalType":"uint256","name":"feeWei","type":"uint256"}],"internalType":"struct ICanonicalBridge.WithdrawMessage","name":"message","type":"tuple"}],"name":"withdrawMessageStatus","outputs":[{"internalType":"enum ICanonicalBridge.WithdrawStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"withdrawMessageId","type":"uint64"}],"name":"withdrawMsgIdProcessed","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"view","type":"function"}]

60e0346200025257601f620030fd38819003918201601f191683019291906001600160401b0384118385101762000256578160809284926040968752833981010312620002525762000051816200026a565b9062000060602082016200026a565b6200007b6060620000738685016200026a565b93016200026a565b6001805460ff1916815560025562093a80600355600480546001600160401b0319168155936001600160a01b0393848216939192918415620002425785811693841562000232578683169687156200022257841697881562000214575080620000e86200012b926200027f565b50620000f481620002fd565b5062000100816200039d565b506200010c8162000438565b506200011881620004d3565b5062000124816200056e565b5062000609565b5060c05260805260a052845191825260208201527fc95935a66d15e0da5e412aca0ad27ae891d20b2fb91cf3994b6a3bf2b8178082843392a282519081527f22c6a7704a34b8976cde83ad421beaf3e9d61e2d9a6adde7501d2bf953f53d8160203392a281519081527f28e45a71b806f884eaa2cec0818696c12a9d51d11e7fff2d18a5c6948e58c91960203392a251612a389081620006a582396080518181816103b901528181610c9101526115d2015260a05181818161040701528181610cf8015261164a015260c051818181611cc801528181611d6f015281816127c6015261292c0152f35b895163e99d5ac560e01b8152fd5b895163e99d5ac560e01b81528990fd5b885163e99d5ac560e01b81528890fd5b875163e99d5ac560e01b81528790fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036200025257565b6001600160a01b03165f8181527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604081205490919060ff16620002f957818052816020526040822081835260205260408220600160ff1982541617905533915f80516020620030dd8339815191528180a4600190565b5090565b6001600160a01b03165f8181527fa1109fe591aa8d3844618999472a1d10db9c7e331f65a2aafe002c00336a446a60205260408120549091907f39935d86204acf3d77da26425d7a46606d2550568c6b1876f3a2e76c804c76269060ff166200039857808352826020526040832082845260205260408320600160ff198254161790555f80516020620030dd833981519152339380a4600190565b505090565b6001600160a01b03165f8181527fe073aef41dc526905b73a8afcb340da5a4ef974efd7f15102e4d3caa11a3a98d60205260408120549091907fac6a94bcd1ac2877eda181de9748e5972fc07f76d4864cecf836b3fca185e53c9060ff166200039857808352826020526040832082845260205260408320600160ff198254161790555f80516020620030dd833981519152339380a4600190565b6001600160a01b03165f8181527f563042ac6f19900ae6f877f555965d3e949234c4788a74f3ca00aa3e8624e39b60205260408120549091907ffe482b7b16acc2ea6eda181934b481a09d50ed8e3579b43c531bc57b84336c539060ff166200039857808352826020526040832082845260205260408320600160ff198254161790555f80516020620030dd833981519152339380a4600190565b6001600160a01b03165f8181527f06246df62a8902d6b7c7ca2049c2a8c1ad05719837cf1f88cc6de0f08d28837660205260408120549091907f49d85f38d8d200e3ac71b7ada9a2786ccb6d016b3c28e43e8057f6bbae438adc9060ff166200039857808352826020526040832082845260205260408320600160ff198254161790555f80516020620030dd833981519152339380a4600190565b6001600160a01b03165f8181527f8c3d7c314c89e16efb740181381b7ce78a4b1e3cd527902e14bd38b2b23379f160205260408120549091907fb7a383a5ef6cc414a168844ee7da5cf32b44a10145b4d0cc573e1b7c231d30409060ff166200039857808352826020526040832082845260205260408320600160ff198254161790555f80516020620030dd833981519152339380a4600190565b6001600160a01b03165f8181527ff5b8dcbf1a298d0af632a6b657ac65647617e80caac50b6b28b3b96c19a3e94f60205260408120549091907fe68a6574a7e933010135bdcdb85f5b60aed1ee2a05b00c7c3b88734a75706cf09060ff166200039857808352826020526040832082845260205260408320600160ff198254161790555f80516020620030dd833981519152339380a460019056fe6080806040526004361015610012575f80fd5b5f90813560e01c90816301ffc9a7146120955750806303cb84991461205a5780631be999531461201f5780631de26e1614611d18578063248a9ca314611cec5780632d2c556514611ca85780632f2ff15d14611c6b57806330053c6914611c4d57806336568abe14611bed5780633b148f5914611bc35780633f4ba83a14611aef57806340a4aa5814611ac75780634442eab214611a605780635c975abb14611a3d57806370cccdfe14611a02578063744ced3d146115625780637b8989391461153a5780638456cb591461148f5780638bcb4fdb1461145257806391d1485414611408578063931da346146112bf578063a217fddf146112a3578063b61b6ee614610acb578063c0cb8f0f14610aab578063c76b99fd146109b7578063cc3cfe37146102d2578063d547741f14610291578063e1e158a51461026f578063e63ab1e914610234578063f75dc048146101f9578063faa62e50146101be5763fd6626101461017e575f80fd5b346101bb5760c03660031901126101bb576101b76101ab6101a66101a1366121d5565b612432565b6123fd565b60405191829182612249565b0390f35b80fd5b50346101bb57806003193601126101bb5760206040517f49d85f38d8d200e3ac71b7ada9a2786ccb6d016b3c28e43e8057f6bbae438adc8152f35b50346101bb57806003193601126101bb5760206040517fb7a383a5ef6cc414a168844ee7da5cf32b44a10145b4d0cc573e1b7c231d30408152f35b50346101bb57806003193601126101bb5760206040517f39935d86204acf3d77da26425d7a46606d2550568c6b1876f3a2e76c804c76268152f35b50346101bb57806003193601126101bb57602060405166071afd498d00008152f35b50346101bb5760403660031901126101bb576102ce6004356102b161213d565b90808452836020526102c960016040862001546122cb565b612389565b5080f35b50346101bb5760c03660031901126101bb576102ec6124af565b6102f4612270565b6102fd366121d5565b80511561095d576001600160a01b0390602091808383015116156109035760408201928351156108a957606083019367ffffffffffffffff9081865116801561085d575060a085019081519051106108035783608086015116156107b45762030d40903a82029182043a036106c257519080821180156107a3575b6106d657505061038784612432565b946003544201938442116106c257828251169060405191638bcb4fdb60e01b90818452600484015260249286818581867f0000000000000000000000000000000000000000000000000000000000000000165afa9081156106b7578b9161068a575b5061063c5785908386865116916040519485938492835260048301527f0000000000000000000000000000000000000000000000000000000000000000165afa908115610631578991610600575b506105b357610445876123fd565b60048110156105a05761055357828251168852600684526040882054610506575090600692918688526005835284604089205551168652524360408520556104d8604051809360a080918051845260208101516001600160a01b0380911660208601526040820151604086015267ffffffffffffffff606083015116606086015260808201511660808501520151910152565b60c08201527ff486b030a91fdad2b9594a1322d19e1fd67f566f96e6501dfbf69fca11ff95ca60e03392a380f35b6040836084935116918151926386c8428160e01b84526004840152820152601960448201527f4d65737361676520496420616c726561647920657869737473000000000000006064820152fd5b6040836084935116918151926386c8428160e01b84526004840152820152601660448201527f4d65737361676520616c726561647920657869737473000000000000000000006064820152fd5b5087634e487b7160e01b81526021600452fd5b6040836084935116918151926386c8428160e01b84526004840152820152601c60448201527f4d657373616765207265706c61792070726f74656374696f6e207632000000006064820152fd5b90508481813d831161062a575b61061781836121b3565b8101031261062657515f610437565b5f80fd5b503d61060d565b6040513d8b823e3d90fd5b608483604087875116918151926386c8428160e01b84526004840152820152601c60448201527f4d657373616765207265706c61792070726f74656374696f6e207631000000006064820152fd5b90508681813d83116106b0575b6106a181836121b3565b8101031261062657515f6103e9565b503d610697565b6040513d8d823e3d90fd5b602488634e487b7160e01b81526011600452fd5b610764603e6106f36106ed6064968b51169561255b565b9361255b565b95604051968161075589938401967f4665652065786365656473206d617820616c6c6f77616e63653a20000000000088526107378151809285603b8901910161251e565b840191620101f160ed1b603b8401528351938491878501910161251e565b0103601e8101875201856121b3565b6107956040519485936386c8428160e01b85526004850152604060248501525180928160448601528585019061251e565b601f01601f19168101030190fd5b506702c68af0bb1400008211610378565b608482875116604051906386c8428160e01b8252600482015260406024820152601860448201527f4e756c6c206d6573736167652e666565526563656976657200000000000000006064820152fd5b60a482875116604051906386c8428160e01b8252600482015260406024820152602260448201527f6d6573736167652e6665652065786365656473206d6573736167652e616d6f756064820152611b9d60f21b6084820152fd5b608490604051906386c8428160e01b8252600482015260406024820152601760448201527f6d6573736167652e7769746864726177496420697320300000000000000000006064820152fd5b608467ffffffffffffffff606085015116604051906386c8428160e01b8252600482015260406024820152601660448201527f6d6573736167652e616d6f756e745765692069732030000000000000000000006064820152fd5b608467ffffffffffffffff606084015116604051906386c8428160e01b8252600482015260406024820152601860448201527f4e756c6c206d6573736167652e64657374696e6174696f6e00000000000000006064820152fd5b67ffffffffffffffff6060608492015116604051906386c8428160e01b8252600482015260406024820152601160448201527f4e756c6c206d6573736167652e66726f6d0000000000000000000000000000006064820152fd5b50346101bb5760203660031901126101bb57335f9081527ff5b8dcbf1a298d0af632a6b657ac65647617e80caac50b6b28b3b96c19a3e94f6020526040902054600435907fe68a6574a7e933010135bdcdb85f5b60aed1ee2a05b00c7c3b88734a75706cf09060ff1615610a8d5750620151808110610a6357806003556040519081527f9892782f1437afb6be047429f988c13aab6dfb7e314d22ac657b062f4f1a548360203392a280f35b60046040517f25c36367000000000000000000000000000000000000000000000000000000008152fd5b6044906040519063e2517d3f60e01b82523360048301526024820152fd5b50346101bb5760203660031901126101bb576101b76101ab6004356123fd565b50346101bb5760203660031901126101bb5767ffffffffffffffff600435116101bb573660236004350112156101bb5767ffffffffffffffff60043560040135116101bb5736602460c060043560040135026004350101116101bb57610b2f6124af565b610b37612270565b8062030d40915b600435600401358110610b4f575080f35b60c081026004350160c060231982360301126106265760405190610b7282612197565b602481013590818352610b8760448201612153565b916020840192835260648201356040850152608482013567ffffffffffffffff8116928382036106265760c4916060870152610bc560a48201612153565b6080870152013560a0850152156112575750516001600160a01b0316156111fd576040810151156111a35767ffffffffffffffff606082015116801561085d575060a081015160408201511061113e576001600160a01b03608082015116156110e457833a8102043a036110d05760a08101513a8502811180156110bf575b61102f5750610c5281612432565b90600354420180421161101b5767ffffffffffffffff60608301511660405190638bcb4fdb60e01b825260048201526020816024816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa908115610f84578691610fe9575b50610f8f5767ffffffffffffffff60608301511660405190638bcb4fdb60e01b825260048201526020816024816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa908115610f84578691610f52575b50610ef857610d36836123fd565b6004811015610ee457610e8a5767ffffffffffffffff606083015116855260066020526040852054610e3057828552600560205280604086205567ffffffffffffffff60608301511685526006602052436040862055610de1604051809360a080918051845260208101516001600160a01b0380911660208601526040820151604086015267ffffffffffffffff606083015116606086015260808201511660808501520151910152565b60c08201527ff486b030a91fdad2b9594a1322d19e1fd67f566f96e6501dfbf69fca11ff95ca60e03392a35f198114610e1c57600101610b3e565b602482634e487b7160e01b81526011600452fd5b608467ffffffffffffffff606084015116604051906386c8428160e01b8252600482015260406024820152601960448201527f4d65737361676520496420616c726561647920657869737473000000000000006064820152fd5b608467ffffffffffffffff606084015116604051906386c8428160e01b8252600482015260406024820152601660448201527f4d65737361676520616c726561647920657869737473000000000000000000006064820152fd5b602486634e487b7160e01b81526021600452fd5b608467ffffffffffffffff606084015116604051906386c8428160e01b8252600482015260406024820152601c60448201527f4d657373616765207265706c61792070726f74656374696f6e207632000000006064820152fd5b90506020813d602011610f7c575b81610f6d602093836121b3565b8101031261062657515f610d28565b3d9150610f60565b6040513d88823e3d90fd5b608467ffffffffffffffff606084015116604051906386c8428160e01b8252600482015260406024820152601c60448201527f4d657373616765207265706c61792070726f74656374696f6e207631000000006064820152fd5b90506020813d602011611013575b81611004602093836121b3565b8101031261062657515f610cc1565b3d9150610ff7565b602485634e487b7160e01b81526011600452fd5b60649061105661104e67ffffffffffffffff606089960151169261255b565b933a0261255b565b610764604051948560208101937f4665652065786365656473206d617820616c6c6f77616e63653a2000000000008552620101f160ed1b603b936110a3815180926020888801910161251e565b830193840152603e92610755825180936020878501910161251e565b506702c68af0bb1400008111610c44565b602483634e487b7160e01b81526011600452fd5b67ffffffffffffffff6060608492015116604051906386c8428160e01b8252600482015260406024820152601860448201527f4e756c6c206d6573736167652e666565526563656976657200000000000000006064820152fd5b67ffffffffffffffff606060a492015116604051906386c8428160e01b8252600482015260406024820152602260448201527f6d6573736167652e6665652065786365656473206d6573736167652e616d6f756064820152611b9d60f21b6084820152fd5b67ffffffffffffffff6060608492015116604051906386c8428160e01b8252600482015260406024820152601660448201527f6d6573736167652e616d6f756e745765692069732030000000000000000000006064820152fd5b67ffffffffffffffff6060608492015116604051906386c8428160e01b8252600482015260406024820152601860448201527f4e756c6c206d6573736167652e64657374696e6174696f6e00000000000000006064820152fd5b608490604051906386c8428160e01b8252600482015260406024820152601160448201527f4e756c6c206d6573736167652e66726f6d0000000000000000000000000000006064820152fd5b50346101bb57806003193601126101bb57602090604051908152f35b50346101bb5760c03660031901126101bb57335f9081527f8c3d7c314c89e16efb740181381b7ce78a4b1e3cd527902e14bd38b2b23379f160205260409020547fb7a383a5ef6cc414a168844ee7da5cf32b44a10145b4d0cc573e1b7c231d30409060ff1615610a8d57506113366101a1366121d5565b61133f816123fd565b60048110156113f457600281141590816113e8575b506113be578152600560205280604081205567ffffffffffffffff6113776126e6565b16815260066020528060408120557fefe476e7ac46b9bde62b3d392a897ae796bfad2fe290ad65adf17b9079b9341e60e06040513381526113ba602082016126fd565ba180f35b60046040517ffbc03578000000000000000000000000000000000000000000000000000000008152fd5b6001915014155f611354565b602483634e487b7160e01b81526021600452fd5b50346101bb5760403660031901126101bb576001600160a01b03604061142c61213d565b926004358152806020522091165f52602052602060ff60405f2054166040519015158152f35b50346101bb5760203660031901126101bb5760043567ffffffffffffffff8116809103610626578160409160209352600683522054604051908152f35b50346101bb57806003193601126101bb57335f9081527fa1109fe591aa8d3844618999472a1d10db9c7e331f65a2aafe002c00336a446a60205260409020547f39935d86204acf3d77da26425d7a46606d2550568c6b1876f3a2e76c804c76269060ff1615610a8d57506115016124af565b600160ff19815416176001557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a180f35b50346101bb57806003193601126101bb57602067ffffffffffffffff60045416604051908152f35b50346101bb5760c03660031901126101bb5761157c6124af565b6115846124e5565b6001600160a01b0360248035828116908190036119fe57331480156119bf575b15611982576115b56101a1366121d5565b906115bf826123fd565b600481101561196f576003146118b557827f00000000000000000000000000000000000000000000000000000000000000001690604051937fc0cb8f0f000000000000000000000000000000000000000000000000000000009081865284600487015260209586818581885afa908115611947578891611952575b50600481101561190757600214907f0000000000000000000000000000000000000000000000000000000000000000169160405190815285600482015286818581865afa90811561194757889161191a575b50600481101561190757600214906116a3866123fd565b60048110156118f457811590816118eb575b816118df575b506118b557156117a55750506116cf6126e6565b846040518093638bcb4fdb60e01b825267ffffffffffffffff809416600483015281865afa918215610f84578692611772575b5061176a948493926005926117156126e6565b168852600682526040882055838752525f1960408620557f59c8adb5b760016054e333eac5c0ea8494e7e59a9ef83f02733788a94b4a452660c060405161175b816126fd565ba3611765366121d5565b612773565b600160025580f35b909291508481813d831161179e575b61178b81836121b3565b810103126106265751909161176a611702565b503d611781565b90925015611895576117b56126e6565b846040518093638bcb4fdb60e01b825267ffffffffffffffff809416600483015281865afa918215610f84578692611862575b5061185d948493926005926117fb6126e6565b168852600682526040882055838752525f1960408620557f59c8adb5b760016054e333eac5c0ea8494e7e59a9ef83f02733788a94b4a452660c0604051611841816126fd565ba361184f81611765366121d5565b611858366121d5565b6128f4565b61176a565b909291508481813d831161188e575b61187b81836121b3565b810103126106265751909161185d6117e8565b503d611871565b5050600561185d92828552525f19604084205561184f81611765366121d5565b60046040517f5cda670e000000000000000000000000000000000000000000000000000000008152fd5b6002915014155f6116bb565b831591506116b5565b8489634e487b7160e01b81526021600452fd5b8388634e487b7160e01b81526021600452fd5b61193a9150873d8911611940575b61193281836121b3565b8101906126ce565b5f61168c565b503d611928565b6040513d8a823e3d90fd5b6119699150873d89116119405761193281836121b3565b5f61163a565b5083634e487b7160e01b81526021600452fd5b6044907f49d85f38d8d200e3ac71b7ada9a2786ccb6d016b3c28e43e8057f6bbae438adc6040519163e2517d3f60e01b8352336004840152820152fd5b507f49d85f38d8d200e3ac71b7ada9a2786ccb6d016b3c28e43e8057f6bbae438adc83528260205260408320335f5260205260ff60405f2054166115a4565b8380fd5b50346101bb57806003193601126101bb5760206040517fe68a6574a7e933010135bdcdb85f5b60aed1ee2a05b00c7c3b88734a75706cf08152f35b50346101bb57806003193601126101bb57602060ff600154166040519015158152f35b50346101bb57806003193601126101bb578060609160408051611a8281612167565b828152826020820152015260ff60405191611a9c83612167565b6003835260406020840193828552019081528160405193600385525116602084015251166040820152f35b50346101bb5760c03660031901126101bb576020611ae76101a1366121d5565b604051908152f35b50346101bb57806003193601126101bb57335f9081527fe073aef41dc526905b73a8afcb340da5a4ef974efd7f15102e4d3caa11a3a98d60205260409020547fac6a94bcd1ac2877eda181de9748e5972fc07f76d4864cecf836b3fca185e53c9060ff1615610a8d575060015460ff811615611b995760ff19166001557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a180f35b60046040517f8dfc202b000000000000000000000000000000000000000000000000000000008152fd5b50346101bb5760203660031901126101bb5760406020916004358152600583522054604051908152f35b50346101bb5760403660031901126101bb57611c0761213d565b336001600160a01b03821603611c23576102ce90600435612389565b60046040517f6697b232000000000000000000000000000000000000000000000000000000008152fd5b50346101bb57806003193601126101bb576020600354604051908152f35b50346101bb5760403660031901126101bb576102ce600435611c8b61213d565b9080845283602052611ca360016040862001546122cb565b61230c565b50346101bb57806003193601126101bb5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346101bb5760203660031901126101bb57600160406020926004358152808452200154604051908152f35b5060403660031901126101bb576004356024803590611d356124af565b8215611ff557813403611fab57633b9aca0090813406611f615766071afd498d00003410611f1757611d656124e5565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001685813b156101bb5784916004604051809481937f439370b10000000000000000000000000000000000000000000000000000000083525af18015610f8457611ee8575b5060045467ffffffffffffffff808216818114611ed55760018291011667ffffffffffffffff19831617600455604051917fffffffffffffffff000000000000000000000000000000000000000000000000602084019160c01b16815260088352604083019383851083861117611ec357509183918793606095604052825190201694860493849187845201527fcc9c1a7566adfa8bdc9f7a63a106576fec355c6b4f61ce07baad45eaa30560c360403392a3604051928352602083015260408201527f97dcb220fc7f84ae61f5c0302e4c05f276c444a8ffb0253f3a86514bf16e815260603392a3600160025580f35b634e487b7160e01b5f5260416004525ffd5b8388634e487b7160e01b81526011600452fd5b67ffffffffffffffff8196929611611f0457604052935f611dd2565b8582634e487b7160e01b81526041600452fd5b8460406084928151926386c8428160e01b84526004840152820152601960448201527f4465706f736974206c657373207468616e206d696e696d756d000000000000006064820152fd5b8460406084928151926386c8428160e01b84526004840152820152601c60448201527f4672616374696f6e616c2076616c7565206e6f7420616c6c6f776564000000006064820152fd5b8360406084928151926386c8428160e01b84526004840152820152601760448201527f4465706f73697420616d6f756e74206d69736d617463680000000000000000006064820152fd5b60046040517f1c25715b000000000000000000000000000000000000000000000000000000008152fd5b50346101bb57806003193601126101bb5760206040517fac6a94bcd1ac2877eda181de9748e5972fc07f76d4864cecf836b3fca185e53c8152f35b50346101bb57806003193601126101bb5760206040517ffe482b7b16acc2ea6eda181934b481a09d50ed8e3579b43c531bc57b84336c538152f35b905034612139576020366003190112612139576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361213557602092507f7965db0b00000000000000000000000000000000000000000000000000000000811490811561210b575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150145f612104565b8280fd5b5080fd5b602435906001600160a01b038216820361062657565b35906001600160a01b038216820361062657565b6060810190811067ffffffffffffffff82111761218357604052565b634e487b7160e01b5f52604160045260245ffd5b60c0810190811067ffffffffffffffff82111761218357604052565b90601f8019910116810190811067ffffffffffffffff82111761218357604052565b60c090600319011261062657604051906121ee82612197565b6004358252816001600160a01b036024358181168103610626576020830152604435604083015260643567ffffffffffffffff81168103610626576060830152608435908116810361062657608082015260a060a435910152565b91906020830192600482101561225c5752565b634e487b7160e01b5f52602160045260245ffd5b335f9081527f563042ac6f19900ae6f877f555965d3e949234c4788a74f3ca00aa3e8624e39b60205260409020547ffe482b7b16acc2ea6eda181934b481a09d50ed8e3579b43c531bc57b84336c539060ff1615610a8d5750565b805f525f60205260405f20335f5260205260ff60405f205416156122ec5750565b60405163e2517d3f60e01b81523360048201526024810191909152604490fd5b905f91808352826020526001600160a01b036040842092169182845260205260ff604084205416155f1461238457808352826020526040832082845260205260408320600160ff198254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b505090565b905f91808352826020526001600160a01b036040842092169182845260205260ff6040842054165f146123845780835282602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b5f52600560205260405f2054801561242d575f19811461242757421061242257600290565b600190565b50600390565b505f90565b60405161248b60208201809360a080918051845260208101516001600160a01b0380911660208601526040820151604086015267ffffffffffffffff606083015116606086015260808201511660808501520151910152565b60c0815260e0810181811067ffffffffffffffff8211176121835760405251902090565b60ff600154166124bb57565b60046040517fd93c0665000000000000000000000000000000000000000000000000000000008152fd5b60028054146124f45760028055565b60046040517f3ee5aeb5000000000000000000000000000000000000000000000000000000008152fd5b5f5b83811061252f5750505f910152565b8181015183820152602001612520565b67ffffffffffffffff811161218357601f01601f191660200190565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000808210156126c0575b506d04ee2d6d415b85acef8100000000808310156126b1575b50662386f26fc10000808310156126a2575b506305f5e10080831015612693575b5061271080831015612684575b506064821015612674575b600a8092101561266a575b600190816021818601956125f38761253f565b9661260160405198896121b3565b808852612610601f199161253f565b01366020890137860101905b612628575b5050505090565b5f19019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156126655791908261261c565b612621565b91600101916125e0565b91906064600291049101916125d5565b6004919392049101915f6125ca565b6008919392049101915f6125bd565b6010919392049101915f6125ae565b6020919392049101915f61259c565b60409350810491505f612583565b90816020910312610626575160048110156106265790565b60643567ffffffffffffffff811681036106265790565b60043581526024356001600160a01b0390818116809103610626576020830152604435604083015260643567ffffffffffffffff811680910361062657606083015260843590811680910361062657608082015260a060a435910152565b90816020910312610626575180151581036106265790565b6001600160a01b03602082018181511660408401519060a085015182039182116128e0576040516306e6a46960e21b81526001600160a01b0391909116600482015260248101919091526020816044815f7f000000000000000000000000000000000000000000000000000000000000000088165af19081156128d5575f916128a7575b501561287d5751167f17301a134abd040120edefa131df2e376da9fb5264e3483c90f23293ab14261160c083519361287a604051809260a080918051845260208101516001600160a01b0380911660208601526040820151604086015267ffffffffffffffff606083015116606086015260808201511660808501520151910152565ba4565b60046040517f750b219c000000000000000000000000000000000000000000000000000000008152fd5b6128c8915060203d81116128ce575b6128c081836121b3565b81019061275b565b5f6127f7565b503d6128b6565b6040513d5f823e3d90fd5b634e487b7160e01b5f52601160045260245ffd5b608081015160a08201516040516306e6a46960e21b81526001600160a01b03928316600482015260248101919091526020816044815f7f000000000000000000000000000000000000000000000000000000000000000087165af19081156128d5575f916129e4575b501561287d576020820151167f26a2bb34c011f942f61c31dfaeff3a3a1b2132da80c36b90d131a5732d7cd96b60c083519361287a604051809260a080918051845260208101516001600160a01b0380911660208601526040820151604086015267ffffffffffffffff606083015116606086015260808201511660808501520151910152565b6129fc915060203d81116128ce576128c081836121b3565b5f61295d56fea264697066735822122029e8a4b241c5f913107125ac0507c440da8be171a73b0dbd29297eadd8b9306164736f6c634300081500332f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d0000000000000000000000004720342419c1d316b948690d12c86d5b485c64e0000000000000000000000000d7e4b67e735733ac98a88f13d087d8aac670e6440000000000000000000000002b08d7cf7eaff0f5f6623d9fb09b080726d4be11000000000000000000000000867a8fcd5bb6774d4d37fb342d669a35ff789a51

Deployed Bytecode

0x6080806040526004361015610012575f80fd5b5f90813560e01c90816301ffc9a7146120955750806303cb84991461205a5780631be999531461201f5780631de26e1614611d18578063248a9ca314611cec5780632d2c556514611ca85780632f2ff15d14611c6b57806330053c6914611c4d57806336568abe14611bed5780633b148f5914611bc35780633f4ba83a14611aef57806340a4aa5814611ac75780634442eab214611a605780635c975abb14611a3d57806370cccdfe14611a02578063744ced3d146115625780637b8989391461153a5780638456cb591461148f5780638bcb4fdb1461145257806391d1485414611408578063931da346146112bf578063a217fddf146112a3578063b61b6ee614610acb578063c0cb8f0f14610aab578063c76b99fd146109b7578063cc3cfe37146102d2578063d547741f14610291578063e1e158a51461026f578063e63ab1e914610234578063f75dc048146101f9578063faa62e50146101be5763fd6626101461017e575f80fd5b346101bb5760c03660031901126101bb576101b76101ab6101a66101a1366121d5565b612432565b6123fd565b60405191829182612249565b0390f35b80fd5b50346101bb57806003193601126101bb5760206040517f49d85f38d8d200e3ac71b7ada9a2786ccb6d016b3c28e43e8057f6bbae438adc8152f35b50346101bb57806003193601126101bb5760206040517fb7a383a5ef6cc414a168844ee7da5cf32b44a10145b4d0cc573e1b7c231d30408152f35b50346101bb57806003193601126101bb5760206040517f39935d86204acf3d77da26425d7a46606d2550568c6b1876f3a2e76c804c76268152f35b50346101bb57806003193601126101bb57602060405166071afd498d00008152f35b50346101bb5760403660031901126101bb576102ce6004356102b161213d565b90808452836020526102c960016040862001546122cb565b612389565b5080f35b50346101bb5760c03660031901126101bb576102ec6124af565b6102f4612270565b6102fd366121d5565b80511561095d576001600160a01b0390602091808383015116156109035760408201928351156108a957606083019367ffffffffffffffff9081865116801561085d575060a085019081519051106108035783608086015116156107b45762030d40903a82029182043a036106c257519080821180156107a3575b6106d657505061038784612432565b946003544201938442116106c257828251169060405191638bcb4fdb60e01b90818452600484015260249286818581867f0000000000000000000000002b08d7cf7eaff0f5f6623d9fb09b080726d4be11165afa9081156106b7578b9161068a575b5061063c5785908386865116916040519485938492835260048301527f000000000000000000000000867a8fcd5bb6774d4d37fb342d669a35ff789a51165afa908115610631578991610600575b506105b357610445876123fd565b60048110156105a05761055357828251168852600684526040882054610506575090600692918688526005835284604089205551168652524360408520556104d8604051809360a080918051845260208101516001600160a01b0380911660208601526040820151604086015267ffffffffffffffff606083015116606086015260808201511660808501520151910152565b60c08201527ff486b030a91fdad2b9594a1322d19e1fd67f566f96e6501dfbf69fca11ff95ca60e03392a380f35b6040836084935116918151926386c8428160e01b84526004840152820152601960448201527f4d65737361676520496420616c726561647920657869737473000000000000006064820152fd5b6040836084935116918151926386c8428160e01b84526004840152820152601660448201527f4d65737361676520616c726561647920657869737473000000000000000000006064820152fd5b5087634e487b7160e01b81526021600452fd5b6040836084935116918151926386c8428160e01b84526004840152820152601c60448201527f4d657373616765207265706c61792070726f74656374696f6e207632000000006064820152fd5b90508481813d831161062a575b61061781836121b3565b8101031261062657515f610437565b5f80fd5b503d61060d565b6040513d8b823e3d90fd5b608483604087875116918151926386c8428160e01b84526004840152820152601c60448201527f4d657373616765207265706c61792070726f74656374696f6e207631000000006064820152fd5b90508681813d83116106b0575b6106a181836121b3565b8101031261062657515f6103e9565b503d610697565b6040513d8d823e3d90fd5b602488634e487b7160e01b81526011600452fd5b610764603e6106f36106ed6064968b51169561255b565b9361255b565b95604051968161075589938401967f4665652065786365656473206d617820616c6c6f77616e63653a20000000000088526107378151809285603b8901910161251e565b840191620101f160ed1b603b8401528351938491878501910161251e565b0103601e8101875201856121b3565b6107956040519485936386c8428160e01b85526004850152604060248501525180928160448601528585019061251e565b601f01601f19168101030190fd5b506702c68af0bb1400008211610378565b608482875116604051906386c8428160e01b8252600482015260406024820152601860448201527f4e756c6c206d6573736167652e666565526563656976657200000000000000006064820152fd5b60a482875116604051906386c8428160e01b8252600482015260406024820152602260448201527f6d6573736167652e6665652065786365656473206d6573736167652e616d6f756064820152611b9d60f21b6084820152fd5b608490604051906386c8428160e01b8252600482015260406024820152601760448201527f6d6573736167652e7769746864726177496420697320300000000000000000006064820152fd5b608467ffffffffffffffff606085015116604051906386c8428160e01b8252600482015260406024820152601660448201527f6d6573736167652e616d6f756e745765692069732030000000000000000000006064820152fd5b608467ffffffffffffffff606084015116604051906386c8428160e01b8252600482015260406024820152601860448201527f4e756c6c206d6573736167652e64657374696e6174696f6e00000000000000006064820152fd5b67ffffffffffffffff6060608492015116604051906386c8428160e01b8252600482015260406024820152601160448201527f4e756c6c206d6573736167652e66726f6d0000000000000000000000000000006064820152fd5b50346101bb5760203660031901126101bb57335f9081527ff5b8dcbf1a298d0af632a6b657ac65647617e80caac50b6b28b3b96c19a3e94f6020526040902054600435907fe68a6574a7e933010135bdcdb85f5b60aed1ee2a05b00c7c3b88734a75706cf09060ff1615610a8d5750620151808110610a6357806003556040519081527f9892782f1437afb6be047429f988c13aab6dfb7e314d22ac657b062f4f1a548360203392a280f35b60046040517f25c36367000000000000000000000000000000000000000000000000000000008152fd5b6044906040519063e2517d3f60e01b82523360048301526024820152fd5b50346101bb5760203660031901126101bb576101b76101ab6004356123fd565b50346101bb5760203660031901126101bb5767ffffffffffffffff600435116101bb573660236004350112156101bb5767ffffffffffffffff60043560040135116101bb5736602460c060043560040135026004350101116101bb57610b2f6124af565b610b37612270565b8062030d40915b600435600401358110610b4f575080f35b60c081026004350160c060231982360301126106265760405190610b7282612197565b602481013590818352610b8760448201612153565b916020840192835260648201356040850152608482013567ffffffffffffffff8116928382036106265760c4916060870152610bc560a48201612153565b6080870152013560a0850152156112575750516001600160a01b0316156111fd576040810151156111a35767ffffffffffffffff606082015116801561085d575060a081015160408201511061113e576001600160a01b03608082015116156110e457833a8102043a036110d05760a08101513a8502811180156110bf575b61102f5750610c5281612432565b90600354420180421161101b5767ffffffffffffffff60608301511660405190638bcb4fdb60e01b825260048201526020816024816001600160a01b037f0000000000000000000000002b08d7cf7eaff0f5f6623d9fb09b080726d4be11165afa908115610f84578691610fe9575b50610f8f5767ffffffffffffffff60608301511660405190638bcb4fdb60e01b825260048201526020816024816001600160a01b037f000000000000000000000000867a8fcd5bb6774d4d37fb342d669a35ff789a51165afa908115610f84578691610f52575b50610ef857610d36836123fd565b6004811015610ee457610e8a5767ffffffffffffffff606083015116855260066020526040852054610e3057828552600560205280604086205567ffffffffffffffff60608301511685526006602052436040862055610de1604051809360a080918051845260208101516001600160a01b0380911660208601526040820151604086015267ffffffffffffffff606083015116606086015260808201511660808501520151910152565b60c08201527ff486b030a91fdad2b9594a1322d19e1fd67f566f96e6501dfbf69fca11ff95ca60e03392a35f198114610e1c57600101610b3e565b602482634e487b7160e01b81526011600452fd5b608467ffffffffffffffff606084015116604051906386c8428160e01b8252600482015260406024820152601960448201527f4d65737361676520496420616c726561647920657869737473000000000000006064820152fd5b608467ffffffffffffffff606084015116604051906386c8428160e01b8252600482015260406024820152601660448201527f4d65737361676520616c726561647920657869737473000000000000000000006064820152fd5b602486634e487b7160e01b81526021600452fd5b608467ffffffffffffffff606084015116604051906386c8428160e01b8252600482015260406024820152601c60448201527f4d657373616765207265706c61792070726f74656374696f6e207632000000006064820152fd5b90506020813d602011610f7c575b81610f6d602093836121b3565b8101031261062657515f610d28565b3d9150610f60565b6040513d88823e3d90fd5b608467ffffffffffffffff606084015116604051906386c8428160e01b8252600482015260406024820152601c60448201527f4d657373616765207265706c61792070726f74656374696f6e207631000000006064820152fd5b90506020813d602011611013575b81611004602093836121b3565b8101031261062657515f610cc1565b3d9150610ff7565b602485634e487b7160e01b81526011600452fd5b60649061105661104e67ffffffffffffffff606089960151169261255b565b933a0261255b565b610764604051948560208101937f4665652065786365656473206d617820616c6c6f77616e63653a2000000000008552620101f160ed1b603b936110a3815180926020888801910161251e565b830193840152603e92610755825180936020878501910161251e565b506702c68af0bb1400008111610c44565b602483634e487b7160e01b81526011600452fd5b67ffffffffffffffff6060608492015116604051906386c8428160e01b8252600482015260406024820152601860448201527f4e756c6c206d6573736167652e666565526563656976657200000000000000006064820152fd5b67ffffffffffffffff606060a492015116604051906386c8428160e01b8252600482015260406024820152602260448201527f6d6573736167652e6665652065786365656473206d6573736167652e616d6f756064820152611b9d60f21b6084820152fd5b67ffffffffffffffff6060608492015116604051906386c8428160e01b8252600482015260406024820152601660448201527f6d6573736167652e616d6f756e745765692069732030000000000000000000006064820152fd5b67ffffffffffffffff6060608492015116604051906386c8428160e01b8252600482015260406024820152601860448201527f4e756c6c206d6573736167652e64657374696e6174696f6e00000000000000006064820152fd5b608490604051906386c8428160e01b8252600482015260406024820152601160448201527f4e756c6c206d6573736167652e66726f6d0000000000000000000000000000006064820152fd5b50346101bb57806003193601126101bb57602090604051908152f35b50346101bb5760c03660031901126101bb57335f9081527f8c3d7c314c89e16efb740181381b7ce78a4b1e3cd527902e14bd38b2b23379f160205260409020547fb7a383a5ef6cc414a168844ee7da5cf32b44a10145b4d0cc573e1b7c231d30409060ff1615610a8d57506113366101a1366121d5565b61133f816123fd565b60048110156113f457600281141590816113e8575b506113be578152600560205280604081205567ffffffffffffffff6113776126e6565b16815260066020528060408120557fefe476e7ac46b9bde62b3d392a897ae796bfad2fe290ad65adf17b9079b9341e60e06040513381526113ba602082016126fd565ba180f35b60046040517ffbc03578000000000000000000000000000000000000000000000000000000008152fd5b6001915014155f611354565b602483634e487b7160e01b81526021600452fd5b50346101bb5760403660031901126101bb576001600160a01b03604061142c61213d565b926004358152806020522091165f52602052602060ff60405f2054166040519015158152f35b50346101bb5760203660031901126101bb5760043567ffffffffffffffff8116809103610626578160409160209352600683522054604051908152f35b50346101bb57806003193601126101bb57335f9081527fa1109fe591aa8d3844618999472a1d10db9c7e331f65a2aafe002c00336a446a60205260409020547f39935d86204acf3d77da26425d7a46606d2550568c6b1876f3a2e76c804c76269060ff1615610a8d57506115016124af565b600160ff19815416176001557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a180f35b50346101bb57806003193601126101bb57602067ffffffffffffffff60045416604051908152f35b50346101bb5760c03660031901126101bb5761157c6124af565b6115846124e5565b6001600160a01b0360248035828116908190036119fe57331480156119bf575b15611982576115b56101a1366121d5565b906115bf826123fd565b600481101561196f576003146118b557827f0000000000000000000000002b08d7cf7eaff0f5f6623d9fb09b080726d4be111690604051937fc0cb8f0f000000000000000000000000000000000000000000000000000000009081865284600487015260209586818581885afa908115611947578891611952575b50600481101561190757600214907f000000000000000000000000867a8fcd5bb6774d4d37fb342d669a35ff789a51169160405190815285600482015286818581865afa90811561194757889161191a575b50600481101561190757600214906116a3866123fd565b60048110156118f457811590816118eb575b816118df575b506118b557156117a55750506116cf6126e6565b846040518093638bcb4fdb60e01b825267ffffffffffffffff809416600483015281865afa918215610f84578692611772575b5061176a948493926005926117156126e6565b168852600682526040882055838752525f1960408620557f59c8adb5b760016054e333eac5c0ea8494e7e59a9ef83f02733788a94b4a452660c060405161175b816126fd565ba3611765366121d5565b612773565b600160025580f35b909291508481813d831161179e575b61178b81836121b3565b810103126106265751909161176a611702565b503d611781565b90925015611895576117b56126e6565b846040518093638bcb4fdb60e01b825267ffffffffffffffff809416600483015281865afa918215610f84578692611862575b5061185d948493926005926117fb6126e6565b168852600682526040882055838752525f1960408620557f59c8adb5b760016054e333eac5c0ea8494e7e59a9ef83f02733788a94b4a452660c0604051611841816126fd565ba361184f81611765366121d5565b611858366121d5565b6128f4565b61176a565b909291508481813d831161188e575b61187b81836121b3565b810103126106265751909161185d6117e8565b503d611871565b5050600561185d92828552525f19604084205561184f81611765366121d5565b60046040517f5cda670e000000000000000000000000000000000000000000000000000000008152fd5b6002915014155f6116bb565b831591506116b5565b8489634e487b7160e01b81526021600452fd5b8388634e487b7160e01b81526021600452fd5b61193a9150873d8911611940575b61193281836121b3565b8101906126ce565b5f61168c565b503d611928565b6040513d8a823e3d90fd5b6119699150873d89116119405761193281836121b3565b5f61163a565b5083634e487b7160e01b81526021600452fd5b6044907f49d85f38d8d200e3ac71b7ada9a2786ccb6d016b3c28e43e8057f6bbae438adc6040519163e2517d3f60e01b8352336004840152820152fd5b507f49d85f38d8d200e3ac71b7ada9a2786ccb6d016b3c28e43e8057f6bbae438adc83528260205260408320335f5260205260ff60405f2054166115a4565b8380fd5b50346101bb57806003193601126101bb5760206040517fe68a6574a7e933010135bdcdb85f5b60aed1ee2a05b00c7c3b88734a75706cf08152f35b50346101bb57806003193601126101bb57602060ff600154166040519015158152f35b50346101bb57806003193601126101bb578060609160408051611a8281612167565b828152826020820152015260ff60405191611a9c83612167565b6003835260406020840193828552019081528160405193600385525116602084015251166040820152f35b50346101bb5760c03660031901126101bb576020611ae76101a1366121d5565b604051908152f35b50346101bb57806003193601126101bb57335f9081527fe073aef41dc526905b73a8afcb340da5a4ef974efd7f15102e4d3caa11a3a98d60205260409020547fac6a94bcd1ac2877eda181de9748e5972fc07f76d4864cecf836b3fca185e53c9060ff1615610a8d575060015460ff811615611b995760ff19166001557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a180f35b60046040517f8dfc202b000000000000000000000000000000000000000000000000000000008152fd5b50346101bb5760203660031901126101bb5760406020916004358152600583522054604051908152f35b50346101bb5760403660031901126101bb57611c0761213d565b336001600160a01b03821603611c23576102ce90600435612389565b60046040517f6697b232000000000000000000000000000000000000000000000000000000008152fd5b50346101bb57806003193601126101bb576020600354604051908152f35b50346101bb5760403660031901126101bb576102ce600435611c8b61213d565b9080845283602052611ca360016040862001546122cb565b61230c565b50346101bb57806003193601126101bb5760206040516001600160a01b037f000000000000000000000000d7e4b67e735733ac98a88f13d087d8aac670e644168152f35b50346101bb5760203660031901126101bb57600160406020926004358152808452200154604051908152f35b5060403660031901126101bb576004356024803590611d356124af565b8215611ff557813403611fab57633b9aca0090813406611f615766071afd498d00003410611f1757611d656124e5565b6001600160a01b037f000000000000000000000000d7e4b67e735733ac98a88f13d087d8aac670e6441685813b156101bb5784916004604051809481937f439370b10000000000000000000000000000000000000000000000000000000083525af18015610f8457611ee8575b5060045467ffffffffffffffff808216818114611ed55760018291011667ffffffffffffffff19831617600455604051917fffffffffffffffff000000000000000000000000000000000000000000000000602084019160c01b16815260088352604083019383851083861117611ec357509183918793606095604052825190201694860493849187845201527fcc9c1a7566adfa8bdc9f7a63a106576fec355c6b4f61ce07baad45eaa30560c360403392a3604051928352602083015260408201527f97dcb220fc7f84ae61f5c0302e4c05f276c444a8ffb0253f3a86514bf16e815260603392a3600160025580f35b634e487b7160e01b5f5260416004525ffd5b8388634e487b7160e01b81526011600452fd5b67ffffffffffffffff8196929611611f0457604052935f611dd2565b8582634e487b7160e01b81526041600452fd5b8460406084928151926386c8428160e01b84526004840152820152601960448201527f4465706f736974206c657373207468616e206d696e696d756d000000000000006064820152fd5b8460406084928151926386c8428160e01b84526004840152820152601c60448201527f4672616374696f6e616c2076616c7565206e6f7420616c6c6f776564000000006064820152fd5b8360406084928151926386c8428160e01b84526004840152820152601760448201527f4465706f73697420616d6f756e74206d69736d617463680000000000000000006064820152fd5b60046040517f1c25715b000000000000000000000000000000000000000000000000000000008152fd5b50346101bb57806003193601126101bb5760206040517fac6a94bcd1ac2877eda181de9748e5972fc07f76d4864cecf836b3fca185e53c8152f35b50346101bb57806003193601126101bb5760206040517ffe482b7b16acc2ea6eda181934b481a09d50ed8e3579b43c531bc57b84336c538152f35b905034612139576020366003190112612139576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361213557602092507f7965db0b00000000000000000000000000000000000000000000000000000000811490811561210b575b5015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150145f612104565b8280fd5b5080fd5b602435906001600160a01b038216820361062657565b35906001600160a01b038216820361062657565b6060810190811067ffffffffffffffff82111761218357604052565b634e487b7160e01b5f52604160045260245ffd5b60c0810190811067ffffffffffffffff82111761218357604052565b90601f8019910116810190811067ffffffffffffffff82111761218357604052565b60c090600319011261062657604051906121ee82612197565b6004358252816001600160a01b036024358181168103610626576020830152604435604083015260643567ffffffffffffffff81168103610626576060830152608435908116810361062657608082015260a060a435910152565b91906020830192600482101561225c5752565b634e487b7160e01b5f52602160045260245ffd5b335f9081527f563042ac6f19900ae6f877f555965d3e949234c4788a74f3ca00aa3e8624e39b60205260409020547ffe482b7b16acc2ea6eda181934b481a09d50ed8e3579b43c531bc57b84336c539060ff1615610a8d5750565b805f525f60205260405f20335f5260205260ff60405f205416156122ec5750565b60405163e2517d3f60e01b81523360048201526024810191909152604490fd5b905f91808352826020526001600160a01b036040842092169182845260205260ff604084205416155f1461238457808352826020526040832082845260205260408320600160ff198254161790557f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d339380a4600190565b505090565b905f91808352826020526001600160a01b036040842092169182845260205260ff6040842054165f146123845780835282602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4600190565b5f52600560205260405f2054801561242d575f19811461242757421061242257600290565b600190565b50600390565b505f90565b60405161248b60208201809360a080918051845260208101516001600160a01b0380911660208601526040820151604086015267ffffffffffffffff606083015116606086015260808201511660808501520151910152565b60c0815260e0810181811067ffffffffffffffff8211176121835760405251902090565b60ff600154166124bb57565b60046040517fd93c0665000000000000000000000000000000000000000000000000000000008152fd5b60028054146124f45760028055565b60046040517f3ee5aeb5000000000000000000000000000000000000000000000000000000008152fd5b5f5b83811061252f5750505f910152565b8181015183820152602001612520565b67ffffffffffffffff811161218357601f01601f191660200190565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000808210156126c0575b506d04ee2d6d415b85acef8100000000808310156126b1575b50662386f26fc10000808310156126a2575b506305f5e10080831015612693575b5061271080831015612684575b506064821015612674575b600a8092101561266a575b600190816021818601956125f38761253f565b9661260160405198896121b3565b808852612610601f199161253f565b01366020890137860101905b612628575b5050505090565b5f19019083907f30313233343536373839616263646566000000000000000000000000000000008282061a8353049182156126655791908261261c565b612621565b91600101916125e0565b91906064600291049101916125d5565b6004919392049101915f6125ca565b6008919392049101915f6125bd565b6010919392049101915f6125ae565b6020919392049101915f61259c565b60409350810491505f612583565b90816020910312610626575160048110156106265790565b60643567ffffffffffffffff811681036106265790565b60043581526024356001600160a01b0390818116809103610626576020830152604435604083015260643567ffffffffffffffff811680910361062657606083015260843590811680910361062657608082015260a060a435910152565b90816020910312610626575180151581036106265790565b6001600160a01b03602082018181511660408401519060a085015182039182116128e0576040516306e6a46960e21b81526001600160a01b0391909116600482015260248101919091526020816044815f7f000000000000000000000000d7e4b67e735733ac98a88f13d087d8aac670e64488165af19081156128d5575f916128a7575b501561287d5751167f17301a134abd040120edefa131df2e376da9fb5264e3483c90f23293ab14261160c083519361287a604051809260a080918051845260208101516001600160a01b0380911660208601526040820151604086015267ffffffffffffffff606083015116606086015260808201511660808501520151910152565ba4565b60046040517f750b219c000000000000000000000000000000000000000000000000000000008152fd5b6128c8915060203d81116128ce575b6128c081836121b3565b81019061275b565b5f6127f7565b503d6128b6565b6040513d5f823e3d90fd5b634e487b7160e01b5f52601160045260245ffd5b608081015160a08201516040516306e6a46960e21b81526001600160a01b03928316600482015260248101919091526020816044815f7f000000000000000000000000d7e4b67e735733ac98a88f13d087d8aac670e64487165af19081156128d5575f916129e4575b501561287d576020820151167f26a2bb34c011f942f61c31dfaeff3a3a1b2132da80c36b90d131a5732d7cd96b60c083519361287a604051809260a080918051845260208101516001600160a01b0380911660208601526040820151604086015267ffffffffffffffff606083015116606086015260808201511660808501520151910152565b6129fc915060203d81116128ce576128c081836121b3565b5f61295d56fea264697066735822122029e8a4b241c5f913107125ac0507c440da8be171a73b0dbd29297eadd8b9306164736f6c63430008150033

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

0000000000000000000000004720342419c1d316b948690d12c86d5b485c64e0000000000000000000000000d7e4b67e735733ac98a88f13d087d8aac670e6440000000000000000000000002b08d7cf7eaff0f5f6623d9fb09b080726d4be11000000000000000000000000867a8fcd5bb6774d4d37fb342d669a35ff789a51

-----Decoded View---------------
Arg [0] : owner (address): 0x4720342419C1D316B948690d12C86D5b485C64E0
Arg [1] : treasuryAddress (address): 0xD7E4b67E735733aC98a88F13d087D8aac670E644
Arg [2] : canonicalBridgeV1 (address): 0x2B08D7cF7EafF0f5f6623d9fB09b080726D4be11
Arg [3] : canonicalBridgeV2 (address): 0x867A8FcD5Bb6774d4d37fb342D669A35FF789a51

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000004720342419c1d316b948690d12c86d5b485c64e0
Arg [1] : 000000000000000000000000d7e4b67e735733ac98a88f13d087d8aac670e644
Arg [2] : 0000000000000000000000002b08d7cf7eaff0f5f6623d9fb09b080726d4be11
Arg [3] : 000000000000000000000000867a8fcd5bb6774d4d37fb342d669a35ff789a51


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