ETH Price: $2,086.31 (-0.81%)

Contract

0xc52Bd1Bdfa0135147D3F01a0B6D6cd0A831dFe77
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Multicall246495832026-03-13 15:56:3529 hrs ago1773417395IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000195570.54905201
Approve Deposits246492322026-03-13 14:45:5931 hrs ago1773413159IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000193030.89917755
Multicall246491632026-03-13 14:32:1131 hrs ago1773412331IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000298060.78643308
Multicall246435372026-03-12 19:40:472 days ago1773344447IN
0xc52Bd1Bd...A831dFe77
0.00065707 ETH0.000063340.0892864
Multicall246433182026-03-12 18:56:592 days ago1773341819IN
0xc52Bd1Bd...A831dFe77
0.00065707 ETH0.000131080.18476288
Approve Deposits246433172026-03-12 18:56:472 days ago1773341807IN
0xc52Bd1Bd...A831dFe77
0.00052673 ETH0.000116940.18591862
Approve Deposits246428452026-03-12 17:22:112 days ago1773336131IN
0xc52Bd1Bd...A831dFe77
0.00052673 ETH0.000164850.26207945
Approve Deposits246428452026-03-12 17:22:112 days ago1773336131IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000056310.26231853
Multicall246426072026-03-12 16:34:112 days ago1773333251IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000077830.17509897
Approve Deposits246364152026-03-11 19:48:473 days ago1773258527IN
0xc52Bd1Bd...A831dFe77
0.00016397 ETH0.000072140.10460255
Approve Deposits246352212026-03-11 15:48:593 days ago1773244139IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000071280.33207775
Multicall246351812026-03-11 15:40:353 days ago1773243635IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000163320.35384028
Multicall246341802026-03-11 12:18:473 days ago1773231527IN
0xc52Bd1Bd...A831dFe77
0.00065707 ETH0.000194580.27205097
Multicall246341372026-03-11 12:09:593 days ago1773230999IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000226660.29906152
Approve Deposits246276552026-03-10 14:26:594 days ago1773152819IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000082640.32493018
Multicall246276542026-03-10 14:26:474 days ago1773152807IN
0xc52Bd1Bd...A831dFe77
0.00065707 ETH0.000206730.28904448
Multicall246276542026-03-10 14:26:474 days ago1773152807IN
0xc52Bd1Bd...A831dFe77
0.00065707 ETH0.00020490.28879948
Approve Deposits246273022026-03-10 13:15:114 days ago1773148511IN
0xc52Bd1Bd...A831dFe77
0.00052673 ETH0.00004480.07123788
Approve Redeems246273012026-03-10 13:14:594 days ago1773148499IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000006080.07195473
Approve Redeems246273002026-03-10 13:14:474 days ago1773148487IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000006180.07313159
Multicall246225742026-03-09 21:23:235 days ago1773091403IN
0xc52Bd1Bd...A831dFe77
0.00002217 ETH0.000037230.05349548
Approve Deposits246225472026-03-09 21:17:595 days ago1773091079IN
0xc52Bd1Bd...A831dFe77
0.00001985 ETH0.000036320.05900677
Multicall246216442026-03-09 18:15:475 days ago1773080147IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000051890.11200426
Approve Redeems246215962026-03-09 18:06:115 days ago1773079571IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000012260.14496739
Approve Redeems246214592026-03-09 17:38:355 days ago1773077915IN
0xc52Bd1Bd...A831dFe77
0 ETH0.000011280.1334973
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
With Batch246501332026-03-13 17:47:1128 hrs ago1773424031
0xc52Bd1Bd...A831dFe77
0.00016892 ETH
Multicall246501332026-03-13 17:47:1128 hrs ago1773424031
0xc52Bd1Bd...A831dFe77
0.00016892 ETH
With Batch246435372026-03-12 19:40:472 days ago1773344447
0xc52Bd1Bd...A831dFe77
0.00065707 ETH
With Batch246433182026-03-12 18:56:592 days ago1773341819
0xc52Bd1Bd...A831dFe77
0.00065707 ETH
Request Callback246433172026-03-12 18:56:472 days ago1773341807
0xc52Bd1Bd...A831dFe77
0.00052673 ETH
Request Callback246428452026-03-12 17:22:112 days ago1773336131
0xc52Bd1Bd...A831dFe77
0.00052673 ETH
Request Callback246364152026-03-11 19:48:473 days ago1773258527
0xc52Bd1Bd...A831dFe77
0.00016397 ETH
Request Callback246360292026-03-11 18:31:113 days ago1773253871
0xc52Bd1Bd...A831dFe77
0.00016397 ETH
Approve Deposits246360292026-03-11 18:31:113 days ago1773253871
0xc52Bd1Bd...A831dFe77
0.00016397 ETH
With Batch246341802026-03-11 12:18:473 days ago1773231527
0xc52Bd1Bd...A831dFe77
0.00065707 ETH
With Batch246276542026-03-10 14:26:474 days ago1773152807
0xc52Bd1Bd...A831dFe77
0.00065707 ETH
With Batch246276542026-03-10 14:26:474 days ago1773152807
0xc52Bd1Bd...A831dFe77
0.00065707 ETH
Request Callback246273022026-03-10 13:15:114 days ago1773148511
0xc52Bd1Bd...A831dFe77
0.00052673 ETH
With Batch246225742026-03-09 21:23:235 days ago1773091403
0xc52Bd1Bd...A831dFe77
0.00002217 ETH
Request Callback246225472026-03-09 21:17:595 days ago1773091079
0xc52Bd1Bd...A831dFe77
0.00001985 ETH
With Batch245994482026-03-06 15:55:478 days ago1772812547
0xc52Bd1Bd...A831dFe77
0.00014952 ETH
Multicall245994482026-03-06 15:55:478 days ago1772812547
0xc52Bd1Bd...A831dFe77
0.00014952 ETH
With Batch245993482026-03-06 15:35:358 days ago1772811335
0xc52Bd1Bd...A831dFe77
0.00016851 ETH
Multicall245993482026-03-06 15:35:358 days ago1772811335
0xc52Bd1Bd...A831dFe77
0.00016851 ETH
Request Callback245992682026-03-06 15:19:238 days ago1772810363
0xc52Bd1Bd...A831dFe77
0.000162 ETH
Approve Deposits245992682026-03-06 15:19:238 days ago1772810363
0xc52Bd1Bd...A831dFe77
0.000162 ETH
With Batch245855792026-03-04 17:26:2310 days ago1772645183
0xc52Bd1Bd...A831dFe77
0.00022756 ETH
Multicall245855792026-03-04 17:26:2310 days ago1772645183
0xc52Bd1Bd...A831dFe77
0.00022756 ETH
Request Callback245853112026-03-04 16:32:3510 days ago1772641955
0xc52Bd1Bd...A831dFe77
0.00021339 ETH
Approve Deposits245853112026-03-04 16:32:3510 days ago1772641955
0xc52Bd1Bd...A831dFe77
0.00021339 ETH
View All Internal Transactions
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

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

Contract Source Code Verified (Exact Match)

Contract Name:
BatchRequestManager

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 {RequestCallbackMessageLib} from "./libraries/RequestCallbackMessageLib.sol";
import {RequestMessageLib, RequestType as RequestMessageType} from "./libraries/RequestMessageLib.sol";
import {
    IBatchRequestManager,
    EpochInvestAmounts,
    EpochRedeemAmounts,
    UserOrder,
    QueuedOrder,
    RequestType,
    EpochId
} from "./interfaces/IBatchRequestManager.sol";

import {Auth} from "../misc/Auth.sol";
import {D18, d18} from "../misc/types/D18.sol";
import {IAuth} from "../misc/interfaces/IAuth.sol";
import {CastLib} from "../misc/libraries/CastLib.sol";
import {MathLib} from "../misc/libraries/MathLib.sol";
import {IERC165} from "../misc/interfaces/IERC165.sol";
import {BytesLib} from "../misc/libraries/BytesLib.sol";

import {PoolId} from "../core/types/PoolId.sol";
import {AssetId} from "../core/types/AssetId.sol";
import {PricingLib} from "../core/libraries/PricingLib.sol";
import {ShareClassId} from "../core/types/ShareClassId.sol";
import {IGateway} from "../core/messaging/interfaces/IGateway.sol";
import {BatchedMulticall} from "../core/utils/BatchedMulticall.sol";
import {IHubRegistry} from "../core/hub/interfaces/IHubRegistry.sol";
import {IHubRequestManagerCallback} from "../core/hub/interfaces/IHubRequestManagerCallback.sol";
import {IHubRequestManager, IHubRequestManagerNotifications} from "../core/hub/interfaces/IHubRequestManager.sol";

