ETH Price: $2,843.82 (-3.23%)
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
329012692025-07-15 15:04:45194 days ago1752591885  Contract Creation0 ETH

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MessageProcessor

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 1 runs

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

import {Auth} from "src/misc/Auth.sol";
import {D18} from "src/misc/types/D18.sol";
import {CastLib} from "src/misc/libraries/CastLib.sol";
import {BytesLib} from "src/misc/libraries/BytesLib.sol";
import {IRecoverable} from "src/misc/interfaces/IRecoverable.sol";

import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
import {IRoot} from "src/common/interfaces/IRoot.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
import {IMessageHandler} from "src/common/interfaces/IMessageHandler.sol";
import {ITokenRecoverer} from "src/common/interfaces/ITokenRecoverer.sol";
import {IMessageProcessor} from "src/common/interfaces/IMessageProcessor.sol";
import {IMessageProperties} from "src/common/interfaces/IMessageProperties.sol";
import {MessageType, MessageLib, VaultUpdateKind} from "src/common/libraries/MessageLib.sol";

import {
    ISpokeGatewayHandler,
    IBalanceSheetGatewayHandler,
    IHubGatewayHandler,
    IUpdateContractGatewayHandler
} from "src/common/interfaces/IGatewayHandlers.sol";

contract MessageProcessor is Auth, IMessageProcessor {
    using CastLib for *;
    using MessageLib for *;
    using BytesLib for bytes;

    IRoot public immutable root;
    ITokenRecoverer public immutable tokenRecoverer;

    IHubGatewayHandler public hub;
    ISpokeGatewayHandler public spoke;
    IBalanceSheetGatewayHandler public balanceSheet;
    IUpdateContractGatewayHandler public contractUpdater;

    constructor(IRoot root_, ITokenRecoverer tokenRecoverer_, address deployer) Auth(deployer) {
        root = root_;
        tokenRecoverer = tokenRecoverer_;
    }

    //----------------------------------------------------------------------------------------------
    // Administration
    //----------------------------------------------------------------------------------------------

    /// @inheritdoc IMessageProcessor
    function file(bytes32 what, address data) external auth {
        if (what == "hub") hub = IHubGatewayHandler(data);
        else if (what == "spoke") spoke = ISpokeGatewayHandler(data);
        else if (what == "balanceSheet") balanceSheet = IBalanceSheetGatewayHandler(data);
        else if (what == "contractUpdater") contractUpdater = IUpdateContractGatewayHandler(data);
        else revert FileUnrecognizedParam();

        emit File(what, data);
    }

    //----------------------------------------------------------------------------------------------
    // Handlers
    //----------------------------------------------------------------------------------------------

    /// @inheritdoc IMessageHandler
    function handle(uint16 centrifugeId, bytes calldata message) external auth {
        MessageType kind = message.messageType();
        uint16 sourceCentrifugeId = message.messageSourceCentrifugeId();

        require(sourceCentrifugeId == 0 || sourceCentrifugeId == centrifugeId, InvalidSourceChain());

        if (kind == MessageType.ScheduleUpgrade) {
            MessageLib.ScheduleUpgrade memory m = message.deserializeScheduleUpgrade();
            root.scheduleRely(m.target.toAddress());
        } else if (kind == MessageType.CancelUpgrade) {
            MessageLib.CancelUpgrade memory m = message.deserializeCancelUpgrade();
            root.cancelRely(m.target.toAddress());
        } else if (kind == MessageType.RecoverTokens) {
            MessageLib.RecoverTokens memory m = message.deserializeRecoverTokens();
            tokenRecoverer.recoverTokens(
                IRecoverable(m.target.toAddress()), m.token.toAddress(), m.tokenId, m.to.toAddress(), m.amount
            );
        } else if (kind == MessageType.RegisterAsset) {
            MessageLib.RegisterAsset memory m = message.deserializeRegisterAsset();
            hub.registerAsset(AssetId.wrap(m.assetId), m.decimals);
        } else if (kind == MessageType.Request) {
            MessageLib.Request memory m = MessageLib.deserializeRequest(message);
            hub.request(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.payload);
        } else if (kind == MessageType.NotifyPool) {
            spoke.addPool(PoolId.wrap(MessageLib.deserializeNotifyPool(message).poolId));
        } else if (kind == MessageType.NotifyShareClass) {
            MessageLib.NotifyShareClass memory m = MessageLib.deserializeNotifyShareClass(message);
            spoke.addShareClass(
                PoolId.wrap(m.poolId),
                ShareClassId.wrap(m.scId),
                m.name,
                m.symbol.toString(),
                m.decimals,
                m.salt,
                m.hook.toAddress()
            );
        } else if (kind == MessageType.NotifyPricePoolPerShare) {
            MessageLib.NotifyPricePoolPerShare memory m = MessageLib.deserializeNotifyPricePoolPerShare(message);
            spoke.updatePricePoolPerShare(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.price, m.timestamp);
        } else if (kind == MessageType.NotifyPricePoolPerAsset) {
            MessageLib.NotifyPricePoolPerAsset memory m = MessageLib.deserializeNotifyPricePoolPerAsset(message);
            spoke.updatePricePoolPerAsset(
                PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.price, m.timestamp
            );
        } else if (kind == MessageType.NotifyShareMetadata) {
            MessageLib.NotifyShareMetadata memory m = MessageLib.deserializeNotifyShareMetadata(message);
            spoke.updateShareMetadata(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.name, m.symbol.toString());
        } else if (kind == MessageType.UpdateShareHook) {
            MessageLib.UpdateShareHook memory m = MessageLib.deserializeUpdateShareHook(message);
            spoke.updateShareHook(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.hook.toAddress());
        } else if (kind == MessageType.InitiateTransferShares) {
            MessageLib.InitiateTransferShares memory m = MessageLib.deserializeInitiateTransferShares(message);
            hub.initiateTransferShares(
                m.centrifugeId, PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.receiver, m.amount, m.extraGasLimit
            );
        } else if (kind == MessageType.ExecuteTransferShares) {
            MessageLib.ExecuteTransferShares memory m = MessageLib.deserializeExecuteTransferShares(message);
            spoke.executeTransferShares(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.receiver, m.amount);
        } else if (kind == MessageType.UpdateRestriction) {
            MessageLib.UpdateRestriction memory m = MessageLib.deserializeUpdateRestriction(message);
            spoke.updateRestriction(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.payload);
        } else if (kind == MessageType.UpdateContract) {
            MessageLib.UpdateContract memory m = MessageLib.deserializeUpdateContract(message);
            contractUpdater.execute(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.target.toAddress(), m.payload);
        } else if (kind == MessageType.RequestCallback) {
            MessageLib.RequestCallback memory m = MessageLib.deserializeRequestCallback(message);
            spoke.requestCallback(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.payload);
        } else if (kind == MessageType.UpdateVault) {
            MessageLib.UpdateVault memory m = MessageLib.deserializeUpdateVault(message);
            spoke.updateVault(
                PoolId.wrap(m.poolId),
                ShareClassId.wrap(m.scId),
                AssetId.wrap(m.assetId),
                m.vaultOrFactory.toAddress(),
                VaultUpdateKind(m.kind)
            );
        } else if (kind == MessageType.SetRequestManager) {
            MessageLib.SetRequestManager memory m = MessageLib.deserializeSetRequestManager(message);
            spoke.setRequestManager(
                PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.manager.toAddress()
            );
        } else if (kind == MessageType.UpdateBalanceSheetManager) {
            MessageLib.UpdateBalanceSheetManager memory m = MessageLib.deserializeUpdateBalanceSheetManager(message);
            balanceSheet.updateManager(PoolId.wrap(m.poolId), m.who.toAddress(), m.canManage);
        } else if (kind == MessageType.UpdateHoldingAmount) {
            MessageLib.UpdateHoldingAmount memory m = message.deserializeUpdateHoldingAmount();
            hub.updateHoldingAmount(
                centrifugeId,
                PoolId.wrap(m.poolId),
                ShareClassId.wrap(m.scId),
                AssetId.wrap(m.assetId),
                m.amount,
                D18.wrap(m.pricePerUnit),
                m.isIncrease,
                m.isSnapshot,
                m.nonce
            );
        } else if (kind == MessageType.UpdateShares) {
            MessageLib.UpdateShares memory m = message.deserializeUpdateShares();
            hub.updateShares(
                centrifugeId,
                PoolId.wrap(m.poolId),
                ShareClassId.wrap(m.scId),
                m.shares,
                m.isIssuance,
                m.isSnapshot,
                m.nonce
            );
        } else if (kind == MessageType.MaxAssetPriceAge) {
            MessageLib.MaxAssetPriceAge memory m = message.deserializeMaxAssetPriceAge();
            spoke.setMaxAssetPriceAge(
                PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.maxPriceAge
            );
        } else if (kind == MessageType.MaxSharePriceAge) {
            MessageLib.MaxSharePriceAge memory m = message.deserializeMaxSharePriceAge();
            spoke.setMaxSharePriceAge(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.maxPriceAge);
        } else {
            revert InvalidMessage(uint8(kind));
        }
    }

    /// @inheritdoc IMessageProperties
    function messageLength(bytes calldata message) external pure returns (uint16) {
        return message.messageLength();
    }

    /// @inheritdoc IMessageProperties
    function messagePoolId(bytes calldata message) external pure returns (PoolId) {
        return message.messagePoolId();
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;

import {IAuth} from "src/misc/interfaces/IAuth.sol";

/// @title  Auth
/// @notice Simple authentication pattern
/// @author Based on code from https://github.com/makerdao/dss
abstract contract Auth is IAuth {
    /// @inheritdoc IAuth
    mapping(address => uint256) public wards;

    constructor(address initialWard) {
        wards[initialWard] = 1;
        emit Rely(initialWard);
    }

    /// @dev Check if the msg.sender has permissions
    modifier auth() {
        require(wards[msg.sender] == 1, NotAuthorized());
        _;
    }

    /// @inheritdoc IAuth
    function rely(address user) public auth {
        wards[user] = 1;
        emit Rely(user);
    }

    /// @inheritdoc IAuth
    function deny(address user) public auth {
        wards[user] = 0;
        emit Deny(user);
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;

// Small library to handle fixed point number operations with 18 decimals with static typing support.

import {MathLib} from "src/misc/libraries/MathLib.sol";

type D18 is uint128;

using MathLib for uint256;

/// @dev add two D18 types
function add(D18 d1, D18 d2) pure returns (D18) {
    return D18.wrap(D18.unwrap(d1) + D18.unwrap(d2));
}

/// @dev substract two D18 types
function sub(D18 d1, D18 d2) pure returns (D18) {
    return D18.wrap(D18.unwrap(d1) - D18.unwrap(d2));
}

/// @dev Divides one D18 by another one while retaining precision:
/// - nominator (decimal): 50e18
/// - denominator (decimal):  2e19
/// - result (decimal): 25e17
function divD18(D18 d1, D18 d2) pure returns (D18) {
    return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), 1e18, D18.unwrap(d2)).toUint128());
}

/// @dev Multiplies one D18 with another one while retaining precision:
/// - value1 (decimal): 50e18
/// - value2 (decimal):  2e19
/// - result (decimal): 100e19
function mulD18(D18 d1, D18 d2) pure returns (D18) {
    return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), D18.unwrap(d2), 1e18).toUint128());
}

/// @dev Returns the reciprocal of a D18 decimal, i.e. 1 / d.
///      Example: if d = 2.0 (2e18 internally), reciprocal(d) = 0.5 (5e17 internally).
function reciprocal(D18 d) pure returns (D18) {
    uint128 val = D18.unwrap(d);
    require(val != 0, "D18/division-by-zero");
    return d18(1e18, val);
}

/// @dev Multiplies a decimal by an integer. i.e:
/// - d (decimal):      1_500_000_000_000_000_000
/// - value (integer):  4_000_000_000_000_000_000
/// - result (integer): 6_000_000_000_000_000_000
function mulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {
    return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding).toUint128();
}

/// @dev Multiplies a decimal by an integer. i.e:
/// - d (decimal):      1_500_000_000_000_000_000
/// - value (integer):  4_000_000_000_000_000_000
/// - result (integer): 6_000_000_000_000_000_000
function mulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {
    return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding);
}

/// @dev  Divides an integer by a decimal, i.e.
/// @dev  Same as mulDiv for integers, i.e:
/// - d (decimal):      2_000_000_000_000_000_000
/// - value (integer):  100_000_000_000_000_000_000
/// - result (integer): 50_000_000_000_000_000_000
function reciprocalMulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {
    return MathLib.mulDiv(value, 1e18, d.raw(), rounding).toUint128();
}

/// @dev  Divides an integer by a decimal, i.e.
/// @dev  Same as mulDiv for integers, i.e:
/// - d (decimal):      2_000_000_000_000_000_000
/// - value (integer):  100_000_000_000_000_000_000
/// - result (integer): 50_000_000_000_000_000_000
function reciprocalMulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {
    return MathLib.mulDiv(value, 1e18, d.raw(), rounding);
}

/// @dev Easy way to construct a decimal number
function d18(uint128 value) pure returns (D18) {
    return D18.wrap(value);
}

/// @dev Easy way to construct a decimal number
function d18(uint128 num, uint128 den) pure returns (D18) {
    return D18.wrap(MathLib.mulDiv(num, 1e18, den).toUint128());
}

function eq(D18 a, D18 b) pure returns (bool) {
    return D18.unwrap(a) == D18.unwrap(b);
}

function isZero(D18 a) pure returns (bool) {
    return D18.unwrap(a) == 0;
}

function isNotZero(D18 a) pure returns (bool) {
    return D18.unwrap(a) != 0;
}

function raw(D18 d) pure returns (uint128) {
    return D18.unwrap(d);
}

using {
    add as +,
    sub as -,
    divD18 as /,
    eq,
    mulD18 as *,
    mulUint128,
    mulUint256,
    reciprocalMulUint128,
    reciprocalMulUint256,
    reciprocal,
    raw,
    isZero,
    isNotZero
} for D18 global;

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;

/// @title  CastLib
library CastLib {
    function toAddressLeftPadded(bytes32 addr) internal pure returns (address) {
        require(bytes12(addr) == 0, "First 12 bytes should be zero");
        return address(uint160(uint256(addr)));
    }

    function toBytes32LeftPadded(address addr) internal pure returns (bytes32) {
        return bytes32(uint256(uint160(addr)));
    }

    function toAddress(bytes32 addr) internal pure returns (address) {
        require(uint96(uint256(addr)) == 0, "Input should be 20 bytes");
        return address(bytes20(addr));
    }

    function toBytes32(address addr) internal pure returns (bytes32) {
        return bytes32(bytes20(addr));
    }

    /// @dev Adds zero padding
    function toBytes32(string memory source) internal pure returns (bytes32) {
        return bytes32(bytes(source));
    }

    /// @dev Removes zero padding
    function bytes128ToString(bytes memory _bytes128) internal pure returns (string memory) {
        require(_bytes128.length == 128, "Input should be 128 bytes");

        uint8 i = 0;
        while (i < 128 && _bytes128[i] != 0) {
            i++;
        }

        bytes memory bytesArray = new bytes(i);

        for (uint8 j; j < i; j++) {
            bytesArray[j] = _bytes128[j];
        }

        return string(bytesArray);
    }

    function toString(bytes32 _bytes32) internal pure returns (string memory) {
        uint8 i = 0;
        while (i < 32 && _bytes32[i] != 0) {
            i++;
        }
        bytes memory bytesArray = new bytes(i);
        for (i = 0; i < 32 && _bytes32[i] != 0; i++) {
            bytesArray[i] = _bytes32[i];
        }
        return string(bytesArray);
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;

/// @title  Bytes Lib
/// @dev    Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
///         The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
/// @author Modified from Solidity Bytes Arrays Utils v0.8.0
library BytesLib {
    error SliceOverflow();
    error SliceOutOfBounds();

    function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {
        unchecked {
            require(_length + 31 >= _length, SliceOverflow());
        }
        require(_bytes.length >= _start + _length, SliceOutOfBounds());

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } { mstore(mc, mload(cc)) }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)
                //zero out the 32 bytes slice we are about to return
                //we need to do it because Solidity does not garbage collect
                mstore(tempBytes, 0)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function sliceZeroPadded(bytes memory _bytes, uint256 _start, uint256 _length)
        internal
        pure
        returns (bytes memory)
    {
        bool needsPad = _bytes.length < _start + _length;
        if (!needsPad) return slice(_bytes, _start, _length);

        bytes memory slice_ = slice(_bytes, _start, _bytes.length - _start);
        bytes memory padding = new bytes(_length + _start - _bytes.length);
        return bytes.concat(slice_, padding);
    }

    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
        require(_bytes.length >= _start + 20, SliceOutOfBounds());
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
        require(_bytes.length >= _start + 1, SliceOutOfBounds());
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
        require(_bytes.length >= _start + 2, SliceOutOfBounds());
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
        require(_bytes.length >= _start + 4, SliceOutOfBounds());
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
        require(_bytes.length >= _start + 8, SliceOutOfBounds());
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
        require(_bytes.length >= _start + 16, SliceOutOfBounds());
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
        require(_bytes.length >= _start + 32, SliceOutOfBounds());
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
        require(_bytes.length >= _start + 32, SliceOutOfBounds());
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function toBytes16(bytes memory _bytes, uint256 _start) internal pure returns (bytes16) {
        require(_bytes.length >= _start + 16, SliceOutOfBounds());
        bytes16 tempBytes16;

        assembly {
            tempBytes16 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes16;
    }

    function toBool(bytes memory _bytes, uint256 _start) internal pure returns (bool) {
        require(_bytes.length > _start, SliceOutOfBounds());
        return _bytes[_start] != 0;
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

address constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);

interface IRecoverable {
    /// @notice Used to recover any ERC-20 token.
    /// @dev    This method is called only by authorized entities
    /// @param  token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
    ///         to recover locked native ETH or token compatible with ERC20.
    /// @param  to Receiver of the funds
    /// @param  amount Amount to send to the receiver.
    function recoverTokens(address token, address to, uint256 amount) external;

    /// @notice Used to recover any ERC-20 or ERC-6909 token.
    /// @dev    This method is called only by authorized entities
    /// @param  token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
    ///         to recover locked native ETH or token compatible with ERC20 or ERC6909.
    /// @param  tokenId The token id, i.e. non-zero if the underlying token is ERC6909 and else zero.
    /// @param  to Receiver of the funds
    /// @param  amount Amount to send to the receiver.
    function recoverTokens(address token, uint256 tokenId, address to, uint256 amount) external;
}

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

import {MathLib} from "src/misc/libraries/MathLib.sol";

using MathLib for uint256;

type PoolId is uint64;

function centrifugeId(PoolId poolId) pure returns (uint16) {
    return uint16(PoolId.unwrap(poolId) >> 48);
}

function newPoolId(uint16 centrifugeId_, uint48 localPoolId) pure returns (PoolId) {
    return PoolId.wrap((uint64(centrifugeId_) << 48) | uint64(localPoolId));
}

function isNull(PoolId poolId) pure returns (bool) {
    return PoolId.unwrap(poolId) == 0;
}

function isEqual(PoolId a, PoolId b) pure returns (bool) {
    return PoolId.unwrap(a) == PoolId.unwrap(b);
}

function raw(PoolId poolId) pure returns (uint64) {
    return PoolId.unwrap(poolId);
}

using {centrifugeId, isNull, raw, isEqual as ==} for PoolId global;

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

/// @dev Composite Id of the centrifugeId (uint16) where the asset resides
///      and a local counter (uint64) that is part of the contract that registers the asset.
type AssetId is uint128;

function isNull(AssetId assetId) pure returns (bool) {
    return AssetId.unwrap(assetId) == 0;
}

function raw(AssetId assetId) pure returns (uint128) {
    return AssetId.unwrap(assetId);
}

function centrifugeId(AssetId assetId) pure returns (uint16) {
    return uint16(AssetId.unwrap(assetId) >> 112);
}

function newAssetId(uint16 centrifugeId_, uint64 counter) pure returns (AssetId) {
    return AssetId.wrap((uint128(centrifugeId_) << 112) + counter);
}

function newAssetId(uint32 isoCode) pure returns (AssetId) {
    return AssetId.wrap(isoCode);
}

function eq(AssetId a, AssetId b) pure returns (bool) {
    return a.raw() == b.raw();
}

using {isNull, raw, centrifugeId, eq} for AssetId global;

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

interface IRoot {
    // --- Events ---
    event File(bytes32 indexed what, uint256 data);
    event Pause();
    event Unpause();
    event ScheduleRely(address indexed target, uint256 indexed scheduledTime);
    event CancelRely(address indexed target);
    event RelyContract(address indexed target, address indexed user);
    event DenyContract(address indexed target, address indexed user);
    event Endorse(address indexed user);
    event Veto(address indexed user);

    error DelayTooLong();
    error FileUnrecognizedParam();
    error TargetNotScheduled();
    error TargetNotReady();

    /// @notice Returns whether the root is paused
    function paused() external view returns (bool);

    /// @notice Returns the current timelock for adding new wards
    function delay() external view returns (uint256);

    /// @notice Trusted contracts within the system
    function endorsements(address target) external view returns (uint256);

    /// @notice Returns when `relyTarget` has passed the timelock
    function schedule(address relyTarget) external view returns (uint256 timestamp);

    // --- Administration ---
    /// @notice Updates a contract parameter
    /// @param what Accepts a bytes32 representation of 'delay'
    function file(bytes32 what, uint256 data) external;

    /// --- Endorsements ---
    /// @notice Endorses the `user`
    /// @dev    Endorsed users are trusted contracts in the system. They are allowed to bypass
    ///         token restrictions (e.g. the Escrow can automatically receive share class tokens by being endorsed), and
    ///         can automatically set operators in ERC-7540 vaults (e.g. the VaultRouter) is always an operator.
    function endorse(address user) external;

    /// @notice Removes the endorsed user
    function veto(address user) external;

    /// @notice Returns whether the user is endorsed
    function endorsed(address user) external view returns (bool);

    // --- Pause management ---
    /// @notice Pause any contracts that depend on `Root.paused()`
    function pause() external;

    /// @notice Unpause any contracts that depend on `Root.paused()`
    function unpause() external;

    /// --- Timelocked ward management ---
    /// @notice Schedule relying a new ward after the delay has passed
    function scheduleRely(address target) external;

    /// @notice Cancel a pending scheduled rely
    function cancelRely(address target) external;

    /// @notice Execute a scheduled rely
    /// @dev    Can be triggered by anyone since the scheduling is protected
    function executeScheduledRely(address target) external;

    /// --- External contract ward management ---
    /// @notice Make an address a ward on any contract that Root is a ward on
    function relyContract(address target, address user) external;

    /// @notice Removes an address as a ward on any contract that Root is a ward on
    function denyContract(address target, address user) external;
}

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

import {PoolId} from "src/common/types/PoolId.sol";

type ShareClassId is bytes16;

function isNull(ShareClassId scId) pure returns (bool) {
    return ShareClassId.unwrap(scId) == 0;
}

function equals(ShareClassId left, ShareClassId right) pure returns (bool) {
    return ShareClassId.unwrap(left) == ShareClassId.unwrap(right);
}

function raw(ShareClassId scId) pure returns (bytes16) {
    return ShareClassId.unwrap(scId);
}

function newShareClassId(PoolId poolId, uint32 index) pure returns (ShareClassId scId) {
    return ShareClassId.wrap(bytes16((uint128(PoolId.unwrap(poolId)) << 64) + index));
}

using {isNull, raw, equals as ==} for ShareClassId global;

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @notice Generic interface for entities that handle incoming messages
interface IMessageHandler {
    /// @notice Dispatched when an invalid message is trying to handle
    error InvalidMessage(uint8 code);

    /// @notice Handling incoming messages.
    /// @param centrifugeId Source chain
    /// @param message Incoming message
    function handle(uint16 centrifugeId, bytes calldata message) external;
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import {IRecoverable} from "src/misc/interfaces/IRecoverable.sol";

interface ITokenRecoverer {
    event RecoverTokens(
        IRecoverable indexed target, address indexed token, uint256 tokenId, address indexed to, uint256 amount
    );

    function recoverTokens(IRecoverable target, address token, uint256 tokenId, address to, uint256 amount) external;
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import {IMessageHandler} from "src/common/interfaces/IMessageHandler.sol";
import {IMessageProperties} from "src/common/interfaces/IMessageProperties.sol";

interface IMessageProcessor is IMessageHandler, IMessageProperties {
    error InvalidSourceChain();

    /// @notice Emitted when a call to `file()` was performed.
    event File(bytes32 indexed what, address addr);

    /// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.
    error FileUnrecognizedParam();

    /// @notice Updates a contract parameter.
    /// @param what Name of the parameter to update.
    /// Accepts a `bytes32` representation of 'hubRegistry' string value.
    /// @param data New value given to the `what` parameter
    function file(bytes32 what, address data) external;
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import {PoolId} from "src/common/types/PoolId.sol";

/// @notice Defines methods to get properties from raw messages
interface IMessageProperties {
    /// @notice Inspect the message to return the length
    function messageLength(bytes calldata message) external pure returns (uint16);

    /// @notice Inspect the message to return the associated PoolId if any
    function messagePoolId(bytes calldata message) external pure returns (PoolId);
}

File 15 of 18 : MessageLib.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import {CastLib} from "src/misc/libraries/CastLib.sol";
import {BytesLib} from "src/misc/libraries/BytesLib.sol";

import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";

// NOTE: Should never exceed 254 messages because id == 255 corresponds to message proofs
enum MessageType {
    /// @dev Placeholder for null message type
    _Invalid,
    // -- Pool independent messages
    ScheduleUpgrade,
    CancelUpgrade,
    RecoverTokens,
    RegisterAsset,
    _Placeholder5,
    _Placeholder6,
    _Placeholder7,
    _Placeholder8,
    _Placeholder9,
    _Placeholder10,
    _Placeholder11,
    _Placeholder12,
    _Placeholder13,
    _Placeholder14,
    _Placeholder15,
    // -- Pool dependent messages
    NotifyPool,
    NotifyShareClass,
    NotifyPricePoolPerShare,
    NotifyPricePoolPerAsset,
    NotifyShareMetadata,
    UpdateShareHook,
    InitiateTransferShares,
    ExecuteTransferShares,
    UpdateRestriction,
    UpdateContract,
    UpdateVault,
    UpdateBalanceSheetManager,
    UpdateHoldingAmount,
    UpdateShares,
    MaxAssetPriceAge,
    MaxSharePriceAge,
    Request,
    RequestCallback,
    SetRequestManager
}

/// @dev Used internally in the UpdateVault message (not represent a submessage)
enum VaultUpdateKind {
    DeployAndLink,
    Link,
    Unlink
}

library MessageLib {
    using MessageLib for bytes;
    using BytesLib for bytes;
    using CastLib for *;

    error UnknownMessageType();

    /// @dev Encode all message lengths in this constant to avoid a large list of if/elseif checks
    /// and reduce generated bytecode.
    /// If the message has some dynamic part, will be added later in `messageLength()`.
    // forgefmt: disable-next-item
    uint256 constant MESSAGE_LENGTHS_1 =
        (33  << uint8(MessageType.ScheduleUpgrade) * 8) +
        (33  << uint8(MessageType.CancelUpgrade) * 8) +
        (161 << uint8(MessageType.RecoverTokens) * 8) +
        (18  << uint8(MessageType.RegisterAsset) * 8) +
        (0   << uint8(MessageType._Placeholder5) * 8) +
        (0   << uint8(MessageType._Placeholder6) * 8) +
        (0   << uint8(MessageType._Placeholder7) * 8) +
        (0   << uint8(MessageType._Placeholder8) * 8) +
        (0   << uint8(MessageType._Placeholder9) * 8) +
        (0   << uint8(MessageType._Placeholder10) * 8) +
        (0   << uint8(MessageType._Placeholder11) * 8) +
        (0   << uint8(MessageType._Placeholder12) * 8) +
        (0   << uint8(MessageType._Placeholder13) * 8) +
        (0   << uint8(MessageType._Placeholder14) * 8) +
        (0   << uint8(MessageType._Placeholder15) * 8) +
        (9   << uint8(MessageType.NotifyPool) * 8) +
        (250 << uint8(MessageType.NotifyShareClass) * 8) +
        (49  << uint8(MessageType.NotifyPricePoolPerShare) * 8) +
        (65  << uint8(MessageType.NotifyPricePoolPerAsset) * 8) +
        (185 << uint8(MessageType.NotifyShareMetadata) * 8) +
        (57  << uint8(MessageType.UpdateShareHook) * 8) +
        (91  << uint8(MessageType.InitiateTransferShares) * 8) +
        (73  << uint8(MessageType.ExecuteTransferShares) * 8) +
        (25  << uint8(MessageType.UpdateRestriction) * 8) +
        (57  << uint8(MessageType.UpdateContract) * 8) +
        (74  << uint8(MessageType.UpdateVault) * 8) +
        (42  << uint8(MessageType.UpdateBalanceSheetManager) * 8) +
        (91  << uint8(MessageType.UpdateHoldingAmount) * 8) +
        (59  << uint8(MessageType.UpdateShares) * 8) +
        (49  << uint8(MessageType.MaxAssetPriceAge) * 8) +
        (33  << uint8(MessageType.MaxSharePriceAge) * 8);

    // forgefmt: disable-next-item
    uint256 constant MESSAGE_LENGTHS_2 =
        (41  << (uint8(MessageType.Request) - 32) * 8) +
        (41  << (uint8(MessageType.RequestCallback) - 32) * 8) +
        (73  << (uint8(MessageType.SetRequestManager) - 32) * 8);

    function messageType(bytes memory message) internal pure returns (MessageType) {
        return MessageType(message.toUint8(0));
    }

    function messageCode(bytes memory message) internal pure returns (uint8) {
        return message.toUint8(0);
    }

    function messageLength(bytes memory message) internal pure returns (uint16 length) {
        uint8 kind = message.toUint8(0);
        require(kind <= uint8(type(MessageType).max), UnknownMessageType());

        length = (kind <= 31)
            ? uint16(uint8(bytes32(MESSAGE_LENGTHS_1)[31 - kind]))
            : uint16(uint8(bytes32(MESSAGE_LENGTHS_2)[63 - kind]));

        // Special treatment for messages with dynamic size:
        if (kind == uint8(MessageType.UpdateRestriction)) {
            length += 2 + message.toUint16(length); //payloadLength
        } else if (kind == uint8(MessageType.UpdateContract)) {
            length += 2 + message.toUint16(length); //payloadLength
        } else if (kind == uint8(MessageType.Request)) {
            length += 2 + message.toUint16(length); //payloadLength
        } else if (kind == uint8(MessageType.RequestCallback)) {
            length += 2 + message.toUint16(length); //payloadLength
        }
    }

    function messagePoolId(bytes memory message) internal pure returns (PoolId poolId) {
        uint8 kind = message.toUint8(0);

        // All messages from NotifyPool to the end contains a PoolId in position 1.
        if (kind >= uint8(MessageType.NotifyPool)) {
            return PoolId.wrap(message.toUint64(1));
        } else {
            return PoolId.wrap(0);
        }
    }

    function messageSourceCentrifugeId(bytes memory message) internal pure returns (uint16) {
        uint8 kind = message.toUint8(0);

        if (kind <= uint8(MessageType.RecoverTokens)) {
            return 0; // Non centrifugeId associated
        } else if (kind == uint8(MessageType.UpdateShares) || kind == uint8(MessageType.InitiateTransferShares)) {
            return 0; // Non centrifugeId associated
        } else if (kind == uint8(MessageType.RegisterAsset)) {
            return AssetId.wrap(message.toUint128(1)).centrifugeId();
        } else if (kind == uint8(MessageType.UpdateHoldingAmount)) {
            return AssetId.wrap(message.toUint128(25)).centrifugeId();
        } else if (kind == uint8(MessageType.Request)) {
            return AssetId.wrap(message.toUint128(25)).centrifugeId();
        } else {
            return message.messagePoolId().centrifugeId();
        }
    }

    //---------------------------------------
    //    ScheduleUpgrade
    //---------------------------------------

    struct ScheduleUpgrade {
        bytes32 target;
    }

    function deserializeScheduleUpgrade(bytes memory data) internal pure returns (ScheduleUpgrade memory) {
        require(messageType(data) == MessageType.ScheduleUpgrade, UnknownMessageType());
        return ScheduleUpgrade({target: data.toBytes32(1)});
    }

    function serialize(ScheduleUpgrade memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.ScheduleUpgrade, t.target);
    }

    //---------------------------------------
    //    CancelUpgrade
    //---------------------------------------

    struct CancelUpgrade {
        bytes32 target;
    }

    function deserializeCancelUpgrade(bytes memory data) internal pure returns (CancelUpgrade memory) {
        require(messageType(data) == MessageType.CancelUpgrade, UnknownMessageType());
        return CancelUpgrade({target: data.toBytes32(1)});
    }

    function serialize(CancelUpgrade memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.CancelUpgrade, t.target);
    }

    //---------------------------------------
    //    RecoverTokens
    //---------------------------------------

    struct RecoverTokens {
        bytes32 target;
        bytes32 token;
        uint256 tokenId;
        bytes32 to;
        uint256 amount;
    }

    function deserializeRecoverTokens(bytes memory data) internal pure returns (RecoverTokens memory) {
        require(messageType(data) == MessageType.RecoverTokens, UnknownMessageType());
        return RecoverTokens({
            target: data.toBytes32(1),
            token: data.toBytes32(33),
            tokenId: data.toUint256(65),
            to: data.toBytes32(97),
            amount: data.toUint256(129)
        });
    }

    function serialize(RecoverTokens memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.RecoverTokens, t.target, t.token, t.tokenId, t.to, t.amount);
    }

    //---------------------------------------
    //    RegisterAsset
    //---------------------------------------

    struct RegisterAsset {
        uint128 assetId;
        uint8 decimals;
    }

    function deserializeRegisterAsset(bytes memory data) internal pure returns (RegisterAsset memory) {
        require(messageType(data) == MessageType.RegisterAsset, UnknownMessageType());
        return RegisterAsset({assetId: data.toUint128(1), decimals: data.toUint8(17)});
    }

    function serialize(RegisterAsset memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.RegisterAsset, t.assetId, t.decimals);
    }

    //---------------------------------------
    //    NotifyPool
    //---------------------------------------

    struct NotifyPool {
        uint64 poolId;
    }

    function deserializeNotifyPool(bytes memory data) internal pure returns (NotifyPool memory) {
        require(messageType(data) == MessageType.NotifyPool, UnknownMessageType());
        return NotifyPool({poolId: data.toUint64(1)});
    }

    function serialize(NotifyPool memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.NotifyPool, t.poolId);
    }

    //---------------------------------------
    //    NotifyShareClass
    //---------------------------------------

    struct NotifyShareClass {
        uint64 poolId;
        bytes16 scId;
        string name; // Fixed to 128 bytes
        bytes32 symbol; // utf8
        uint8 decimals;
        bytes32 salt;
        bytes32 hook;
    }

    function deserializeNotifyShareClass(bytes memory data) internal pure returns (NotifyShareClass memory) {
        require(messageType(data) == MessageType.NotifyShareClass, UnknownMessageType());
        return NotifyShareClass({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            name: data.slice(25, 128).bytes128ToString(),
            symbol: data.toBytes32(153),
            decimals: data.toUint8(185),
            salt: data.toBytes32(186),
            hook: data.toBytes32(218)
        });
    }

    function serialize(NotifyShareClass memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(
            MessageType.NotifyShareClass,
            t.poolId,
            t.scId,
            bytes(t.name).sliceZeroPadded(0, 128),
            t.symbol,
            t.decimals,
            t.salt,
            t.hook
        );
    }

    //---------------------------------------
    //    NotifyPricePoolPerShare
    //---------------------------------------

    struct NotifyPricePoolPerShare {
        uint64 poolId;
        bytes16 scId;
        uint128 price;
        uint64 timestamp;
    }

    function deserializeNotifyPricePoolPerShare(bytes memory data)
        internal
        pure
        returns (NotifyPricePoolPerShare memory)
    {
        require(messageType(data) == MessageType.NotifyPricePoolPerShare, UnknownMessageType());
        return NotifyPricePoolPerShare({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            price: data.toUint128(25),
            timestamp: data.toUint64(41)
        });
    }

    function serialize(NotifyPricePoolPerShare memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.NotifyPricePoolPerShare, t.poolId, t.scId, t.price, t.timestamp);
    }

    //---------------------------------------
    //    NotifyPricePoolPerAsset
    //---------------------------------------

    struct NotifyPricePoolPerAsset {
        uint64 poolId;
        bytes16 scId;
        uint128 assetId;
        uint128 price;
        uint64 timestamp;
    }

    function deserializeNotifyPricePoolPerAsset(bytes memory data)
        internal
        pure
        returns (NotifyPricePoolPerAsset memory)
    {
        require(messageType(data) == MessageType.NotifyPricePoolPerAsset, UnknownMessageType());
        return NotifyPricePoolPerAsset({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            assetId: data.toUint128(25),
            price: data.toUint128(41),
            timestamp: data.toUint64(57)
        });
    }

    function serialize(NotifyPricePoolPerAsset memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.NotifyPricePoolPerAsset, t.poolId, t.scId, t.assetId, t.price, t.timestamp);
    }

    //---------------------------------------
    //    NotifyShareMetadata
    //---------------------------------------

    struct NotifyShareMetadata {
        uint64 poolId;
        bytes16 scId;
        string name; // Fixed to 128 bytes
        bytes32 symbol; // utf8
    }

    function deserializeNotifyShareMetadata(bytes memory data) internal pure returns (NotifyShareMetadata memory) {
        require(messageType(data) == MessageType.NotifyShareMetadata, UnknownMessageType());
        return NotifyShareMetadata({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            name: data.slice(25, 128).bytes128ToString(),
            symbol: data.toBytes32(153)
        });
    }

    function serialize(NotifyShareMetadata memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(
            MessageType.NotifyShareMetadata, t.poolId, t.scId, bytes(t.name).sliceZeroPadded(0, 128), t.symbol
        );
    }

    //---------------------------------------
    //    UpdateShareHook
    //---------------------------------------

    struct UpdateShareHook {
        uint64 poolId;
        bytes16 scId;
        bytes32 hook;
    }

    function deserializeUpdateShareHook(bytes memory data) internal pure returns (UpdateShareHook memory) {
        require(messageType(data) == MessageType.UpdateShareHook, UnknownMessageType());
        return UpdateShareHook({poolId: data.toUint64(1), scId: data.toBytes16(9), hook: data.toBytes32(25)});
    }

    function serialize(UpdateShareHook memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.UpdateShareHook, t.poolId, t.scId, t.hook);
    }

    //---------------------------------------
    //    InitiateTransferShares
    //---------------------------------------

    struct InitiateTransferShares {
        uint64 poolId;
        bytes16 scId;
        uint16 centrifugeId;
        bytes32 receiver;
        uint128 amount;
        uint128 extraGasLimit;
    }

    function deserializeInitiateTransferShares(bytes memory data)
        internal
        pure
        returns (InitiateTransferShares memory)
    {
        require(messageType(data) == MessageType.InitiateTransferShares, UnknownMessageType());
        return InitiateTransferShares({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            centrifugeId: data.toUint16(25),
            receiver: data.toBytes32(27),
            amount: data.toUint128(59),
            extraGasLimit: data.toUint128(75)
        });
    }

    function serialize(InitiateTransferShares memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(
            MessageType.InitiateTransferShares, t.poolId, t.scId, t.centrifugeId, t.receiver, t.amount, t.extraGasLimit
        );
    }

    //---------------------------------------
    //    ExecuteTransferShares
    //---------------------------------------

    struct ExecuteTransferShares {
        uint64 poolId;
        bytes16 scId;
        bytes32 receiver;
        uint128 amount;
    }

    function deserializeExecuteTransferShares(bytes memory data) internal pure returns (ExecuteTransferShares memory) {
        require(messageType(data) == MessageType.ExecuteTransferShares, UnknownMessageType());
        return ExecuteTransferShares({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            receiver: data.toBytes32(25),
            amount: data.toUint128(57)
        });
    }

    function serialize(ExecuteTransferShares memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.ExecuteTransferShares, t.poolId, t.scId, t.receiver, t.amount);
    }

    //---------------------------------------
    //    UpdateRestriction
    //---------------------------------------

    struct UpdateRestriction {
        uint64 poolId;
        bytes16 scId;
        bytes payload; // As sequence of bytes
    }

    function deserializeUpdateRestriction(bytes memory data) internal pure returns (UpdateRestriction memory) {
        require(messageType(data) == MessageType.UpdateRestriction, UnknownMessageType());

        uint16 payloadLength = data.toUint16(25);
        return UpdateRestriction({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            payload: data.slice(27, payloadLength)
        });
    }

    function serialize(UpdateRestriction memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.UpdateRestriction, t.poolId, t.scId, uint16(t.payload.length), t.payload);
    }

    //---------------------------------------
    //    UpdateContract
    //---------------------------------------

    struct UpdateContract {
        uint64 poolId;
        bytes16 scId;
        bytes32 target;
        bytes payload; // As sequence of bytes
    }

    function deserializeUpdateContract(bytes memory data) internal pure returns (UpdateContract memory) {
        require(messageType(data) == MessageType.UpdateContract, UnknownMessageType());
        uint16 payloadLength = data.toUint16(57);
        return UpdateContract({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            target: data.toBytes32(25),
            payload: data.slice(59, payloadLength)
        });
    }

    function serialize(UpdateContract memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(
            MessageType.UpdateContract, t.poolId, t.scId, t.target, uint16(t.payload.length), t.payload
        );
    }

    //---------------------------------------
    //    Request
    //---------------------------------------

    struct Request {
        uint64 poolId;
        bytes16 scId;
        uint128 assetId;
        bytes payload; // As sequence of bytes
    }

    function deserializeRequest(bytes memory data) internal pure returns (Request memory) {
        require(messageType(data) == MessageType.Request, UnknownMessageType());
        uint16 payloadLength = data.toUint16(41);
        return Request({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            assetId: data.toUint128(25),
            payload: data.slice(43, payloadLength)
        });
    }

    function serialize(Request memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.Request, t.poolId, t.scId, t.assetId, uint16(t.payload.length), t.payload);
    }

    //---------------------------------------
    //    RequestCallback
    //---------------------------------------

    struct RequestCallback {
        uint64 poolId;
        bytes16 scId;
        uint128 assetId;
        bytes payload; // As sequence of bytes
    }

    function deserializeRequestCallback(bytes memory data) internal pure returns (RequestCallback memory) {
        require(messageType(data) == MessageType.RequestCallback, UnknownMessageType());
        uint16 payloadLength = data.toUint16(41);
        return RequestCallback({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            assetId: data.toUint128(25),
            payload: data.slice(43, payloadLength)
        });
    }

    function serialize(RequestCallback memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(
            MessageType.RequestCallback, t.poolId, t.scId, t.assetId, uint16(t.payload.length), t.payload
        );
    }

    //---------------------------------------
    //   VaultUpdate
    //---------------------------------------

    struct UpdateVault {
        uint64 poolId;
        bytes16 scId;
        uint128 assetId;
        bytes32 vaultOrFactory;
        uint8 kind;
    }

    function deserializeUpdateVault(bytes memory data) internal pure returns (UpdateVault memory) {
        require(messageType(data) == MessageType.UpdateVault, UnknownMessageType());
        return UpdateVault({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            assetId: data.toUint128(25),
            vaultOrFactory: data.toBytes32(41),
            kind: data.toUint8(73)
        });
    }

    function serialize(UpdateVault memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.UpdateVault, t.poolId, t.scId, t.assetId, t.vaultOrFactory, t.kind);
    }

    //---------------------------------------
    //   SetRequestManager
    //---------------------------------------

    struct SetRequestManager {
        uint64 poolId;
        bytes16 scId;
        uint128 assetId;
        bytes32 manager;
    }

    function deserializeSetRequestManager(bytes memory data) internal pure returns (SetRequestManager memory) {
        require(messageType(data) == MessageType.SetRequestManager, UnknownMessageType());
        return SetRequestManager({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            assetId: data.toUint128(25),
            manager: data.toBytes32(41)
        });
    }

    function serialize(SetRequestManager memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.SetRequestManager, t.poolId, t.scId, t.assetId, t.manager);
    }

    //---------------------------------------
    //   UpdateBalanceSheetManager
    //---------------------------------------

    struct UpdateBalanceSheetManager {
        uint64 poolId;
        bytes32 who;
        bool canManage;
    }

    function deserializeUpdateBalanceSheetManager(bytes memory data)
        internal
        pure
        returns (UpdateBalanceSheetManager memory)
    {
        require(messageType(data) == MessageType.UpdateBalanceSheetManager, UnknownMessageType());
        return UpdateBalanceSheetManager({poolId: data.toUint64(1), who: data.toBytes32(9), canManage: data.toBool(41)});
    }

    function serialize(UpdateBalanceSheetManager memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.UpdateBalanceSheetManager, t.poolId, t.who, t.canManage);
    }

    //---------------------------------------
    //    UpdateHoldingAmount
    //---------------------------------------

    struct UpdateHoldingAmount {
        uint64 poolId;
        bytes16 scId;
        uint128 assetId;
        uint128 amount;
        uint128 pricePerUnit;
        uint64 timestamp;
        bool isIncrease;
        bool isSnapshot;
        uint64 nonce;
    }

    function deserializeUpdateHoldingAmount(bytes memory data) internal pure returns (UpdateHoldingAmount memory h) {
        require(messageType(data) == MessageType.UpdateHoldingAmount, "UnknownMessageType");

        return UpdateHoldingAmount({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            assetId: data.toUint128(25),
            amount: data.toUint128(41),
            pricePerUnit: data.toUint128(57),
            timestamp: data.toUint64(73),
            isIncrease: data.toBool(81),
            isSnapshot: data.toBool(82),
            nonce: data.toUint64(83)
        });
    }

    function serialize(UpdateHoldingAmount memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(
            MessageType.UpdateHoldingAmount,
            t.poolId,
            t.scId,
            t.assetId,
            t.amount,
            t.pricePerUnit,
            t.timestamp,
            t.isIncrease,
            t.isSnapshot,
            t.nonce
        );
    }

    //---------------------------------------
    //    UpdateShares
    //---------------------------------------

    struct UpdateShares {
        uint64 poolId;
        bytes16 scId;
        uint128 shares;
        uint64 timestamp;
        bool isIssuance;
        bool isSnapshot;
        uint64 nonce;
    }

    function deserializeUpdateShares(bytes memory data) internal pure returns (UpdateShares memory) {
        require(messageType(data) == MessageType.UpdateShares, UnknownMessageType());

        return UpdateShares({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            shares: data.toUint128(25),
            timestamp: data.toUint64(41),
            isIssuance: data.toBool(49),
            isSnapshot: data.toBool(50),
            nonce: data.toUint64(51)
        });
    }

    function serialize(UpdateShares memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(
            MessageType.UpdateShares, t.poolId, t.scId, t.shares, t.timestamp, t.isIssuance, t.isSnapshot, t.nonce
        );
    }

    //---------------------------------------
    //   MaxAssetPriceAge
    //---------------------------------------

    struct MaxAssetPriceAge {
        uint64 poolId;
        bytes16 scId;
        uint128 assetId;
        uint64 maxPriceAge;
    }

    function deserializeMaxAssetPriceAge(bytes memory data) internal pure returns (MaxAssetPriceAge memory) {
        require(messageType(data) == MessageType.MaxAssetPriceAge, UnknownMessageType());
        return MaxAssetPriceAge({
            poolId: data.toUint64(1),
            scId: data.toBytes16(9),
            assetId: data.toUint128(25),
            maxPriceAge: data.toUint64(41)
        });
    }

    function serialize(MaxAssetPriceAge memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.MaxAssetPriceAge, t.poolId, t.scId, t.assetId, t.maxPriceAge);
    }

    //---------------------------------------
    //   MaxSharePriceAge
    //---------------------------------------

    struct MaxSharePriceAge {
        uint64 poolId;
        bytes16 scId;
        uint64 maxPriceAge;
    }

    function deserializeMaxSharePriceAge(bytes memory data) internal pure returns (MaxSharePriceAge memory) {
        require(messageType(data) == MessageType.MaxSharePriceAge, UnknownMessageType());
        return MaxSharePriceAge({poolId: data.toUint64(1), scId: data.toBytes16(9), maxPriceAge: data.toUint64(25)});
    }

    function serialize(MaxSharePriceAge memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(MessageType.MaxSharePriceAge, t.poolId, t.scId, t.maxPriceAge);
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import {D18} from "src/misc/types/D18.sol";

import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
import {VaultUpdateKind} from "src/common/libraries/MessageLib.sol";

/// -----------------------------------------------------
///  Hub Handlers
/// -----------------------------------------------------

/// @notice Interface for Hub methods called by messages
interface IHubGatewayHandler {
    /// @notice Tells that an asset was already registered in Vaults, in order to perform the corresponding register.
    function registerAsset(AssetId assetId, uint8 decimals) external;

    /// @notice Handles a request originating from the Spoke side.
    /// @param  poolId The pool id
    /// @param  scId The share class id
    /// @param  assetId The asset id
    /// @param  payload The request payload to be processed
    function request(PoolId poolId, ShareClassId scId, AssetId assetId, bytes calldata payload) external payable;

    /// @notice Update a holding by request from Vaults.
    function updateHoldingAmount(
        uint16 centrifugeId,
        PoolId poolId,
        ShareClassId scId,
        AssetId assetId,
        uint128 amount,
        D18 pricePoolPerAsset,
        bool isIncrease,
        bool isSnapshot,
        uint64 nonce
    ) external;

    /// @notice Forward an initiated share transfer to the destination chain.
    function initiateTransferShares(
        uint16 centrifugeId,
        PoolId poolId,
        ShareClassId scId,
        bytes32 receiver,
        uint128 amount,
        uint128 extraGasLimit
    ) external;

    /// @notice Updates the total issuance of shares by request from vaults.
    function updateShares(
        uint16 centrifugeId,
        PoolId poolId,
        ShareClassId scId,
        uint128 amount,
        bool isIssuance,
        bool isSnapshot,
        uint64 nonce
    ) external;
}

/// -----------------------------------------------------
///  Vaults Handlers
/// -----------------------------------------------------

/// @notice Interface for spoke related methods called by messages
interface ISpokeGatewayHandler {
    /// @notice    New pool details from an existing Centrifuge pool are added.
    /// @param     poolId The pool id
    function addPool(PoolId poolId) external;

    /// @notice     New share class details from an existing Centrifuge pool are added.
    function addShareClass(
        PoolId poolId,
        ShareClassId scId,
        string memory tokenName,
        string memory tokenSymbol,
        uint8 decimals,
        bytes32 salt,
        address hook
    ) external;

    /// @notice Updates the request manager for a specific asset
    /// @param  poolId The centrifuge pool id
    /// @param  scId The share class id
    /// @param  assetId The asset id
    /// @param  manager The new request manager address
    function setRequestManager(PoolId poolId, ShareClassId scId, AssetId assetId, address manager) external;

    /// @notice   Updates the tokenName and tokenSymbol of a share class token
    function updateShareMetadata(PoolId poolId, ShareClassId scId, string memory tokenName, string memory tokenSymbol)
        external;

    /// @notice  Updates the price of a share class token, i.e. the factor of pool currency amount per share class token
    /// @param  poolId The pool id
    /// @param  scId The share class id
    /// @param  price The price of pool currency per share class token as factor.
    /// @param  computedAt The timestamp when the price was computed
    function updatePricePoolPerShare(PoolId poolId, ShareClassId scId, uint128 price, uint64 computedAt) external;

    /// @notice  Updates the price of an asset, i.e. the factor of pool currency amount per asset unit
    /// @param  poolId The pool id
    /// @param  scId The share class id
    /// @param  assetId The asset id
    /// @param  poolPerAsset The price of pool currency per asset unit as factor.
    /// @param  computedAt The timestamp when the price was computed
    function updatePricePoolPerAsset(
        PoolId poolId,
        ShareClassId scId,
        AssetId assetId,
        uint128 poolPerAsset,
        uint64 computedAt
    ) external;

    /// @notice Updates the hook of a share class token
    /// @param  poolId The centrifuge pool id
    /// @param  scId The share class id
    /// @param  hook The new hook addres
    function updateShareHook(PoolId poolId, ShareClassId scId, address hook) external;

    /// @notice Updates the restrictions on a share class token for a specific user
    /// @param  poolId The centrifuge pool id
    /// @param  scId The share class id
    /// @param  update The restriction update in the form of a bytes array indicating
    ///                the restriction to be updated, the user to be updated, and a validUntil timestamp.
    function updateRestriction(PoolId poolId, ShareClassId scId, bytes memory update) external;

    /// @notice Mints share class tokens to a recipient
    function executeTransferShares(PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount) external;

    /// @notice Updates a vault based on VaultUpdateKind
    /// @param  poolId The centrifuge pool id
    /// @param  scId The share class id
    /// @param  assetId The asset id
    /// @param  vaultOrFactory The address of the vault or the factory, depending on the kind value
    /// @param  kind The kind of action applied
    function updateVault(
        PoolId poolId,
        ShareClassId scId,
        AssetId assetId,
        address vaultOrFactory,
        VaultUpdateKind kind
    ) external;

    /// @notice Updates the max price age of an asset
    /// @param  poolId The centrifuge pool id
    /// @param  scId The share class id
    /// @param  assetId The asset id
    /// @param  maxPriceAge new max price age value
    function setMaxAssetPriceAge(PoolId poolId, ShareClassId scId, AssetId assetId, uint64 maxPriceAge) external;

    /// @notice Updates the max price age of a share
    /// @param  poolId The centrifuge pool id
    /// @param  scId The share class id
    /// @param  maxPriceAge new max price age value
    function setMaxSharePriceAge(PoolId poolId, ShareClassId scId, uint64 maxPriceAge) external;

    /// @notice Handles a request callback originating from the Hub side.
    /// @dev    Results from a Spoke-to-Hub-request as second order callback from the Hub.
    /// @param  poolId The pool id
    /// @param  scId The share class id
    /// @param  assetId The asset id
    /// @param  payload The payload to be processed by the request callback
    function requestCallback(PoolId poolId, ShareClassId scId, AssetId assetId, bytes memory payload) external;
}

/// @notice Interface for the update contract method, called by message
interface IUpdateContractGatewayHandler {
    /// @notice Updates the target address. Generic update function from Hub to Vaults
    /// @param  poolId The centrifuge pool id
    /// @param  scId The share class id
    /// @param  target The target address to be called
    /// @param  update The payload to be processed by the target address
    function execute(PoolId poolId, ShareClassId scId, address target, bytes memory update) external;
}

/// @notice Interface for methods implemented by a balance sheet
interface IBalanceSheetGatewayHandler {
    function updateManager(PoolId poolId, address who, bool canManage) external;
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

interface IAuth {
    event Rely(address indexed user);
    event Deny(address indexed user);

    error NotAuthorized();

    /// @notice Returns whether the target is a ward (has admin access)
    function wards(address target) external view returns (uint256);

    /// @notice Make user a ward (give them admin access)
    function rely(address user) external;

    /// @notice Remove user as a ward (remove admin access)
    function deny(address user) external;
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;

library MathLib {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero

    }

    error MulDiv_Overflow();
    error Uint8_Overflow();
    error Uint32_Overflow();
    error Uint64_Overflow();
    error Uint128_Overflow();
    error Int128_Overflow();

    uint256 public constant One27 = 10 ** 27;

    /// @notice Returns x^n with rounding precision of base
    ///
    /// @dev Source: https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/jug.sol#L62
    ///
    /// @param x The base value which should be exponentiated
    /// @param n The exponent
    /// @param base The scaling base, typically used for fix-point calculations
    function rpow(uint256 x, uint256 n, uint256 base) public pure returns (uint256 z) {
        assembly {
            switch x
            case 0 {
                switch n
                case 0 { z := base }
                default { z := 0 }
            }
            default {
                switch mod(n, 2)
                case 0 { z := base }
                default { z := x }
                let half := div(base, 2) // for rounding.
                for { n := div(n, 2) } n { n := div(n, 2) } {
                    let xx := mul(x, x)
                    if iszero(eq(div(xx, x), x)) { revert(0, 0) }
                    let xxRound := add(xx, half)
                    if lt(xxRound, xx) { revert(0, 0) }
                    x := div(xxRound, base)
                    if mod(n, 2) {
                        let zx := mul(z, x)
                        if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) }
                        let zxRound := add(zx, half)
                        if lt(zxRound, zx) { revert(0, 0) }
                        z := div(zxRound, base)
                    }
                }
            }
        }
    }

    /// @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.
    // slither-disable-start divide-before-multiply
    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; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                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.
            require(denominator > prod1, MulDiv_Overflow());

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

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            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;
        }
    }
    // slither-disable-end divide-before-multiply

    /// @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 (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /// @notice Safe type conversion from uint256 to uint8.
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value <= type(uint8).max, Uint8_Overflow());
        return uint8(value);
    }

    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value <= type(uint32).max, Uint32_Overflow());
        return uint32(value);
    }

    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value <= type(uint64).max, Uint64_Overflow());
        return uint64(value);
    }

    /// @notice Safe type conversion from uint256 to uint128.
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value <= type(uint128).max, Uint128_Overflow());
        return uint128(value);
    }

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

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