/// @title  Batch Request Manager
/// @notice Manager for handling deposit/redeem requests, epochs, and fulfillment logic for share classes
contract BatchRequestManager is Auth, BatchedMulticall, IBatchRequestManager {
    using MathLib for *;
    using CastLib for *;
    using BytesLib for bytes;
    using RequestMessageLib for *;
    using RequestCallbackMessageLib for *;

    IHubRequestManagerCallback public hub;
    IHubRegistry public immutable hubRegistry;

    // Epochs
    mapping(PoolId => mapping(ShareClassId => mapping(AssetId => EpochId))) public epochId;
    mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(uint32 epochId_ => EpochInvestAmounts))))
        public epochInvestAmounts;
    mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(uint32 epochId_ => EpochRedeemAmounts))))
        public epochRedeemAmounts;

    // Pending requests
    mapping(PoolId => mapping(ShareClassId => mapping(AssetId => uint128))) public pendingRedeem;
    mapping(PoolId => mapping(ShareClassId => mapping(AssetId => uint128))) public pendingDeposit;
    mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(bytes32 investor => UserOrder)))) public
        redeemRequest;
    mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(bytes32 investor => UserOrder)))) public
        depositRequest;

    // Queued requests
    mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(bytes32 investor => QueuedOrder)))) public
        queuedRedeemRequest;
    mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(bytes32 investor => QueuedOrder)))) public
        queuedDepositRequest;

    // Force cancel request safeguards
    mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(bytes32 investor => bool)))) public
        allowForceDepositCancel;
    mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(bytes32 investor => bool)))) public
        allowForceRedeemCancel;

    constructor(IHubRegistry hubRegistry_, IGateway gateway_, address deployer)
        Auth(deployer)
        BatchedMulticall(gateway_)
    {
        hubRegistry = hubRegistry_;
    }

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

    /// Accepts a `bytes32` representation of 'hub'
    function file(bytes32 what, address data) external auth {
        if (what == "hub") hub = IHubRequestManagerCallback(data);
        else revert FileUnrecognizedParam();

        emit File(what, data);
    }

    modifier isManager(PoolId poolId) {
        require(hubRegistry.manager(poolId, msgSender()), IAuth.NotAuthorized());
        _;
    }

    /// @dev used only for migrations
    function setEpochIds(PoolId poolId, ShareClassId scId, AssetId assetId, EpochId memory epochIdData) external auth {
        epochId[poolId][scId][assetId] = epochIdData;
        emit EpochIdModified(poolId, scId, assetId, epochIdData);
    }

    //----------------------------------------------------------------------------------------------
    // Incoming requests
    //----------------------------------------------------------------------------------------------

    /// @inheritdoc IHubRequestManager
    function request(PoolId poolId, ShareClassId scId, AssetId assetId, bytes calldata payload) external auth {
        uint8 kind = uint8(RequestMessageLib.requestType(payload));

        if (kind == uint8(RequestMessageType.DepositRequest)) {
            RequestMessageLib.DepositRequest memory m = payload.deserializeDepositRequest();
            requestDeposit(poolId, scId, m.amount, m.investor, assetId);
        } else if (kind == uint8(RequestMessageType.RedeemRequest)) {
            RequestMessageLib.RedeemRequest memory m = payload.deserializeRedeemRequest();
            requestRedeem(poolId, scId, m.amount, m.investor, assetId);
        } else if (kind == uint8(RequestMessageType.CancelDepositRequest)) {
            RequestMessageLib.CancelDepositRequest memory m = payload.deserializeCancelDepositRequest();
            uint128 cancelledAssetAmount = cancelDepositRequest(poolId, scId, m.investor, assetId);

            // Cancellation might have been queued such that it will be executed in the future during claiming
            if (cancelledAssetAmount > 0) {
                hub.requestCallback(
                    poolId,
                    scId,
                    assetId,
                    RequestCallbackMessageLib.FulfilledDepositRequest(m.investor, 0, 0, cancelledAssetAmount)
                        .serialize(),
                    0,
                    true,
                    address(0) // Refund is not used because we're in unpaid mode with no payment
                );
            }
        } else if (kind == uint8(RequestMessageType.CancelRedeemRequest)) {
            RequestMessageLib.CancelRedeemRequest memory m = payload.deserializeCancelRedeemRequest();
            uint128 cancelledShareAmount = cancelRedeemRequest(poolId, scId, m.investor, assetId);

            // Cancellation might have been queued such that it will be executed in the future during claiming
            if (cancelledShareAmount > 0) {
                hub.requestCallback(
                    poolId,
                    scId,
                    assetId,
                    RequestCallbackMessageLib.FulfilledRedeemRequest(m.investor, 0, 0, cancelledShareAmount)
                        .serialize(),
                    0,
                    true,
                    address(0) // Refund is not used because we're in unpaid mode with no payment
                );
            }
        } else {
            revert UnknownRequestType();
        }
    }

    /// @inheritdoc IBatchRequestManager
    function requestDeposit(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId depositAssetId)
        public
        auth
    {
        // NOTE: Vaults ensure amount > 0
        _updatePending(poolId, scId_, amount, true, investor, depositAssetId, RequestType.Deposit);
    }

    /// @inheritdoc IBatchRequestManager
    function cancelDepositRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)
        public
        auth
        returns (uint128 cancelledAssetAmount)
    {
        allowForceDepositCancel[poolId][scId_][depositAssetId][investor] = true;
        uint128 cancellingAmount = depositRequest[poolId][scId_][depositAssetId][investor].pending;

        return _updatePending(poolId, scId_, cancellingAmount, false, investor, depositAssetId, RequestType.Deposit);
    }

    /// @inheritdoc IBatchRequestManager
    function requestRedeem(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId payoutAssetId)
        public
        auth
    {
        // NOTE: Vaults ensure amount > 0
        _updatePending(poolId, scId_, amount, true, investor, payoutAssetId, RequestType.Redeem);
    }

    /// @inheritdoc IBatchRequestManager
    function cancelRedeemRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)
        public
        auth
        returns (uint128 cancelledShareAmount)
    {
        allowForceRedeemCancel[poolId][scId_][payoutAssetId][investor] = true;
        uint128 cancellingAmount = redeemRequest[poolId][scId_][payoutAssetId][investor].pending;

        return _updatePending(poolId, scId_, cancellingAmount, false, investor, payoutAssetId, RequestType.Redeem);
    }

    //----------------------------------------------------------------------------------------------
    // Manager actions
    //----------------------------------------------------------------------------------------------

    /// @inheritdoc IBatchRequestManager
    function approveDeposits(
        PoolId poolId,
        ShareClassId scId_,
        AssetId depositAssetId,
        uint32 nowDepositEpochId,
        uint128 approvedAssetAmount,
        D18 pricePoolPerAsset,
        address refund
    ) external payable isManager(poolId) {
        require(
            nowDepositEpochId == nowDepositEpoch(poolId, scId_, depositAssetId),
            EpochNotInSequence(nowDepositEpochId, nowDepositEpoch(poolId, scId_, depositAssetId))
        );

        // Limit in case approved > pending due to race condition of FM approval and async incoming requests
        uint128 pendingAssetAmount = pendingDeposit[poolId][scId_][depositAssetId];
        require(approvedAssetAmount <= pendingAssetAmount, InsufficientPending());
        require(approvedAssetAmount > 0, ZeroApprovalAmount());

        uint128 approvedPoolAmount = PricingLib.convertWithPrice(
            approvedAssetAmount, hubRegistry.decimals(depositAssetId), hubRegistry.decimals(poolId), pricePoolPerAsset
        );

        // Update epoch data
        EpochInvestAmounts storage epochAmounts = epochInvestAmounts[poolId][scId_][depositAssetId][nowDepositEpochId];
        epochAmounts.approvedAssetAmount = approvedAssetAmount;
        epochAmounts.approvedPoolAmount = approvedPoolAmount;
        epochAmounts.pendingAssetAmount = pendingAssetAmount;
        epochAmounts.pricePoolPerAsset = pricePoolPerAsset;

        // Reduce pending
        pendingDeposit[poolId][scId_][depositAssetId] -= approvedAssetAmount;
        pendingAssetAmount -= approvedAssetAmount;

        epochId[poolId][scId_][depositAssetId].deposit = nowDepositEpochId;
        emit ApproveDeposits(
            poolId,
            scId_,
            depositAssetId,
            nowDepositEpochId,
            approvedPoolAmount,
            approvedAssetAmount,
            pendingAssetAmount
        );

        bytes memory callback =
            RequestCallbackMessageLib.ApprovedDeposits(approvedAssetAmount, pricePoolPerAsset.raw()).serialize();
        hub.requestCallback{value: msgValue()}(poolId, scId_, depositAssetId, callback, 0, false, refund);
    }

    /// @inheritdoc IBatchRequestManager
    function approveRedeems(
        PoolId poolId,
        ShareClassId scId_,
        AssetId payoutAssetId,
        uint32 nowRedeemEpochId,
        uint128 approvedShareAmount,
        D18 pricePoolPerAsset
    ) external payable isManager(poolId) {
        require(
            nowRedeemEpochId == nowRedeemEpoch(poolId, scId_, payoutAssetId),
            EpochNotInSequence(nowRedeemEpochId, nowRedeemEpoch(poolId, scId_, payoutAssetId))
        );

        // Limit in case approved > pending due to race condition of FM approval and async incoming requests
        uint128 pendingShareAmount = pendingRedeem[poolId][scId_][payoutAssetId];
        require(approvedShareAmount <= pendingShareAmount, InsufficientPending());
        require(approvedShareAmount > 0, ZeroApprovalAmount());

        // Update epoch data
        EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[poolId][scId_][payoutAssetId][nowRedeemEpochId];
        epochAmounts.approvedShareAmount = approvedShareAmount;
        epochAmounts.pendingShareAmount = pendingShareAmount;
        epochAmounts.pricePoolPerAsset = pricePoolPerAsset;

        // Reduce pending
        pendingRedeem[poolId][scId_][payoutAssetId] -= approvedShareAmount;
        pendingShareAmount -= approvedShareAmount;
        epochId[poolId][scId_][payoutAssetId].redeem = nowRedeemEpochId;
        emit ApproveRedeems(poolId, scId_, payoutAssetId, nowRedeemEpochId, approvedShareAmount, pendingShareAmount);
    }

    /// @inheritdoc IBatchRequestManager
    function issueShares(
        PoolId poolId,
        ShareClassId scId_,
        AssetId depositAssetId,
        uint32 nowIssueEpochId,
        D18 pricePoolPerShare,
        uint128 extraGasLimit,
        address refund
    ) external payable isManager(poolId) {
        require(nowIssueEpochId <= epochId[poolId][scId_][depositAssetId].deposit, EpochNotFound());
        require(
            nowIssueEpochId == nowIssueEpoch(poolId, scId_, depositAssetId),
            EpochNotInSequence(nowIssueEpochId, nowIssueEpoch(poolId, scId_, depositAssetId))
        );

        EpochInvestAmounts storage epochAmounts = epochInvestAmounts[poolId][scId_][depositAssetId][nowIssueEpochId];
        epochAmounts.pricePoolPerShare = pricePoolPerShare;

        uint128 issuedShareAmount = pricePoolPerShare.isNotZero()
            ? PricingLib.assetToShareAmount(
                epochAmounts.approvedAssetAmount,
                hubRegistry.decimals(depositAssetId),
                hubRegistry.decimals(poolId),
                epochAmounts.pricePoolPerAsset,
                pricePoolPerShare,
                MathLib.Rounding.Down
            )
            : 0;

        epochAmounts.issuedAt = block.timestamp.toUint64();
        epochId[poolId][scId_][depositAssetId].issue = nowIssueEpochId;

        emit IssueShares(
            poolId,
            scId_,
            depositAssetId,
            nowIssueEpochId,
            pricePoolPerShare,
            epochAmounts.pricePoolPerAsset.isNotZero()
                ? PricingLib.priceAssetPerShare(epochAmounts.pricePoolPerShare, epochAmounts.pricePoolPerAsset)
                : d18(0),
            issuedShareAmount
        );

        bytes memory callback =
            RequestCallbackMessageLib.IssuedShares(issuedShareAmount, pricePoolPerShare.raw()).serialize();
        hub.requestCallback{value: msgValue()}(poolId, scId_, depositAssetId, callback, extraGasLimit, false, refund);
    }

    /// @inheritdoc IBatchRequestManager
    function revokeShares(
        PoolId poolId,
        ShareClassId scId_,
        AssetId payoutAssetId,
        uint32 nowRevokeEpochId,
        D18 pricePoolPerShare,
        uint128 extraGasLimit,
        address refund
    ) external payable isManager(poolId) {
        (uint128 payoutAssetAmount, uint128 revokedShareAmount) =
            _revokeShares(poolId, scId_, payoutAssetId, nowRevokeEpochId, pricePoolPerShare);

        bytes memory callback = RequestCallbackMessageLib.RevokedShares(
                payoutAssetAmount, revokedShareAmount, pricePoolPerShare.raw()
            ).serialize();
        hub.requestCallback{value: msgValue()}(poolId, scId_, payoutAssetId, callback, extraGasLimit, false, refund);
    }

    function _revokeShares(
        PoolId poolId,
        ShareClassId scId_,
        AssetId payoutAssetId,
        uint32 nowRevokeEpochId,
        D18 pricePoolPerShare
    ) internal returns (uint128 payoutAssetAmount, uint128 revokedShareAmount) {
        require(nowRevokeEpochId <= epochId[poolId][scId_][payoutAssetId].redeem, EpochNotFound());
        require(
            nowRevokeEpochId == nowRevokeEpoch(poolId, scId_, payoutAssetId),
            EpochNotInSequence(nowRevokeEpochId, nowRevokeEpoch(poolId, scId_, payoutAssetId))
        );

        EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[poolId][scId_][payoutAssetId][nowRevokeEpochId];
        epochAmounts.pricePoolPerShare = pricePoolPerShare;

        // NOTE: shares and pool currency have the same decimals - no conversion needed!
        uint128 payoutPoolAmount = pricePoolPerShare.mulUint128(epochAmounts.approvedShareAmount, MathLib.Rounding.Down);

        payoutAssetAmount = epochAmounts.pricePoolPerAsset.isNotZero()
            ? PricingLib.shareToAssetAmount(
                epochAmounts.approvedShareAmount,
                hubRegistry.decimals(poolId),
                hubRegistry.decimals(payoutAssetId),
                epochAmounts.pricePoolPerShare,
                epochAmounts.pricePoolPerAsset,
                MathLib.Rounding.Down
            )
            : 0;
        revokedShareAmount = epochAmounts.approvedShareAmount;

        epochAmounts.payoutAssetAmount = payoutAssetAmount;
        epochAmounts.revokedAt = block.timestamp.toUint64();
        epochId[poolId][scId_][payoutAssetId].revoke = nowRevokeEpochId;

        emit RevokeShares(
            poolId,
            scId_,
            payoutAssetId,
            nowRevokeEpochId,
            pricePoolPerShare,
            epochAmounts.pricePoolPerAsset.isNotZero()
                ? PricingLib.priceAssetPerShare(epochAmounts.pricePoolPerShare, epochAmounts.pricePoolPerAsset)
                : d18(0),
            epochAmounts.approvedShareAmount,
            payoutAssetAmount,
            payoutPoolAmount
        );
    }

    /// @inheritdoc IBatchRequestManager
    function forceCancelDepositRequest(
        PoolId poolId,
        ShareClassId scId_,
        bytes32 investor,
        AssetId depositAssetId,
        address refund
    ) external payable isManager(poolId) {
        require(allowForceDepositCancel[poolId][scId_][depositAssetId][investor], CancellationInitializationRequired());

        uint128 cancellingAmount = depositRequest[poolId][scId_][depositAssetId][investor].pending;
        uint128 cancelledAssetAmount =
            _updatePending(poolId, scId_, cancellingAmount, false, investor, depositAssetId, RequestType.Deposit);

        // Cancellation might have been queued such that it will be executed in the future during claiming
        if (cancelledAssetAmount > 0) {
            bytes memory callback =
                RequestCallbackMessageLib.FulfilledDepositRequest(investor, 0, 0, cancelledAssetAmount).serialize();
            hub.requestCallback{value: msgValue()}(poolId, scId_, depositAssetId, callback, 0, false, refund);
        }
    }

    /// @inheritdoc IBatchRequestManager
    function forceCancelRedeemRequest(
        PoolId poolId,
        ShareClassId scId_,
        bytes32 investor,
        AssetId payoutAssetId,
        address refund
    ) external payable isManager(poolId) {
        require(allowForceRedeemCancel[poolId][scId_][payoutAssetId][investor], CancellationInitializationRequired());

        uint128 cancellingAmount = redeemRequest[poolId][scId_][payoutAssetId][investor].pending;
        uint128 cancelledShareAmount =
            _updatePending(poolId, scId_, cancellingAmount, false, investor, payoutAssetId, RequestType.Redeem);

        // Cancellation might have been queued such that it will be executed in the future during claiming
        if (cancelledShareAmount > 0) {
            bytes memory callback =
                RequestCallbackMessageLib.FulfilledRedeemRequest(investor, 0, 0, cancelledShareAmount).serialize();
            hub.requestCallback{value: msgValue()}(poolId, scId_, payoutAssetId, callback, 0, false, refund);
        }
    }

    //----------------------------------------------------------------------------------------------
    // Claiming methods
    //----------------------------------------------------------------------------------------------

    /// @inheritdoc IHubRequestManagerNotifications
    function notifyDeposit(
        PoolId poolId,
        ShareClassId scId,
        AssetId assetId,
        bytes32 investor,
        uint32 maxClaims,
        address refund
    ) external payable protected {
        uint128 totalPayoutShareAmount;
        uint128 totalPaymentAssetAmount;
        uint128 cancelledAssetAmount;

        for (uint32 i = 0; i < maxClaims; i++) {
            (uint128 payoutShareAmount, uint128 paymentAssetAmount, uint128 cancelled, bool canClaimAgain) =
                _claimDeposit(poolId, scId, investor, assetId);

            totalPayoutShareAmount += payoutShareAmount;
            totalPaymentAssetAmount += paymentAssetAmount;

            // Should be written at most once with non-zero amount iff the last claimable epoch was processed and
            // the user had a pending cancellation
            // NOTE: Purposely delaying corresponding message dispatch after deposit fulfillment message
            if (cancelled > 0) {
                cancelledAssetAmount = cancelled;
            }

            if (!canClaimAgain) {
                break;
            }
        }

        if (totalPaymentAssetAmount > 0 || cancelledAssetAmount > 0) {
            hub.requestCallback{value: msgValue()}(
                poolId,
                scId,
                assetId,
                RequestCallbackMessageLib.FulfilledDepositRequest(
                        investor, totalPaymentAssetAmount, totalPayoutShareAmount, cancelledAssetAmount
                    ).serialize(),
                0,
                false,
                refund
            );
        }
    }

    function _claimDeposit(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)
        internal
        returns (
            uint128 payoutShareAmount,
            uint128 paymentAssetAmount,
            uint128 cancelledAssetAmount,
            bool canClaimAgain
        )
    {
        UserOrder storage userOrder = depositRequest[poolId][scId_][depositAssetId][investor];
        require(userOrder.pending > 0, NoOrderFound());
        require(userOrder.lastUpdate <= epochId[poolId][scId_][depositAssetId].issue, IssuanceRequired());
        canClaimAgain = userOrder.lastUpdate < epochId[poolId][scId_][depositAssetId].issue;
        EpochInvestAmounts storage epochAmounts =
            epochInvestAmounts[poolId][scId_][depositAssetId][userOrder.lastUpdate];

        // Calculate ceiling for pending reduction (ensures sum(user.pending) <= pendingTotal)
        paymentAssetAmount = epochAmounts.approvedAssetAmount == 0
            ? 0
            : userOrder.pending
                .mulDiv(epochAmounts.approvedAssetAmount, epochAmounts.pendingAssetAmount, MathLib.Rounding.Up)
                .toUint128();

        // NOTE: To ensure sum(user.pending) <= pendingTotal, we reduce pending by ceiling of the
        // proportional share. Payout amounts use floor to ensure sum(claimed) <= sum(issued).
        // This means users may lose up to 1 wei per claim, but prevents unbounded drift.
        if (paymentAssetAmount > 0) {
            // Calculate floor for share payout (ensures sum(shares claimed) <= shares issued)
            uint128 paymentAssetFloor = userOrder.pending
                .mulDiv(epochAmounts.approvedAssetAmount, epochAmounts.pendingAssetAmount, MathLib.Rounding.Down)
                .toUint128();

            if (paymentAssetFloor > 0) {
                payoutShareAmount = epochAmounts.pricePoolPerShare.isNotZero()
                    ? PricingLib.assetToShareAmount(
                        paymentAssetFloor,
                        hubRegistry.decimals(depositAssetId),
                        hubRegistry.decimals(poolId),
                        epochAmounts.pricePoolPerAsset,
                        epochAmounts.pricePoolPerShare,
                        MathLib.Rounding.Down
                    )
                    : 0;
            }

            userOrder.pending -= paymentAssetAmount;
        }

        emit ClaimDeposit(
            poolId,
            scId_,
            userOrder.lastUpdate,
            investor,
            depositAssetId,
            paymentAssetAmount,
            userOrder.pending,
            payoutShareAmount,
            epochAmounts.issuedAt
        );

        // If there is nothing to claim anymore we can short circuit to the latest epoch
        if (userOrder.pending == 0) {
            // The current epoch is always one step ahead of the stored one
            userOrder.lastUpdate = nowDepositEpoch(poolId, scId_, depositAssetId);
            canClaimAgain = false;
        } else {
            userOrder.lastUpdate += 1;
        }

        // If user claimed up to latest approval epoch, move queued to pending
        if (userOrder.lastUpdate == nowDepositEpoch(poolId, scId_, depositAssetId)) {
            cancelledAssetAmount =
                _postClaimUpdateQueued(poolId, scId_, investor, depositAssetId, userOrder, RequestType.Deposit);
        }
    }

    /// @inheritdoc IHubRequestManagerNotifications
    function notifyRedeem(
        PoolId poolId,
        ShareClassId scId,
        AssetId assetId,
        bytes32 investor,
        uint32 maxClaims,
        address refund
    ) external payable protected {
        uint128 totalPayoutAssetAmount;
        uint128 totalPaymentShareAmount;
        uint128 cancelledShareAmount;

        for (uint32 i = 0; i < maxClaims; i++) {
            (uint128 payoutAssetAmount, uint128 paymentShareAmount, uint128 cancelled, bool canClaimAgain) =
                _claimRedeem(poolId, scId, investor, assetId);

            totalPayoutAssetAmount += payoutAssetAmount;
            totalPaymentShareAmount += paymentShareAmount;

            // Should be written at most once with non-zero amount iff the last claimable epoch was processed and
            // the user had a pending cancellation
            // NOTE: Purposely delaying corresponding message dispatch after redemption fulfillment message
            if (cancelled > 0) {
                cancelledShareAmount = cancelled;
            }

            if (!canClaimAgain) {
                break;
            }
        }
        if (totalPaymentShareAmount > 0 || cancelledShareAmount > 0) {
            hub.requestCallback{value: msgValue()}(
                poolId,
                scId,
                assetId,
                RequestCallbackMessageLib.FulfilledRedeemRequest(
                        investor, totalPayoutAssetAmount, totalPaymentShareAmount, cancelledShareAmount
                    ).serialize(),
                0,
                false,
                refund
            );
        }
    }

    function _claimRedeem(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)
        internal
        returns (
            uint128 payoutAssetAmount,
            uint128 paymentShareAmount,
            uint128 cancelledShareAmount,
            bool canClaimAgain
        )
    {
        UserOrder storage userOrder = redeemRequest[poolId][scId_][payoutAssetId][investor];
        require(userOrder.pending > 0, NoOrderFound());
        require(userOrder.lastUpdate <= epochId[poolId][scId_][payoutAssetId].revoke, RevocationRequired());
        canClaimAgain = userOrder.lastUpdate < epochId[poolId][scId_][payoutAssetId].revoke;

        EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[poolId][scId_][payoutAssetId][userOrder.lastUpdate];

        // Calculate ceiling for pending reduction (ensures sum(user.pending) <= pendingTotal)
        paymentShareAmount = epochAmounts.approvedShareAmount == 0
            ? 0
            : userOrder.pending
                .mulDiv(epochAmounts.approvedShareAmount, epochAmounts.pendingShareAmount, MathLib.Rounding.Up)
                .toUint128();

        // NOTE: To ensure sum(user.pending) <= pendingTotal, we reduce pending by ceiling of the
        // proportional share. Payout amounts use floor to ensure sum(claimed) <= sum(issued).
        // This means users may lose up to 1 wei per claim, but prevents unbounded drift.
        if (paymentShareAmount > 0) {
            // Calculate floor for asset payout (ensures sum(assets claimed) <= assets available)
            uint128 paymentShareFloor = userOrder.pending
                .mulDiv(epochAmounts.approvedShareAmount, epochAmounts.pendingShareAmount, MathLib.Rounding.Down)
                .toUint128();

            if (paymentShareFloor > 0) {
                payoutAssetAmount = epochAmounts.pricePoolPerAsset.isNotZero()
                    ? PricingLib.shareToAssetAmount(
                        paymentShareFloor,
                        hubRegistry.decimals(poolId),
                        hubRegistry.decimals(payoutAssetId),
                        epochAmounts.pricePoolPerShare,
                        epochAmounts.pricePoolPerAsset,
                        MathLib.Rounding.Down
                    )
                    : 0;
            }

            userOrder.pending -= paymentShareAmount;
        }

        emit ClaimRedeem(
            poolId,
            scId_,
            userOrder.lastUpdate,
            investor,
            payoutAssetId,
            paymentShareAmount,
            userOrder.pending,
            payoutAssetAmount,
            epochAmounts.revokedAt
        );

        // If there is nothing to claim anymore we can short circuit the in between epochs
        if (userOrder.pending == 0) {
            // The current epoch is always one step ahead of the stored one
            userOrder.lastUpdate = nowRedeemEpoch(poolId, scId_, payoutAssetId);
            canClaimAgain = false;
        } else {
            userOrder.lastUpdate += 1;
        }

        if (userOrder.lastUpdate == nowRedeemEpoch(poolId, scId_, payoutAssetId)) {
            cancelledShareAmount =
                _postClaimUpdateQueued(poolId, scId_, investor, payoutAssetId, userOrder, RequestType.Redeem);
        }
    }

    //----------------------------------------------------------------------------------------------
    // ERC-165
    //----------------------------------------------------------------------------------------------

    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public pure returns (bool) {
        return interfaceId == type(IBatchRequestManager).interfaceId
            || interfaceId == type(IHubRequestManager).interfaceId
            || interfaceId == type(IHubRequestManagerNotifications).interfaceId
            || interfaceId == type(IERC165).interfaceId;
    }

    //----------------------------------------------------------------------------------------------
    // View methods
    //----------------------------------------------------------------------------------------------

    /// @inheritdoc IBatchRequestManager
    function nowDepositEpoch(PoolId poolId, ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {
        return epochId[poolId][scId_][depositAssetId].deposit + 1;
    }

    /// @inheritdoc IBatchRequestManager
    function nowIssueEpoch(PoolId poolId, ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {
        return epochId[poolId][scId_][depositAssetId].issue + 1;
    }

    /// @inheritdoc IBatchRequestManager
    function nowRedeemEpoch(PoolId poolId, ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {
        return epochId[poolId][scId_][depositAssetId].redeem + 1;
    }

    /// @inheritdoc IBatchRequestManager
    function nowRevokeEpoch(PoolId poolId, ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {
        return epochId[poolId][scId_][depositAssetId].revoke + 1;
    }

    /// @inheritdoc IBatchRequestManager
    function maxDepositClaims(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)
        public
        view
        returns (uint32)
    {
        return _maxClaims(
            depositRequest[poolId][scId_][depositAssetId][investor], epochId[poolId][scId_][depositAssetId].issue
        );
    }

    /// @inheritdoc IBatchRequestManager
    function maxRedeemClaims(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)
        public
        view
        returns (uint32)
    {
        return _maxClaims(
            redeemRequest[poolId][scId_][payoutAssetId][investor], epochId[poolId][scId_][payoutAssetId].revoke
        );
    }

    function _maxClaims(UserOrder memory userOrder, uint32 lastEpoch) internal pure returns (uint32) {
        // User order either not set or not processed
        if (userOrder.pending == 0 || userOrder.lastUpdate > lastEpoch) {
            return 0;
        }

        return lastEpoch - userOrder.lastUpdate + 1;
    }

    //----------------------------------------------------------------------------------------------
    // Internal methods
    //----------------------------------------------------------------------------------------------

    function _postClaimUpdateQueued(
        PoolId poolId,
        ShareClassId scId_,
        bytes32 investor,
        AssetId assetId,
        UserOrder storage userOrder,
        RequestType requestType
    ) internal returns (uint128 cancelledAmount) {
        QueuedOrder storage queued = requestType == RequestType.Deposit
            ? queuedDepositRequest[poolId][scId_][assetId][investor]
            : queuedRedeemRequest[poolId][scId_][assetId][investor];

        // Increment pending by queued or cancel everything
        uint128 updatePendingAmount = queued.isCancelling ? userOrder.pending : queued.amount;
        if (queued.isCancelling) {
            cancelledAmount = userOrder.pending + queued.amount;
            userOrder.pending = 0;
        } else {
            userOrder.pending += queued.amount;
        }

        if (requestType == RequestType.Deposit) {
            _updatePendingDeposit(
                poolId,
                scId_,
                updatePendingAmount,
                !queued.isCancelling,
                investor,
                assetId,
                userOrder,
                QueuedOrder(false, 0)
            );
        } else {
            _updatePendingRedeem(
                poolId,
                scId_,
                updatePendingAmount,
                !queued.isCancelling,
                investor,
                assetId,
                userOrder,
                QueuedOrder(false, 0)
            );
        }

        // Clear queued
        queued.isCancelling = false;
        queued.amount = 0;
    }

    /// @notice Updates the amount of a deposit or redeem request.
    ///
    /// @param poolId Identifier of the pool
    /// @param scId_ Identifier of the share class
    /// @param amount Amount which is updated
    /// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)
    /// @param investor Address of the entity which is depositing
    /// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to
    /// @param requestType Flag indicating whether the request is a deposit or redeem request
    /// @return cancelledAmount Pending amount which was cancelled
    function _updatePending(
        PoolId poolId,
        ShareClassId scId_,
        uint128 amount,
        bool isIncrement,
        bytes32 investor,
        AssetId assetId,
        RequestType requestType
    ) internal returns (uint128 cancelledAmount) {
        UserOrder storage userOrder = requestType == RequestType.Deposit
            ? depositRequest[poolId][scId_][assetId][investor]
            : redeemRequest[poolId][scId_][assetId][investor];
        QueuedOrder storage queued = requestType == RequestType.Deposit
            ? queuedDepositRequest[poolId][scId_][assetId][investor]
            : queuedRedeemRequest[poolId][scId_][assetId][investor];

        // We must only update either queued or pending
        if (_updateQueued(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued, requestType)) {
            return 0;
        }

        cancelledAmount = isIncrement ? 0 : amount;
        // NOTE: If we decrease the pending, we decrease usually by the full amount
        //       We keep subtraction of amount over setting to zero on purpose to not limit future higher level logic
        userOrder.pending = isIncrement ? userOrder.pending + amount : userOrder.pending - amount;

        userOrder.lastUpdate = requestType == RequestType.Deposit
            ? nowDepositEpoch(poolId, scId_, assetId)
            : nowRedeemEpoch(poolId, scId_, assetId);

        if (requestType == RequestType.Deposit) {
            _updatePendingDeposit(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);
        } else {
            _updatePendingRedeem(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);
        }
    }

    /// @notice Checks whether the pending amount can be updated. If not, it updates the queued amount.
    ///
    /// @param poolId Identifier of the pool
    /// @param scId_ Identifier of the share class
    /// @param amount Amount which is updated
    /// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)
    /// @param investor Address of the entity which is depositing
    /// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to
    /// @param userOrder User order storage for the deposit or redeem request
    /// @param requestType Flag indicating whether the request is a deposit or redeem request
    /// @return skipPendingUpdate Flag indicating whether the pending amount can be updated which is true if the user
    /// does not need to claim
    function _updateQueued(
        PoolId poolId,
        ShareClassId scId_,
        uint128 amount,
        bool isIncrement,
        bytes32 investor,
        AssetId assetId,
        UserOrder storage userOrder,
        QueuedOrder storage queued,
        RequestType requestType
    ) internal returns (bool skipPendingUpdate) {
        uint32 currentEpoch = requestType == RequestType.Deposit
            ? nowDepositEpoch(poolId, scId_, assetId)
            : nowRedeemEpoch(poolId, scId_, assetId);

        // Short circuit if user can mutate pending, i.e. last update happened after latest approval or is first update
        if (_canMutatePending(userOrder, currentEpoch)) {
            return false;
        }

        // Block increasing queued amount if cancelling is already queued
        // NOTE: Can only happen due to race condition as Vaults blocks requests if cancellation is in progress
        require(!(queued.isCancelling && amount > 0), CancellationQueued());

        if (!isIncrement) {
            queued.isCancelling = true;
        } else {
            queued.amount += amount;
        }

        if (requestType == RequestType.Deposit) {
            uint128 pendingTotal = pendingDeposit[poolId][scId_][assetId];
            emit UpdateDepositRequest(
                poolId,
                scId_,
                assetId,
                currentEpoch,
                investor,
                userOrder.pending,
                pendingTotal,
                queued.amount,
                queued.isCancelling
            );
        } else {
            uint128 pendingTotal = pendingRedeem[poolId][scId_][assetId];

            emit UpdateRedeemRequest(
                poolId,
                scId_,
                assetId,
                currentEpoch,
                investor,
                userOrder.pending,
                pendingTotal,
                queued.amount,
                queued.isCancelling
            );
        }

        return true;
    }

    function _updatePendingDeposit(
        PoolId poolId,
        ShareClassId scId_,
        uint128 amount,
        bool isIncrement,
        bytes32 investor,
        AssetId assetId,
        UserOrder storage userOrder,
        QueuedOrder memory queued
    ) internal {
        uint128 pendingTotal = pendingDeposit[poolId][scId_][assetId];
        pendingTotal = isIncrement ? pendingTotal + amount : amount > pendingTotal ? 0 : pendingTotal - amount;
        pendingDeposit[poolId][scId_][assetId] = pendingTotal;

        emit UpdateDepositRequest(
            poolId,
            scId_,
            assetId,
            nowDepositEpoch(poolId, scId_, assetId),
            investor,
            userOrder.pending,
            pendingTotal,
            queued.amount,
            queued.isCancelling
        );
    }

    function _updatePendingRedeem(
        PoolId poolId,
        ShareClassId scId_,
        uint128 amount,
        bool isIncrement,
        bytes32 investor,
        AssetId assetId,
        UserOrder storage userOrder,
        QueuedOrder memory queued
    ) internal {
        uint128 pendingTotal = pendingRedeem[poolId][scId_][assetId];
        pendingTotal = isIncrement ? pendingTotal + amount : amount > pendingTotal ? 0 : pendingTotal - amount;
        pendingRedeem[poolId][scId_][assetId] = pendingTotal;

        emit UpdateRedeemRequest(
            poolId,
            scId_,
            assetId,
            nowRedeemEpoch(poolId, scId_, assetId),
            investor,
            userOrder.pending,
            pendingTotal,
            queued.amount,
            queued.isCancelling
        );
    }

    /// @dev A user cannot mutate their pending amount at all times because it affects the total pending amount. It is
    ///     restricted to the following three conditions:
    ///         1. It's the first epoch (currentEpoch <= 1), which implies userOrder.lastUpdate == 0
    ///         2. User has no pending amount (userOrder.pending == 0)
    ///         3. User's last update is not behind the current epoch (userOrder.lastUpdate >= currentEpoch)
    function _canMutatePending(UserOrder memory userOrder, uint32 currentEpoch) internal pure returns (bool) {
        return currentEpoch <= 1 || userOrder.pending == 0 || userOrder.lastUpdate >= currentEpoch;
    }
}

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

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

enum RequestCallbackType {
    /// @dev Placeholder for null request callback type
    Invalid,
    ApprovedDeposits,
    IssuedShares,
    RevokedShares,
    FulfilledDepositRequest,
    FulfilledRedeemRequest
}

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

    error UnknownRequestCallbackType();

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

    //---------------------------------------
    //    RequestCallback.ApprovedDeposits (submsg)
    //---------------------------------------

    struct ApprovedDeposits {
        uint128 assetAmount;
        uint128 pricePoolPerAsset;
    }

    function deserializeApprovedDeposits(bytes memory data) internal pure returns (ApprovedDeposits memory) {
        require(requestCallbackType(data) == RequestCallbackType.ApprovedDeposits, UnknownRequestCallbackType());

        return ApprovedDeposits({assetAmount: data.toUint128(1), pricePoolPerAsset: data.toUint128(17)});
    }

    function serialize(ApprovedDeposits memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(RequestCallbackType.ApprovedDeposits, t.assetAmount, t.pricePoolPerAsset);
    }

    //---------------------------------------
    //    RequestCallback.IssuedShares (submsg)
    //---------------------------------------

    struct IssuedShares {
        uint128 shareAmount;
        uint128 pricePoolPerShare;
    }

    function deserializeIssuedShares(bytes memory data) internal pure returns (IssuedShares memory) {
        require(requestCallbackType(data) == RequestCallbackType.IssuedShares, UnknownRequestCallbackType());

        return IssuedShares({shareAmount: data.toUint128(1), pricePoolPerShare: data.toUint128(17)});
    }

    function serialize(IssuedShares memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(RequestCallbackType.IssuedShares, t.shareAmount, t.pricePoolPerShare);
    }

    //---------------------------------------
    //    RequestCallback.RevokedShares (submsg)
    //---------------------------------------

    struct RevokedShares {
        uint128 assetAmount;
        uint128 shareAmount;
        uint128 pricePoolPerShare;
    }

    function deserializeRevokedShares(bytes memory data) internal pure returns (RevokedShares memory) {
        require(requestCallbackType(data) == RequestCallbackType.RevokedShares, UnknownRequestCallbackType());

        return RevokedShares({
            assetAmount: data.toUint128(1), shareAmount: data.toUint128(17), pricePoolPerShare: data.toUint128(33)
        });
    }

    function serialize(RevokedShares memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(RequestCallbackType.RevokedShares, t.assetAmount, t.shareAmount, t.pricePoolPerShare);
    }

    //---------------------------------------
    //    RequestCallback.FulfilledDepositRequest (submsg)
    //---------------------------------------

    struct FulfilledDepositRequest {
        bytes32 investor;
        uint128 fulfilledAssetAmount;
        uint128 fulfilledShareAmount;
        uint128 cancelledAssetAmount;
    }

    function deserializeFulfilledDepositRequest(bytes memory data)
        internal
        pure
        returns (FulfilledDepositRequest memory)
    {
        require(requestCallbackType(data) == RequestCallbackType.FulfilledDepositRequest, UnknownRequestCallbackType());
        return FulfilledDepositRequest({
            investor: data.toBytes32(1),
            fulfilledAssetAmount: data.toUint128(33),
            fulfilledShareAmount: data.toUint128(49),
            cancelledAssetAmount: data.toUint128(65)
        });
    }

    function serialize(FulfilledDepositRequest memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(
            RequestCallbackType.FulfilledDepositRequest,
            t.investor,
            t.fulfilledAssetAmount,
            t.fulfilledShareAmount,
            t.cancelledAssetAmount
        );
    }

    //---------------------------------------
    //    RequestCallback.FulfilledRedeemRequest (submsg)
    //---------------------------------------

    struct FulfilledRedeemRequest {
        bytes32 investor;
        uint128 fulfilledAssetAmount;
        uint128 fulfilledShareAmount;
        uint128 cancelledShareAmount;
    }

    function deserializeFulfilledRedeemRequest(bytes memory data)
        internal
        pure
        returns (FulfilledRedeemRequest memory)
    {
        require(requestCallbackType(data) == RequestCallbackType.FulfilledRedeemRequest, UnknownRequestCallbackType());
        return FulfilledRedeemRequest({
            investor: data.toBytes32(1),
            fulfilledAssetAmount: data.toUint128(33),
            fulfilledShareAmount: data.toUint128(49),
            cancelledShareAmount: data.toUint128(65)
        });
    }

    function serialize(FulfilledRedeemRequest memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(
            RequestCallbackType.FulfilledRedeemRequest,
            t.investor,
            t.fulfilledAssetAmount,
            t.fulfilledShareAmount,
            t.cancelledShareAmount
        );
    }
}

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

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

enum RequestType {
    /// @dev Placeholder for null request type
    Invalid,
    DepositRequest,
    RedeemRequest,
    CancelDepositRequest,
    CancelRedeemRequest
}

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

    error UnknownRequestType();

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

    //---------------------------------------
    //    Request.DepositRequest (submsg)
    //---------------------------------------

    struct DepositRequest {
        bytes32 investor;
        uint128 amount;
    }

    function deserializeDepositRequest(bytes memory data) internal pure returns (DepositRequest memory) {
        require(requestType(data) == RequestType.DepositRequest, UnknownRequestType());
        return DepositRequest({investor: data.toBytes32(1), amount: data.toUint128(33)});
    }

    function serialize(DepositRequest memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(RequestType.DepositRequest, t.investor, t.amount);
    }

    //---------------------------------------
    //    Request.RedeemRequest (submsg)
    //---------------------------------------

    struct RedeemRequest {
        bytes32 investor;
        uint128 amount;
    }

    function deserializeRedeemRequest(bytes memory data) internal pure returns (RedeemRequest memory) {
        require(requestType(data) == RequestType.RedeemRequest, UnknownRequestType());
        return RedeemRequest({investor: data.toBytes32(1), amount: data.toUint128(33)});
    }

    function serialize(RedeemRequest memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(RequestType.RedeemRequest, t.investor, t.amount);
    }

    //---------------------------------------
    //    Request.CancelDepositRequest (submsg)
    //---------------------------------------

    struct CancelDepositRequest {
        bytes32 investor;
    }

    function deserializeCancelDepositRequest(bytes memory data) internal pure returns (CancelDepositRequest memory) {
        require(requestType(data) == RequestType.CancelDepositRequest, UnknownRequestType());
        return CancelDepositRequest({investor: data.toBytes32(1)});
    }

    function serialize(CancelDepositRequest memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(RequestType.CancelDepositRequest, t.investor);
    }

    //---------------------------------------
    //    Request.CancelRedeemRequest (submsg)
    //---------------------------------------

    struct CancelRedeemRequest {
        bytes32 investor;
    }

    function deserializeCancelRedeemRequest(bytes memory data) internal pure returns (CancelRedeemRequest memory) {
        require(requestType(data) == RequestType.CancelRedeemRequest, UnknownRequestType());
        return CancelRedeemRequest({investor: data.toBytes32(1)});
    }

    function serialize(CancelRedeemRequest memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(RequestType.CancelRedeemRequest, t.investor);
    }
}

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

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

import {PoolId} from "../../core/types/PoolId.sol";
import {AssetId} from "../../core/types/AssetId.sol";
import {ShareClassId} from "../../core/types/ShareClassId.sol";
import {IHubRequestManager, IHubRequestManagerNotifications} from "../../core/hub/interfaces/IHubRequestManager.sol";

/// @notice Struct containing the epoch data for issuing share class tokens
/// @param approvedPoolAmount The amount of pool currency which was approved by the Fund Manager
/// @param approvedAssetAmount The amount of assets which was approved by the Fund Manager
/// @param pendingAssetAmount The amount of assets for which issuance was pending by the Fund Manager
/// @param pricePoolPerAsset The price of one asset unit in terms of pool currency at the time of approval
/// @param pricePoolPerShare The price of 1 pool currency token in terms of share class tokens at the time of issuance
/// @param issuedAt The timestamp when shares were issued
struct EpochInvestAmounts {
    uint128 approvedPoolAmount;
    uint128 approvedAssetAmount;
    uint128 pendingAssetAmount;
    D18 pricePoolPerAsset;
    D18 pricePoolPerShare;
    uint64 issuedAt;
}

/// @notice Struct containing the epoch data for paying out assets of a share class token
/// @param approvedShareAmount The amount of share class tokens which was approved by the Fund Manager for payout
/// @param pendingShareAmount The amount of share class tokens for which payout was pending by the Fund Manager
/// @param pricePoolPerAsset The price of one asset unit in terms of pool currency at the time of approval
/// @param pricePoolPerShare The price of 1 pool currency token in terms of share class tokens at the time of revocation
/// @param payoutAssetAmount The amount of payout assets to claim by redeeming share class tokens
/// @param revokedAt The timestamp when shares were revoked
struct EpochRedeemAmounts {
    uint128 approvedShareAmount;
    uint128 pendingShareAmount;
    D18 pricePoolPerAsset;
    D18 pricePoolPerShare;
    uint128 payoutAssetAmount;
    uint64 revokedAt;
}

/// @notice Struct containing the user's deposit or redeem request data
/// @param pending The amount of assets or shares which is pending for a user
/// @param lastUpdate The epoch at which the user most recently deposited or redeemed
struct UserOrder {
    uint128 pending;
    uint32 lastUpdate;
}

/// @notice Struct containing the user's queued deposit or redeem request data
/// @param isCancelling Whether the user is cancelling their pending requests
/// @param amount The amount of assets or shares which is queued for a user
struct QueuedOrder {
    bool isCancelling;
    uint128 amount;
}

/// @notice Enum indicating the type of request, either deposit or redeem
enum RequestType {
    Deposit,
    Redeem
}

/// @notice Struct containing the epoch IDs for each action
/// @param deposit The epoch ID for deposits
/// @param issue The epoch ID for issuing shares
/// @param redeem The epoch ID for redeems
/// @param revoke The epoch ID for revoking shares
struct EpochId {
    uint32 deposit;
    uint32 issue;
    uint32 redeem;
    uint32 revoke;
}

interface IBatchRequestManager is IHubRequestManager, IHubRequestManagerNotifications {
    //----------------------------------------------------------------------------------------------
    // Events
    //----------------------------------------------------------------------------------------------

    event ApproveDeposits(
        PoolId indexed poolId,
        ShareClassId indexed shareClassId,
        AssetId indexed assetId,
        uint32 epochId,
        uint128 approvedPoolAmount,
        uint128 approvedAssetAmount,
        uint128 pendingAssetAmount
    );

    event ApproveRedeems(
        PoolId indexed poolId,
        ShareClassId indexed shareClassId,
        AssetId indexed assetId,
        uint32 epochId,
        uint128 approvedShareAmount,
        uint128 pendingShareAmount
    );

    event IssueShares(
        PoolId indexed poolId,
        ShareClassId indexed shareClassId,
        AssetId indexed assetId,
        uint32 epochId,
        D18 pricePoolPerShare,
        D18 priceAssetPerShare,
        uint128 issuedShareAmount
    );

    event RevokeShares(
        PoolId indexed poolId,
        ShareClassId indexed shareClassId,
        AssetId indexed assetId,
        uint32 epochId,
        D18 pricePoolPerShare,
        D18 priceAssetPerShare,
        uint128 approvedShareAmount,
        uint128 payoutAssetAmount,
        uint128 payoutPoolAmount
    );

    event ClaimDeposit(
        PoolId indexed poolId,
        ShareClassId indexed shareClassId,
        uint32 indexed epochId,
        bytes32 investor,
        AssetId assetId,
        uint128 paymentAssetAmount,
        uint128 pendingAssetAmount,
        uint128 payoutShareAmount,
        uint64 issuedAt
    );

    event ClaimRedeem(
        PoolId indexed poolId,
        ShareClassId indexed shareClassId,
        uint32 indexed epochId,
        bytes32 investor,
        AssetId assetId,
        uint128 paymentShareAmount,
        uint128 pendingShareAmount,
        uint128 payoutAssetAmount,
        uint64 revokedAt
    );

    event UpdateDepositRequest(
        PoolId indexed poolId,
        ShareClassId indexed shareClassId,
        AssetId indexed assetId,
        uint32 epochId,
        bytes32 investor,
        uint128 pendingAmount,
        uint128 totalPendingAmount,
        uint128 queuedAmount,
        bool isQueuedCancellation
    );

    event UpdateRedeemRequest(
        PoolId indexed poolId,
        ShareClassId indexed shareClassId,
        AssetId indexed assetId,
        uint32 epochId,
        bytes32 investor,
        uint128 pendingAmount,
        uint128 totalPendingAmount,
        uint128 queuedAmount,
        bool isQueuedCancellation
    );

    //----------------------------------------------------------------------------------------------
    // Events
    //----------------------------------------------------------------------------------------------

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

    /// @notice Emitted when epoch IDs are modified via setEpochIds during migration
    event EpochIdModified(
        PoolId indexed poolId, ShareClassId indexed scId, AssetId indexed assetId, EpochId epochIdData
    );

    //----------------------------------------------------------------------------------------------
    // Errors
    //----------------------------------------------------------------------------------------------

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

    /// @notice Dispatched when unknown request type is encountered.
    error UnknownRequestType();

    error InsufficientPending();
    error ZeroApprovalAmount();
    error EpochNotFound();
    error EpochNotInSequence(uint32 epochId, uint32 actualEpochId);
    error NoOrderFound();
    error IssuanceRequired();
    error RevocationRequired();
    error CancellationInitializationRequired();
    error CancellationQueued();

    //----------------------------------------------------------------------------------------------
    // Incoming requests
    //----------------------------------------------------------------------------------------------

    /// @notice Submit a deposit request to invest assets into a pool's share class
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param amount The amount of assets to deposit
    /// @param investor The investor's address as bytes32
    /// @param depositAssetId The asset identifier for the deposit
    function requestDeposit(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId depositAssetId)
        external;

    /// @notice Cancel a pending deposit request and return the deposited assets
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param investor The investor's address as bytes32
    /// @param depositAssetId The asset identifier for the deposit
    /// @return cancelledAssetAmount The amount of assets returned to the investor
    function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)
        external
        returns (uint128 cancelledAssetAmount);

    /// @notice Submit a redemption request to redeem shares for assets
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param amount The amount of shares to redeem
    /// @param investor The investor's address as bytes32
    /// @param payoutAssetId The asset identifier for the payout
    function requestRedeem(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId payoutAssetId)
        external;

    /// @notice Cancel a pending redemption request and return the shares
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param investor The investor's address as bytes32
    /// @param payoutAssetId The asset identifier for the payout
    /// @return cancelledShareAmount The amount of shares returned to the investor
    function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)
        external
        returns (uint128 cancelledShareAmount);

    //----------------------------------------------------------------------------------------------
    // Manager actions
    //----------------------------------------------------------------------------------------------

    /// @notice Approve pending deposit requests for an epoch
    /// @dev This function approves a specific amount of assets from the current deposit epoch
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param depositAssetId The asset identifier for deposits
    /// @param nowDepositEpochId The current deposit epoch identifier
    /// @param approvedAssetAmount The amount of assets approved for this epoch
    /// @param pricePoolPerAsset The price of one asset unit in terms of pool currency
    /// @param refund Address to receive unused gas refund
    function approveDeposits(
        PoolId poolId,
        ShareClassId scId,
        AssetId depositAssetId,
        uint32 nowDepositEpochId,
        uint128 approvedAssetAmount,
        D18 pricePoolPerAsset,
        address refund
    ) external payable;

    /// @notice Approve pending redemption requests for an epoch
    /// @dev This function approves a specific amount of shares from the current redeem epoch
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param payoutAssetId The asset identifier for payouts
    /// @param nowRedeemEpochId The current redeem epoch identifier
    /// @param approvedShareAmount The amount of shares approved for redemption
    /// @param pricePoolPerAsset The price of one asset unit in terms of pool currency
    function approveRedeems(
        PoolId poolId,
        ShareClassId scId,
        AssetId payoutAssetId,
        uint32 nowRedeemEpochId,
        uint128 approvedShareAmount,
        D18 pricePoolPerAsset
    ) external payable;

    /// @notice Issue shares to investors based on approved deposits
    /// @dev This function mints shares for the approved deposit epoch using the provided share price
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param depositAssetId The asset identifier for deposits
    /// @param nowIssueEpochId The current issue epoch identifier
    /// @param pricePoolPerShare The price of pool currency per share unit
    /// @param extraGasLimit Additional gas limit for cross-chain operations
    /// @param refund Address to receive unused gas refund
    function issueShares(
        PoolId poolId,
        ShareClassId scId,
        AssetId depositAssetId,
        uint32 nowIssueEpochId,
        D18 pricePoolPerShare,
        uint128 extraGasLimit,
        address refund
    ) external payable;

    /// @notice Revoke shares and prepare asset payouts for redemptions
    /// @dev This function burns shares for the approved redeem epoch and calculates asset payouts
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param payoutAssetId The asset identifier for payouts
    /// @param nowRevokeEpochId The current revoke epoch identifier
    /// @param pricePoolPerShare The price of pool currency per share unit
    /// @param extraGasLimit Additional gas limit for cross-chain operations
    /// @param refund Address to receive unused gas refund
    function revokeShares(
        PoolId poolId,
        ShareClassId scId,
        AssetId payoutAssetId,
        uint32 nowRevokeEpochId,
        D18 pricePoolPerShare,
        uint128 extraGasLimit,
        address refund
    ) external payable;

    /// @notice Force cancel a user's deposit request (manager action)
    /// @dev This allows the manager to cancel a deposit request on behalf of a user
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param investor The investor's address as bytes32
    /// @param depositAssetId The asset identifier for the deposit
    /// @param refund Address to receive unused gas refund
    function forceCancelDepositRequest(
        PoolId poolId,
        ShareClassId scId,
        bytes32 investor,
        AssetId depositAssetId,
        address refund
    ) external payable;

    /// @notice Force cancel a user's redemption request (manager action)
    /// @dev This allows the manager to cancel a redemption request on behalf of a user
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param investor The investor's address as bytes32
    /// @param payoutAssetId The asset identifier for the payout
    /// @param refund Address to receive unused gas refund
    function forceCancelRedeemRequest(
        PoolId poolId,
        ShareClassId scId,
        bytes32 investor,
        AssetId payoutAssetId,
        address refund
    ) external payable;

    //----------------------------------------------------------------------------------------------
    // View methods
    //----------------------------------------------------------------------------------------------

    /// @notice Get the current deposit epoch identifier
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param depositAssetId The asset identifier for deposits
    /// @return The current deposit epoch ID
    function nowDepositEpoch(PoolId poolId, ShareClassId scId, AssetId depositAssetId) external view returns (uint32);

    /// @notice Get the current issue epoch identifier
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param depositAssetId The asset identifier for deposits
    /// @return The current issue epoch ID
    function nowIssueEpoch(PoolId poolId, ShareClassId scId, AssetId depositAssetId) external view returns (uint32);

    /// @notice Get the current redeem epoch identifier
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param depositAssetId The asset identifier for payouts
    /// @return The current redeem epoch ID
    function nowRedeemEpoch(PoolId poolId, ShareClassId scId, AssetId depositAssetId) external view returns (uint32);

    /// @notice Get the current revoke epoch identifier
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param depositAssetId The asset identifier for payouts
    /// @return The current revoke epoch ID
    function nowRevokeEpoch(PoolId poolId, ShareClassId scId, AssetId depositAssetId) external view returns (uint32);

    /// @notice Get the maximum number of deposit claims available for an investor
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param investor The investor's address as bytes32
    /// @param depositAssetId The asset identifier for deposits
    /// @return The maximum number of claimable deposit epochs
    function maxDepositClaims(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)
        external
        view
        returns (uint32);

    /// @notice Get the maximum number of redeem claims available for an investor
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param investor The investor's address as bytes32
    /// @param payoutAssetId The asset identifier for payouts
    /// @return The maximum number of claimable redeem epochs
    function maxRedeemClaims(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)
        external
        view
        returns (uint32);

    //----------------------------------------------------------------------------------------------
    // Epoch data access
    //----------------------------------------------------------------------------------------------

    /// @notice Get detailed investment amounts and pricing for a specific epoch
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param assetId The asset identifier
    /// @param epochId The epoch identifier
    /// @return pendingAssetAmount Assets waiting to be approved
    /// @return approvedAssetAmount Assets approved for investment
    /// @return approvedPoolAmount Pool currency amount after asset-to-pool conversion
    /// @return pricePoolPerAsset Price of pool currency per asset unit
    /// @return pricePoolPerShare Price of pool currency per share unit
    /// @return issuedAt Timestamp when shares were issued
    function epochInvestAmounts(PoolId poolId, ShareClassId scId, AssetId assetId, uint32 epochId)
        external
        view
        returns (
            uint128 pendingAssetAmount,
            uint128 approvedAssetAmount,
            uint128 approvedPoolAmount,
            D18 pricePoolPerAsset,
            D18 pricePoolPerShare,
            uint64 issuedAt
        );

    /// @notice Get detailed redemption amounts and pricing for a specific epoch
    /// @param poolId The pool identifier
    /// @param scId The share class identifier
    /// @param assetId The asset identifier
    /// @param epochId The epoch identifier
    /// @return approvedShareAmount Shares approved for redemption
    /// @return pendingShareAmount Shares waiting to be approved
    /// @return pricePoolPerAsset Price of pool currency per asset unit
    /// @return pricePoolPerShare Price of pool currency per share unit
    /// @return payoutAssetAmount Asset amount to be paid out
    /// @return revokedAt Timestamp when shares were revoked
    function epochRedeemAmounts(PoolId poolId, ShareClassId scId, AssetId assetId, uint32 epochId)
        external
        view
        returns (
            uint128 approvedShareAmount,
            uint128 pendingShareAmount,
            D18 pricePoolPerAsset,
            D18 pricePoolPerShare,
            uint128 payoutAssetAmount,
            uint64 revokedAt
        );
}

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

import {IAuth} from "./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 "../libraries/MathLib.sol";

type D18 is uint128;

error D18_DivisionByZero();

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 subtract 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_DivisionByZero());
    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.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)
    /// @param target The address to check for ward status
    /// @return The ward status (1 if ward, 0 if not)
    function wards(address target) external view returns (uint256);

    /// @notice Make user a ward (give them admin access)
    /// @param user The address to grant ward status to
    function rely(address user) external;

    /// @notice Remove user as a ward (remove admin access)
    /// @param user The address to remove ward status from
    function deny(address user) external;
}

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

/// @title  CastLib
library CastLib {
    error PrefixNotZero();
    error SizeNot128();

    function toAddressLeftPadded(bytes32 addr) internal pure returns (address) {
        require(bytes12(addr) == 0, PrefixNotZero());
        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, PrefixNotZero());
        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, SizeNot128());

        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;

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

    error MulDiv_Overflow();
    error Uint8_Overflow();
    error Uint16_Overflow();
    error Uint32_Overflow();
    error Uint64_Overflow();
    error Uint96_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);
    }

    /// @notice Safe type conversion from uint256 to uint16.
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value <= type(uint16).max, Uint16_Overflow());
        return uint16(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);
    }

    function toUint96(uint256 value) internal pure returns (uint96) {
        require(value <= type(uint96).max, Uint96_Overflow());
        return uint96(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;
    }
}

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

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

// 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: BUSL-1.1
pragma solidity 0.8.28;

import {MathLib} from "../../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 as ==} for AssetId global;

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

import {D18, d18} from "../../misc/types/D18.sol";
import {MathLib} from "../../misc/libraries/MathLib.sol";
import {IERC20Metadata} from "../../misc/interfaces/IERC20.sol";
import {IERC6909MetadataExt} from "../../misc/interfaces/IERC6909.sol";

library PricingLib {
    using MathLib for *;

    error DivisionByZero();

    /// @dev Prices are fixed-point integers with 18 decimals
    uint8 internal constant PRICE_DECIMALS = 18;

    //----------------------------------------------------------------------------------------------
    // View methods
    //----------------------------------------------------------------------------------------------

    /// @dev Converts the given asset amount to share amount. Returned value is in share decimals.
    /// @dev Assumes handling of zero denominator price (priceAssetPerShare_) by consumer.
    ///
    ///      NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from
    ///      Fulfilled* message amounts. Any other codepath must use the variant with pricePoolPerAsset
    ///      and pricePoolPerShare
    function assetToShareAmount(
        address shareToken,
        address asset,
        uint256 tokenId,
        uint128 assetAmount,
        D18 priceAssetPerShare_,
        MathLib.Rounding rounding
    ) internal view returns (uint128 shares) {
        if (assetAmount == 0) {
            return 0;
        }

        uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
        uint8 shareDecimals = IERC20Metadata(shareToken).decimals();

        return PricingLib.convertWithReciprocalPrice(
                assetAmount, assetDecimals, shareDecimals, priceAssetPerShare_, rounding
            ).toUint128();
    }

    /// @dev Converts the given asset amount to share amount. Returned value is in share decimals.
    /// @dev Assumes handling of zero denominator price (pricePoolPerShare) by consumer.
    function assetToShareAmount(
        address shareToken,
        address asset,
        uint256 tokenId,
        uint128 assetAmount,
        D18 pricePoolPerAsset,
        D18 pricePoolPerShare,
        MathLib.Rounding rounding
    ) internal view returns (uint128 shares) {
        if (assetAmount == 0 || pricePoolPerAsset.isZero()) {
            return 0;
        }

        uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
        uint8 shareDecimals = IERC20Metadata(shareToken).decimals();

        return PricingLib.assetToShareAmount(
                assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, pricePoolPerShare, rounding
            ).toUint128();
    }

    /// @dev Converts the given share amount to asset amount. Returned value is in share decimals.
    ///
    ///      NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from
    ///      Fulfilled*  message amounts. Any other codepath must use the variant with pricePoolPerAsset and
    ///      pricePoolPerShare
    function shareToAssetAmount(
        address shareToken,
        uint128 shareAmount,
        address asset,
        uint256 tokenId,
        D18 priceAssetPerShare_,
        MathLib.Rounding rounding
    ) internal view returns (uint128 assets) {
        if (shareAmount == 0 || priceAssetPerShare_.isZero()) {
            return 0;
        }

        uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
        uint8 shareDecimals = IERC20Metadata(shareToken).decimals();

        return PricingLib.convertWithPrice(shareAmount, shareDecimals, assetDecimals, priceAssetPerShare_, rounding);
    }

    /// @dev Converts the given share amount to asset amount. Returned value is in share decimals.
    /// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
    function shareToAssetAmount(
        address shareToken,
        uint128 shareAmount,
        address asset,
        uint256 tokenId,
        D18 pricePoolPerShare,
        D18 pricePoolPerAsset,
        MathLib.Rounding rounding
    ) internal view returns (uint128 shares) {
        if (shareAmount == 0 || pricePoolPerShare.isZero()) {
            return 0;
        }

        uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
        uint8 shareDecimals = IERC20Metadata(shareToken).decimals();

        // NOTE: Pool and share denomination are always equal by design
        return PricingLib.shareToAssetAmount(
                shareAmount, shareDecimals, assetDecimals, pricePoolPerShare, pricePoolPerAsset, rounding
            ).toUint128();
    }

    /// @dev Calculates the asset price per share returns the value in price decimals
    ///      Denominated in ASSET_UNIT/SHARE_UNIT
    /// @dev Assumes handling of zero denominator (shares == 0) by consumer.
    function calculatePriceAssetPerShare(
        address shareToken,
        uint128 shares,
        address asset,
        uint256 tokenId,
        uint128 assets,
        MathLib.Rounding rounding
    ) internal view returns (D18 priceAssetPerShare_) {
        if (assets == 0) {
            return d18(0);
        }

        uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
        uint8 shareDecimals = IERC20Metadata(shareToken).decimals();

        // NOTE: More precise than utilizing D18
        return d18(
            _toPriceDecimals(assets, assetDecimals)
                .mulDiv(10 ** PRICE_DECIMALS, _toPriceDecimals(shares, shareDecimals), rounding).toUint128()
        );
    }

    /// @dev Calculates the maximum amount of assets that can be converted to shares without uint128 overflow.
    ///      Returns the maximum asset amount such that assetToShareAmount(result) <= maxShares.
    /// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
    /// @param  shareToken Address of the share token
    /// @param  asset Address of the asset
    /// @param  tokenId Token ID for ERC6909 (0 for ERC20)
    /// @param  maxShares Maximum allowed shares (typically type(uint128).max)
    /// @param  pricePoolPerShare Price of share in pool units (numerator)
    /// @param  pricePoolPerAsset Price of asset in pool units (denominator)
    /// @return Maximum asset amount that won't cause overflow, or type(uint256).max if no overflow possible
    function maxConvertibleAssetAmount(
        address shareToken,
        address asset,
        uint256 tokenId,
        uint256 maxShares,
        D18 pricePoolPerShare,
        D18 pricePoolPerAsset
    ) internal view returns (uint256) {
        require(pricePoolPerAsset.isNotZero(), DivisionByZero());

        uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
        uint8 shareDecimals = IERC20Metadata(shareToken).decimals();

        return MathLib.mulDiv(
            maxShares,
            uint256(10 ** assetDecimals) * pricePoolPerShare.raw(),
            uint256(10 ** shareDecimals) * pricePoolPerAsset.raw(),
            MathLib.Rounding.Down
        );
    }

    //----------------------------------------------------------------------------------------------
    // Pure methods
    //----------------------------------------------------------------------------------------------

    /// @dev Converts an amount using decimals and price with implicit rounding down
    function convertWithPrice(uint256 baseAmount, uint8 baseDecimals, uint8 quoteDecimals, D18 priceQuotePerBase)
        internal
        pure
        returns (uint128 quoteAmount)
    {
        return convertWithPrice(baseAmount, baseDecimals, quoteDecimals, priceQuotePerBase, MathLib.Rounding.Down);
    }

    /// @dev Converts an amount using decimals and price with explicit rounding.
    function convertWithPrice(
        uint256 baseAmount,
        uint8 baseDecimals,
        uint8 quoteDecimals,
        D18 priceQuotePerBase,
        MathLib.Rounding rounding
    ) internal pure returns (uint128 quoteAmount) {
        if (baseDecimals == quoteDecimals) {
            return priceQuotePerBase.mulUint256(baseAmount, rounding).toUint128();
        }

        return MathLib.mulDiv(
                priceQuotePerBase.raw(),
                baseAmount * 10 ** quoteDecimals,
                10 ** (baseDecimals + PRICE_DECIMALS),
                rounding
            ) // cancel out exponentiation from D18 multiplication
            .toUint128();
    }

    /// @dev Converts an amount using decimals and reciprocal price.
    /// @dev Assumes handling of zero denominator price (priceBasePerQuote) by consumer.
    ///
    ///      NOTE: More precise than convertWithPrice(,,,price.reciprocal,)
    function convertWithReciprocalPrice(
        uint256 baseAmount,
        uint8 baseDecimals,
        uint8 quoteDecimals,
        D18 priceBasePerQuote,
        MathLib.Rounding rounding
    ) internal pure returns (uint128 quoteAmount) {
        require(priceBasePerQuote.isNotZero(), DivisionByZero());

        if (baseDecimals == quoteDecimals) {
            return priceBasePerQuote.reciprocalMulUint256(baseAmount, rounding).toUint128();
        }

        return MathLib.mulDiv(
                10 ** quoteDecimals * baseAmount,
                10 ** PRICE_DECIMALS,
                10 ** baseDecimals * priceBasePerQuote.raw(),
                rounding
            ).toUint128();
    }

    /// @dev Converts an amount using decimals and two prices.
    /// @dev Assumes handling of zero denominator price (priceDenominator) by consumer.
    ///
    ///      NOTE: More precise than custom math with one price and convertWith{Reciprocal}Price for the other
    function convertWithPrices(
        uint256 baseAmount,
        uint8 baseDecimals,
        uint8 quoteDecimals,
        D18 priceNumerator,
        D18 priceDenominator,
        MathLib.Rounding rounding
    ) internal pure returns (uint128 quoteAmount) {
        require(priceDenominator.isNotZero(), DivisionByZero());

        return MathLib.mulDiv(
                priceNumerator.raw(),
                10 ** quoteDecimals * baseAmount,
                10 ** baseDecimals * priceDenominator.raw(),
                rounding
            ).toUint128();
    }

    /// @dev Converts asset amount to share amount.
    /// @dev Assumes handling of zero denominator price (pricePoolPerShare) by consumer.
    ///
    ///      NOTE: Pool and share denomination are always equal by design
    function assetToShareAmount(
        uint256 assetAmount,
        uint8 assetDecimals,
        uint8 shareDecimals,
        D18 pricePoolPerAsset,
        D18 pricePoolPerShare,
        MathLib.Rounding rounding
    ) internal pure returns (uint128 shareAmount) {
        return convertWithPrices(
            assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, pricePoolPerShare, rounding
        );
    }

    /// @dev Converts share amount to asset asset amount.
    /// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
    ///
    ///      NOTE: Pool and share denomination are always equal by design
    function shareToAssetAmount(
        uint256 shareAmount,
        uint8 shareDecimals,
        uint8 assetDecimals,
        D18 pricePoolPerShare,
        D18 pricePoolPerAsset,
        MathLib.Rounding rounding
    ) internal pure returns (uint128 assetAmount) {
        return convertWithPrices(
            shareAmount, shareDecimals, assetDecimals, pricePoolPerShare, pricePoolPerAsset, rounding
        );
    }

    /// @dev Converts pool amount to asset amount.
    /// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
    function poolToAssetAmount(
        uint256 poolAmount,
        uint8 poolDecimals,
        uint8 assetDecimals,
        D18 pricePoolPerAsset,
        MathLib.Rounding rounding
    ) internal pure returns (uint128 assetAmount) {
        return convertWithReciprocalPrice(poolAmount, poolDecimals, assetDecimals, pricePoolPerAsset, rounding);
    }

    /// @dev Converts asset amount to pool amount.
    function assetToPoolAmount(
        uint128 assetAmount,
        uint8 assetDecimals,
        uint8 poolDecimals,
        D18 pricePoolPerAsset,
        MathLib.Rounding rounding
    ) internal pure returns (uint128 poolAmount) {
        return convertWithPrice(assetAmount, assetDecimals, poolDecimals, pricePoolPerAsset, rounding);
    }

    /// @dev Returns the asset price per share denominated in ASSET_UNIT/SHARE_UNIT
    /// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
    ///
    ///      NOTE: Should never be used for calculating amounts due to precision loss. Instead, please refer to
    ///      conversion relying on pricePoolPerShare and pricePoolPerAsset.
    function priceAssetPerShare(D18 pricePoolPerShare, D18 pricePoolPerAsset)
        internal
        pure
        returns (D18 priceAssetPerShare_)
    {
        return pricePoolPerShare / pricePoolPerAsset;
    }

    //----------------------------------------------------------------------------------------------
    // Private methods
    //----------------------------------------------------------------------------------------------

    /// @dev Returns the asset decimals
    function _getAssetDecimals(address asset, uint256 tokenId) private view returns (uint8 assetDecimals) {
        return tokenId == 0 ? IERC20Metadata(asset).decimals() : IERC6909MetadataExt(asset).decimals(tokenId);
    }

    /// @dev When converting assets to shares using the price, all values are normalized to PRICE_DECIMALS
    ///      NOTE: We require all assets to have 2 <= decimals <= 18, see `Spoke.registerAsset`
    function _toPriceDecimals(uint128 _value, uint8 decimals) private pure returns (uint256) {
        if (PRICE_DECIMALS == decimals) return uint256(_value);
        return uint256(_value) * 10 ** (PRICE_DECIMALS - decimals);
    }
}

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

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