Settings
{
  "remappings": [
    "forge-std/=lib/forge-std/src/",
    "@chimera/=lib/chimera/src/",
    "createx-forge/=lib/createx-forge/",
    "chimera/=lib/chimera/src/",
    "ds-test/=lib/chimera/lib/forge-std/lib/ds-test/src/",
    "setup-helpers/=lib/setup-helpers/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IRoot","name":"root_","type":"address"},{"internalType":"contract ITokenRecoverer","name":"tokenRecoverer_","type":"address"},{"internalType":"address","name":"deployer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FileUnrecognizedParam","type":"error"},{"inputs":[{"internalType":"uint8","name":"code","type":"uint8"}],"name":"InvalidMessage","type":"error"},{"inputs":[],"name":"InvalidSourceChain","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"SliceOutOfBounds","type":"error"},{"inputs":[],"name":"SliceOverflow","type":"error"},{"inputs":[],"name":"UnknownMessageType","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Deny","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"what","type":"bytes32"},{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"File","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Rely","type":"event"},{"inputs":[],"name":"balanceSheet","outputs":[{"internalType":"contract IBalanceSheetGatewayHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractUpdater","outputs":[{"internalType":"contract IUpdateContractGatewayHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"what","type":"bytes32"},{"internalType":"address","name":"data","type":"address"}],"name":"file","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"centrifugeId","type":"uint16"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"handle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"hub","outputs":[{"internalType":"contract IHubGatewayHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"message","type":"bytes"}],"name":"messageLength","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"message","type":"bytes"}],"name":"messagePoolId","outputs":[{"internalType":"PoolId","name":"","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"root","outputs":[{"internalType":"contract IRoot","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"spoke","outputs":[{"internalType":"contract ISpokeGatewayHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenRecoverer","outputs":[{"internalType":"contract ITokenRecoverer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60c060405234801561000f575f5ffd5b506040516138be3803806138be83398101604081905261002e916100a1565b6001600160a01b0381165f8181526020819052604080822060019055518392917fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a6091a250506001600160a01b039182166080521660a0526100eb565b6001600160a01b038116811461009e575f5ffd5b50565b5f5f5f606084860312156100b3575f5ffd5b83516100be8161008a565b60208501519093506100cf8161008a565b60408501519092506100e08161008a565b809150509250925092565b60805160a05161379e6101205f395f818160df015261052501525f81816101ed015281816103ac0152610490015261379e5ff3fe608060405234801561000f575f5ffd5b50600436106100ad575f3560e01c806322285cf6146100b1578063268808c6146100da578063365a86fc146101015780633b514cf11461011457806347bfbcc6146101345780634f35b71c1461014757806365fae35e1461015c5780636c3be0ce1461016f5780639c52a7f114610195578063bf353dbb146101a8578063d4e8be83146101d5578063ebf0c717146101e8578063ed15d9601461020f575b5f5ffd5b6003546100c4906001600160a01b031681565b6040516100d191906132d2565b60405180910390f35b6100c47f000000000000000000000000000000000000000000000000000000000000000081565b6001546100c4906001600160a01b031681565b61012761012236600461332a565b610222565b6040516100d19190613368565b6002546100c4906001600160a01b031681565b61015a61015536600461337c565b61026a565b005b61015a61016a3660046133ed565b611535565b61018261017d36600461332a565b6115a8565b60405161ffff90911681526020016100d1565b61015a6101a33660046133ed565b6115e7565b6101c76101b63660046133ed565b5f6020819052908152604090205481565b6040519081526020016100d1565b61015a6101e3366004613406565b611659565b6100c47f000000000000000000000000000000000000000000000000000000000000000081565b6004546100c4906001600160a01b031681565b5f61026183838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506117a892505050565b90505b92915050565b335f908152602081905260409020546001146102995760405163ea8e4eb560e01b815260040160405180910390fd5b5f6102d883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506117e192505050565b90505f61031984848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061180092505050565b905061ffff8116158061033357508461ffff168161ffff16145b61035057604051639284b19760e01b815260040160405180910390fd5b600182602281111561036457610364613430565b03610434575f6103a885858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506118b192505050565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633b6874616103e5835f0151611919565b6040518263ffffffff1660e01b815260040161040191906132d2565b5f604051808303815f87803b158015610418575f5ffd5b505af115801561042a573d5f5f3e3d5ffd5b505050505061152e565b600282602281111561044857610448613430565b036104c9575f61048c85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061197392505050565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166311fd3baa6103e5835f0151611919565b60038260228111156104dd576104dd613430565b036105ce575f61052185858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061198892505050565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663109037c061055e835f0151611919565b61056b8460200151611919565b846040015161057d8660600151611919565b608087015160405160e087901b6001600160e01b03191681526001600160a01b039586166004820152938516602485015260448401929092529092166064820152608481019190915260a401610401565b60048260228111156105e2576105e2613430565b03610670575f61062685858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611a4692505050565b60015481516020830151604051633207adab60e01b81526001600160801b03909216600483015260ff1660248201529192506001600160a01b031690633207adab90604401610401565b602082602281111561068457610684613430565b0361070e575f6106c885858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611acd92505050565b6001548151602083015160408085015160608601519151632f6c33bf60e01b81529596506001600160a01b0390941694632f6c33bf946104019493929091600401613472565b601082602281111561072257610722613430565b036107cd57600254604080516020601f87018190048102820181019092528581526001600160a01b0390921691632b89610191610779919088908890819084018382808284375f92019190915250611bae92505050565b516040516001600160e01b031960e084901b16815261079b9190600401613368565b5f604051808303815f87803b1580156107b2575f5ffd5b505af11580156107c4573d5f5f3e3d5ffd5b5050505061152e565b60118260228111156107e1576107e1613430565b03610891575f61082585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611c1e92505050565b60025481516020830151604084015160608501519495506001600160a01b0390931693636ea6e0a1939061085890611d3f565b86608001518760a0015161086f8960c00151611919565b6040518863ffffffff1660e01b815260040161040197969594939291906134be565b60128260228111156108a5576108a5613430565b0361092f575f6108e985858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611e6a92505050565b6002548151602083015160408085015160608601519151634869ac6960e01b81529596506001600160a01b0390941694634869ac6994610401949392909160040161352f565b601382602281111561094357610943613430565b03610a08575f61098785858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611f2b92505050565b60025481516020830151604080850151606086015160808701519251633a4ba8bf60e01b81526001600160401b0395861660048201526001600160801b031990941660248501526001600160801b0391821660448501521660648301529190911660848201529192506001600160a01b031690633a4ba8bf9060a401610401565b6014826022811115610a1c57610a1c613430565b03610ab2575f610a6085858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061200b92505050565b60025481516020830151604084015160608501519495506001600160a01b039093169363931efb549390610a9390611d3f565b6040518563ffffffff1660e01b8152600401610401949392919061356d565b6015826022811115610ac657610ac6613430565b03610b83575f610b0a85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506120c892505050565b6002548151602083015160408401519394506001600160a01b039092169263fb59077a9290610b3890611919565b6040516001600160e01b031960e086901b1681526001600160401b0390931660048401526001600160801b031990911660248301526001600160a01b03166044820152606401610401565b6016826022811115610b9757610b97613430565b03610c6a575f610bdb85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061216892505050565b600154604082810151835160208501516060860151608087015160a0880151955163ecca8cf760e01b815261ffff90951660048601526001600160401b0390931660248501526001600160801b0319909116604484015260648301526001600160801b03908116608483015290911660a48201529192506001600160a01b03169063ecca8cf79060c401610401565b6017826022811115610c7e57610c7e613430565b03610d35575f610cc285858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061226b92505050565b600254815160208301516040808501516060860151915163bccbfa8960e01b81526001600160401b0390941660048501526001600160801b0319909216602484015260448301919091526001600160801b031660648201529192506001600160a01b03169063bccbfa8990608401610401565b6018826022811115610d4957610d49613430565b03610dcc575f610d8d85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061232292505050565b600254815160208301516040808501519051630f8dad5d60e11b81529495506001600160a01b0390931693631f1b5aba936104019392916004016135bd565b6019826022811115610de057610de0613430565b03610e76575f610e2485858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506123dc92505050565b6004548151602083015160408401519394506001600160a01b0390921692630b1271059290610e5290611919565b85606001516040518563ffffffff1660e01b815260040161040194939291906135f9565b6021826022811115610e8a57610e8a613430565b03610f14575f610ece85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506124ad92505050565b60025481516020830151604080850151606086015191516336c6cf3760e21b81529596506001600160a01b039094169463db1b3cdc946104019493929091600401613472565b601a826022811115610f2857610f28613430565b03610fd8575f610f6c85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506124d692505050565b60025481516020830151604084015160608501519495506001600160a01b039093169363b3cfb8179390610f9f90611919565b866080015160ff166002811115610fb857610fb8613430565b6040518663ffffffff1660e01b815260040161040195949392919061363b565b6022826022811115610fec57610fec613430565b036110bc575f61103085858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506125ad92505050565b60025481516020830151604084015160608501519495506001600160a01b03909316936325dc4956939061106390611919565b6040516001600160e01b031960e087901b1681526001600160401b0390941660048501526001600160801b031990921660248401526001600160801b031660448301526001600160a01b03166064820152608401610401565b601b8260228111156110d0576110d0613430565b03611185575f61111485858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061266d92505050565b600354815160208301519293506001600160a01b039091169163a6fd509b919061113d90611919565b60408086015190516001600160e01b031960e086901b1681526001600160401b0390931660048401526001600160a01b03909116602483015215156044820152606401610401565b601c82602281111561119957611199613430565b036112b1575f6111dd85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061270d92505050565b905060015f9054906101000a90046001600160a01b03166001600160a01b0316630646affc87835f015184602001518560400151866060015187608001518860c001518960e001518a61010001516040518a63ffffffff1660e01b81526004016104019998979695949392919061ffff9990991689526001600160401b0397881660208a01526001600160801b03199690961660408901526001600160801b0394851660608901529284166080880152921660a086015290151560c0850152151560e0840152166101008201526101200190565b601d8260228111156112c5576112c5613430565b036113a1575f61130985858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061288692505050565b60015481516020830151604080850151608086015160a087015160c08801519351631de0563360e21b815261ffff8f1660048201526001600160401b0396871660248201526001600160801b031990951660448601526001600160801b03909216606485015215156084840152151560a48301529190911660c48201529192506001600160a01b03169063778158cc9060e401610401565b601e8260228111156113b5576113b5613430565b0361143f575f6113f985858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061299892505050565b6002548151602083015160408085015160608601519151636a4873e160e11b81529596506001600160a01b039094169463d490e7c294610401949392909160040161352f565b601f82602281111561145357611453613430565b036114f8575f61149785858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506129c292505050565b60025481516020830151604080850151905163eece6c4360e01b81526001600160401b0393841660048201526001600160801b031990921660248301529190911660448201529192506001600160a01b03169063eece6c4390606401610401565b81602281111561150a5761150a613430565b604051630391465960e11b815260ff90911660048201526024015b60405180910390fd5b5050505050565b335f908152602081905260409020546001146115645760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b5f61026183838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612a6292505050565b335f908152602081905260409020546001146116165760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b335f908152602081905260409020546001146116885760405163ea8e4eb560e01b815260040160405180910390fd5b8162343ab160e91b036116b557600180546001600160a01b0319166001600160a01b03831617905561176c565b816473706f6b6560d81b036116e457600280546001600160a01b0319166001600160a01b03831617905561176c565b816b18985b185b98d954da19595d60a21b0361171a57600380546001600160a01b0319166001600160a01b03831617905561176c565b816e31b7b73a3930b1ba2ab83230ba32b960891b0361175357600480546001600160a01b0319166001600160a01b03831617905561176c565b604051633db0d5b960e01b815260040160405180910390fd5b817f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba8260405161179c91906132d2565b60405180910390a25050565b5f806117b48382612f58565b9050601060ff8216106117d3576117cc836001612f8e565b9392505050565b505f92915050565b50919050565b5f6117ec8282612f58565b60ff16602281111561026457610264613430565b5f8061180c8382612f58565b9050600360ff82161161182157505f92915050565b60ff8116601d1480611836575060ff81166016145b1561184357505f92915050565b60031960ff821601611867576117cc61185d846001612fc4565b60701c61ffff1690565b601b1960ff821601611881576117cc61185d846019612fc4565b601f1960ff82160161189b576117cc61185d846019612fc4565b6117cc6118a7846117a8565b60301c61ffff1690565b60408051602081019091525f815260015b6118cb836117e1565b60228111156118dc576118dc613430565b146118fa576040516304c735eb60e11b815260040160405180910390fd5b604080516020810190915280611911846001612ffa565b905292915050565b5f6001600160601b0382161561196c5760405162461bcd60e51b8152602060048201526018602482015277496e7075742073686f756c6420626520323020627974657360401b6044820152606401611525565b5060601c90565b60408051602081019091525f815260026118c2565b6119b56040518060a001604052805f81526020015f81526020015f81526020015f81526020015f81525090565b60036119c0836117e1565b60228111156119d1576119d1613430565b146119ef576040516304c735eb60e11b815260040160405180910390fd5b6040805160a0810190915280611a06846001612ffa565b8152602001611a16846021612ffa565b8152602001611a26846041612ffa565b8152602001611a36846061612ffa565b8152602001611911846081612ffa565b604080518082019091525f80825260208201526004611a64836117e1565b6022811115611a7557611a75613430565b14611a93576040516304c735eb60e11b815260040160405180910390fd5b6040805180820190915280611aa9846001612fc4565b6001600160801b03168152602001611ac2846011612f58565b60ff16905292915050565b604080516080810182525f808252602080830182905292820152606080820152905b611af8836117e1565b6022811115611b0957611b09613430565b14611b27576040516304c735eb60e11b815260040160405180910390fd5b5f611b33836029613030565b90506040518060800160405280611b54600186612f8e90919063ffffffff16565b6001600160401b03168152602001611b6d856009613066565b6001600160801b0319168152602001611b87856019612fc4565b6001600160801b03168152602001611ba585602b61ffff8616613072565b90529392505050565b60408051602081019091525f81526010611bc7836117e1565b6022811115611bd857611bd8613430565b14611bf6576040516304c735eb60e11b815260040160405180910390fd5b604080516020810190915280611c0d846001612f8e565b6001600160401b0316905292915050565b611c6e6040518060e001604052805f6001600160401b031681526020015f6001600160801b0319168152602001606081526020015f81526020015f60ff1681526020015f81526020015f81525090565b6011611c79836117e1565b6022811115611c8a57611c8a613430565b14611ca8576040516304c735eb60e11b815260040160405180910390fd5b6040805160e0810190915280611cbf846001612f8e565b6001600160401b03168152602001611cd8846009613066565b6001600160801b0319168152602001611cfc611cf78560196080613072565b613134565b8152602001611d0c846099612ffa565b8152602001611d1c8460b9612f58565b60ff168152602001611d2f8460ba612ffa565b81526020016119118460da612ffa565b60605f5b60208160ff16108015611d775750828160ff1660208110611d6657611d666136a5565b1a60f81b6001600160f81b03191615155b15611d8e5780611d86816136cd565b915050611d43565b5f8160ff166001600160401b03811115611daa57611daa6136eb565b6040519080825280601f01601f191660200182016040528015611dd4576020820181803683370190505b5090505f91505b60208260ff16108015611e0f5750838260ff1660208110611dfe57611dfe6136a5565b1a60f81b6001600160f81b03191615155b156117cc57838260ff1660208110611e2957611e296136a5565b1a60f81b818360ff1681518110611e4257611e426136a5565b60200101906001600160f81b03191690815f1a90535081611e62816136cd565b925050611ddb565b604080516080810182525f80825260208201819052918101829052606081019190915260125b611e99836117e1565b6022811115611eaa57611eaa613430565b14611ec8576040516304c735eb60e11b815260040160405180910390fd5b604080516080810190915280611edf846001612f8e565b6001600160401b03168152602001611ef8846009613066565b6001600160801b0319168152602001611f12846019612fc4565b6001600160801b03168152602001611c0d846029612f8e565b6040805160a0810182525f808252602082018190529181018290526060810182905260808101919091526013611f60836117e1565b6022811115611f7157611f71613430565b14611f8f576040516304c735eb60e11b815260040160405180910390fd5b6040805160a0810190915280611fa6846001612f8e565b6001600160401b03168152602001611fbf846009613066565b6001600160801b0319168152602001611fd9846019612fc4565b6001600160801b03168152602001611ff2846029612fc4565b6001600160801b03168152602001611c0d846039612f8e565b604080516080810182525f80825260208201819052606092820183905291810191909152601461203a836117e1565b602281111561204b5761204b613430565b14612069576040516304c735eb60e11b815260040160405180910390fd5b604080516080810190915280612080846001612f8e565b6001600160401b03168152602001612099846009613066565b6001600160801b03191681526020016120b8611cf78560196080613072565b8152602001611911846099612ffa565b604080516060810182525f808252602082018190529181019190915260156120ef836117e1565b602281111561210057612100613430565b1461211e576040516304c735eb60e11b815260040160405180910390fd5b604080516060810190915280612135846001612f8e565b6001600160401b0316815260200161214e846009613066565b6001600160801b0319168152602001611911846019612ffa565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a081019190915260166121a4836117e1565b60228111156121b5576121b5613430565b146121d3576040516304c735eb60e11b815260040160405180910390fd5b6040805160c08101909152806121ea846001612f8e565b6001600160401b03168152602001612203846009613066565b6001600160801b031916815260200161221d846019613030565b61ffff16815260200161223184601b612ffa565b815260200161224184603b612fc4565b6001600160801b0316815260200161225a84604b612fc4565b6001600160801b0316905292915050565b604080516080810182525f8082526020820181905291810182905260608101919091526017612299836117e1565b60228111156122aa576122aa613430565b146122c8576040516304c735eb60e11b815260040160405180910390fd5b6040805160808101909152806122df846001612f8e565b6001600160401b031681526020016122f8846009613066565b6001600160801b0319168152602001612312846019612ffa565b815260200161225a846039612fc4565b60408051606080820183525f8083526020830152918101919091526018612348836117e1565b602281111561235957612359613430565b14612377576040516304c735eb60e11b815260040160405180910390fd5b5f612383836019613030565b905060405180606001604052806123a4600186612f8e90919063ffffffff16565b6001600160401b031681526020016123bd856009613066565b6001600160801b0319168152602001611ba585601b61ffff8616613072565b604080516080810182525f80825260208201819052918101919091526060808201526019612409836117e1565b602281111561241a5761241a613430565b14612438576040516304c735eb60e11b815260040160405180910390fd5b5f612444836039613030565b90506040518060800160405280612465600186612f8e90919063ffffffff16565b6001600160401b0316815260200161247e856009613066565b6001600160801b0319168152602001612498856019612ffa565b8152602001611ba585603b61ffff8616613072565b604080516080810182525f80825260208201819052918101919091526060808201526021611aef565b6040805160a0810182525f80825260208201819052918101829052606081018290526080810191909152601a61250b836117e1565b602281111561251c5761251c613430565b1461253a576040516304c735eb60e11b815260040160405180910390fd5b6040805160a0810190915280612551846001612f8e565b6001600160401b0316815260200161256a846009613066565b6001600160801b0319168152602001612584846019612fc4565b6001600160801b0316815260200161259d846029612ffa565b8152602001611ac2846049612f58565b604080516080810182525f80825260208201819052918101829052606081019190915260226125db836117e1565b60228111156125ec576125ec613430565b1461260a576040516304c735eb60e11b815260040160405180910390fd5b604080516080810190915280612621846001612f8e565b6001600160401b0316815260200161263a846009613066565b6001600160801b0319168152602001612654846019612fc4565b6001600160801b03168152602001611911846029612ffa565b604080516060810182525f8082526020820181905291810191909152601b612694836117e1565b60228111156126a5576126a5613430565b146126c3576040516304c735eb60e11b815260040160405180910390fd5b6040805160608101909152806126da846001612f8e565b6001600160401b031681526020016126f3846009612ffa565b8152602001612703846029613285565b1515905292915050565b60408051610120810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810191909152601c612760836117e1565b602281111561277157612771613430565b146127b35760405162461bcd60e51b8152602060048201526012602482015271556e6b6e6f776e4d6573736167655479706560701b6044820152606401611525565b604080516101208101909152806127cb846001612f8e565b6001600160401b031681526020016127e4846009613066565b6001600160801b03191681526020016127fe846019612fc4565b6001600160801b03168152602001612817846029612fc4565b6001600160801b03168152602001612830846039612fc4565b6001600160801b03168152602001612849846049612f8e565b6001600160401b03168152602001612862846051613285565b15158152602001612874846052613285565b15158152602001611c0d846053612f8e565b6040805160e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152601d6128c9836117e1565b60228111156128da576128da613430565b146128f8576040516304c735eb60e11b815260040160405180910390fd5b6040805160e081019091528061290f846001612f8e565b6001600160401b03168152602001612928846009613066565b6001600160801b0319168152602001612942846019612fc4565b6001600160801b0316815260200161295b846029612f8e565b6001600160401b03168152602001612974846031613285565b15158152602001612986846032613285565b15158152602001611c0d846033612f8e565b604080516080810182525f808252602082018190529181018290526060810191909152601e611e90565b604080516060810182525f8082526020820181905291810191909152601f6129e9836117e1565b60228111156129fa576129fa613430565b14612a18576040516304c735eb60e11b815260040160405180910390fd5b604080516060810190915280612a2f846001612f8e565b6001600160401b03168152602001612a48846009613066565b6001600160801b0319168152602001611c0d846019612f8e565b5f80612a6e8382612f58565b9050602260ff82161115612a95576040516304c735eb60e11b815260040160405180910390fd5b601f8160ff161115612b3657612aad602060226136ff565b612ab8906008613718565b604960ff919091161b612acd602060216136ff565b612ad8906008613718565b602960ff919091161b612aec6020806136ff565b612af7906008613718565b60ff166029901b612b08919061373b565b612b12919061373b565b612b1d82603f6136ff565b60ff1660208110612b3057612b306136a5565b1a612ebd565b612b42601f6008613718565b602160ff919091161b612b57601e6008613718565b603160ff919091161b612b6c601d6008613718565b603b60ff919091161b612b81601c6008613718565b605b60ff919091161b612b96601b6008613718565b602a60ff919091161b612bab601a6008613718565b604a60ff919091161b612bc060196008613718565b603960ff919091161b612bd560186008613718565b601960ff919091161b612bea60176008613718565b604960ff919091161b612bff60166008613718565b605b60ff919091161b612c1460156008613718565b603960ff919091161b612c2960146008613718565b60b960ff919091161b612c3e60136008613718565b604160ff919091161b612c5360126008613718565b603160ff919091161b612c6860116008613718565b60fa60ff919091161b612c7d60106008613718565b600960ff919091161b612c92600f6008613718565b505f612ca0600e6008613718565b505f612cae600d6008613718565b505f612cbc600c6008613718565b505f612cca600b6008613718565b505f612cd8600a6008613718565b505f612ce660096008613718565b505f612cf3600880613718565b505f612d0160076008613718565b505f612d0f60066008613718565b505f612d1d60056008613718565b505f612d2b60046008613718565b601260ff919091161b612d4060036008613718565b60a160ff919091161b612d5560026008613718565b602160ff919091161b612d6a60016008613718565b60ff166021901b612d7b919061373b565b612d85919061373b565b612d8f919061373b565b612d99919061373b565b612da3919061373b565b612dad919061373b565b612db7919061373b565b612dc1919061373b565b612dcb919061373b565b612dd5919061373b565b612ddf919061373b565b612de9919061373b565b612df3919061373b565b612dfd919061373b565b612e07919061373b565b612e11919061373b565b612e1b919061373b565b612e25919061373b565b612e2f919061373b565b612e39919061373b565b612e43919061373b565b612e4d919061373b565b612e57919061373b565b612e61919061373b565b612e6b919061373b565b612e75919061373b565b612e7f919061373b565b612e89919061373b565b612e93919061373b565b612e9d919061373b565b612ea882601f6136ff565b60ff1660208110612ebb57612ebb6136a5565b1a5b915060171960ff821601612ef557612ed98361ffff8416613030565b612ee490600261374e565b612eee908361374e565b91506117db565b60181960ff821601612f0f57612ed98361ffff8416613030565b601f1960ff821601612f2957612ed98361ffff8416613030565b60201960ff8216016117db57612f438361ffff8416613030565b612f4e90600261374e565b6117cc908361374e565b5f612f6482600161373b565b83511015612f8557604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f612f9a82600861373b565b83511015612fbb57604051633b99b53d60e01b815260040160405180910390fd5b50016008015190565b5f612fd082601061373b565b83511015612ff157604051633b99b53d60e01b815260040160405180910390fd5b50016010015190565b5f61300682602061373b565b8351101561302757604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f61303c82600261373b565b8351101561305d57604051633b99b53d60e01b815260040160405180910390fd5b50016002015190565b5f61300682601061373b565b60608182601f011015613098576040516323d5783d60e11b815260040160405180910390fd5b6130a2828461373b565b845110156130c357604051633b99b53d60e01b815260040160405180910390fd5b6060821580156130e15760405191505f82526020820160405261312b565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561311a578051835260209283019201613102565b5050858452601f01601f1916604052505b50949350505050565b606081516080146131835760405162461bcd60e51b8152602060048201526019602482015278496e7075742073686f756c642062652031323820627974657360381b6044820152606401611525565b5f5b60808160ff161080156131ba5750828160ff16815181106131a8576131a86136a5565b01602001516001600160f81b03191615155b156131d157806131c9816136cd565b915050613185565b5f8160ff166001600160401b038111156131ed576131ed6136eb565b6040519080825280601f01601f191660200182016040528015613217576020820181803683370190505b5090505f5b8260ff168160ff16101561327d57848160ff168151811061323f5761323f6136a5565b602001015160f81c60f81b828260ff168151811061325f5761325f6136a5565b60200101906001600160f81b03191690815f1a90535060010161321c565b509392505050565b5f818351116132a757604051633b99b53d60e01b815260040160405180910390fd5b8282815181106132b9576132b96136a5565b01602001516001600160f81b0319161515905092915050565b6001600160a01b0391909116815260200190565b5f5f83601f8401126132f6575f5ffd5b5081356001600160401b0381111561330c575f5ffd5b602083019150836020828501011115613323575f5ffd5b9250929050565b5f5f6020838503121561333b575f5ffd5b82356001600160401b03811115613350575f5ffd5b61335c858286016132e6565b90969095509350505050565b6001600160401b0391909116815260200190565b5f5f5f6040848603121561338e575f5ffd5b833561ffff8116811461339f575f5ffd5b925060208401356001600160401b038111156133b9575f5ffd5b6133c5868287016132e6565b9497909650939450505050565b80356001600160a01b03811681146133e8575f5ffd5b919050565b5f602082840312156133fd575f5ffd5b610261826133d2565b5f5f60408385031215613417575f5ffd5b82359150613427602084016133d2565b90509250929050565b634e487b7160e01b5f52602160045260245ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160401b03851681526001600160801b0319841660208201526001600160801b03831660408201526080606082018190525f906134b490830184613444565b9695505050505050565b6001600160401b03881681526001600160801b03198716602082015260e0604082018190525f906134f190830188613444565b82810360608401526135038188613444565b60ff969096166080840152505060a08101929092526001600160a01b031660c090910152949350505050565b6001600160401b0394851681526001600160801b03199390931660208401526001600160801b03919091166040830152909116606082015260800190565b6001600160401b03851681526001600160801b0319841660208201526080604082018190525f906135a090830185613444565b82810360608401526135b28185613444565b979650505050505050565b6001600160401b03841681526001600160801b0319831660208201526060604082018190525f906135f090830184613444565b95945050505050565b6001600160401b03851681526001600160801b0319841660208201526001600160a01b03831660408201526080606082018190525f906134b490830184613444565b6001600160401b03861681526001600160801b0319851660208201526001600160801b03841660408201526001600160a01b038316606082015260a081016003831061369557634e487b7160e01b5f52602160045260245ffd5b8260808301529695505050505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f60ff821660ff81036136e2576136e26136b9565b60010192915050565b634e487b7160e01b5f52604160045260245ffd5b60ff8281168282160390811115610264576102646136b9565b60ff8181168382160290811690818114613734576137346136b9565b5092915050565b80820180821115610264576102646136b9565b61ffff8181168382160190811115610264576102646136b956fea26469706673582212204ddc3189e664c8eacd053fd177c15840896bdc59375965b656c8c1e82211de9f64736f6c634300081c00330000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f00000000000000000000000094269dbaba605b63321221679df1356be0c00e630000000000000000000000005f3f8ea3b54bff7795de7754866e0eac52e0881d

Deployed Bytecode

0x608060405234801561000f575f5ffd5b50600436106100ad575f3560e01c806322285cf6146100b1578063268808c6146100da578063365a86fc146101015780633b514cf11461011457806347bfbcc6146101345780634f35b71c1461014757806365fae35e1461015c5780636c3be0ce1461016f5780639c52a7f114610195578063bf353dbb146101a8578063d4e8be83146101d5578063ebf0c717146101e8578063ed15d9601461020f575b5f5ffd5b6003546100c4906001600160a01b031681565b6040516100d191906132d2565b60405180910390f35b6100c47f00000000000000000000000094269dbaba605b63321221679df1356be0c00e6381565b6001546100c4906001600160a01b031681565b61012761012236600461332a565b610222565b6040516100d19190613368565b6002546100c4906001600160a01b031681565b61015a61015536600461337c565b61026a565b005b61015a61016a3660046133ed565b611535565b61018261017d36600461332a565b6115a8565b60405161ffff90911681526020016100d1565b61015a6101a33660046133ed565b6115e7565b6101c76101b63660046133ed565b5f6020819052908152604090205481565b6040519081526020016100d1565b61015a6101e3366004613406565b611659565b6100c47f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f81565b6004546100c4906001600160a01b031681565b5f61026183838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506117a892505050565b90505b92915050565b335f908152602081905260409020546001146102995760405163ea8e4eb560e01b815260040160405180910390fd5b5f6102d883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506117e192505050565b90505f61031984848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061180092505050565b905061ffff8116158061033357508461ffff168161ffff16145b61035057604051639284b19760e01b815260040160405180910390fd5b600182602281111561036457610364613430565b03610434575f6103a885858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506118b192505050565b90507f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f6001600160a01b0316633b6874616103e5835f0151611919565b6040518263ffffffff1660e01b815260040161040191906132d2565b5f604051808303815f87803b158015610418575f5ffd5b505af115801561042a573d5f5f3e3d5ffd5b505050505061152e565b600282602281111561044857610448613430565b036104c9575f61048c85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061197392505050565b90507f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f6001600160a01b03166311fd3baa6103e5835f0151611919565b60038260228111156104dd576104dd613430565b036105ce575f61052185858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061198892505050565b90507f00000000000000000000000094269dbaba605b63321221679df1356be0c00e636001600160a01b031663109037c061055e835f0151611919565b61056b8460200151611919565b846040015161057d8660600151611919565b608087015160405160e087901b6001600160e01b03191681526001600160a01b039586166004820152938516602485015260448401929092529092166064820152608481019190915260a401610401565b60048260228111156105e2576105e2613430565b03610670575f61062685858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611a4692505050565b60015481516020830151604051633207adab60e01b81526001600160801b03909216600483015260ff1660248201529192506001600160a01b031690633207adab90604401610401565b602082602281111561068457610684613430565b0361070e575f6106c885858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611acd92505050565b6001548151602083015160408085015160608601519151632f6c33bf60e01b81529596506001600160a01b0390941694632f6c33bf946104019493929091600401613472565b601082602281111561072257610722613430565b036107cd57600254604080516020601f87018190048102820181019092528581526001600160a01b0390921691632b89610191610779919088908890819084018382808284375f92019190915250611bae92505050565b516040516001600160e01b031960e084901b16815261079b9190600401613368565b5f604051808303815f87803b1580156107b2575f5ffd5b505af11580156107c4573d5f5f3e3d5ffd5b5050505061152e565b60118260228111156107e1576107e1613430565b03610891575f61082585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611c1e92505050565b60025481516020830151604084015160608501519495506001600160a01b0390931693636ea6e0a1939061085890611d3f565b86608001518760a0015161086f8960c00151611919565b6040518863ffffffff1660e01b815260040161040197969594939291906134be565b60128260228111156108a5576108a5613430565b0361092f575f6108e985858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611e6a92505050565b6002548151602083015160408085015160608601519151634869ac6960e01b81529596506001600160a01b0390941694634869ac6994610401949392909160040161352f565b601382602281111561094357610943613430565b03610a08575f61098785858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611f2b92505050565b60025481516020830151604080850151606086015160808701519251633a4ba8bf60e01b81526001600160401b0395861660048201526001600160801b031990941660248501526001600160801b0391821660448501521660648301529190911660848201529192506001600160a01b031690633a4ba8bf9060a401610401565b6014826022811115610a1c57610a1c613430565b03610ab2575f610a6085858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061200b92505050565b60025481516020830151604084015160608501519495506001600160a01b039093169363931efb549390610a9390611d3f565b6040518563ffffffff1660e01b8152600401610401949392919061356d565b6015826022811115610ac657610ac6613430565b03610b83575f610b0a85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506120c892505050565b6002548151602083015160408401519394506001600160a01b039092169263fb59077a9290610b3890611919565b6040516001600160e01b031960e086901b1681526001600160401b0390931660048401526001600160801b031990911660248301526001600160a01b03166044820152606401610401565b6016826022811115610b9757610b97613430565b03610c6a575f610bdb85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061216892505050565b600154604082810151835160208501516060860151608087015160a0880151955163ecca8cf760e01b815261ffff90951660048601526001600160401b0390931660248501526001600160801b0319909116604484015260648301526001600160801b03908116608483015290911660a48201529192506001600160a01b03169063ecca8cf79060c401610401565b6017826022811115610c7e57610c7e613430565b03610d35575f610cc285858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061226b92505050565b600254815160208301516040808501516060860151915163bccbfa8960e01b81526001600160401b0390941660048501526001600160801b0319909216602484015260448301919091526001600160801b031660648201529192506001600160a01b03169063bccbfa8990608401610401565b6018826022811115610d4957610d49613430565b03610dcc575f610d8d85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061232292505050565b600254815160208301516040808501519051630f8dad5d60e11b81529495506001600160a01b0390931693631f1b5aba936104019392916004016135bd565b6019826022811115610de057610de0613430565b03610e76575f610e2485858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506123dc92505050565b6004548151602083015160408401519394506001600160a01b0390921692630b1271059290610e5290611919565b85606001516040518563ffffffff1660e01b815260040161040194939291906135f9565b6021826022811115610e8a57610e8a613430565b03610f14575f610ece85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506124ad92505050565b60025481516020830151604080850151606086015191516336c6cf3760e21b81529596506001600160a01b039094169463db1b3cdc946104019493929091600401613472565b601a826022811115610f2857610f28613430565b03610fd8575f610f6c85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506124d692505050565b60025481516020830151604084015160608501519495506001600160a01b039093169363b3cfb8179390610f9f90611919565b866080015160ff166002811115610fb857610fb8613430565b6040518663ffffffff1660e01b815260040161040195949392919061363b565b6022826022811115610fec57610fec613430565b036110bc575f61103085858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506125ad92505050565b60025481516020830151604084015160608501519495506001600160a01b03909316936325dc4956939061106390611919565b6040516001600160e01b031960e087901b1681526001600160401b0390941660048501526001600160801b031990921660248401526001600160801b031660448301526001600160a01b03166064820152608401610401565b601b8260228111156110d0576110d0613430565b03611185575f61111485858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061266d92505050565b600354815160208301519293506001600160a01b039091169163a6fd509b919061113d90611919565b60408086015190516001600160e01b031960e086901b1681526001600160401b0390931660048401526001600160a01b03909116602483015215156044820152606401610401565b601c82602281111561119957611199613430565b036112b1575f6111dd85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061270d92505050565b905060015f9054906101000a90046001600160a01b03166001600160a01b0316630646affc87835f015184602001518560400151866060015187608001518860c001518960e001518a61010001516040518a63ffffffff1660e01b81526004016104019998979695949392919061ffff9990991689526001600160401b0397881660208a01526001600160801b03199690961660408901526001600160801b0394851660608901529284166080880152921660a086015290151560c0850152151560e0840152166101008201526101200190565b601d8260228111156112c5576112c5613430565b036113a1575f61130985858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061288692505050565b60015481516020830151604080850151608086015160a087015160c08801519351631de0563360e21b815261ffff8f1660048201526001600160401b0396871660248201526001600160801b031990951660448601526001600160801b03909216606485015215156084840152151560a48301529190911660c48201529192506001600160a01b03169063778158cc9060e401610401565b601e8260228111156113b5576113b5613430565b0361143f575f6113f985858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061299892505050565b6002548151602083015160408085015160608601519151636a4873e160e11b81529596506001600160a01b039094169463d490e7c294610401949392909160040161352f565b601f82602281111561145357611453613430565b036114f8575f61149785858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506129c292505050565b60025481516020830151604080850151905163eece6c4360e01b81526001600160401b0393841660048201526001600160801b031990921660248301529190911660448201529192506001600160a01b03169063eece6c4390606401610401565b81602281111561150a5761150a613430565b604051630391465960e11b815260ff90911660048201526024015b60405180910390fd5b5050505050565b335f908152602081905260409020546001146115645760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b5f61026183838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612a6292505050565b335f908152602081905260409020546001146116165760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b335f908152602081905260409020546001146116885760405163ea8e4eb560e01b815260040160405180910390fd5b8162343ab160e91b036116b557600180546001600160a01b0319166001600160a01b03831617905561176c565b816473706f6b6560d81b036116e457600280546001600160a01b0319166001600160a01b03831617905561176c565b816b18985b185b98d954da19595d60a21b0361171a57600380546001600160a01b0319166001600160a01b03831617905561176c565b816e31b7b73a3930b1ba2ab83230ba32b960891b0361175357600480546001600160a01b0319166001600160a01b03831617905561176c565b604051633db0d5b960e01b815260040160405180910390fd5b817f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba8260405161179c91906132d2565b60405180910390a25050565b5f806117b48382612f58565b9050601060ff8216106117d3576117cc836001612f8e565b9392505050565b505f92915050565b50919050565b5f6117ec8282612f58565b60ff16602281111561026457610264613430565b5f8061180c8382612f58565b9050600360ff82161161182157505f92915050565b60ff8116601d1480611836575060ff81166016145b1561184357505f92915050565b60031960ff821601611867576117cc61185d846001612fc4565b60701c61ffff1690565b601b1960ff821601611881576117cc61185d846019612fc4565b601f1960ff82160161189b576117cc61185d846019612fc4565b6117cc6118a7846117a8565b60301c61ffff1690565b60408051602081019091525f815260015b6118cb836117e1565b60228111156118dc576118dc613430565b146118fa576040516304c735eb60e11b815260040160405180910390fd5b604080516020810190915280611911846001612ffa565b905292915050565b5f6001600160601b0382161561196c5760405162461bcd60e51b8152602060048201526018602482015277496e7075742073686f756c6420626520323020627974657360401b6044820152606401611525565b5060601c90565b60408051602081019091525f815260026118c2565b6119b56040518060a001604052805f81526020015f81526020015f81526020015f81526020015f81525090565b60036119c0836117e1565b60228111156119d1576119d1613430565b146119ef576040516304c735eb60e11b815260040160405180910390fd5b6040805160a0810190915280611a06846001612ffa565b8152602001611a16846021612ffa565b8152602001611a26846041612ffa565b8152602001611a36846061612ffa565b8152602001611911846081612ffa565b604080518082019091525f80825260208201526004611a64836117e1565b6022811115611a7557611a75613430565b14611a93576040516304c735eb60e11b815260040160405180910390fd5b6040805180820190915280611aa9846001612fc4565b6001600160801b03168152602001611ac2846011612f58565b60ff16905292915050565b604080516080810182525f808252602080830182905292820152606080820152905b611af8836117e1565b6022811115611b0957611b09613430565b14611b27576040516304c735eb60e11b815260040160405180910390fd5b5f611b33836029613030565b90506040518060800160405280611b54600186612f8e90919063ffffffff16565b6001600160401b03168152602001611b6d856009613066565b6001600160801b0319168152602001611b87856019612fc4565b6001600160801b03168152602001611ba585602b61ffff8616613072565b90529392505050565b60408051602081019091525f81526010611bc7836117e1565b6022811115611bd857611bd8613430565b14611bf6576040516304c735eb60e11b815260040160405180910390fd5b604080516020810190915280611c0d846001612f8e565b6001600160401b0316905292915050565b611c6e6040518060e001604052805f6001600160401b031681526020015f6001600160801b0319168152602001606081526020015f81526020015f60ff1681526020015f81526020015f81525090565b6011611c79836117e1565b6022811115611c8a57611c8a613430565b14611ca8576040516304c735eb60e11b815260040160405180910390fd5b6040805160e0810190915280611cbf846001612f8e565b6001600160401b03168152602001611cd8846009613066565b6001600160801b0319168152602001611cfc611cf78560196080613072565b613134565b8152602001611d0c846099612ffa565b8152602001611d1c8460b9612f58565b60ff168152602001611d2f8460ba612ffa565b81526020016119118460da612ffa565b60605f5b60208160ff16108015611d775750828160ff1660208110611d6657611d666136a5565b1a60f81b6001600160f81b03191615155b15611d8e5780611d86816136cd565b915050611d43565b5f8160ff166001600160401b03811115611daa57611daa6136eb565b6040519080825280601f01601f191660200182016040528015611dd4576020820181803683370190505b5090505f91505b60208260ff16108015611e0f5750838260ff1660208110611dfe57611dfe6136a5565b1a60f81b6001600160f81b03191615155b156117cc57838260ff1660208110611e2957611e296136a5565b1a60f81b818360ff1681518110611e4257611e426136a5565b60200101906001600160f81b03191690815f1a90535081611e62816136cd565b925050611ddb565b604080516080810182525f80825260208201819052918101829052606081019190915260125b611e99836117e1565b6022811115611eaa57611eaa613430565b14611ec8576040516304c735eb60e11b815260040160405180910390fd5b604080516080810190915280611edf846001612f8e565b6001600160401b03168152602001611ef8846009613066565b6001600160801b0319168152602001611f12846019612fc4565b6001600160801b03168152602001611c0d846029612f8e565b6040805160a0810182525f808252602082018190529181018290526060810182905260808101919091526013611f60836117e1565b6022811115611f7157611f71613430565b14611f8f576040516304c735eb60e11b815260040160405180910390fd5b6040805160a0810190915280611fa6846001612f8e565b6001600160401b03168152602001611fbf846009613066565b6001600160801b0319168152602001611fd9846019612fc4565b6001600160801b03168152602001611ff2846029612fc4565b6001600160801b03168152602001611c0d846039612f8e565b604080516080810182525f80825260208201819052606092820183905291810191909152601461203a836117e1565b602281111561204b5761204b613430565b14612069576040516304c735eb60e11b815260040160405180910390fd5b604080516080810190915280612080846001612f8e565b6001600160401b03168152602001612099846009613066565b6001600160801b03191681526020016120b8611cf78560196080613072565b8152602001611911846099612ffa565b604080516060810182525f808252602082018190529181019190915260156120ef836117e1565b602281111561210057612100613430565b1461211e576040516304c735eb60e11b815260040160405180910390fd5b604080516060810190915280612135846001612f8e565b6001600160401b0316815260200161214e846009613066565b6001600160801b0319168152602001611911846019612ffa565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a081019190915260166121a4836117e1565b60228111156121b5576121b5613430565b146121d3576040516304c735eb60e11b815260040160405180910390fd5b6040805160c08101909152806121ea846001612f8e565b6001600160401b03168152602001612203846009613066565b6001600160801b031916815260200161221d846019613030565b61ffff16815260200161223184601b612ffa565b815260200161224184603b612fc4565b6001600160801b0316815260200161225a84604b612fc4565b6001600160801b0316905292915050565b604080516080810182525f8082526020820181905291810182905260608101919091526017612299836117e1565b60228111156122aa576122aa613430565b146122c8576040516304c735eb60e11b815260040160405180910390fd5b6040805160808101909152806122df846001612f8e565b6001600160401b031681526020016122f8846009613066565b6001600160801b0319168152602001612312846019612ffa565b815260200161225a846039612fc4565b60408051606080820183525f8083526020830152918101919091526018612348836117e1565b602281111561235957612359613430565b14612377576040516304c735eb60e11b815260040160405180910390fd5b5f612383836019613030565b905060405180606001604052806123a4600186612f8e90919063ffffffff16565b6001600160401b031681526020016123bd856009613066565b6001600160801b0319168152602001611ba585601b61ffff8616613072565b604080516080810182525f80825260208201819052918101919091526060808201526019612409836117e1565b602281111561241a5761241a613430565b14612438576040516304c735eb60e11b815260040160405180910390fd5b5f612444836039613030565b90506040518060800160405280612465600186612f8e90919063ffffffff16565b6001600160401b0316815260200161247e856009613066565b6001600160801b0319168152602001612498856019612ffa565b8152602001611ba585603b61ffff8616613072565b604080516080810182525f80825260208201819052918101919091526060808201526021611aef565b6040805160a0810182525f80825260208201819052918101829052606081018290526080810191909152601a61250b836117e1565b602281111561251c5761251c613430565b1461253a576040516304c735eb60e11b815260040160405180910390fd5b6040805160a0810190915280612551846001612f8e565b6001600160401b0316815260200161256a846009613066565b6001600160801b0319168152602001612584846019612fc4565b6001600160801b0316815260200161259d846029612ffa565b8152602001611ac2846049612f58565b604080516080810182525f80825260208201819052918101829052606081019190915260226125db836117e1565b60228111156125ec576125ec613430565b1461260a576040516304c735eb60e11b815260040160405180910390fd5b604080516080810190915280612621846001612f8e565b6001600160401b0316815260200161263a846009613066565b6001600160801b0319168152602001612654846019612fc4565b6001600160801b03168152602001611911846029612ffa565b604080516060810182525f8082526020820181905291810191909152601b612694836117e1565b60228111156126a5576126a5613430565b146126c3576040516304c735eb60e11b815260040160405180910390fd5b6040805160608101909152806126da846001612f8e565b6001600160401b031681526020016126f3846009612ffa565b8152602001612703846029613285565b1515905292915050565b60408051610120810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810191909152601c612760836117e1565b602281111561277157612771613430565b146127b35760405162461bcd60e51b8152602060048201526012602482015271556e6b6e6f776e4d6573736167655479706560701b6044820152606401611525565b604080516101208101909152806127cb846001612f8e565b6001600160401b031681526020016127e4846009613066565b6001600160801b03191681526020016127fe846019612fc4565b6001600160801b03168152602001612817846029612fc4565b6001600160801b03168152602001612830846039612fc4565b6001600160801b03168152602001612849846049612f8e565b6001600160401b03168152602001612862846051613285565b15158152602001612874846052613285565b15158152602001611c0d846053612f8e565b6040805160e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152601d6128c9836117e1565b60228111156128da576128da613430565b146128f8576040516304c735eb60e11b815260040160405180910390fd5b6040805160e081019091528061290f846001612f8e565b6001600160401b03168152602001612928846009613066565b6001600160801b0319168152602001612942846019612fc4565b6001600160801b0316815260200161295b846029612f8e565b6001600160401b03168152602001612974846031613285565b15158152602001612986846032613285565b15158152602001611c0d846033612f8e565b604080516080810182525f808252602082018190529181018290526060810191909152601e611e90565b604080516060810182525f8082526020820181905291810191909152601f6129e9836117e1565b60228111156129fa576129fa613430565b14612a18576040516304c735eb60e11b815260040160405180910390fd5b604080516060810190915280612a2f846001612f8e565b6001600160401b03168152602001612a48846009613066565b6001600160801b0319168152602001611c0d846019612f8e565b5f80612a6e8382612f58565b9050602260ff82161115612a95576040516304c735eb60e11b815260040160405180910390fd5b601f8160ff161115612b3657612aad602060226136ff565b612ab8906008613718565b604960ff919091161b612acd602060216136ff565b612ad8906008613718565b602960ff919091161b612aec6020806136ff565b612af7906008613718565b60ff166029901b612b08919061373b565b612b12919061373b565b612b1d82603f6136ff565b60ff1660208110612b3057612b306136a5565b1a612ebd565b612b42601f6008613718565b602160ff919091161b612b57601e6008613718565b603160ff919091161b612b6c601d6008613718565b603b60ff919091161b612b81601c6008613718565b605b60ff919091161b612b96601b6008613718565b602a60ff919091161b612bab601a6008613718565b604a60ff919091161b612bc060196008613718565b603960ff919091161b612bd560186008613718565b601960ff919091161b612bea60176008613718565b604960ff919091161b612bff60166008613718565b605b60ff919091161b612c1460156008613718565b603960ff919091161b612c2960146008613718565b60b960ff919091161b612c3e60136008613718565b604160ff919091161b612c5360126008613718565b603160ff919091161b612c6860116008613718565b60fa60ff919091161b612c7d60106008613718565b600960ff919091161b612c92600f6008613718565b505f612ca0600e6008613718565b505f612cae600d6008613718565b505f612cbc600c6008613718565b505f612cca600b6008613718565b505f612cd8600a6008613718565b505f612ce660096008613718565b505f612cf3600880613718565b505f612d0160076008613718565b505f612d0f60066008613718565b505f612d1d60056008613718565b505f612d2b60046008613718565b601260ff919091161b612d4060036008613718565b60a160ff919091161b612d5560026008613718565b602160ff919091161b612d6a60016008613718565b60ff166021901b612d7b919061373b565b612d85919061373b565b612d8f919061373b565b612d99919061373b565b612da3919061373b565b612dad919061373b565b612db7919061373b565b612dc1919061373b565b612dcb919061373b565b612dd5919061373b565b612ddf919061373b565b612de9919061373b565b612df3919061373b565b612dfd919061373b565b612e07919061373b565b612e11919061373b565b612e1b919061373b565b612e25919061373b565b612e2f919061373b565b612e39919061373b565b612e43919061373b565b612e4d919061373b565b612e57919061373b565b612e61919061373b565b612e6b919061373b565b612e75919061373b565b612e7f919061373b565b612e89919061373b565b612e93919061373b565b612e9d919061373b565b612ea882601f6136ff565b60ff1660208110612ebb57612ebb6136a5565b1a5b915060171960ff821601612ef557612ed98361ffff8416613030565b612ee490600261374e565b612eee908361374e565b91506117db565b60181960ff821601612f0f57612ed98361ffff8416613030565b601f1960ff821601612f2957612ed98361ffff8416613030565b60201960ff8216016117db57612f438361ffff8416613030565b612f4e90600261374e565b6117cc908361374e565b5f612f6482600161373b565b83511015612f8557604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f612f9a82600861373b565b83511015612fbb57604051633b99b53d60e01b815260040160405180910390fd5b50016008015190565b5f612fd082601061373b565b83511015612ff157604051633b99b53d60e01b815260040160405180910390fd5b50016010015190565b5f61300682602061373b565b8351101561302757604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f61303c82600261373b565b8351101561305d57604051633b99b53d60e01b815260040160405180910390fd5b50016002015190565b5f61300682601061373b565b60608182601f011015613098576040516323d5783d60e11b815260040160405180910390fd5b6130a2828461373b565b845110156130c357604051633b99b53d60e01b815260040160405180910390fd5b6060821580156130e15760405191505f82526020820160405261312b565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561311a578051835260209283019201613102565b5050858452601f01601f1916604052505b50949350505050565b606081516080146131835760405162461bcd60e51b8152602060048201526019602482015278496e7075742073686f756c642062652031323820627974657360381b6044820152606401611525565b5f5b60808160ff161080156131ba5750828160ff16815181106131a8576131a86136a5565b01602001516001600160f81b03191615155b156131d157806131c9816136cd565b915050613185565b5f8160ff166001600160401b038111156131ed576131ed6136eb565b6040519080825280601f01601f191660200182016040528015613217576020820181803683370190505b5090505f5b8260ff168160ff16101561327d57848160ff168151811061323f5761323f6136a5565b602001015160f81c60f81b828260ff168151811061325f5761325f6136a5565b60200101906001600160f81b03191690815f1a90535060010161321c565b509392505050565b5f818351116132a757604051633b99b53d60e01b815260040160405180910390fd5b8282815181106132b9576132b96136a5565b01602001516001600160f81b0319161515905092915050565b6001600160a01b0391909116815260200190565b5f5f83601f8401126132f6575f5ffd5b5081356001600160401b0381111561330c575f5ffd5b602083019150836020828501011115613323575f5ffd5b9250929050565b5f5f6020838503121561333b575f5ffd5b82356001600160401b03811115613350575f5ffd5b61335c858286016132e6565b90969095509350505050565b6001600160401b0391909116815260200190565b5f5f5f6040848603121561338e575f5ffd5b833561ffff8116811461339f575f5ffd5b925060208401356001600160401b038111156133b9575f5ffd5b6133c5868287016132e6565b9497909650939450505050565b80356001600160a01b03811681146133e8575f5ffd5b919050565b5f602082840312156133fd575f5ffd5b610261826133d2565b5f5f60408385031215613417575f5ffd5b82359150613427602084016133d2565b90509250929050565b634e487b7160e01b5f52602160045260245ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160401b03851681526001600160801b0319841660208201526001600160801b03831660408201526080606082018190525f906134b490830184613444565b9695505050505050565b6001600160401b03881681526001600160801b03198716602082015260e0604082018190525f906134f190830188613444565b82810360608401526135038188613444565b60ff969096166080840152505060a08101929092526001600160a01b031660c090910152949350505050565b6001600160401b0394851681526001600160801b03199390931660208401526001600160801b03919091166040830152909116606082015260800190565b6001600160401b03851681526001600160801b0319841660208201526080604082018190525f906135a090830185613444565b82810360608401526135b28185613444565b979650505050505050565b6001600160401b03841681526001600160801b0319831660208201526060604082018190525f906135f090830184613444565b95945050505050565b6001600160401b03851681526001600160801b0319841660208201526001600160a01b03831660408201526080606082018190525f906134b490830184613444565b6001600160401b03861681526001600160801b0319851660208201526001600160801b03841660408201526001600160a01b038316606082015260a081016003831061369557634e487b7160e01b5f52602160045260245ffd5b8260808301529695505050505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f60ff821660ff81036136e2576136e26136b9565b60010192915050565b634e487b7160e01b5f52604160045260245ffd5b60ff8281168282160390811115610264576102646136b9565b60ff8181168382160290811690818114613734576137346136b9565b5092915050565b80820180821115610264576102646136b9565b61ffff8181168382160190811115610264576102646136b956fea26469706673582212204ddc3189e664c8eacd053fd177c15840896bdc59375965b656c8c1e82211de9f64736f6c634300081c0033

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

0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f00000000000000000000000094269dbaba605b63321221679df1356be0c00e630000000000000000000000005f3f8ea3b54bff7795de7754866e0eac52e0881d

-----Decoded View---------------
Arg [0] : root_ (address): 0x7Ed48C31f2fdC40d37407cBaBf0870B2b688368f
Arg [1] : tokenRecoverer_ (address): 0x94269dBaBA605b63321221679df1356be0c00E63
Arg [2] : deployer (address): 0x5f3f8ea3b54BFF7795dE7754866e0Eac52e0881d

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f
Arg [1] : 00000000000000000000000094269dbaba605b63321221679df1356be0c00e63
Arg [2] : 0000000000000000000000005f3f8ea3b54bff7795de7754866e0eac52e0881d


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

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.