type ShareClassId is bytes16;

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

function index(ShareClassId scId) pure returns (uint32) {
    return uint32(uint128(ShareClassId.unwrap(scId)));
}

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, index, raw, equals as ==} for ShareClassId global;

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

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

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

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

// Reserved gas amount for processing a message failure (assuming the worst case)
uint256 constant PROCESS_FAIL_MESSAGE_GAS = 35_000;

// Max length for a supported message. Note that a batch can use several messages with this length.
uint256 constant MESSAGE_MAX_LENGTH = 1_000;

// Max length of an error that happens when processing a message.
uint16 constant ERR_MAX_LENGTH = 32 * 4; // enough for most errors

/// @notice Interface for dispatch-only gateway
interface IGateway is IMessageHandler, IRecoverable {
    //----------------------------------------------------------------------------------------------
    // Structs
    //----------------------------------------------------------------------------------------------

    struct Underpaid {
        uint128 gasLimit;
        uint64 counter;
    }

    //----------------------------------------------------------------------------------------------
    // Events
    //----------------------------------------------------------------------------------------------

    event File(bytes32 indexed what, address addr);
    event UpdateManager(PoolId poolId, address who, bool canManage);
    event BlockOutgoing(uint16 centrifugeId, PoolId poolId, bool isBlocked);
    event PrepareMessage(uint16 indexed centrifugeId, PoolId poolId, bytes message);
    event UnderpaidBatch(uint16 indexed centrifugeId, bytes batch, bytes32 batchHash);
    event RepayBatch(uint16 indexed centrifugeId, bytes batch);
    event ExecuteMessage(uint16 indexed centrifugeId, bytes32 messageHash);
    event FailMessage(uint16 indexed centrifugeId, bytes32 messageHash, bytes error);
    event SetRefundAddress(PoolId poolId, IRecoverable refund);
    event DepositSubsidy(PoolId indexed poolId, address indexed sender, uint256 amount);
    event WithdrawSubsidy(PoolId indexed poolId, address indexed sender, uint256 amount);

    //----------------------------------------------------------------------------------------------
    // Errors
    //----------------------------------------------------------------------------------------------

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

    /// @notice Dispatched when the batch is ended without starting it.
    error NoBatched();

    /// @notice Dispatched when the gateway is paused.
    error Paused();

    /// @notice Dispatched when the gateway tries to send an empty message.
    error EmptyMessage();

    /// @notice Dispatched when the message exceeds MESSAGE_MAX_LENGTH.
    error TooLongMessage();

    /// @notice Dispatched when a message that has not failed is retried.
    error NotFailedMessage();

    /// @notice Dispatched when a batch that has not been underpaid is repaid.
    error NotUnderpaidBatch();

    /// @notice Dispatched when the content of a batch doesn't belong to the same pool
    error MalformedBatch();

    /// @notice Dispatched when a message is sent but the gateway is blocked for sending messages
    error OutgoingBlocked();

    /// @notice Dispatched when an account is not valid to withdraw subsidized pool funds
    error CannotRefund();

    /// @notice Dispatched when there is not enough gas to send the message
    error NotEnoughGas();

    /// @notice Dispatched when the batch requires more gas than the destination chain can execute in a single transaction
    error BatchTooExpensive();

    /// @notice Dispatched when a message was batched but there was a payment for it
    error NotPayable();

    /// @notice Dispatched when the callback fails with no error
    error CallFailedWithEmptyRevert();

    /// @notice Dispatched when the callback is called inside the callback
    error CallbackIsLocked();

    /// @notice Dispatched when the user doesn't call lockCallback()
    error CallbackWasNotLocked();

    /// @notice Dispatched when the callback was not from the sender
    error CallbackWasNotFromSender();

    /// @notice Dispatched when there is not enough msg.value to send to the callback
    error NotEnoughValueForCallback();

    /// @notice Dispatched when trying to create a batch during the send loop
    error ReentrantBatchCreation();

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

    /// @notice Used to update an address (state variable) on very rare occasions
    /// @param what The name of the variable to be updated
    /// @param data New address
    function file(bytes32 what, address data) external;

    /// @notice Configures a manager address for a pool
    /// @param poolId PoolId associated to the adapters
    /// @param who Manager address
    /// @param canManage If enabled as manager
    function updateManager(PoolId poolId, address who, bool canManage) external;

    /// @notice Indicates if the gateway for a determined pool can send messages or not
    /// @param centrifugeId Centrifuge ID associated to this block
    /// @param poolId PoolId associated to this block
    /// @param canSend If can send messages or not
    function blockOutgoing(uint16 centrifugeId, PoolId poolId, bool canSend) external;

    //----------------------------------------------------------------------------------------------
    // Message handling
    //----------------------------------------------------------------------------------------------

    /// @notice Repay an underpaid batch
    /// @param centrifugeId The destination chain
    /// @param batch The batch to repay
    /// @param refund Address to refund excess payment
    function repay(uint16 centrifugeId, bytes memory batch, address refund) external payable;

    /// @notice Retry a failed message
    /// @param centrifugeId The destination chain
    /// @param message The message to retry
    function retry(uint16 centrifugeId, bytes memory message) external;

    /// @notice Handling outgoing messages
    /// @param centrifugeId Destination chain
    /// @param message The message to send
    /// @param unpaidMode Tells if storing the message as unpaid if not enough funds
    /// @param refund Address to refund excess payment
    function send(uint16 centrifugeId, bytes calldata message, bool unpaidMode, address refund) external payable;

    //----------------------------------------------------------------------------------------------
    // Batching
    //----------------------------------------------------------------------------------------------

    /// @notice Automatic batching of cross-chain transactions through a callback.
    ///         Any cross-chain transactions triggered in this callback will automatically be batched.
    /// @dev    Should be used like:
    ///         ```
    ///         contract Integration {
    ///             IGateway gateway;
    ///
    ///             function doSomething(PoolId poolId) external {
    ///                 gateway.withBatch(abi.encodeWithSelector(Integration.callback.selector, poolId));
    ///             }
    ///
    ///             function callback(PoolId poolId) external {
    ///                 // Avoid reentrancy to the callback and ensure it's called from withBatch in the same contract:
    ///                 gateway.lockCallback();
    ///
    ///                 // Call several hub, balance sheet, or spoke methods that trigger cross-chain transactions
    ///             }
    ///         }
    ///         ```
    ///
    ///         NOTE: inside callback, `msgSender` should be used instead of msg.sender
    /// @param  callbackData encoding data for the callback method
    /// @param  callbackValue msg.value to send to the callback
    /// @param  refund Address to refund excess payment
    function withBatch(bytes memory callbackData, uint256 callbackValue, address refund) external payable;

    /// @notice Same as withBatch(..), but without sending any msg.value to the callback
    function withBatch(bytes memory callbackData, address refund) external payable;

    /// @notice Ensures the callback is called by withBatch in the same contract.
    /// @dev calling this at the very beginning inside the multicall means:
    ///         - The callback is called from the gateway under `withBatch`.
    ///         - The callback is called from the same contract, because withBatch uses `msg.sender` as target for the callback
    ///         - The callback that uses this can only be called once inside withBatch scope. No reentrancy.
    function lockCallback() external;

    //----------------------------------------------------------------------------------------------
    // View methods
    //----------------------------------------------------------------------------------------------

    /// @notice Returns the current gateway batching level
    /// @return Whether the gateway is currently batching
    function isBatching() external view returns (bool);
}

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

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

import {Multicall, IMulticall} from "../../misc/Multicall.sol";

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

/// @title  BatchedMulticall
/// @notice Abstract contract that extends Multicall with gateway batching support, enabling efficient
///         aggregation of multiple cross-chain messages into a single batch to reduce transaction costs
///         while coordinating payment handling across batched operations.
/// @dev    IMPORTANT: Integrators MUST replace msg.sender with msgSender() and msg.value with msgValue()
///         for the methods called by the multicall.
/// @dev    IMPORTANT: The contract which extends BatchedMulticall must not treat the gateway
///         as a permissioned/authenticated msg.sender to avoid the multicall execution to call auth methods,
///         opening security issues.
abstract contract BatchedMulticall is Multicall, IBatchedMulticall {
    IGateway public gateway;
    address private transient _sender;

    constructor(IGateway gateway_) {
        gateway = gateway_;
    }

    /// @inheritdoc IMulticall
    /// @notice     With extra support for batching
    function multicall(bytes[] calldata data) public payable override {
        require(_sender == address(0), AlreadyBatching());

        _sender = msg.sender;
        gateway.withBatch{value: msg.value}(
            abi.encodeWithSelector(BatchedMulticall.executeMulticall.selector, data), msg.sender
        );
        _sender = address(0);
    }

    function executeMulticall(bytes[] calldata data) external payable protected {
        gateway.lockCallback();
        super.multicall(data);
    }

    /// @dev Integrators MUST use msgSender() instead of msg.sender, since this is replaced
    ///      by the gateway address inside the multicall.
    function msgSender() internal view virtual returns (address) {
        return _sender != address(0) && msg.sender == address(gateway) ? _sender : msg.sender;
    }

    /// @dev Only the call to multicall should pass the msg.value, which is then passed
    ///      in `gateway.withBatch`. No inner calls should pass any msg.value.
    function msgValue() internal view returns (uint256 value) {
        return _sender != address(0) ? 0 : msg.value;
    }
}

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

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

import {IERC6909Decimals} from "../../../misc/interfaces/IERC6909.sol";

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

interface IHubRegistry is IERC6909Decimals {
    //----------------------------------------------------------------------------------------------
    // Events
    //----------------------------------------------------------------------------------------------

    event NewAsset(AssetId indexed assetId, uint8 decimals);
    event NewPool(PoolId poolId, address indexed manager, AssetId indexed currency);
    event UpdateManager(PoolId indexed poolId, address indexed manager, bool canManage);
    event SetMetadata(PoolId indexed poolId, bytes metadata);
    event UpdateDependency(PoolId indexed poolId, bytes32 indexed what, address dependency);
    event UpdateCurrency(PoolId indexed poolId, AssetId currency);
    event SetHubRequestManager(PoolId indexed poolId, uint16 indexed centrifugeId, IHubRequestManager manager);

    //----------------------------------------------------------------------------------------------
    // Errors
    //----------------------------------------------------------------------------------------------

    error NonExistingPool(PoolId id);
    error AssetAlreadyRegistered();
    error PoolAlreadyRegistered();
    error EmptyAccount();
    error EmptyCurrency();
    error EmptyShareClassManager();
    error AssetNotFound();

    //----------------------------------------------------------------------------------------------
    // Registration methods
    //----------------------------------------------------------------------------------------------

    /// @notice Register a new asset
    /// @param assetId The asset identifier
    /// @param decimals_ The number of decimals for the asset
    function registerAsset(AssetId assetId, uint8 decimals_) external;

    /// @notice Register a new pool
    /// @param poolId The pool identifier
    /// @param manager The initial manager address for the pool
    /// @param currency The currency asset for the pool
    function registerPool(PoolId poolId, address manager, AssetId currency) external;

    //----------------------------------------------------------------------------------------------
    // Update methods
    //----------------------------------------------------------------------------------------------

    /// @notice Allow/disallow an address as a manager for the pool
    /// @param poolId The pool identifier
    /// @param newManager The address to update manager status for
    /// @param canManage Whether the address can manage the pool
    function updateManager(PoolId poolId, address newManager, bool canManage) external;

    /// @notice Set the hub request manager for a pool on a specific network
    /// @param poolId The pool identifier
    /// @param centrifuge The network identifier
    /// @param manager The hub request manager contract
    function setHubRequestManager(PoolId poolId, uint16 centrifuge, IHubRequestManager manager) external;

    /// @notice Sets metadata for this pool
    /// @param poolId The pool identifier
    /// @param metadata The metadata to attach
    function setMetadata(PoolId poolId, bytes calldata metadata) external;

    /// @notice Updates a dependency of the system
    /// @param poolId The pool identifier
    /// @param what The dependency identifier
    /// @param dependency The dependency contract address
    function updateDependency(PoolId poolId, bytes32 what, address dependency) external;

    /// @notice Updates the currency of the pool
    /// @param poolId The pool identifier
    /// @param currency The new currency asset
    function updateCurrency(PoolId poolId, AssetId currency) external;

    //----------------------------------------------------------------------------------------------
    // View methods
    //----------------------------------------------------------------------------------------------

    /// @notice Returns the metadata attached to the pool, if any
    /// @param poolId The pool identifier
    /// @return The metadata bytes
    function metadata(PoolId poolId) external view returns (bytes memory);

    /// @notice Returns the currency of the pool
    /// @param poolId The pool identifier
    /// @return The currency asset identifier
    function currency(PoolId poolId) external view returns (AssetId);

    /// @notice Returns the dependency used in the system
    /// @param poolId The pool identifier
    /// @param what The dependency identifier
    /// @return The dependency contract address
    function dependency(PoolId poolId, bytes32 what) external view returns (address);

    /// @notice Returns whether the account is a manager
    /// @param poolId The pool identifier
    /// @param who The address to check
    /// @return Whether the address is a manager
    function manager(PoolId poolId, address who) external view returns (bool);

    /// @notice Returns the hub request manager for a pool and centrifuge ID
    /// @param poolId The pool identifier
    /// @param centrifugeId The network identifier
    /// @return The hub request manager contract
    function hubRequestManager(PoolId poolId, uint16 centrifugeId) external view returns (IHubRequestManager);

    /// @notice Compute a pool ID given an ID postfix
    /// @param centrifugeId The network identifier
    /// @param postfix The pool ID postfix
    /// @return poolId The computed pool identifier
    function poolId(uint16 centrifugeId, uint48 postfix) external view returns (PoolId poolId);

    /// @notice Returns the decimals for an asset
    /// @param assetId The asset identifier
    /// @return The number of decimals
    function decimals(AssetId assetId) external view returns (uint8);

    /// @notice Returns the decimals for a pool
    /// @param poolId The pool identifier
    /// @return The number of decimals
    function decimals(PoolId poolId) external view returns (uint8);

    /// @notice Checks the existence of a pool
    /// @param poolId The pool identifier
    /// @return Whether the pool exists
    function exists(PoolId poolId) external view returns (bool);

    /// @notice Checks the existence of an asset
    /// @param assetId The asset identifier
    /// @return Whether the asset is registered
    function isRegistered(AssetId assetId) external view returns (bool);
}

File 19 of 29 : IHubRequestManagerCallback.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

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

interface IHubRequestManagerCallback {
    /// @notice Handles a request callback originating from a hub request manager.
    /// @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
    /// @param  extraGasLimit Extra gas limit for the callback
    /// @param refund address to refund the excedent of the payment
    function requestCallback(
        PoolId poolId,
        ShareClassId scId,
        AssetId assetId,
        bytes calldata payload,
        uint128 extraGasLimit,
        bool unpaidMode,
        address refund
    ) external payable;
}

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

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

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

interface IHubRequestManager is IERC165 {
    /// @notice Handles a request originating from the Hub side, similar to HubHelpers.request
    function request(PoolId poolId, ShareClassId scId, AssetId assetId, bytes calldata payload) external;
}

interface IHubRequestManagerNotifications is IERC165 {
    /// @notice Notify a deposit for an investor address located in the chain where the asset belongs
    function notifyDeposit(
        PoolId poolId,
        ShareClassId scId,
        AssetId depositAssetId,
        bytes32 investor,
        uint32 maxClaims,
        address refund
    ) external payable;

    /// @notice Notify a redemption for an investor address located in the chain where the asset belongs
    function notifyRedeem(
        PoolId poolId,
        ShareClassId scId,
        AssetId payoutAssetId,
        bytes32 investor,
        uint32 maxClaims,
        address refund
    ) external payable;
}

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

/// @title  IERC20
/// @dev    Interface of the ERC20 standard as defined in the EIP.
/// @author Modified from OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
interface IERC20 {
    error InvalidAddress();
    error InsufficientBalance();
    error InsufficientAllowance();

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

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

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

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

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

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

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

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    error PermitExpired();
    error InvalidPermit();

    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

interface IERC20Wrapper {
    /**
     * @dev Returns the address of the underlying ERC-20 token that is being wrapped.
     */
    function underlying() external view returns (address);

    /**
     * @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens.
     */
    function depositFor(address account, uint256 value) external returns (bool);

    /**
     * @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens.
     */
    function withdrawTo(address account, uint256 value) external returns (bool);
}

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

import {IERC165} from "forge-std/interfaces/IERC165.sol";

interface IERC6909 is IERC165 {
    error EmptyOwner();
    error EmptyAmount();
    error InvalidTokenId();
    error InsufficientBalance(address owner, uint256 tokenId);
    error InsufficientAllowance(address sender, uint256 tokenId);

    event OperatorSet(address indexed owner, address indexed operator, bool approved);
    event Approval(address indexed owner, address indexed spender, uint256 indexed tokenId, uint256 amount);
    event Transfer(address caller, address indexed from, address indexed to, uint256 indexed tokenId, uint256 amount);

    /// @notice           Owner balance of a tokenId.
    /// @param owner      The address of the owner.
    /// @param tokenId    The id of the token.
    /// @return amount    The balance of the token.
    function balanceOf(address owner, uint256 tokenId) external view returns (uint256 amount);

    /// @notice           Spender allowance of a tokenId.
    /// @param owner      The address of the owner.
    /// @param spender    The address of the spender.
    /// @param tokenId    The id of the token.
    /// @return amount    The allowance of the token.
    function allowance(address owner, address spender, uint256 tokenId) external view returns (uint256 amount);

    /// @notice           Checks if a spender is approved by an owner as an operator.
    /// @param owner      The address of the owner.
    /// @param spender    The address of the spender.
    /// @return approved  The approval status.
    function isOperator(address owner, address spender) external view returns (bool approved);

    /// @notice           Transfers an amount of a tokenId from the caller to a receiver.
    /// @param receiver   The address of the receiver.
    /// @param tokenId    The id of the token.
    /// @param amount     The amount of the token.
    /// @return bool      True, always, unless the function reverts.
    function transfer(address receiver, uint256 tokenId, uint256 amount) external returns (bool);

    /// @notice           Transfers an amount of a tokenId from a sender to a receiver.
    /// @param sender     The address of the sender.
    /// @param receiver   The address of the receiver.
    /// @param tokenId    The id of the token.
    /// @param amount     The amount of the token.
    /// @return bool      True, always, unless the function reverts.
    function transferFrom(address sender, address receiver, uint256 tokenId, uint256 amount) external returns (bool);

    /// @notice           Approves an amount of a tokenId to a spender.
    /// @param spender    The address of the spender.
    /// @param tokenId    The id of the token.
    /// @param amount     The amount of the token.
    /// @return bool      True, always.
    function approve(address spender, uint256 tokenId, uint256 amount) external returns (bool);

    /// @notice           Sets or removes an operator for the caller.
    /// @param operator   The address of the operator.
    /// @param approved   The approval status.
    /// @return bool      True, always.
    function setOperator(address operator, bool approved) external returns (bool);
}

interface IERC6909URIExt {
    event TokenURISet(uint256 indexed tokenId, string uri);
    event ContractURISet(address indexed target, string uri);

    error EmptyURI();

    /// @return uri     Returns the common token URI.
    function contractURI() external view returns (string memory);

    /// @dev            Returns empty string if tokenId does not exist.
    ///                 MAY implemented to throw MissingURI(tokenId) error.
    /// @param tokenId  The token to query URI for.
    /// @return uri     A string representing the uri for the specific tokenId.
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

interface IERC6909NFT is IERC6909, IERC6909URIExt {
    error UnknownTokenId(address owner, uint256 tokenId);
    error LessThanMinimalDecimal(uint8 minimal, uint8 actual);

    /// @notice             Provide URI for a specific tokenId.
    /// @param tokenId      Token Id.
    /// @param URI          URI to a document defining the collection as a whole.
    function setTokenURI(uint256 tokenId, string memory URI) external;

    /// @dev                Optional method to set up the contract URI if needed.
    /// @param URI          URI to a document defining the collection as a whole.
    function setContractURI(string memory URI) external;

    /// @notice             Mint new tokens for a given owner and sets tokenURI.
    /// @dev                For non-fungible tokens, call with amount = 1, for fungible it could be any amount.
    ///                     TokenId is auto incremented by one.
    ///
    /// @param owner        Creates supply of a given tokenId by amount for owner.
    /// @param tokenURI     URI fortestBurningToken the newly minted token.
    /// @return tokenId     Id of the newly minted token.
    function mint(address owner, string memory tokenURI) external returns (uint256 tokenId);

    /// @notice             Destroy supply of a given tokenId by amount.
    /// @dev                The msg.sender MUST be the owner.
    ///
    /// @param tokenId      Item which have reduced supply.
    function burn(uint256 tokenId) external;
}

/// @notice Extension of ERC6909 Standard for tracking total supply
interface IERC6909TotalSupplyExt {
    /// @notice         The totalSupply for a token id.
    ///
    /// @param tokenId  Id of the token
    /// @return supply  Total supply for a given `tokenId`
    function totalSupply(uint256 tokenId) external returns (uint256 supply);
}

interface IERC6909Decimals {
    /// @notice             Used to retrieve the decimals of an asset
    /// @dev                address is used but the value corresponds to a AssetId
    function decimals(uint256 assetId) external view returns (uint8);
}

interface IERC6909MetadataExt is IERC6909Decimals {
    /// @notice             Used to retrieve the decimals of an asset
    /// @dev                address is used but the value corresponds to a AssetId
    function decimals(uint256 assetId) external view returns (uint8);

    /// @notice             Used to retrieve the name of an asset
    /// @dev                address is used but the value corresponds to a AssetId
    function name(uint256 assetId) external view returns (string memory);

    /// @notice             Used to retrieve the symbol of an asset
    /// @dev                address is used but the value corresponds to a AssetId
    function symbol(uint256 assetId) external view returns (string memory);
}

interface IERC6909Fungible is IERC6909 {
    /// @notice             Mint new tokens for a specific tokenid and assign them to an owner
    ///
    /// @param owner        Creates supply of a given `tokenId` by `amount` for owner.
    /// @param tokenId      Id of the item
    /// @param amount       Adds `amount` to the total supply of the given `tokenId`
    function mint(address owner, uint256 tokenId, uint256 amount) external;

    /// @notice             Destroy supply of a given tokenId by amount.
    /// @dev                The msg.sender MUST be the owner.
    ///
    /// @param owner        Owner of the `tokenId`
    /// @param tokenId      Id of the item.
    /// @param amount       Subtract `amount` from the total supply of the given `tokenId`
    function burn(address owner, uint256 tokenId, uint256 amount) external;

    /// @notice             Enforces a transfer from `spender` point of view.
    ///
    ///
    /// @param sender       The owner of the `tokenId`
    /// @param receiver     Address of the receiving party
    /// @param tokenId      Token Id
    /// @param amount       Amount to be transferred
    function authTransferFrom(address sender, address receiver, uint256 tokenId, uint256 amount) external returns (bool);
}

/// @dev  A factory contract to deploy new collateral contracts implementing IERC6909.
interface IERC6909Factory {
    /// Events
    event NewTokenDeployment(address indexed owner, address instance);

    /// @notice       Deploys new install of a contract that implements IERC6909.
    /// @dev          Factory should deploy deterministically if possible.
    ///
    /// @param owner  Owner of the deployed collateral contract which has initial full rights.
    /// @param salt   Used to make a deterministic deployment.
    /// @return       An address of the newly deployed contract.
    function deploy(address owner, bytes32 salt) external returns (address);

    /// @notice       Generates a new deterministic address based on the owner and the salt.
    ///
    /// @param owner  Owner of the deployed collateral contract which has initial full rights.
    /// @param salt   Used to make a deterministic deployment.
    /// @return       An address of the newly deployed contract.
    function previewAddress(address owner, bytes32 salt) external returns (address);
}

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

/// @notice Generic interface for entities that handle incoming messages
interface IMessageHandler {
    //----------------------------------------------------------------------------------------------
    // Incoming
    //----------------------------------------------------------------------------------------------

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

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

File 25 of 29 : IBatchedMulticall.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

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

/// @notice A multicall that batches the messages using the gateway
interface IBatchedMulticall {
    error AlreadyBatching();

    /// @notice Returns the gateway contract used for batching messages
    /// @return The gateway contract instance
    function gateway() external view returns (IGateway);
}

File 26 of 29 : Multicall.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.28;

// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359
// If perform any change on it, please ensure no other warnings appears

import {IMulticall} from "./interfaces/IMulticall.sol";
import {ReentrancyProtection} from "./ReentrancyProtection.sol";

/// @title  Multicall
/// @notice Abstract contract that enables batch execution of multiple function calls in a single transaction.
abstract contract Multicall is ReentrancyProtection, IMulticall {
    function multicall(bytes[] calldata data) public payable virtual protected {
        uint256 totalBytes = data.length;
        for (uint256 i; i < totalBytes; ++i) {
            (bool success, bytes memory returnData) = address(this).delegatecall(data[i]);
            if (!success) {
                uint256 length = returnData.length;
                require(length != 0, CallFailedWithEmptyRevert());

                assembly ("memory-safe") {
                    revert(add(32, returnData), length)
                }
            }
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;

interface IERC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceID The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function
    /// uses less than 30,000 gas.
    /// @return `true` if the contract implements `interfaceID` and
    /// `interfaceID` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

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

/// @notice Allows to call several calls of the same contract in a single transaction
interface IMulticall {
    /// @notice Dispatched when an empty revert is dispatched in a method in the multicall
    error CallFailedWithEmptyRevert();

    /// @notice Allows caller to execute multiple (batched) messages calls in one transaction.
    /// @param data An array of encoded methods of the same contract.
    /// @dev No reentrant execution is allowed.
    ///         If one call fails, it reverts the whole transaction.
    ///         In order to provide the correct value for functions that require top up,
    ///         the caller must estimate separately, in advance, how much each of the message call will cost.
    ///         The `msg.value` when calling this method must be the sum of all estimates.
    function multicall(bytes[] calldata data) external payable;
}

File 29 of 29 : ReentrancyProtection.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.28;

// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359
// If perform any change on it, please ensure no other warnings appears

/// @title  ReentrancyProtection
/// @notice Abstract contract that implements reentrancy protection using transient storage.
abstract contract ReentrancyProtection {
    /// @notice Dispatched when there is a re-entrancy issue
    error UnauthorizedSender();

    address private transient _initiator;

    /// @dev The method is protected for reentrancy issues.
    modifier protected() {
        if (_initiator == address(0)) {
            // Single call re-entrancy lock
            _initiator = msg.sender;
            _;
            _initiator = address(0);
        } else {
            // Multicall re-entrancy lock
            require(msg.sender == _initiator, UnauthorizedSender());
            _;
        }
    }
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IHubRegistry","name":"hubRegistry_","type":"address"},{"internalType":"contract IGateway","name":"gateway_","type":"address"},{"internalType":"address","name":"deployer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyBatching","type":"error"},{"inputs":[],"name":"CallFailedWithEmptyRevert","type":"error"},{"inputs":[],"name":"CancellationInitializationRequired","type":"error"},{"inputs":[],"name":"CancellationQueued","type":"error"},{"inputs":[],"name":"DivisionByZero","type":"error"},{"inputs":[],"name":"EpochNotFound","type":"error"},{"inputs":[{"internalType":"uint32","name":"epochId","type":"uint32"},{"internalType":"uint32","name":"actualEpochId","type":"uint32"}],"name":"EpochNotInSequence","type":"error"},{"inputs":[],"name":"FileUnrecognizedParam","type":"error"},{"inputs":[],"name":"InsufficientPending","type":"error"},{"inputs":[],"name":"IssuanceRequired","type":"error"},{"inputs":[],"name":"MulDiv_Overflow","type":"error"},{"inputs":[],"name":"NoOrderFound","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"RevocationRequired","type":"error"},{"inputs":[],"name":"SliceOutOfBounds","type":"error"},{"inputs":[],"name":"Uint128_Overflow","type":"error"},{"inputs":[],"name":"Uint64_Overflow","type":"error"},{"inputs":[],"name":"UnauthorizedSender","type":"error"},{"inputs":[],"name":"UnknownRequestType","type":"error"},{"inputs":[],"name":"UnknownRequestType","type":"error"},{"inputs":[],"name":"ZeroApprovalAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"uint128","name":"approvedPoolAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"approvedAssetAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"pendingAssetAmount","type":"uint128"}],"name":"ApproveDeposits","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"uint128","name":"approvedShareAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"pendingShareAmount","type":"uint128"}],"name":"ApproveRedeems","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"investor","type":"bytes32"},{"indexed":false,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"paymentAssetAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"pendingAssetAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"payoutShareAmount","type":"uint128"},{"indexed":false,"internalType":"uint64","name":"issuedAt","type":"uint64"}],"name":"ClaimDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"investor","type":"bytes32"},{"indexed":false,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"paymentShareAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"pendingShareAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"payoutAssetAmount","type":"uint128"},{"indexed":false,"internalType":"uint64","name":"revokedAt","type":"uint64"}],"name":"ClaimRedeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Deny","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"components":[{"internalType":"uint32","name":"deposit","type":"uint32"},{"internalType":"uint32","name":"issue","type":"uint32"},{"internalType":"uint32","name":"redeem","type":"uint32"},{"internalType":"uint32","name":"revoke","type":"uint32"}],"indexed":false,"internalType":"struct EpochId","name":"epochIdData","type":"tuple"}],"name":"EpochIdModified","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"what","type":"bytes32"},{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"File","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"D18","name":"pricePoolPerShare","type":"uint128"},{"indexed":false,"internalType":"D18","name":"priceAssetPerShare","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"issuedShareAmount","type":"uint128"}],"name":"IssueShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Rely","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"D18","name":"pricePoolPerShare","type":"uint128"},{"indexed":false,"internalType":"D18","name":"priceAssetPerShare","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"approvedShareAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"payoutAssetAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"payoutPoolAmount","type":"uint128"}],"name":"RevokeShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"investor","type":"bytes32"},{"indexed":false,"internalType":"uint128","name":"pendingAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"totalPendingAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"queuedAmount","type":"uint128"},{"indexed":false,"internalType":"bool","name":"isQueuedCancellation","type":"bool"}],"name":"UpdateDepositRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"investor","type":"bytes32"},{"indexed":false,"internalType":"uint128","name":"pendingAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"totalPendingAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"queuedAmount","type":"uint128"},{"indexed":false,"internalType":"bool","name":"isQueuedCancellation","type":"bool"}],"name":"UpdateRedeemRequest","type":"event"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"}],"name":"allowForceDepositCancel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"}],"name":"allowForceRedeemCancel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"},{"internalType":"uint32","name":"nowDepositEpochId","type":"uint32"},{"internalType":"uint128","name":"approvedAssetAmount","type":"uint128"},{"internalType":"D18","name":"pricePoolPerAsset","type":"uint128"},{"internalType":"address","name":"refund","type":"address"}],"name":"approveDeposits","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"payoutAssetId","type":"uint128"},{"internalType":"uint32","name":"nowRedeemEpochId","type":"uint32"},{"internalType":"uint128","name":"approvedShareAmount","type":"uint128"},{"internalType":"D18","name":"pricePoolPerAsset","type":"uint128"}],"name":"approveRedeems","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"cancelDepositRequest","outputs":[{"internalType":"uint128","name":"cancelledAssetAmount","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"payoutAssetId","type":"uint128"}],"name":"cancelRedeemRequest","outputs":[{"internalType":"uint128","name":"cancelledShareAmount","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"}],"name":"depositRequest","outputs":[{"internalType":"uint128","name":"pending","type":"uint128"},{"internalType":"uint32","name":"lastUpdate","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"}],"name":"epochId","outputs":[{"internalType":"uint32","name":"deposit","type":"uint32"},{"internalType":"uint32","name":"issue","type":"uint32"},{"internalType":"uint32","name":"redeem","type":"uint32"},{"internalType":"uint32","name":"revoke","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"uint32","name":"epochId_","type":"uint32"}],"name":"epochInvestAmounts","outputs":[{"internalType":"uint128","name":"approvedPoolAmount","type":"uint128"},{"internalType":"uint128","name":"approvedAssetAmount","type":"uint128"},{"internalType":"uint128","name":"pendingAssetAmount","type":"uint128"},{"internalType":"D18","name":"pricePoolPerAsset","type":"uint128"},{"internalType":"D18","name":"pricePoolPerShare","type":"uint128"},{"internalType":"uint64","name":"issuedAt","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"uint32","name":"epochId_","type":"uint32"}],"name":"epochRedeemAmounts","outputs":[{"internalType":"uint128","name":"approvedShareAmount","type":"uint128"},{"internalType":"uint128","name":"pendingShareAmount","type":"uint128"},{"internalType":"D18","name":"pricePoolPerAsset","type":"uint128"},{"internalType":"D18","name":"pricePoolPerShare","type":"uint128"},{"internalType":"uint128","name":"payoutAssetAmount","type":"uint128"},{"internalType":"uint64","name":"revokedAt","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"executeMulticall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"what","type":"bytes32"},{"internalType":"address","name":"data","type":"address"}],"name":"file","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"},{"internalType":"address","name":"refund","type":"address"}],"name":"forceCancelDepositRequest","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"payoutAssetId","type":"uint128"},{"internalType":"address","name":"refund","type":"address"}],"name":"forceCancelRedeemRequest","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gateway","outputs":[{"internalType":"contract IGateway","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hub","outputs":[{"internalType":"contract IHubRequestManagerCallback","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hubRegistry","outputs":[{"internalType":"contract IHubRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"},{"internalType":"uint32","name":"nowIssueEpochId","type":"uint32"},{"internalType":"D18","name":"pricePoolPerShare","type":"uint128"},{"internalType":"uint128","name":"extraGasLimit","type":"uint128"},{"internalType":"address","name":"refund","type":"address"}],"name":"issueShares","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"maxDepositClaims","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"payoutAssetId","type":"uint128"}],"name":"maxRedeemClaims","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"AssetId","name":"assetId","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"uint32","name":"maxClaims","type":"uint32"},{"internalType":"address","name":"refund","type":"address"}],"name":"notifyDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"AssetId","name":"assetId","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"uint32","name":"maxClaims","type":"uint32"},{"internalType":"address","name":"refund","type":"address"}],"name":"notifyRedeem","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"nowDepositEpoch","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"nowIssueEpoch","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"nowRedeemEpoch","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"nowRevokeEpoch","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"}],"name":"pendingDeposit","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"}],"name":"pendingRedeem","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"}],"name":"queuedDepositRequest","outputs":[{"internalType":"bool","name":"isCancelling","type":"bool"},{"internalType":"uint128","name":"amount","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"}],"name":"queuedRedeemRequest","outputs":[{"internalType":"bool","name":"isCancelling","type":"bool"},{"internalType":"uint128","name":"amount","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"}],"name":"redeemRequest","outputs":[{"internalType":"uint128","name":"pending","type":"uint128"},{"internalType":"uint32","name":"lastUpdate","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"AssetId","name":"assetId","type":"uint128"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"request","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"requestDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"payoutAssetId","type":"uint128"}],"name":"requestRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"payoutAssetId","type":"uint128"},{"internalType":"uint32","name":"nowRevokeEpochId","type":"uint32"},{"internalType":"D18","name":"pricePoolPerShare","type":"uint128"},{"internalType":"uint128","name":"extraGasLimit","type":"uint128"},{"internalType":"address","name":"refund","type":"address"}],"name":"revokeShares","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"AssetId","name":"assetId","type":"uint128"},{"components":[{"internalType":"uint32","name":"deposit","type":"uint32"},{"internalType":"uint32","name":"issue","type":"uint32"},{"internalType":"uint32","name":"redeem","type":"uint32"},{"internalType":"uint32","name":"revoke","type":"uint32"}],"internalType":"struct EpochId","name":"epochIdData","type":"tuple"}],"name":"setEpochIds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60a060405234801561000f575f5ffd5b50604051615e23380380615e2383398101604081905261002e916100b8565b6001600160a01b0381165f8181526020819052604080822060019055518492849290917fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250600180546001600160a01b0319166001600160a01b0392831617905592909216608052506101029050565b6001600160a01b03811681146100b5575f5ffd5b50565b5f5f5f606084860312156100ca575f5ffd5b83516100d5816100a1565b60208501519093506100e6816100a1565b60408501519092506100f7816100a1565b809150509250925092565b608051615c9961018a5f395f818161086701528181610e7a0152818161173e015281816118db0152818161196601528181611ec7015281816120c301528181612141015281816123bd015281816124cf01528181612de401528181613947015281816139d201528181613e3201528181613ebd0152818161433c01526143dc0152615c995ff3fe6080604052600436106101d5575f3560e01c806301ffc9a7146101d95780630a6670631461020d578063116191b61461024157806328537d06146102785780632f6c33bf14610344578063365a86fc146103655780633f92bf831461038457806342e413391461039757806346bfcc8f146103b65780635eb4d168146103e257806365fae35e1461046357806366e960e31461048257806371c4482614610503578063730316d114610522578063790b56ce146105415780637fe50ab2146105605780638a93ba581461057f5780638baa4083146105925780639b884cd5146105b15780639c52a7f1146105d05780639d26e184146105ef5780639e5d3a7a14610637578063ac9650d81461064a578063ae7275201461065d578063b5eaa51d1461067c578063bcf16c93146106c4578063be3bad4a14610721578063bf353dbb14610734578063c076a59f1461076d578063c3f4d5ed146107fe578063c592045514610811578063c88854a314610856578063d0d4133114610889578063d4e8be831461089c578063da8336ba146108bb578063e0aeab1e146108ce578063e3b304d4146108e1578063e47091c914610926578063ee1cb43d1461099d578063fc689b78146109b0578063fdfa8fe0146109cf575b5f5ffd5b3480156101e4575f5ffd5b506101f86101f3366004615055565b610a27565b60405190151581526020015b60405180910390f35b348015610218575f5ffd5b5061022c6102273660046150c5565b610a93565b60405163ffffffff9091168152602001610204565b34801561024c575f5ffd5b50600154610260906001600160a01b031681565b6040516001600160a01b039091168152602001610204565b348015610283575f5ffd5b506102f9610292366004615124565b600460209081525f94855260408086208252938552838520815291845282842090915282529020805460018201546002909201546001600160801b0380831693600160801b938490048216938282169391819004831692821691046001600160401b031686565b604080516001600160801b039788168152958716602087015293861693850193909352908416606084015290921660808201526001600160401b0390911660a082015260c001610204565b34801561034f575f5ffd5b5061036361035e366004615177565b610b37565b005b348015610370575f5ffd5b50600254610260906001600160a01b031681565b610363610392366004615229565b610e77565b3480156103a2575f5ffd5b5061022c6103b1366004615285565b6110ac565b3480156103c1575f5ffd5b506103d56103d03660046150c5565b61110c565b60405161020491906152c9565b3480156103ed575f5ffd5b506102f96103fc366004615124565b600560209081525f94855260408086208252938552838520815291845282842090915282529020805460018201546002909201546001600160801b0380831693600160801b938490048216938282169391819004831692821691046001600160401b031686565b34801561046e575f5ffd5b5061036361047d3660046152dd565b6111d4565b34801561048d575f5ffd5b506104df61049c3660046152f6565b600860209081525f94855260408086208252938552838520815291845282842090915282529020546001600160801b03811690600160801b900463ffffffff1682565b604080516001600160801b03909316835263ffffffff909116602083015201610204565b34801561050e575f5ffd5b5061022c61051d366004615285565b611247565b34801561052d575f5ffd5b5061036361053c366004615340565b61129d565b34801561054c575f5ffd5b5061036361055b36600461540c565b6113f8565b34801561056b575f5ffd5b5061022c61057a366004615285565b611437565b61036361058d36600461546c565b61148d565b34801561059d575f5ffd5b506103636105ac36600461540c565b6115c9565b3480156105bc575f5ffd5b506103d56105cb3660046150c5565b611609565b3480156105db575f5ffd5b506103636105ea3660046152dd565b6116c9565b3480156105fa575f5ffd5b506101f86106093660046152f6565b600c60209081525f948552604080862082529385528385208152918452828420909152825290205460ff1681565b6103636106453660046154db565b61173b565b61036361065836600461546c565b611d78565b348015610668575f5ffd5b5061022c610677366004615285565b611e75565b348015610687575f5ffd5b506101f86106963660046152f6565b600d60209081525f948552604080862082529385528385208152918452828420909152825290205460ff1681565b3480156106cf575f5ffd5b506104df6106de3660046152f6565b600960209081525f94855260408086208252938552838520815291845282842090915282529020546001600160801b03811690600160801b900463ffffffff1682565b61036361072f3660046154db565b611ec4565b34801561073f575f5ffd5b5061075f61074e3660046152dd565b5f6020819052908152604090205481565b604051908152602001610204565b348015610778575f5ffd5b506107ce610787366004615285565b600360209081525f938452604080852082529284528284209052825290205463ffffffff80821691600160201b8104821691600160401b8204811691600160601b90041684565b6040805163ffffffff95861681529385166020850152918416918301919091529091166060820152608001610204565b61036361080c3660046154db565b6123ba565b34801561081c575f5ffd5b506103d561082b366004615285565b600760209081525f93845260408085208252928452828420905282529020546001600160801b031681565b348015610861575f5ffd5b506102607f000000000000000000000000000000000000000000000000000000000000000081565b610363610897366004615562565b6124cc565b3480156108a7575f5ffd5b506103636108b63660046155da565b6127ee565b6103636108c9366004615604565b6128a8565b6103636108dc366004615604565b612b93565b3480156108ec575f5ffd5b506103d56108fb366004615285565b600660209081525f93845260408085208252928452828420905282529020546001600160801b031681565b348015610931575f5ffd5b5061097e6109403660046152f6565b600a60209081525f948552604080862082529385528385208152918452828420909152825290205460ff81169061010090046001600160801b031682565b6040805192151583526001600160801b03909116602083015201610204565b6103636109ab366004615229565b612de1565b3480156109bb575f5ffd5b5061022c6109ca3660046150c5565b612f96565b3480156109da575f5ffd5b5061097e6109e93660046152f6565b600b60209081525f948552604080862082529385528385208152918452828420909152825290205460ff81169061010090046001600160801b031682565b5f6001600160e01b0319821663af00afbd60e01b1480610a5757506001600160e01b03198216632f6c33bf60e01b145b80610a7257506001600160e01b03198216630e8b676960e21b145b80610a8d57506001600160e01b031982166301ffc9a760e01b145b92915050565b6001600160401b0384165f8181526008602090815260408083206001600160801b031988168085529083528184206001600160801b0387811680875291855283862089875285528386208451808601865290549182168152600160801b90910463ffffffff90811682870152968652600385528386209286529184528285209085529092528220549192610b2e92600160601b90041661302d565b95945050505050565b335f90815260208190526040902054600114610b665760405163ea8e4eb560e01b815260040160405180910390fd5b5f610ba583838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061307b92505050565b6004811115610bb657610bb661566f565b90505f1960ff821601610c1e575f610c0284848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061309a92505050565b9050610c1887878360200151845f0151896113f8565b50610e6f565b60011960ff821601610c7f575f610c6984848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061311f92505050565b9050610c1887878360200151845f0151896115c9565b60021960ff821601610d98575f610cca84848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061313992505050565b90505f610cdc8888845f01518961110c565b90506001600160801b03811615610d915760025460408051608081018252845181525f60208201819052918101919091526001600160801b03831660608201526001600160a01b039091169063c3ab3924908a908a908a90610d3d906131a1565b5f60015f6040518863ffffffff1660e01b8152600401610d6397969594939291906156b1565b5f604051808303815f87803b158015610d7a575f5ffd5b505af1158015610d8c573d5f5f3e3d5ffd5b505050505b5050610e6f565b60031960ff821601610e56575f610de384848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506131e292505050565b90505f610df58888845f015189611609565b90506001600160801b03811615610d915760025460408051608081018252845181525f60208201819052918101919091526001600160801b03831660608201526001600160a01b039091169063c3ab3924908a908a908a90610d3d906131f7565b604051638d54989d60e01b815260040160405180910390fd5b505050505050565b847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633625342b82610eb0613222565b6040518363ffffffff1660e01b8152600401610ecd929190615724565b602060405180830381865afa158015610ee8573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0c9190615746565b610f295760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0386165f908152600d602090815260408083206001600160801b03198916845282528083206001600160801b0387168452825280832087845290915290205460ff16610f8f57604051635fb581dd60e01b815260040160405180910390fd5b6001600160401b0386165f9081526008602090815260408083206001600160801b03198916845282528083206001600160801b0387811685529083528184208885529092528220541690610fe9888884848a8a6001613260565b90506001600160801b038116156110a257604080516080810182528781525f602082018190529181018290526001600160801b038316606082015261102d906131f7565b6002549091506001600160a01b031663c3ab3924611049613531565b8b8b8a865f5f8d6040518963ffffffff1660e01b815260040161107297969594939291906156b1565b5f604051808303818588803b158015611089575f5ffd5b505af115801561109b573d5f5f3e3d5ffd5b5050505050505b5050505050505050565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b038516845290915281205461110290600160401b900463ffffffff166001615779565b90505b9392505050565b335f9081526020819052604081205460011461113b5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0385165f818152600c602090815260408083206001600160801b031989168085529083528184206001600160801b038881168087529185528386208a87528552838620805460ff19166001179055958552600984528285209185529083528184209084528252808320878452909152812054909116906111ca90879087908490888882613260565b9695505050505050565b335f908152602081905260409020546001146112035760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b038516845290915281205461110290600160201b900463ffffffff166001615779565b335f908152602081905260409020546001146112cc5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0384165f8181526003602090815260408083206001600160801b031988168085529083528184206001600160801b0388168086529084529382902086518154948801518489015160608a015163ffffffff908116600160601b0263ffffffff60601b19928216600160401b0292909216600160401b600160801b0319938216600160201b026001600160401b031990991691909416179690961716179390931790925551919290917f0f7c52086fe372e36e65c8c21cbcc8254ac152ce8c02cd914c162f62ed80237b906113ea9086905f60808201905063ffffffff835116825263ffffffff602084015116602083015263ffffffff604084015116604083015263ffffffff606084015116606083015292915050565b60405180910390a450505050565b335f908152602081905260409020546001146114275760405163ea8e4eb560e01b815260040160405180910390fd5b610e6f858585600186865f613260565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b038516845290915281205461110290600160601b900463ffffffff166001615779565b5f5c6001600160a01b031661152f57335f805c6001600160a01b0319168217905d5060015f9054906101000a90046001600160a01b03166001600160a01b031663d988dd406040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156114fb575f5ffd5b505af115801561150d573d5f5f3e3d5ffd5b5050505061151b828261354c565b5f6001600160a01b0319815c16815d505050565b336001600160a01b035f5c161461155957604051630101292160e31b815260040160405180910390fd5b60015f9054906101000a90046001600160a01b03166001600160a01b031663d988dd406040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156115a5575f5ffd5b505af11580156115b7573d5f5f3e3d5ffd5b505050506115c5828261354c565b5050565b335f908152602081905260409020546001146115f85760405163ea8e4eb560e01b815260040160405180910390fd5b610e6f858585600186866001613260565b335f908152602081905260408120546001146116385760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0385165f818152600d602090815260408083206001600160801b031989168085529083528184206001600160801b038881168087529185528386208a87528552838620805460ff1916600190811790915596865260088552838620928652918452828520908552835281842088855290925282205416916111ca9188918891859189908990613260565b335f908152602081905260409020546001146116f85760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633625342b82611774613222565b6040518363ffffffff1660e01b8152600401611791929190615724565b602060405180830381865afa1580156117ac573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117d09190615746565b6117ed5760405163ea8e4eb560e01b815260040160405180910390fd5b6117f8888888611e75565b63ffffffff168563ffffffff1614856118128a8a8a611e75565b909161183c57604051632c647e3760e21b8152600401611833929190615795565b60405180910390fd5b50506001600160401b0388165f9081526007602090815260408083206001600160801b03198b16845282528083206001600160801b038a8116855292529091205481169085168110156118a25760405163776a3aa960e11b815260040160405180910390fd5b5f856001600160801b0316116118cb5760405163035a9e4760e11b815260040160405180910390fd5b5f6119f5866001600160801b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166309d2f9b48b6040518263ffffffff1660e01b815260040161192591906152c9565b602060405180830381865afa158015611940573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061196491906157ac565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ff01a6f78e6040518263ffffffff1660e01b81526004016119b091906157cc565b602060405180830381865afa1580156119cb573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ef91906157ac565b88613724565b90505f60045f8c6001600160401b03166001600160401b031681526020019081526020015f205f8b6001600160801b0319166001600160801b03191681526020019081526020015f205f8a6001600160801b03166001600160801b031681526020019081526020015f205f8963ffffffff1663ffffffff1681526020019081526020015f20905086815f0160106101000a8154816001600160801b0302191690836001600160801b0316021790555081815f015f6101000a8154816001600160801b0302191690836001600160801b0316021790555082816001015f6101000a8154816001600160801b0302191690836001600160801b03160217905550858160010160106101000a8154816001600160801b0302191690836001600160801b031602179055508660075f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f8b6001600160801b03166001600160801b031681526020019081526020015f205f8282829054906101000a90046001600160801b0316611ba491906157e0565b92506101000a8154816001600160801b0302191690836001600160801b031602179055508683611bd491906157e0565b92508760035f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f8b6001600160801b03166001600160801b031681526020019081526020015f205f015f6101000a81548163ffffffff021916908363ffffffff160217905550886001600160801b03168a6001600160801b0319168c6001600160401b03167f1785217365be01fea67dbce22680b382886fe6a3a22156830b3cda5823a42a8e8b868c89604051611cb194939291906157ff565b60405180910390a45f611cf760405180604001604052808a6001600160801b03168152602001611ce78a6001600160801b031690565b6001600160801b03169052613732565b6002549091506001600160a01b031663c3ab3924611d13613531565b8e8e8e865f5f8e6040518963ffffffff1660e01b8152600401611d3c97969594939291906156b1565b5f604051808303818588803b158015611d53575f5ffd5b505af1158015611d65573d5f5f3e3d5ffd5b5050505050505050505050505050505050565b60015c6001600160a01b031615611da257604051631ccdbfa560e21b815260040160405180910390fd5b336001805c6001600160a01b0319168217905d506001546040516001600160a01b03909116906329d43364903490631152774b60e31b90611de99087908790602401615856565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e085901b9092168252611e309133906004016158f4565b5f604051808303818588803b158015611e47575f5ffd5b505af1158015611e59573d5f5f3e3d5ffd5b505f935050506001805c6001600160a01b03191691505d505050565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b03851684529091528120546111029063ffffffff166001615779565b867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633625342b82611efd613222565b6040518363ffffffff1660e01b8152600401611f1a929190615724565b602060405180830381865afa158015611f35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f599190615746565b611f765760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0388165f9081526003602090815260408083206001600160801b03198b16845282528083206001600160801b038a16845290915290205463ffffffff9081169086161115611fde576040516386d1007760e01b815260040160405180910390fd5b611fe9888888611247565b63ffffffff168563ffffffff1614856120038a8a8a611247565b909161202457604051632c647e3760e21b8152600401611833929190615795565b50506001600160401b0388165f9081526004602090815260408083206001600160801b0319808c1685529083528184206001600160801b038b8116865290845282852063ffffffff8b16865290935290832060028101805493891693909216831790915591906120939061374f565b61209d575f6121e6565b8154604051630274be6d60e21b81526121e691600160801b90046001600160801b0316907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906309d2f9b490612100908d906004016152c9565b602060405180830381865afa15801561211b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061213f91906157ac565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ff01a6f78e6040518263ffffffff1660e01b815260040161218b91906157cc565b602060405180830381865afa1580156121a6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121ca91906157ac565b6001860154600160801b90046001600160801b03168a5f61375d565b90506121f14261376c565b600283018054600160801b600160c01b031916600160801b6001600160401b03938416810291909117909155908b165f8181526003602090815260408083206001600160801b03198f168085529083528184206001600160801b038f81168087529190945291909320805463ffffffff60201b1916600160201b63ffffffff8f1602179055600187015490949293927f75d54fc68ce51f85af6cc4bc67a5d7d3267296e63539b2d428743a1a8a8380de928d928d926122b29291041661374f565b6122bc575f6122e3565b600288015460018901546122e3916001600160801b0390811691600160801b900416613799565b876040516122f494939291906157ff565b60405180910390a45f61233a6040518060400160405280846001600160801b0316815260200161232a8a6001600160801b031690565b6001600160801b031690526137a4565b6002549091506001600160a01b031663c3ab3924612356613531565b8d8d8d868c5f8d6040518963ffffffff1660e01b815260040161237f97969594939291906156b1565b5f604051808303818588803b158015612396575f5ffd5b505af11580156123a8573d5f5f3e3d5ffd5b50505050505050505050505050505050565b867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633625342b826123f3613222565b6040518363ffffffff1660e01b8152600401612410929190615724565b602060405180830381865afa15801561242b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061244f9190615746565b61246c5760405163ea8e4eb560e01b815260040160405180910390fd5b5f5f61247b8a8a8a8a8a6137c1565b915091505f61233a6040518060600160405280856001600160801b03168152602001846001600160801b031681526020016124bc8a6001600160801b031690565b6001600160801b03169052613bce565b857f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633625342b82612505613222565b6040518363ffffffff1660e01b8152600401612522929190615724565b602060405180830381865afa15801561253d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125619190615746565b61257e5760405163ea8e4eb560e01b815260040160405180910390fd5b6125898787876110ac565b63ffffffff168463ffffffff1614846125a38989896110ac565b90916125c457604051632c647e3760e21b8152600401611833929190615795565b50506001600160401b0387165f9081526006602090815260408083206001600160801b03198a16845282528083206001600160801b038981168552925290912054811690841681101561262a5760405163776a3aa960e11b815260040160405180910390fd5b5f846001600160801b0316116126535760405163035a9e4760e11b815260040160405180910390fd5b6001600160401b0388165f8181526005602090815260408083206001600160801b03198c81168086529184528285206001600160801b038d811680885291865284872063ffffffff8e16885286528487208c8216600160801b8b8416021781556001810180549094168c831617909355968652600685528386209286529184528285209185529252822080549193889391926126f1918591166157e0565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550848261272191906157e0565b6001600160401b038a165f8181526003602090815260408083206001600160801b03198e168085529083528184206001600160801b038e16808652935292819020805463ffffffff8d16600160401b0263ffffffff60401b1990911617905551939550929091907f679cd78fb2cbc9b1fa61043bb803ac3d5a5a8e0dd7aaa5a94e8bc5721dd2b8aa906127db908b908b90899063ffffffff9390931683526001600160801b03918216602084015216604082015260600190565b60405180910390a4505050505050505050565b335f9081526020819052604090205460011461281d5760405163ea8e4eb560e01b815260040160405180910390fd5b8162343ab160e91b0361284a57600280546001600160a01b0319166001600160a01b038316179055612863565b604051633db0d5b960e01b815260040160405180910390fd5b604080518381526001600160a01b03831660208201527f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba910160405180910390a15050565b5f5c6001600160a01b0316612a3857335f805c6001600160a01b0319168217905d505f8080805b8563ffffffff168163ffffffff161015612946575f5f5f5f6128f38e8e8d8f613bf3565b93509350935093508388612907919061591d565b9750612913838861591d565b96506001600160801b03821615612928578195505b806129365750505050612946565b5050600190920191506128cf9050565b505f826001600160801b0316118061296657505f816001600160801b0316115b15612a1f576002546001600160a01b031663c3ab3924612984613531565b8b8b8b6129cb60405180608001604052808e81526020018a6001600160801b031681526020018b6001600160801b03168152602001896001600160801b03168152506131a1565b5f5f8c6040518963ffffffff1660e01b81526004016129f097969594939291906156b1565b5f604051808303818588803b158015612a07575f5ffd5b505af1158015612a19573d5f5f3e3d5ffd5b50505050505b505f9150506001600160a01b0319815c16815d50610e6f565b336001600160a01b035f5c1614612a6257604051630101292160e31b815260040160405180910390fd5b5f8080805b8563ffffffff168163ffffffff161015612ade575f5f5f5f612a8b8e8e8d8f613bf3565b93509350935093508388612a9f919061591d565b9750612aab838861591d565b96506001600160801b03821615612ac0578195505b80612ace5750505050612ade565b505060019092019150612a679050565b505f826001600160801b03161180612afe57505f816001600160801b0316115b15612b88576002546001600160a01b031663c3ab3924612b1c613531565b8b8b8b612b6360405180608001604052808e81526020018a6001600160801b031681526020018b6001600160801b03168152602001896001600160801b03168152506131a1565b5f5f8c6040518963ffffffff1660e01b815260040161107297969594939291906156b1565b505050505050505050565b5f5c6001600160a01b0316612cb657335f805c6001600160a01b0319168217905d505f8080805b8563ffffffff168163ffffffff161015612c31575f5f5f5f612bde8e8e8d8f614113565b93509350935093508388612bf2919061591d565b9750612bfe838861591d565b96506001600160801b03821615612c13578195505b80612c215750505050612c31565b505060019092019150612bba9050565b505f826001600160801b03161180612c5157505f816001600160801b0316115b15612a1f576002546001600160a01b031663c3ab3924612c6f613531565b8b8b8b6129cb60405180608001604052808e81526020018b6001600160801b031681526020018a6001600160801b03168152602001896001600160801b03168152506131f7565b336001600160a01b035f5c1614612ce057604051630101292160e31b815260040160405180910390fd5b5f8080805b8563ffffffff168163ffffffff161015612d5c575f5f5f5f612d098e8e8d8f614113565b93509350935093508388612d1d919061591d565b9750612d29838861591d565b96506001600160801b03821615612d3e578195505b80612d4c5750505050612d5c565b505060019092019150612ce59050565b505f826001600160801b03161180612d7c57505f816001600160801b0316115b15612b88576002546001600160a01b031663c3ab3924612d9a613531565b8b8b8b612b6360405180608001604052808e81526020018b6001600160801b031681526020018a6001600160801b03168152602001896001600160801b03168152506131f7565b847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633625342b82612e1a613222565b6040518363ffffffff1660e01b8152600401612e37929190615724565b602060405180830381865afa158015612e52573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e769190615746565b612e935760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0386165f908152600c602090815260408083206001600160801b03198916845282528083206001600160801b0387168452825280832087845290915290205460ff16612ef957604051635fb581dd60e01b815260040160405180910390fd5b6001600160401b0386165f9081526009602090815260408083206001600160801b03198916845282528083206001600160801b0387811685529083528184208885529092528220541690612f52888884848a8a82613260565b90506001600160801b038116156110a257604080516080810182528781525f602082018190529181018290526001600160801b038316606082015261102d906131a1565b6001600160401b0384165f8181526009602090815260408083206001600160801b031988168085529083528184206001600160801b0387811680875291855283862089875285528386208451808601865290549182168152600160801b90910463ffffffff90811682870152968652600385528386209286529184528285209085529092528220549192610b2e92600160201b9004165b81515f906001600160801b0316158061305557508163ffffffff16836020015163ffffffff16115b1561306157505f610a8d565b6020830151613070908361593c565b611105906001615779565b5f61308682826145ab565b60ff166004811115610a8d57610a8d61566f565b604080518082019091525f808252602082015260015b6130b98361307b565b60048111156130ca576130ca61566f565b146130e857604051638d54989d60e01b815260040160405180910390fd5b60408051808201909152806130fe8460016145e1565b815260200161310e846021614617565b6001600160801b0316905292915050565b604080518082019091525f808252602082015260026130b0565b60408051602081019091525f815260035b6131538361307b565b60048111156131645761316461566f565b1461318257604051638d54989d60e01b815260040160405180910390fd5b6040805160208101909152806131998460016145e1565b905292915050565b60606004825f01518360200151846040015185606001516040516020016131cc95949392919061597b565b6040516020818303038152906040529050919050565b60408051602081019091525f8152600461314a565b60606005825f01518360200151846040015185606001516040516020016131cc95949392919061597b565b5f60015c6001600160a01b03161580159061324757506001546001600160a01b031633145b61325057503390565b5060015c6001600160a01b031690565b5f80808360018111156132755761327561566f565b146132c4576001600160401b0389165f9081526008602090815260408083206001600160801b03198c16845282528083206001600160801b03881684528252808320888452909152902061330a565b6001600160401b0389165f9081526009602090815260408083206001600160801b03198c16845282528083206001600160801b0388168452825280832088845290915290205b90505f808460018111156133205761332061566f565b1461336f576001600160401b038a165f908152600a602090815260408083206001600160801b03198d16845282528083206001600160801b0389168452825280832089845290915290206133b5565b6001600160401b038a165f908152600b602090815260408083206001600160801b03198d16845282528083206001600160801b0389168452825280832089845290915290205b90506133c88a8a8a8a8a8a88888c61464d565b156133d7575f92505050613526565b866133e257876133e4565b5f5b9250866134065781546134019089906001600160801b03166157e0565b61341c565b815461341c9089906001600160801b031661591d565b82546001600160801b0319166001600160801b03919091161782555f84600181111561344a5761344a61566f565b1461345f5761345a8a8a876110ac565b61346a565b61346a8a8a87611e75565b825463ffffffff91909116600160801b0263ffffffff60801b199091161782555f84600181111561349d5761349d61566f565b036134e55760408051808201909152815460ff81161515825261010090046001600160801b031660208201526134e0908b908b908b908b908b908b908990614995565b613523565b60408051808201909152815460ff81161515825261010090046001600160801b03166020820152613523908b908b908b908b908b908b908990614aaa565b50505b979650505050505050565b5f60015c6001600160a01b031661354757503490565b505f90565b5f5c6001600160a01b031661364057335f805c6001600160a01b0319168217905d50805f5b81811015613629575f803086868581811061358e5761358e6159bd565b90506020028101906135a091906159d1565b6040516135ae929190615a1a565b5f60405180830381855af49150503d805f81146135e6576040519150601f19603f3d011682016040523d82523d5f602084013e6135eb565b606091505b50915091508161361f5780515f81900361361857604051632b9e168960e21b815260040160405180910390fd5b8082602001fd5b5050600101613571565b505f90506001600160a01b0319815c16815d505050565b336001600160a01b035f5c161461366a57604051630101292160e31b815260040160405180910390fd5b805f5b8181101561371e575f803086868581811061368a5761368a6159bd565b905060200281019061369c91906159d1565b6040516136aa929190615a1a565b5f60405180830381855af49150503d805f81146136e2576040519150601f19603f3d011682016040523d82523d5f602084013e6136e7565b606091505b5091509150816137145780515f81900361361857604051632b9e168960e21b815260040160405180910390fd5b505060010161366d565b50505050565b5f610b2e858585855f614b99565b80516020808301516040516060936131cc93600193919201615a29565b6001600160801b0316151590565b5f613526878787878787614c06565b5f6001600160401b038211156137955760405163397df9e960e21b815260040160405180910390fd5b5090565b5f6111058383614c7b565b80516020808301516040516060936131cc93600293919201615a29565b6001600160401b0385165f9081526003602090815260408083206001600160801b03198816845282528083206001600160801b0387168452909152812054819063ffffffff600160401b90910481169085161115613832576040516386d1007760e01b815260040160405180910390fd5b61383d878787611437565b63ffffffff168463ffffffff161484613857898989611437565b909161387857604051632c647e3760e21b8152600401611833929190615795565b50506001600160401b0387165f9081526005602090815260408083206001600160801b03198a16845282528083206001600160801b03898116855290835281842063ffffffff808a1686529352908320600181018054888416600160801b81029185169190911790915581549194936138f9939192909116908490614ca416565b6001830154909150613913906001600160801b031661374f565b61391d575f613a64565b8154604051600162fe590960e01b03198152613a64916001600160801b0316906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ff01a6f79061397c908e906004016157cc565b602060405180830381865afa158015613997573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139bb91906157ac565b604051630274be6d60e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906309d2f9b490613a07908d906004016152c9565b602060405180830381865afa158015613a22573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a4691906157ac565b60018601546001600160801b03600160801b8204811691165f61375d565b82546002840180546001600160801b0319166001600160801b0384811691909117909155919550169250613a974261376c565b600283018054600160801b600160c01b031916600160801b6001600160401b039384160217905589165f8181526003602090815260408083206001600160801b03198d168085529083528184206001600160801b038d81168087529190945291909320805463ffffffff60601b1916600160601b63ffffffff8d160217905560018601549093917f14f07afe7ac79d02cc585b7f76d4d9687e82b16083b19e225a2fde74b32bf36e918b918b91613b4e911661374f565b613b58575f613b79565b6001880154613b79906001600160801b03600160801b820481169116613799565b88546040805163ffffffff9590951685526001600160801b03938416602086015291831684830152821660608401528a8216608084015290871660a0830152519081900360c00190a450509550959350505050565b60606003825f0151836020015184604001516040516020016131cc9493929190615a5a565b6001600160401b0384165f9081526009602090815260408083206001600160801b03198716845282528083206001600160801b03858116855290835281842086855290925282208054839283928392909116613c625760405163484a885b60e01b815260040160405180910390fd5b6001600160401b0389165f9081526003602090815260408083206001600160801b03198c16845282528083206001600160801b038a1684529091529020548154600160201b90910463ffffffff908116600160801b909204161115613cda57604051638691a7e760e01b815260040160405180910390fd5b6001600160401b0389165f8181526003602090815260408083206001600160801b03198d168085529083528184206001600160801b038c81168087529185528386205488549787526004865284872093875292855283862091865290845282852063ffffffff600160801b97889004811680885291909552929094208054600160201b9092049093169091109550909290041615613dae5780546001808301548454613da993613da4936001600160801b0392831693600160801b90920483169290911690614cca565b614d19565b613db0565b5f5b94506001600160801b03851615613faf578054600182015483545f92613df192613da4926001600160801b0390811692600160801b90048116911685614cca565b90506001600160801b03811615613f6d576002820154613e19906001600160801b031661374f565b613e23575f613f6a565b613f6a816001600160801b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166309d2f9b48b6040518263ffffffff1660e01b8152600401613e7c91906152c9565b602060405180830381865afa158015613e97573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ebb91906157ac565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ff01a6f78f6040518263ffffffff1660e01b8152600401613f0791906157cc565b602060405180830381865afa158015613f22573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f4691906157ac565b600186015460028701546001600160801b03600160801b909204821691165f61375d565b96505b8254869084905f90613f899084906001600160801b03166157e0565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505b815f0160109054906101000a900463ffffffff1663ffffffff16896001600160801b0319168b6001600160401b03167f49c87cda7a22a30abb60733a70e9787c6607d32928c46528890206fdc06fabce8b8b8a885f015f9054906101000a90046001600160801b03168d8960020160109054906101000a90046001600160401b031660405161404396959493929190615a93565b60405180910390a481546001600160801b03165f0361408f576140678a8a89611e75565b825463ffffffff91909116600160801b0263ffffffff60801b199091161782555f92506140d0565b815460019083906010906140b1908490600160801b900463ffffffff16615779565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b6140db8a8a89611e75565b825463ffffffff918216600160801b90910490911603614106576141038a8a8a8a865f614d42565b93505b5050945094509450949050565b6001600160401b0384165f9081526008602090815260408083206001600160801b03198716845282528083206001600160801b038581168552908352818420868552909252822080548392839283929091166141825760405163484a885b60e01b815260040160405180910390fd5b6001600160401b0389165f9081526003602090815260408083206001600160801b03198c16845282528083206001600160801b038a1684529091529020548154600160601b90910463ffffffff908116600160801b9092041611156141fa57604051639aac3e0b60e01b815260040160405180910390fd5b6001600160401b0389165f8181526003602090815260408083206001600160801b03198d168085529083528184206001600160801b038c81168087529185528386205488549787526005865284872093875292855283862091865290845282852063ffffffff600160801b90970487168087529452919093208054600160601b909404909416909110945016156142bc57805482546142b791613da4916001600160801b039081169181811691600160801b909104166001614cca565b6142be565b5f5b94506001600160801b0385161561445657805482545f916142fb91613da4916001600160801b039182169180821691600160801b90041685614cca565b90506001600160801b03811615614414576001820154614323906001600160801b031661374f565b61432d575f614411565b614411816001600160801b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ff01a6f78e6040518263ffffffff1660e01b815260040161438691906157cc565b602060405180830381865afa1580156143a1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906143c591906157ac565b604051630274be6d60e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906309d2f9b490613a07908e906004016152c9565b96505b8254869084905f906144309084906001600160801b03166157e0565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505b815f0160109054906101000a900463ffffffff1663ffffffff16896001600160801b0319168b6001600160401b03167fbaedde181510aaa5fcaded7a64ddd81c51a9b07b5ed0209b6e3a92801c93959e8b8b8a885f015f9054906101000a90046001600160801b03168d8960020160109054906101000a90046001600160401b03166040516144ea96959493929190615a93565b60405180910390a481546001600160801b03165f036145365761450e8a8a896110ac565b825463ffffffff91909116600160801b0263ffffffff60801b199091161782555f9250614577565b81546001908390601090614558908490600160801b900463ffffffff16615779565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b6145828a8a896110ac565b825463ffffffff918216600160801b90910490911603614106576141038a8a8a8a866001614d42565b5f6145b7826001615ad2565b835110156145d857604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f6145ed826020615ad2565b8351101561460e57604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f614623826010615ad2565b8351101561464457604051633b99b53d60e01b815260040160405180910390fd5b50016010015190565b5f80808360018111156146625761466261566f565b14614677576146728b8b886110ac565b614682565b6146828b8b88611e75565b6040805180820190915286546001600160801b0381168252600160801b900463ffffffff1660208201529091506146b99082614f3e565b156146c7575f915050614988565b835460ff1680156146e057505f896001600160801b0316115b156146fe57604051637643c0f960e01b815260040160405180910390fd5b8761471357835460ff1916600117845561475a565b83548990859060019061473590849061010090046001600160801b031661591d565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b5f83600181111561476d5761476d61566f565b0361487c575f60075f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f886001600160801b03166001600160801b031681526020019081526020015f205f9054906101000a90046001600160801b03169050866001600160801b03168b6001600160801b0319168d6001600160401b03165f516020615c595f395f51905f52858c8b5f015f9054906101000a90046001600160801b0316878c5f0160019054906101000a90046001600160801b03168d5f015f9054906101000a900460ff1660405161486e96959493929190615ae5565b60405180910390a450614982565b5f60065f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f886001600160801b03166001600160801b031681526020019081526020015f205f9054906101000a90046001600160801b03169050866001600160801b03168b6001600160801b0319168d6001600160401b03165f516020615c795f395f51905f52858c8b5f015f9054906101000a90046001600160801b0316878c5f0160019054906101000a90046001600160801b03168d5f015f9054906101000a900460ff1660405161497896959493929190615ae5565b60405180910390a4505b60019150505b9998505050505050505050565b6001600160401b0388165f9081526007602090815260408083206001600160801b03198b16845282528083206001600160801b0387811685529252909120541685614a0857806001600160801b0316876001600160801b031611614a02576149fd87826157e0565b614a12565b5f614a12565b614a12878261591d565b6001600160401b038a165f8181526007602090815260408083206001600160801b03198e81168086529184528285206001600160801b038c8116808852919095529290942080549094169286169290921790925592935091905f516020615c595f395f51905f52614a848d8d8a611e75565b8754602088015188516040516127db94938e936001600160801b03909116928b92615ae5565b6001600160401b0388165f9081526006602090815260408083206001600160801b03198b16845282528083206001600160801b0387811685529252909120541685614b1d57806001600160801b0316876001600160801b031611614b1757614b1287826157e0565b614b27565b5f614b27565b614b27878261591d565b6001600160401b038a165f8181526006602090815260408083206001600160801b03198e81168086529184528285206001600160801b038c8116808852919095529290942080549094169286169290921790925592935091905f516020615c795f395f51905f52614a848d8d8a6110ac565b5f8360ff168560ff1603614bc557614bbe613da46001600160801b0385168885614f79565b9050610b2e565b6111ca613da46001600160801b038516614be087600a615c06565b614bea908a615c14565b614bf560128a615c2b565b614c0090600a615c06565b86614cca565b5f614c19836001600160801b031661374f565b614c36576040516323d359a360e01b815260040160405180910390fd5b613526613da46001600160801b03861689614c5289600a615c06565b614c5c9190615c14565b6001600160801b038716614c718b600a615c06565b614c009190615c14565b5f611105613da4846001600160801b0316670de0b6b3a7640000856001600160801b0316614f97565b5f611102613da4856001600160801b0316856001600160801b0316670de0b6b3a7640000865b5f5f614cd7868686614f97565b90506001836002811115614ced57614ced61566f565b148015614d0957505f8480614d0457614d04615c44565b868809115b15610b2e576111ca600182615ad2565b5f6001600160801b038211156137955760405163e999826d60e01b815260040160405180910390fd5b5f8080836001811115614d5757614d5761566f565b14614da6576001600160401b0388165f908152600a602090815260408083206001600160801b03198b16845282528083206001600160801b038916845282528083208984529091529020614dec565b6001600160401b0388165f908152600b602090815260408083206001600160801b03198b16845282528083206001600160801b0389168452825280832089845290915290205b80549091505f9060ff16614e0f57815461010090046001600160801b0316614e1b565b84546001600160801b03165b825490915060ff1615614e5c5781548554614e47916001600160801b036101009091048116911661591d565b85546001600160801b03191686559250614ea6565b815485546001600160801b0361010090920482169187915f91614e819185911661591d565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b5f846001811115614eb957614eb961566f565b03614ef4578154604080518082019091525f8082526020820152614eef918b918b91859160ff90911615908c908c908c90614995565b614f25565b8154604080518082019091525f8082526020820152614f25918b918b91859160ff90911615908c908c908c90614aaa565b5080546001600160881b03191690559695505050505050565b5f60018263ffffffff16111580614f5d575082516001600160801b0316155b8061110557505060209091015163ffffffff9182169116101590565b5f611102846001600160801b031684670de0b6b3a764000085614cca565b5f80805f19858709858702925082811083820303915050805f03614fce57838281614fc457614fc4615c44565b0492505050611105565b808411614fee57604051637ee8242b60e01b815260040160405180910390fd5b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b5f60208284031215615065575f5ffd5b81356001600160e01b031981168114611105575f5ffd5b80356001600160401b0381168114615092575f5ffd5b919050565b80356001600160801b031981168114615092575f5ffd5b6001600160801b03811681146150c2575f5ffd5b50565b5f5f5f5f608085870312156150d8575f5ffd5b6150e18561507c565b93506150ef60208601615097565b9250604085013591506060850135615106816150ae565b939692955090935050565b803563ffffffff81168114615092575f5ffd5b5f5f5f5f60808587031215615137575f5ffd5b6151408561507c565b935061514e60208601615097565b9250604085013561515e816150ae565b915061516c60608601615111565b905092959194509250565b5f5f5f5f5f6080868803121561518b575f5ffd5b6151948661507c565b94506151a260208701615097565b935060408601356151b2816150ae565b925060608601356001600160401b038111156151cc575f5ffd5b8601601f810188136151dc575f5ffd5b80356001600160401b038111156151f1575f5ffd5b886020828401011115615202575f5ffd5b959894975092955050506020019190565b80356001600160a01b0381168114615092575f5ffd5b5f5f5f5f5f60a0868803121561523d575f5ffd5b6152468661507c565b945061525460208701615097565b935060408601359250606086013561526b816150ae565b915061527960808701615213565b90509295509295909350565b5f5f5f60608486031215615297575f5ffd5b6152a08461507c565b92506152ae60208501615097565b915060408401356152be816150ae565b809150509250925092565b6001600160801b0391909116815260200190565b5f602082840312156152ed575f5ffd5b61110582615213565b5f5f5f5f60808587031215615309575f5ffd5b6153128561507c565b935061532060208601615097565b92506040850135615330816150ae565b9396929550929360600135925050565b5f5f5f5f84860360e0811215615354575f5ffd5b61535d8661507c565b945061536b60208701615097565b9350604086013561537b816150ae565b92506080605f198201121561538e575f5ffd5b50604051608081016001600160401b03811182821017156153bd57634e487b7160e01b5f52604160045260245ffd5b6040526153cc60608701615111565b81526153da60808701615111565b60208201526153eb60a08701615111565b60408201526153fc60c08701615111565b6060820152939692955090935050565b5f5f5f5f5f60a08688031215615420575f5ffd5b6154298661507c565b945061543760208701615097565b93506040860135615447816150ae565b925060608601359150608086013561545e816150ae565b809150509295509295909350565b5f5f6020838503121561547d575f5ffd5b82356001600160401b03811115615492575f5ffd5b8301601f810185136154a2575f5ffd5b80356001600160401b038111156154b7575f5ffd5b8560208260051b84010111156154cb575f5ffd5b6020919091019590945092505050565b5f5f5f5f5f5f5f60e0888a0312156154f1575f5ffd5b6154fa8861507c565b965061550860208901615097565b95506040880135615518816150ae565b945061552660608901615111565b93506080880135615536816150ae565b925060a0880135615546816150ae565b915061555460c08901615213565b905092959891949750929550565b5f5f5f5f5f5f60c08789031215615577575f5ffd5b6155808761507c565b955061558e60208801615097565b9450604087013561559e816150ae565b93506155ac60608801615111565b925060808701356155bc816150ae565b915060a08701356155cc816150ae565b809150509295509295509295565b5f5f604083850312156155eb575f5ffd5b823591506155fb60208401615213565b90509250929050565b5f5f5f5f5f5f60c08789031215615619575f5ffd5b6156228761507c565b955061563060208801615097565b94506040870135615640816150ae565b93506060870135925061565560808801615111565b915061566360a08801615213565b90509295509295509295565b634e487b7160e01b5f52602160045260245ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160401b03881681526001600160801b0319871660208201526001600160801b038616604082015260e0606082018190525f906156f390830187615683565b6001600160801b039590951660808301525091151560a08301526001600160a01b031660c090910152949350505050565b6001600160401b039290921682526001600160a01b0316602082015260400190565b5f60208284031215615756575f5ffd5b81518015158114611105575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b63ffffffff8181168382160190811115610a8d57610a8d615765565b63ffffffff92831681529116602082015260400190565b5f602082840312156157bc575f5ffd5b815160ff81168114611105575f5ffd5b6001600160401b0391909116815260200190565b6001600160801b038281168282160390811115610a8d57610a8d615765565b63ffffffff9490941684526001600160801b039283166020850152908216604084015216606082015260800190565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b602080825281018290525f6040600584901b830181019083018583601e1936839003015b878210156158e757868503603f190184528235818112615898575f5ffd5b89016020810190356001600160401b038111156158b3575f5ffd5b8036038213156158c1575f5ffd5b6158cc87828461582e565b9650505060208301925060208401935060018201915061587a565b5092979650505050505050565b604081525f6159066040830185615683565b905060018060a01b03831660208301529392505050565b6001600160801b038181168382160190811115610a8d57610a8d615765565b63ffffffff8281168282160390811115610a8d57610a8d615765565b6006811061597457634e487b7160e01b5f52602160045260245ffd5b60f81b9052565b6159858187615958565b60018101949094526001600160801b0319608093841b8116602186015291831b8216603185015290911b166041820152605101919050565b634e487b7160e01b5f52603260045260245ffd5b5f5f8335601e198436030181126159e6575f5ffd5b8301803591506001600160401b038211156159ff575f5ffd5b602001915036819003821315615a13575f5ffd5b9250929050565b818382375f9101908152919050565b615a338185615958565b6001600160801b0319608093841b811660018301529190921b166011820152602101919050565b615a648186615958565b6001600160801b0319608094851b8116600183015292841b83166011820152921b166021820152603101919050565b9586526001600160801b0394851660208701529284166040860152908316606085015290911660808301526001600160401b031660a082015260c00190565b80820180821115610a8d57610a8d615765565b63ffffffff96909616865260208601949094526001600160801b0392831660408601529082166060850152166080830152151560a082015260c00190565b6001815b6001841115615b5e57808504811115615b4257615b42615765565b6001841615615b5057908102905b60019390931c928002615b27565b935093915050565b5f82615b7457506001610a8d565b81615b8057505f610a8d565b8160018114615b965760028114615ba057615bbc565b6001915050610a8d565b60ff841115615bb157615bb1615765565b50506001821b610a8d565b5060208310610133831016604e8410600b8410161715615bdf575081810a610a8d565b615beb5f198484615b23565b805f1904821115615bfe57615bfe615765565b029392505050565b5f61110560ff841683615b66565b8082028115828204841417610a8d57610a8d615765565b60ff8181168382160190811115610a8d57610a8d615765565b634e487b7160e01b5f52601260045260245ffdfe1f5a5e518a04d4ae04df91bdcdfc726fd04628d7968eb87c8a177f55336765ff688670c8bdbd011a5a7703624480229795dd54b1ead47cb9a66061fa8b2e0b7a00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade9300000000000000000000000019a524d03aa94ecee41a80341537bcfcb47d3172000000000000000000000000b3c086db30c1be6e40d8775607c3662ab160bda5

Deployed Bytecode

0x6080604052600436106101d5575f3560e01c806301ffc9a7146101d95780630a6670631461020d578063116191b61461024157806328537d06146102785780632f6c33bf14610344578063365a86fc146103655780633f92bf831461038457806342e413391461039757806346bfcc8f146103b65780635eb4d168146103e257806365fae35e1461046357806366e960e31461048257806371c4482614610503578063730316d114610522578063790b56ce146105415780637fe50ab2146105605780638a93ba581461057f5780638baa4083146105925780639b884cd5146105b15780639c52a7f1146105d05780639d26e184146105ef5780639e5d3a7a14610637578063ac9650d81461064a578063ae7275201461065d578063b5eaa51d1461067c578063bcf16c93146106c4578063be3bad4a14610721578063bf353dbb14610734578063c076a59f1461076d578063c3f4d5ed146107fe578063c592045514610811578063c88854a314610856578063d0d4133114610889578063d4e8be831461089c578063da8336ba146108bb578063e0aeab1e146108ce578063e3b304d4146108e1578063e47091c914610926578063ee1cb43d1461099d578063fc689b78146109b0578063fdfa8fe0146109cf575b5f5ffd5b3480156101e4575f5ffd5b506101f86101f3366004615055565b610a27565b60405190151581526020015b60405180910390f35b348015610218575f5ffd5b5061022c6102273660046150c5565b610a93565b60405163ffffffff9091168152602001610204565b34801561024c575f5ffd5b50600154610260906001600160a01b031681565b6040516001600160a01b039091168152602001610204565b348015610283575f5ffd5b506102f9610292366004615124565b600460209081525f94855260408086208252938552838520815291845282842090915282529020805460018201546002909201546001600160801b0380831693600160801b938490048216938282169391819004831692821691046001600160401b031686565b604080516001600160801b039788168152958716602087015293861693850193909352908416606084015290921660808201526001600160401b0390911660a082015260c001610204565b34801561034f575f5ffd5b5061036361035e366004615177565b610b37565b005b348015610370575f5ffd5b50600254610260906001600160a01b031681565b610363610392366004615229565b610e77565b3480156103a2575f5ffd5b5061022c6103b1366004615285565b6110ac565b3480156103c1575f5ffd5b506103d56103d03660046150c5565b61110c565b60405161020491906152c9565b3480156103ed575f5ffd5b506102f96103fc366004615124565b600560209081525f94855260408086208252938552838520815291845282842090915282529020805460018201546002909201546001600160801b0380831693600160801b938490048216938282169391819004831692821691046001600160401b031686565b34801561046e575f5ffd5b5061036361047d3660046152dd565b6111d4565b34801561048d575f5ffd5b506104df61049c3660046152f6565b600860209081525f94855260408086208252938552838520815291845282842090915282529020546001600160801b03811690600160801b900463ffffffff1682565b604080516001600160801b03909316835263ffffffff909116602083015201610204565b34801561050e575f5ffd5b5061022c61051d366004615285565b611247565b34801561052d575f5ffd5b5061036361053c366004615340565b61129d565b34801561054c575f5ffd5b5061036361055b36600461540c565b6113f8565b34801561056b575f5ffd5b5061022c61057a366004615285565b611437565b61036361058d36600461546c565b61148d565b34801561059d575f5ffd5b506103636105ac36600461540c565b6115c9565b3480156105bc575f5ffd5b506103d56105cb3660046150c5565b611609565b3480156105db575f5ffd5b506103636105ea3660046152dd565b6116c9565b3480156105fa575f5ffd5b506101f86106093660046152f6565b600c60209081525f948552604080862082529385528385208152918452828420909152825290205460ff1681565b6103636106453660046154db565b61173b565b61036361065836600461546c565b611d78565b348015610668575f5ffd5b5061022c610677366004615285565b611e75565b348015610687575f5ffd5b506101f86106963660046152f6565b600d60209081525f948552604080862082529385528385208152918452828420909152825290205460ff1681565b3480156106cf575f5ffd5b506104df6106de3660046152f6565b600960209081525f94855260408086208252938552838520815291845282842090915282529020546001600160801b03811690600160801b900463ffffffff1682565b61036361072f3660046154db565b611ec4565b34801561073f575f5ffd5b5061075f61074e3660046152dd565b5f6020819052908152604090205481565b604051908152602001610204565b348015610778575f5ffd5b506107ce610787366004615285565b600360209081525f938452604080852082529284528284209052825290205463ffffffff80821691600160201b8104821691600160401b8204811691600160601b90041684565b6040805163ffffffff95861681529385166020850152918416918301919091529091166060820152608001610204565b61036361080c3660046154db565b6123ba565b34801561081c575f5ffd5b506103d561082b366004615285565b600760209081525f93845260408085208252928452828420905282529020546001600160801b031681565b348015610861575f5ffd5b506102607f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade9381565b610363610897366004615562565b6124cc565b3480156108a7575f5ffd5b506103636108b63660046155da565b6127ee565b6103636108c9366004615604565b6128a8565b6103636108dc366004615604565b612b93565b3480156108ec575f5ffd5b506103d56108fb366004615285565b600660209081525f93845260408085208252928452828420905282529020546001600160801b031681565b348015610931575f5ffd5b5061097e6109403660046152f6565b600a60209081525f948552604080862082529385528385208152918452828420909152825290205460ff81169061010090046001600160801b031682565b6040805192151583526001600160801b03909116602083015201610204565b6103636109ab366004615229565b612de1565b3480156109bb575f5ffd5b5061022c6109ca3660046150c5565b612f96565b3480156109da575f5ffd5b5061097e6109e93660046152f6565b600b60209081525f948552604080862082529385528385208152918452828420909152825290205460ff81169061010090046001600160801b031682565b5f6001600160e01b0319821663af00afbd60e01b1480610a5757506001600160e01b03198216632f6c33bf60e01b145b80610a7257506001600160e01b03198216630e8b676960e21b145b80610a8d57506001600160e01b031982166301ffc9a760e01b145b92915050565b6001600160401b0384165f8181526008602090815260408083206001600160801b031988168085529083528184206001600160801b0387811680875291855283862089875285528386208451808601865290549182168152600160801b90910463ffffffff90811682870152968652600385528386209286529184528285209085529092528220549192610b2e92600160601b90041661302d565b95945050505050565b335f90815260208190526040902054600114610b665760405163ea8e4eb560e01b815260040160405180910390fd5b5f610ba583838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061307b92505050565b6004811115610bb657610bb661566f565b90505f1960ff821601610c1e575f610c0284848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061309a92505050565b9050610c1887878360200151845f0151896113f8565b50610e6f565b60011960ff821601610c7f575f610c6984848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061311f92505050565b9050610c1887878360200151845f0151896115c9565b60021960ff821601610d98575f610cca84848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061313992505050565b90505f610cdc8888845f01518961110c565b90506001600160801b03811615610d915760025460408051608081018252845181525f60208201819052918101919091526001600160801b03831660608201526001600160a01b039091169063c3ab3924908a908a908a90610d3d906131a1565b5f60015f6040518863ffffffff1660e01b8152600401610d6397969594939291906156b1565b5f604051808303815f87803b158015610d7a575f5ffd5b505af1158015610d8c573d5f5f3e3d5ffd5b505050505b5050610e6f565b60031960ff821601610e56575f610de384848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506131e292505050565b90505f610df58888845f015189611609565b90506001600160801b03811615610d915760025460408051608081018252845181525f60208201819052918101919091526001600160801b03831660608201526001600160a01b039091169063c3ab3924908a908a908a90610d3d906131f7565b604051638d54989d60e01b815260040160405180910390fd5b505050505050565b847f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316633625342b82610eb0613222565b6040518363ffffffff1660e01b8152600401610ecd929190615724565b602060405180830381865afa158015610ee8573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0c9190615746565b610f295760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0386165f908152600d602090815260408083206001600160801b03198916845282528083206001600160801b0387168452825280832087845290915290205460ff16610f8f57604051635fb581dd60e01b815260040160405180910390fd5b6001600160401b0386165f9081526008602090815260408083206001600160801b03198916845282528083206001600160801b0387811685529083528184208885529092528220541690610fe9888884848a8a6001613260565b90506001600160801b038116156110a257604080516080810182528781525f602082018190529181018290526001600160801b038316606082015261102d906131f7565b6002549091506001600160a01b031663c3ab3924611049613531565b8b8b8a865f5f8d6040518963ffffffff1660e01b815260040161107297969594939291906156b1565b5f604051808303818588803b158015611089575f5ffd5b505af115801561109b573d5f5f3e3d5ffd5b5050505050505b5050505050505050565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b038516845290915281205461110290600160401b900463ffffffff166001615779565b90505b9392505050565b335f9081526020819052604081205460011461113b5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0385165f818152600c602090815260408083206001600160801b031989168085529083528184206001600160801b038881168087529185528386208a87528552838620805460ff19166001179055958552600984528285209185529083528184209084528252808320878452909152812054909116906111ca90879087908490888882613260565b9695505050505050565b335f908152602081905260409020546001146112035760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b038516845290915281205461110290600160201b900463ffffffff166001615779565b335f908152602081905260409020546001146112cc5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0384165f8181526003602090815260408083206001600160801b031988168085529083528184206001600160801b0388168086529084529382902086518154948801518489015160608a015163ffffffff908116600160601b0263ffffffff60601b19928216600160401b0292909216600160401b600160801b0319938216600160201b026001600160401b031990991691909416179690961716179390931790925551919290917f0f7c52086fe372e36e65c8c21cbcc8254ac152ce8c02cd914c162f62ed80237b906113ea9086905f60808201905063ffffffff835116825263ffffffff602084015116602083015263ffffffff604084015116604083015263ffffffff606084015116606083015292915050565b60405180910390a450505050565b335f908152602081905260409020546001146114275760405163ea8e4eb560e01b815260040160405180910390fd5b610e6f858585600186865f613260565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b038516845290915281205461110290600160601b900463ffffffff166001615779565b5f5c6001600160a01b031661152f57335f805c6001600160a01b0319168217905d5060015f9054906101000a90046001600160a01b03166001600160a01b031663d988dd406040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156114fb575f5ffd5b505af115801561150d573d5f5f3e3d5ffd5b5050505061151b828261354c565b5f6001600160a01b0319815c16815d505050565b336001600160a01b035f5c161461155957604051630101292160e31b815260040160405180910390fd5b60015f9054906101000a90046001600160a01b03166001600160a01b031663d988dd406040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156115a5575f5ffd5b505af11580156115b7573d5f5f3e3d5ffd5b505050506115c5828261354c565b5050565b335f908152602081905260409020546001146115f85760405163ea8e4eb560e01b815260040160405180910390fd5b610e6f858585600186866001613260565b335f908152602081905260408120546001146116385760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0385165f818152600d602090815260408083206001600160801b031989168085529083528184206001600160801b038881168087529185528386208a87528552838620805460ff1916600190811790915596865260088552838620928652918452828520908552835281842088855290925282205416916111ca9188918891859189908990613260565b335f908152602081905260409020546001146116f85760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b867f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316633625342b82611774613222565b6040518363ffffffff1660e01b8152600401611791929190615724565b602060405180830381865afa1580156117ac573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117d09190615746565b6117ed5760405163ea8e4eb560e01b815260040160405180910390fd5b6117f8888888611e75565b63ffffffff168563ffffffff1614856118128a8a8a611e75565b909161183c57604051632c647e3760e21b8152600401611833929190615795565b60405180910390fd5b50506001600160401b0388165f9081526007602090815260408083206001600160801b03198b16845282528083206001600160801b038a8116855292529091205481169085168110156118a25760405163776a3aa960e11b815260040160405180910390fd5b5f856001600160801b0316116118cb5760405163035a9e4760e11b815260040160405180910390fd5b5f6119f5866001600160801b03167f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b03166309d2f9b48b6040518263ffffffff1660e01b815260040161192591906152c9565b602060405180830381865afa158015611940573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061196491906157ac565b7f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b031663ff01a6f78e6040518263ffffffff1660e01b81526004016119b091906157cc565b602060405180830381865afa1580156119cb573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ef91906157ac565b88613724565b90505f60045f8c6001600160401b03166001600160401b031681526020019081526020015f205f8b6001600160801b0319166001600160801b03191681526020019081526020015f205f8a6001600160801b03166001600160801b031681526020019081526020015f205f8963ffffffff1663ffffffff1681526020019081526020015f20905086815f0160106101000a8154816001600160801b0302191690836001600160801b0316021790555081815f015f6101000a8154816001600160801b0302191690836001600160801b0316021790555082816001015f6101000a8154816001600160801b0302191690836001600160801b03160217905550858160010160106101000a8154816001600160801b0302191690836001600160801b031602179055508660075f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f8b6001600160801b03166001600160801b031681526020019081526020015f205f8282829054906101000a90046001600160801b0316611ba491906157e0565b92506101000a8154816001600160801b0302191690836001600160801b031602179055508683611bd491906157e0565b92508760035f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f8b6001600160801b03166001600160801b031681526020019081526020015f205f015f6101000a81548163ffffffff021916908363ffffffff160217905550886001600160801b03168a6001600160801b0319168c6001600160401b03167f1785217365be01fea67dbce22680b382886fe6a3a22156830b3cda5823a42a8e8b868c89604051611cb194939291906157ff565b60405180910390a45f611cf760405180604001604052808a6001600160801b03168152602001611ce78a6001600160801b031690565b6001600160801b03169052613732565b6002549091506001600160a01b031663c3ab3924611d13613531565b8e8e8e865f5f8e6040518963ffffffff1660e01b8152600401611d3c97969594939291906156b1565b5f604051808303818588803b158015611d53575f5ffd5b505af1158015611d65573d5f5f3e3d5ffd5b5050505050505050505050505050505050565b60015c6001600160a01b031615611da257604051631ccdbfa560e21b815260040160405180910390fd5b336001805c6001600160a01b0319168217905d506001546040516001600160a01b03909116906329d43364903490631152774b60e31b90611de99087908790602401615856565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e085901b9092168252611e309133906004016158f4565b5f604051808303818588803b158015611e47575f5ffd5b505af1158015611e59573d5f5f3e3d5ffd5b505f935050506001805c6001600160a01b03191691505d505050565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b03851684529091528120546111029063ffffffff166001615779565b867f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316633625342b82611efd613222565b6040518363ffffffff1660e01b8152600401611f1a929190615724565b602060405180830381865afa158015611f35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f599190615746565b611f765760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0388165f9081526003602090815260408083206001600160801b03198b16845282528083206001600160801b038a16845290915290205463ffffffff9081169086161115611fde576040516386d1007760e01b815260040160405180910390fd5b611fe9888888611247565b63ffffffff168563ffffffff1614856120038a8a8a611247565b909161202457604051632c647e3760e21b8152600401611833929190615795565b50506001600160401b0388165f9081526004602090815260408083206001600160801b0319808c1685529083528184206001600160801b038b8116865290845282852063ffffffff8b16865290935290832060028101805493891693909216831790915591906120939061374f565b61209d575f6121e6565b8154604051630274be6d60e21b81526121e691600160801b90046001600160801b0316907f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316906309d2f9b490612100908d906004016152c9565b602060405180830381865afa15801561211b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061213f91906157ac565b7f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b031663ff01a6f78e6040518263ffffffff1660e01b815260040161218b91906157cc565b602060405180830381865afa1580156121a6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121ca91906157ac565b6001860154600160801b90046001600160801b03168a5f61375d565b90506121f14261376c565b600283018054600160801b600160c01b031916600160801b6001600160401b03938416810291909117909155908b165f8181526003602090815260408083206001600160801b03198f168085529083528184206001600160801b038f81168087529190945291909320805463ffffffff60201b1916600160201b63ffffffff8f1602179055600187015490949293927f75d54fc68ce51f85af6cc4bc67a5d7d3267296e63539b2d428743a1a8a8380de928d928d926122b29291041661374f565b6122bc575f6122e3565b600288015460018901546122e3916001600160801b0390811691600160801b900416613799565b876040516122f494939291906157ff565b60405180910390a45f61233a6040518060400160405280846001600160801b0316815260200161232a8a6001600160801b031690565b6001600160801b031690526137a4565b6002549091506001600160a01b031663c3ab3924612356613531565b8d8d8d868c5f8d6040518963ffffffff1660e01b815260040161237f97969594939291906156b1565b5f604051808303818588803b158015612396575f5ffd5b505af11580156123a8573d5f5f3e3d5ffd5b50505050505050505050505050505050565b867f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316633625342b826123f3613222565b6040518363ffffffff1660e01b8152600401612410929190615724565b602060405180830381865afa15801561242b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061244f9190615746565b61246c5760405163ea8e4eb560e01b815260040160405180910390fd5b5f5f61247b8a8a8a8a8a6137c1565b915091505f61233a6040518060600160405280856001600160801b03168152602001846001600160801b031681526020016124bc8a6001600160801b031690565b6001600160801b03169052613bce565b857f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316633625342b82612505613222565b6040518363ffffffff1660e01b8152600401612522929190615724565b602060405180830381865afa15801561253d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125619190615746565b61257e5760405163ea8e4eb560e01b815260040160405180910390fd5b6125898787876110ac565b63ffffffff168463ffffffff1614846125a38989896110ac565b90916125c457604051632c647e3760e21b8152600401611833929190615795565b50506001600160401b0387165f9081526006602090815260408083206001600160801b03198a16845282528083206001600160801b038981168552925290912054811690841681101561262a5760405163776a3aa960e11b815260040160405180910390fd5b5f846001600160801b0316116126535760405163035a9e4760e11b815260040160405180910390fd5b6001600160401b0388165f8181526005602090815260408083206001600160801b03198c81168086529184528285206001600160801b038d811680885291865284872063ffffffff8e16885286528487208c8216600160801b8b8416021781556001810180549094168c831617909355968652600685528386209286529184528285209185529252822080549193889391926126f1918591166157e0565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550848261272191906157e0565b6001600160401b038a165f8181526003602090815260408083206001600160801b03198e168085529083528184206001600160801b038e16808652935292819020805463ffffffff8d16600160401b0263ffffffff60401b1990911617905551939550929091907f679cd78fb2cbc9b1fa61043bb803ac3d5a5a8e0dd7aaa5a94e8bc5721dd2b8aa906127db908b908b90899063ffffffff9390931683526001600160801b03918216602084015216604082015260600190565b60405180910390a4505050505050505050565b335f9081526020819052604090205460011461281d5760405163ea8e4eb560e01b815260040160405180910390fd5b8162343ab160e91b0361284a57600280546001600160a01b0319166001600160a01b038316179055612863565b604051633db0d5b960e01b815260040160405180910390fd5b604080518381526001600160a01b03831660208201527f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba910160405180910390a15050565b5f5c6001600160a01b0316612a3857335f805c6001600160a01b0319168217905d505f8080805b8563ffffffff168163ffffffff161015612946575f5f5f5f6128f38e8e8d8f613bf3565b93509350935093508388612907919061591d565b9750612913838861591d565b96506001600160801b03821615612928578195505b806129365750505050612946565b5050600190920191506128cf9050565b505f826001600160801b0316118061296657505f816001600160801b0316115b15612a1f576002546001600160a01b031663c3ab3924612984613531565b8b8b8b6129cb60405180608001604052808e81526020018a6001600160801b031681526020018b6001600160801b03168152602001896001600160801b03168152506131a1565b5f5f8c6040518963ffffffff1660e01b81526004016129f097969594939291906156b1565b5f604051808303818588803b158015612a07575f5ffd5b505af1158015612a19573d5f5f3e3d5ffd5b50505050505b505f9150506001600160a01b0319815c16815d50610e6f565b336001600160a01b035f5c1614612a6257604051630101292160e31b815260040160405180910390fd5b5f8080805b8563ffffffff168163ffffffff161015612ade575f5f5f5f612a8b8e8e8d8f613bf3565b93509350935093508388612a9f919061591d565b9750612aab838861591d565b96506001600160801b03821615612ac0578195505b80612ace5750505050612ade565b505060019092019150612a679050565b505f826001600160801b03161180612afe57505f816001600160801b0316115b15612b88576002546001600160a01b031663c3ab3924612b1c613531565b8b8b8b612b6360405180608001604052808e81526020018a6001600160801b031681526020018b6001600160801b03168152602001896001600160801b03168152506131a1565b5f5f8c6040518963ffffffff1660e01b815260040161107297969594939291906156b1565b505050505050505050565b5f5c6001600160a01b0316612cb657335f805c6001600160a01b0319168217905d505f8080805b8563ffffffff168163ffffffff161015612c31575f5f5f5f612bde8e8e8d8f614113565b93509350935093508388612bf2919061591d565b9750612bfe838861591d565b96506001600160801b03821615612c13578195505b80612c215750505050612c31565b505060019092019150612bba9050565b505f826001600160801b03161180612c5157505f816001600160801b0316115b15612a1f576002546001600160a01b031663c3ab3924612c6f613531565b8b8b8b6129cb60405180608001604052808e81526020018b6001600160801b031681526020018a6001600160801b03168152602001896001600160801b03168152506131f7565b336001600160a01b035f5c1614612ce057604051630101292160e31b815260040160405180910390fd5b5f8080805b8563ffffffff168163ffffffff161015612d5c575f5f5f5f612d098e8e8d8f614113565b93509350935093508388612d1d919061591d565b9750612d29838861591d565b96506001600160801b03821615612d3e578195505b80612d4c5750505050612d5c565b505060019092019150612ce59050565b505f826001600160801b03161180612d7c57505f816001600160801b0316115b15612b88576002546001600160a01b031663c3ab3924612d9a613531565b8b8b8b612b6360405180608001604052808e81526020018b6001600160801b031681526020018a6001600160801b03168152602001896001600160801b03168152506131f7565b847f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316633625342b82612e1a613222565b6040518363ffffffff1660e01b8152600401612e37929190615724565b602060405180830381865afa158015612e52573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e769190615746565b612e935760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0386165f908152600c602090815260408083206001600160801b03198916845282528083206001600160801b0387168452825280832087845290915290205460ff16612ef957604051635fb581dd60e01b815260040160405180910390fd5b6001600160401b0386165f9081526009602090815260408083206001600160801b03198916845282528083206001600160801b0387811685529083528184208885529092528220541690612f52888884848a8a82613260565b90506001600160801b038116156110a257604080516080810182528781525f602082018190529181018290526001600160801b038316606082015261102d906131a1565b6001600160401b0384165f8181526009602090815260408083206001600160801b031988168085529083528184206001600160801b0387811680875291855283862089875285528386208451808601865290549182168152600160801b90910463ffffffff90811682870152968652600385528386209286529184528285209085529092528220549192610b2e92600160201b9004165b81515f906001600160801b0316158061305557508163ffffffff16836020015163ffffffff16115b1561306157505f610a8d565b6020830151613070908361593c565b611105906001615779565b5f61308682826145ab565b60ff166004811115610a8d57610a8d61566f565b604080518082019091525f808252602082015260015b6130b98361307b565b60048111156130ca576130ca61566f565b146130e857604051638d54989d60e01b815260040160405180910390fd5b60408051808201909152806130fe8460016145e1565b815260200161310e846021614617565b6001600160801b0316905292915050565b604080518082019091525f808252602082015260026130b0565b60408051602081019091525f815260035b6131538361307b565b60048111156131645761316461566f565b1461318257604051638d54989d60e01b815260040160405180910390fd5b6040805160208101909152806131998460016145e1565b905292915050565b60606004825f01518360200151846040015185606001516040516020016131cc95949392919061597b565b6040516020818303038152906040529050919050565b60408051602081019091525f8152600461314a565b60606005825f01518360200151846040015185606001516040516020016131cc95949392919061597b565b5f60015c6001600160a01b03161580159061324757506001546001600160a01b031633145b61325057503390565b5060015c6001600160a01b031690565b5f80808360018111156132755761327561566f565b146132c4576001600160401b0389165f9081526008602090815260408083206001600160801b03198c16845282528083206001600160801b03881684528252808320888452909152902061330a565b6001600160401b0389165f9081526009602090815260408083206001600160801b03198c16845282528083206001600160801b0388168452825280832088845290915290205b90505f808460018111156133205761332061566f565b1461336f576001600160401b038a165f908152600a602090815260408083206001600160801b03198d16845282528083206001600160801b0389168452825280832089845290915290206133b5565b6001600160401b038a165f908152600b602090815260408083206001600160801b03198d16845282528083206001600160801b0389168452825280832089845290915290205b90506133c88a8a8a8a8a8a88888c61464d565b156133d7575f92505050613526565b866133e257876133e4565b5f5b9250866134065781546134019089906001600160801b03166157e0565b61341c565b815461341c9089906001600160801b031661591d565b82546001600160801b0319166001600160801b03919091161782555f84600181111561344a5761344a61566f565b1461345f5761345a8a8a876110ac565b61346a565b61346a8a8a87611e75565b825463ffffffff91909116600160801b0263ffffffff60801b199091161782555f84600181111561349d5761349d61566f565b036134e55760408051808201909152815460ff81161515825261010090046001600160801b031660208201526134e0908b908b908b908b908b908b908990614995565b613523565b60408051808201909152815460ff81161515825261010090046001600160801b03166020820152613523908b908b908b908b908b908b908990614aaa565b50505b979650505050505050565b5f60015c6001600160a01b031661354757503490565b505f90565b5f5c6001600160a01b031661364057335f805c6001600160a01b0319168217905d50805f5b81811015613629575f803086868581811061358e5761358e6159bd565b90506020028101906135a091906159d1565b6040516135ae929190615a1a565b5f60405180830381855af49150503d805f81146135e6576040519150601f19603f3d011682016040523d82523d5f602084013e6135eb565b606091505b50915091508161361f5780515f81900361361857604051632b9e168960e21b815260040160405180910390fd5b8082602001fd5b5050600101613571565b505f90506001600160a01b0319815c16815d505050565b336001600160a01b035f5c161461366a57604051630101292160e31b815260040160405180910390fd5b805f5b8181101561371e575f803086868581811061368a5761368a6159bd565b905060200281019061369c91906159d1565b6040516136aa929190615a1a565b5f60405180830381855af49150503d805f81146136e2576040519150601f19603f3d011682016040523d82523d5f602084013e6136e7565b606091505b5091509150816137145780515f81900361361857604051632b9e168960e21b815260040160405180910390fd5b505060010161366d565b50505050565b5f610b2e858585855f614b99565b80516020808301516040516060936131cc93600193919201615a29565b6001600160801b0316151590565b5f613526878787878787614c06565b5f6001600160401b038211156137955760405163397df9e960e21b815260040160405180910390fd5b5090565b5f6111058383614c7b565b80516020808301516040516060936131cc93600293919201615a29565b6001600160401b0385165f9081526003602090815260408083206001600160801b03198816845282528083206001600160801b0387168452909152812054819063ffffffff600160401b90910481169085161115613832576040516386d1007760e01b815260040160405180910390fd5b61383d878787611437565b63ffffffff168463ffffffff161484613857898989611437565b909161387857604051632c647e3760e21b8152600401611833929190615795565b50506001600160401b0387165f9081526005602090815260408083206001600160801b03198a16845282528083206001600160801b03898116855290835281842063ffffffff808a1686529352908320600181018054888416600160801b81029185169190911790915581549194936138f9939192909116908490614ca416565b6001830154909150613913906001600160801b031661374f565b61391d575f613a64565b8154604051600162fe590960e01b03198152613a64916001600160801b0316906001600160a01b037f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade93169063ff01a6f79061397c908e906004016157cc565b602060405180830381865afa158015613997573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139bb91906157ac565b604051630274be6d60e21b81526001600160a01b037f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade9316906309d2f9b490613a07908d906004016152c9565b602060405180830381865afa158015613a22573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a4691906157ac565b60018601546001600160801b03600160801b8204811691165f61375d565b82546002840180546001600160801b0319166001600160801b0384811691909117909155919550169250613a974261376c565b600283018054600160801b600160c01b031916600160801b6001600160401b039384160217905589165f8181526003602090815260408083206001600160801b03198d168085529083528184206001600160801b038d81168087529190945291909320805463ffffffff60601b1916600160601b63ffffffff8d160217905560018601549093917f14f07afe7ac79d02cc585b7f76d4d9687e82b16083b19e225a2fde74b32bf36e918b918b91613b4e911661374f565b613b58575f613b79565b6001880154613b79906001600160801b03600160801b820481169116613799565b88546040805163ffffffff9590951685526001600160801b03938416602086015291831684830152821660608401528a8216608084015290871660a0830152519081900360c00190a450509550959350505050565b60606003825f0151836020015184604001516040516020016131cc9493929190615a5a565b6001600160401b0384165f9081526009602090815260408083206001600160801b03198716845282528083206001600160801b03858116855290835281842086855290925282208054839283928392909116613c625760405163484a885b60e01b815260040160405180910390fd5b6001600160401b0389165f9081526003602090815260408083206001600160801b03198c16845282528083206001600160801b038a1684529091529020548154600160201b90910463ffffffff908116600160801b909204161115613cda57604051638691a7e760e01b815260040160405180910390fd5b6001600160401b0389165f8181526003602090815260408083206001600160801b03198d168085529083528184206001600160801b038c81168087529185528386205488549787526004865284872093875292855283862091865290845282852063ffffffff600160801b97889004811680885291909552929094208054600160201b9092049093169091109550909290041615613dae5780546001808301548454613da993613da4936001600160801b0392831693600160801b90920483169290911690614cca565b614d19565b613db0565b5f5b94506001600160801b03851615613faf578054600182015483545f92613df192613da4926001600160801b0390811692600160801b90048116911685614cca565b90506001600160801b03811615613f6d576002820154613e19906001600160801b031661374f565b613e23575f613f6a565b613f6a816001600160801b03167f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b03166309d2f9b48b6040518263ffffffff1660e01b8152600401613e7c91906152c9565b602060405180830381865afa158015613e97573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ebb91906157ac565b7f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b031663ff01a6f78f6040518263ffffffff1660e01b8152600401613f0791906157cc565b602060405180830381865afa158015613f22573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f4691906157ac565b600186015460028701546001600160801b03600160801b909204821691165f61375d565b96505b8254869084905f90613f899084906001600160801b03166157e0565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505b815f0160109054906101000a900463ffffffff1663ffffffff16896001600160801b0319168b6001600160401b03167f49c87cda7a22a30abb60733a70e9787c6607d32928c46528890206fdc06fabce8b8b8a885f015f9054906101000a90046001600160801b03168d8960020160109054906101000a90046001600160401b031660405161404396959493929190615a93565b60405180910390a481546001600160801b03165f0361408f576140678a8a89611e75565b825463ffffffff91909116600160801b0263ffffffff60801b199091161782555f92506140d0565b815460019083906010906140b1908490600160801b900463ffffffff16615779565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b6140db8a8a89611e75565b825463ffffffff918216600160801b90910490911603614106576141038a8a8a8a865f614d42565b93505b5050945094509450949050565b6001600160401b0384165f9081526008602090815260408083206001600160801b03198716845282528083206001600160801b038581168552908352818420868552909252822080548392839283929091166141825760405163484a885b60e01b815260040160405180910390fd5b6001600160401b0389165f9081526003602090815260408083206001600160801b03198c16845282528083206001600160801b038a1684529091529020548154600160601b90910463ffffffff908116600160801b9092041611156141fa57604051639aac3e0b60e01b815260040160405180910390fd5b6001600160401b0389165f8181526003602090815260408083206001600160801b03198d168085529083528184206001600160801b038c81168087529185528386205488549787526005865284872093875292855283862091865290845282852063ffffffff600160801b90970487168087529452919093208054600160601b909404909416909110945016156142bc57805482546142b791613da4916001600160801b039081169181811691600160801b909104166001614cca565b6142be565b5f5b94506001600160801b0385161561445657805482545f916142fb91613da4916001600160801b039182169180821691600160801b90041685614cca565b90506001600160801b03811615614414576001820154614323906001600160801b031661374f565b61432d575f614411565b614411816001600160801b03167f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b031663ff01a6f78e6040518263ffffffff1660e01b815260040161438691906157cc565b602060405180830381865afa1580156143a1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906143c591906157ac565b604051630274be6d60e21b81526001600160a01b037f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade9316906309d2f9b490613a07908e906004016152c9565b96505b8254869084905f906144309084906001600160801b03166157e0565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505b815f0160109054906101000a900463ffffffff1663ffffffff16896001600160801b0319168b6001600160401b03167fbaedde181510aaa5fcaded7a64ddd81c51a9b07b5ed0209b6e3a92801c93959e8b8b8a885f015f9054906101000a90046001600160801b03168d8960020160109054906101000a90046001600160401b03166040516144ea96959493929190615a93565b60405180910390a481546001600160801b03165f036145365761450e8a8a896110ac565b825463ffffffff91909116600160801b0263ffffffff60801b199091161782555f9250614577565b81546001908390601090614558908490600160801b900463ffffffff16615779565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b6145828a8a896110ac565b825463ffffffff918216600160801b90910490911603614106576141038a8a8a8a866001614d42565b5f6145b7826001615ad2565b835110156145d857604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f6145ed826020615ad2565b8351101561460e57604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f614623826010615ad2565b8351101561464457604051633b99b53d60e01b815260040160405180910390fd5b50016010015190565b5f80808360018111156146625761466261566f565b14614677576146728b8b886110ac565b614682565b6146828b8b88611e75565b6040805180820190915286546001600160801b0381168252600160801b900463ffffffff1660208201529091506146b99082614f3e565b156146c7575f915050614988565b835460ff1680156146e057505f896001600160801b0316115b156146fe57604051637643c0f960e01b815260040160405180910390fd5b8761471357835460ff1916600117845561475a565b83548990859060019061473590849061010090046001600160801b031661591d565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b5f83600181111561476d5761476d61566f565b0361487c575f60075f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f886001600160801b03166001600160801b031681526020019081526020015f205f9054906101000a90046001600160801b03169050866001600160801b03168b6001600160801b0319168d6001600160401b03165f516020615c595f395f51905f52858c8b5f015f9054906101000a90046001600160801b0316878c5f0160019054906101000a90046001600160801b03168d5f015f9054906101000a900460ff1660405161486e96959493929190615ae5565b60405180910390a450614982565b5f60065f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f886001600160801b03166001600160801b031681526020019081526020015f205f9054906101000a90046001600160801b03169050866001600160801b03168b6001600160801b0319168d6001600160401b03165f516020615c795f395f51905f52858c8b5f015f9054906101000a90046001600160801b0316878c5f0160019054906101000a90046001600160801b03168d5f015f9054906101000a900460ff1660405161497896959493929190615ae5565b60405180910390a4505b60019150505b9998505050505050505050565b6001600160401b0388165f9081526007602090815260408083206001600160801b03198b16845282528083206001600160801b0387811685529252909120541685614a0857806001600160801b0316876001600160801b031611614a02576149fd87826157e0565b614a12565b5f614a12565b614a12878261591d565b6001600160401b038a165f8181526007602090815260408083206001600160801b03198e81168086529184528285206001600160801b038c8116808852919095529290942080549094169286169290921790925592935091905f516020615c595f395f51905f52614a848d8d8a611e75565b8754602088015188516040516127db94938e936001600160801b03909116928b92615ae5565b6001600160401b0388165f9081526006602090815260408083206001600160801b03198b16845282528083206001600160801b0387811685529252909120541685614b1d57806001600160801b0316876001600160801b031611614b1757614b1287826157e0565b614b27565b5f614b27565b614b27878261591d565b6001600160401b038a165f8181526006602090815260408083206001600160801b03198e81168086529184528285206001600160801b038c8116808852919095529290942080549094169286169290921790925592935091905f516020615c795f395f51905f52614a848d8d8a6110ac565b5f8360ff168560ff1603614bc557614bbe613da46001600160801b0385168885614f79565b9050610b2e565b6111ca613da46001600160801b038516614be087600a615c06565b614bea908a615c14565b614bf560128a615c2b565b614c0090600a615c06565b86614cca565b5f614c19836001600160801b031661374f565b614c36576040516323d359a360e01b815260040160405180910390fd5b613526613da46001600160801b03861689614c5289600a615c06565b614c5c9190615c14565b6001600160801b038716614c718b600a615c06565b614c009190615c14565b5f611105613da4846001600160801b0316670de0b6b3a7640000856001600160801b0316614f97565b5f611102613da4856001600160801b0316856001600160801b0316670de0b6b3a7640000865b5f5f614cd7868686614f97565b90506001836002811115614ced57614ced61566f565b148015614d0957505f8480614d0457614d04615c44565b868809115b15610b2e576111ca600182615ad2565b5f6001600160801b038211156137955760405163e999826d60e01b815260040160405180910390fd5b5f8080836001811115614d5757614d5761566f565b14614da6576001600160401b0388165f908152600a602090815260408083206001600160801b03198b16845282528083206001600160801b038916845282528083208984529091529020614dec565b6001600160401b0388165f908152600b602090815260408083206001600160801b03198b16845282528083206001600160801b0389168452825280832089845290915290205b80549091505f9060ff16614e0f57815461010090046001600160801b0316614e1b565b84546001600160801b03165b825490915060ff1615614e5c5781548554614e47916001600160801b036101009091048116911661591d565b85546001600160801b03191686559250614ea6565b815485546001600160801b0361010090920482169187915f91614e819185911661591d565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b5f846001811115614eb957614eb961566f565b03614ef4578154604080518082019091525f8082526020820152614eef918b918b91859160ff90911615908c908c908c90614995565b614f25565b8154604080518082019091525f8082526020820152614f25918b918b91859160ff90911615908c908c908c90614aaa565b5080546001600160881b03191690559695505050505050565b5f60018263ffffffff16111580614f5d575082516001600160801b0316155b8061110557505060209091015163ffffffff9182169116101590565b5f611102846001600160801b031684670de0b6b3a764000085614cca565b5f80805f19858709858702925082811083820303915050805f03614fce57838281614fc457614fc4615c44565b0492505050611105565b808411614fee57604051637ee8242b60e01b815260040160405180910390fd5b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b5f60208284031215615065575f5ffd5b81356001600160e01b031981168114611105575f5ffd5b80356001600160401b0381168114615092575f5ffd5b919050565b80356001600160801b031981168114615092575f5ffd5b6001600160801b03811681146150c2575f5ffd5b50565b5f5f5f5f608085870312156150d8575f5ffd5b6150e18561507c565b93506150ef60208601615097565b9250604085013591506060850135615106816150ae565b939692955090935050565b803563ffffffff81168114615092575f5ffd5b5f5f5f5f60808587031215615137575f5ffd5b6151408561507c565b935061514e60208601615097565b9250604085013561515e816150ae565b915061516c60608601615111565b905092959194509250565b5f5f5f5f5f6080868803121561518b575f5ffd5b6151948661507c565b94506151a260208701615097565b935060408601356151b2816150ae565b925060608601356001600160401b038111156151cc575f5ffd5b8601601f810188136151dc575f5ffd5b80356001600160401b038111156151f1575f5ffd5b886020828401011115615202575f5ffd5b959894975092955050506020019190565b80356001600160a01b0381168114615092575f5ffd5b5f5f5f5f5f60a0868803121561523d575f5ffd5b6152468661507c565b945061525460208701615097565b935060408601359250606086013561526b816150ae565b915061527960808701615213565b90509295509295909350565b5f5f5f60608486031215615297575f5ffd5b6152a08461507c565b92506152ae60208501615097565b915060408401356152be816150ae565b809150509250925092565b6001600160801b0391909116815260200190565b5f602082840312156152ed575f5ffd5b61110582615213565b5f5f5f5f60808587031215615309575f5ffd5b6153128561507c565b935061532060208601615097565b92506040850135615330816150ae565b9396929550929360600135925050565b5f5f5f5f84860360e0811215615354575f5ffd5b61535d8661507c565b945061536b60208701615097565b9350604086013561537b816150ae565b92506080605f198201121561538e575f5ffd5b50604051608081016001600160401b03811182821017156153bd57634e487b7160e01b5f52604160045260245ffd5b6040526153cc60608701615111565b81526153da60808701615111565b60208201526153eb60a08701615111565b60408201526153fc60c08701615111565b6060820152939692955090935050565b5f5f5f5f5f60a08688031215615420575f5ffd5b6154298661507c565b945061543760208701615097565b93506040860135615447816150ae565b925060608601359150608086013561545e816150ae565b809150509295509295909350565b5f5f6020838503121561547d575f5ffd5b82356001600160401b03811115615492575f5ffd5b8301601f810185136154a2575f5ffd5b80356001600160401b038111156154b7575f5ffd5b8560208260051b84010111156154cb575f5ffd5b6020919091019590945092505050565b5f5f5f5f5f5f5f60e0888a0312156154f1575f5ffd5b6154fa8861507c565b965061550860208901615097565b95506040880135615518816150ae565b945061552660608901615111565b93506080880135615536816150ae565b925060a0880135615546816150ae565b915061555460c08901615213565b905092959891949750929550565b5f5f5f5f5f5f60c08789031215615577575f5ffd5b6155808761507c565b955061558e60208801615097565b9450604087013561559e816150ae565b93506155ac60608801615111565b925060808701356155bc816150ae565b915060a08701356155cc816150ae565b809150509295509295509295565b5f5f604083850312156155eb575f5ffd5b823591506155fb60208401615213565b90509250929050565b5f5f5f5f5f5f60c08789031215615619575f5ffd5b6156228761507c565b955061563060208801615097565b94506040870135615640816150ae565b93506060870135925061565560808801615111565b915061566360a08801615213565b90509295509295509295565b634e487b7160e01b5f52602160045260245ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160401b03881681526001600160801b0319871660208201526001600160801b038616604082015260e0606082018190525f906156f390830187615683565b6001600160801b039590951660808301525091151560a08301526001600160a01b031660c090910152949350505050565b6001600160401b039290921682526001600160a01b0316602082015260400190565b5f60208284031215615756575f5ffd5b81518015158114611105575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b63ffffffff8181168382160190811115610a8d57610a8d615765565b63ffffffff92831681529116602082015260400190565b5f602082840312156157bc575f5ffd5b815160ff81168114611105575f5ffd5b6001600160401b0391909116815260200190565b6001600160801b038281168282160390811115610a8d57610a8d615765565b63ffffffff9490941684526001600160801b039283166020850152908216604084015216606082015260800190565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b602080825281018290525f6040600584901b830181019083018583601e1936839003015b878210156158e757868503603f190184528235818112615898575f5ffd5b89016020810190356001600160401b038111156158b3575f5ffd5b8036038213156158c1575f5ffd5b6158cc87828461582e565b9650505060208301925060208401935060018201915061587a565b5092979650505050505050565b604081525f6159066040830185615683565b905060018060a01b03831660208301529392505050565b6001600160801b038181168382160190811115610a8d57610a8d615765565b63ffffffff8281168282160390811115610a8d57610a8d615765565b6006811061597457634e487b7160e01b5f52602160045260245ffd5b60f81b9052565b6159858187615958565b60018101949094526001600160801b0319608093841b8116602186015291831b8216603185015290911b166041820152605101919050565b634e487b7160e01b5f52603260045260245ffd5b5f5f8335601e198436030181126159e6575f5ffd5b8301803591506001600160401b038211156159ff575f5ffd5b602001915036819003821315615a13575f5ffd5b9250929050565b818382375f9101908152919050565b615a338185615958565b6001600160801b0319608093841b811660018301529190921b166011820152602101919050565b615a648186615958565b6001600160801b0319608094851b8116600183015292841b83166011820152921b166021820152603101919050565b9586526001600160801b0394851660208701529284166040860152908316606085015290911660808301526001600160401b031660a082015260c00190565b80820180821115610a8d57610a8d615765565b63ffffffff96909616865260208601949094526001600160801b0392831660408601529082166060850152166080830152151560a082015260c00190565b6001815b6001841115615b5e57808504811115615b4257615b42615765565b6001841615615b5057908102905b60019390931c928002615b27565b935093915050565b5f82615b7457506001610a8d565b81615b8057505f610a8d565b8160018114615b965760028114615ba057615bbc565b6001915050610a8d565b60ff841115615bb157615bb1615765565b50506001821b610a8d565b5060208310610133831016604e8410600b8410161715615bdf575081810a610a8d565b615beb5f198484615b23565b805f1904821115615bfe57615bfe615765565b029392505050565b5f61110560ff841683615b66565b8082028115828204841417610a8d57610a8d615765565b60ff8181168382160190811115610a8d57610a8d615765565b634e487b7160e01b5f52601260045260245ffdfe1f5a5e518a04d4ae04df91bdcdfc726fd04628d7968eb87c8a177f55336765ff688670c8bdbd011a5a7703624480229795dd54b1ead47cb9a66061fa8b2e0b7a

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

00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade9300000000000000000000000019a524d03aa94ecee41a80341537bcfcb47d3172000000000000000000000000b3c086db30c1be6e40d8775607c3662ab160bda5

-----Decoded View---------------
Arg [0] : hubRegistry_ (address): 0x19f46D8130e610C6C0f0116EA40Fb781dEFaDE93
Arg [1] : gateway_ (address): 0x19a524D03aA94ECEe41a80341537BCFCb47D3172
Arg [2] : deployer (address): 0xB3C086Db30c1BE6e40D8775607C3662ab160bda5

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade93
Arg [1] : 00000000000000000000000019a524d03aa94ecee41a80341537bcfcb47d3172
Arg [2] : 000000000000000000000000b3c086db30c1be6e40d8775607c3662ab160bda5


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.