ETH Price: $2,862.42 (-2.68%)
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
329014392025-07-15 15:10:25194 days ago1752592225  Contract Creation0 ETH

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SyncManager

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 1 runs

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

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

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

import {IBalanceSheet} from "src/spoke/interfaces/IBalanceSheet.sol";
import {ISpoke, VaultDetails} from "src/spoke/interfaces/ISpoke.sol";
import {IUpdateContract} from "src/spoke/interfaces/IUpdateContract.sol";
import {UpdateContractMessageLib, UpdateContractType} from "src/spoke/libraries/UpdateContractMessageLib.sol";

import {IBaseVault} from "src/vaults/interfaces/IBaseVault.sol";
import {IDepositManager} from "src/vaults/interfaces/IVaultManagers.sol";
import {ISyncDepositManager} from "src/vaults/interfaces/IVaultManagers.sol";
import {ISyncManager, ISyncDepositValuation} from "src/vaults/interfaces/IVaultManagers.sol";

/// @title  Sync Manager
/// @notice This is the main contract for synchronous ERC-4626 deposits.
contract SyncManager is Auth, Recoverable, ISyncManager {
    using MathLib for *;
    using CastLib for *;
    using BytesLib for bytes;
    using UpdateContractMessageLib for *;

    ISpoke public spoke;
    IBalanceSheet public balanceSheet;

    mapping(PoolId => mapping(ShareClassId scId => ISyncDepositValuation)) public valuation;
    mapping(PoolId => mapping(ShareClassId scId => mapping(address asset => mapping(uint256 tokenId => uint128))))
        public maxReserve;

    constructor(address deployer) Auth(deployer) {}

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

    /// @inheritdoc ISyncManager
    function file(bytes32 what, address data) external auth {
        if (what == "spoke") spoke = ISpoke(data);
        else if (what == "balanceSheet") balanceSheet = IBalanceSheet(data);
        else revert FileUnrecognizedParam();
        emit File(what, data);
    }

    /// @inheritdoc IUpdateContract
    function update(PoolId poolId, ShareClassId scId, bytes memory payload) external auth {
        uint8 kind = uint8(UpdateContractMessageLib.updateContractType(payload));

        if (kind == uint8(UpdateContractType.Valuation)) {
            UpdateContractMessageLib.UpdateContractValuation memory m =
                UpdateContractMessageLib.deserializeUpdateContractValuation(payload);

            require(address(spoke.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());

            setValuation(poolId, scId, m.valuation.toAddress());
        } else if (kind == uint8(UpdateContractType.SyncDepositMaxReserve)) {
            UpdateContractMessageLib.UpdateContractSyncDepositMaxReserve memory m =
                UpdateContractMessageLib.deserializeUpdateContractSyncDepositMaxReserve(payload);

            require(address(spoke.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());
            (address asset, uint256 tokenId) = spoke.idToAsset(AssetId.wrap(m.assetId));

            setMaxReserve(poolId, scId, asset, tokenId, m.maxReserve);
        } else {
            revert UnknownUpdateContractType();
        }
    }

    /// @inheritdoc ISyncManager
    function setValuation(PoolId poolId, ShareClassId scId, address valuation_) public auth {
        valuation[poolId][scId] = ISyncDepositValuation(valuation_);

        emit SetValuation(poolId, scId, address(valuation_));
    }

    /// @inheritdoc ISyncManager
    function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve_)
        public
        auth
    {
        maxReserve[poolId][scId][asset][tokenId] = maxReserve_;

        emit SetMaxReserve(poolId, scId, asset, tokenId, maxReserve_);
    }

    //----------------------------------------------------------------------------------------------
    // Deposit handlers
    //----------------------------------------------------------------------------------------------

    /// @inheritdoc IDepositManager
    function mint(IBaseVault vault_, uint256 shares, address receiver, address owner)
        external
        auth
        returns (uint256 assets)
    {
        require(maxMint(vault_, owner) >= shares, ExceedsMaxMint());
        assets = previewMint(vault_, owner, shares);

        _issueShares(vault_, shares.toUint128(), receiver, assets.toUint128());
    }

    /// @inheritdoc IDepositManager
    function deposit(IBaseVault vault_, uint256 assets, address receiver, address owner)
        external
        auth
        returns (uint256 shares)
    {
        require(maxDeposit(vault_, owner) >= assets, ExceedsMaxDeposit());
        shares = previewDeposit(vault_, owner, assets);

        _issueShares(vault_, shares.toUint128(), receiver, assets.toUint128());
    }

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

    /// @inheritdoc ISyncDepositManager
    function previewMint(IBaseVault vault_, address, /* sender */ uint256 shares)
        public
        view
        returns (uint256 assets)
    {
        return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Up);
    }

    /// @inheritdoc ISyncDepositManager
    function previewDeposit(IBaseVault vault_, address, /* sender */ uint256 assets)
        public
        view
        returns (uint256 shares)
    {
        return convertToShares(vault_, assets);
    }

    /// @inheritdoc IDepositManager
    function maxMint(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {
        VaultDetails memory vaultDetails = spoke.vaultDetails(vault_);
        uint128 maxAssets =
            _maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId, vault_);
        return convertToShares(vault_, maxAssets);
    }

    /// @inheritdoc IDepositManager
    function maxDeposit(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {
        VaultDetails memory vaultDetails = spoke.vaultDetails(vault_);
        return _maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId, vault_);
    }

    /// @inheritdoc ISyncManager
    function convertToShares(IBaseVault vault_, uint256 assets) public view returns (uint256 shares) {
        VaultDetails memory vaultDetails = spoke.vaultDetails(vault_);

        D18 poolPerShare = pricePoolPerShare(vault_.poolId(), vault_.scId());
        D18 poolPerAsset = spoke.pricePoolPerAsset(vault_.poolId(), vault_.scId(), vaultDetails.assetId, true);

        return poolPerShare.isZero()
            ? 0
            : PricingLib.assetToShareAmount(
                vault_.share(),
                vaultDetails.asset,
                vaultDetails.tokenId,
                assets.toUint128(),
                poolPerAsset,
                poolPerShare,
                MathLib.Rounding.Down
            );
    }

    /// @inheritdoc ISyncManager
    function convertToAssets(IBaseVault vault_, uint256 shares) public view returns (uint256 assets) {
        return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Down);
    }

    /// @inheritdoc ISyncDepositValuation
    function pricePoolPerShare(PoolId poolId, ShareClassId scId) public view returns (D18 price) {
        ISyncDepositValuation valuation_ = valuation[poolId][scId];

        if (address(valuation_) == address(0)) {
            price = spoke.pricePoolPerShare(poolId, scId, true);
        } else {
            price = valuation_.pricePoolPerShare(poolId, scId);
        }
    }

    //----------------------------------------------------------------------------------------------
    // Internal
    //----------------------------------------------------------------------------------------------

    /// @dev Issues shares to the receiver and instruct the balance sheet
    //       to react on the issuance and the updated holding.
    function _issueShares(IBaseVault vault_, uint128 shares, address receiver, uint128 assets) internal {
        PoolId poolId = vault_.poolId();
        ShareClassId scId = vault_.scId();
        VaultDetails memory vaultDetails = spoke.vaultDetails(vault_);

        // Note deposit into the pool escrow, to make assets available for managers of the balance sheet.
        // ERC-20 transfer is handled by the vault to the pool escrow afterwards.
        balanceSheet.noteDeposit(poolId, scId, vaultDetails.asset, vaultDetails.tokenId, assets);

        // Mint shares to the receiver.
        balanceSheet.overridePricePoolPerShare(poolId, scId, pricePoolPerShare(poolId, scId));
        balanceSheet.issue(poolId, scId, receiver, shares);
        balanceSheet.resetPricePoolPerShare(poolId, scId);
    }

    function _maxDeposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, IBaseVault vault_)
        internal
        view
        returns (uint128 maxDeposit_)
    {
        if (!spoke.isLinked(vault_)) return 0;

        uint128 availableBalance = balanceSheet.availableBalanceOf(poolId, scId, asset, tokenId);
        uint128 maxReserve_ = maxReserve[poolId][scId][asset][tokenId];

        if (maxReserve_ < availableBalance) {
            maxDeposit_ = 0;
        } else {
            maxDeposit_ = maxReserve_ - availableBalance;
        }
    }

    function _shareToAssetAmount(IBaseVault vault_, uint256 shares, MathLib.Rounding rounding)
        internal
        view
        returns (uint256 assets)
    {
        VaultDetails memory vaultDetails = spoke.vaultDetails(vault_);

        D18 poolPerShare = pricePoolPerShare(vault_.poolId(), vault_.scId());
        D18 poolPerAsset = spoke.pricePoolPerAsset(vault_.poolId(), vault_.scId(), vaultDetails.assetId, true);

        return poolPerAsset.isZero()
            ? 0
            : PricingLib.shareToAssetAmount(
                vault_.share(),
                shares.toUint128(),
                vaultDetails.asset,
                vaultDetails.tokenId,
                poolPerShare,
                poolPerAsset,
                rounding
            );
    }
}

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

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

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

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

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

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

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

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

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

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

type D18 is uint128;

using MathLib for uint256;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

import {Auth} from "src/misc/Auth.sol";
import {IERC6909} from "src/misc/interfaces/IERC6909.sol";
import {SafeTransferLib} from "src/misc/libraries/SafeTransferLib.sol";
import {IRecoverable, ETH_ADDRESS} from "src/misc/interfaces/IRecoverable.sol";

abstract contract Recoverable is Auth, IRecoverable {
    /// @inheritdoc IRecoverable
    function recoverTokens(address token, address receiver, uint256 amount) public auth {
        if (token == ETH_ADDRESS) {
            SafeTransferLib.safeTransferETH(receiver, amount);
        } else {
            SafeTransferLib.safeTransfer(token, receiver, amount);
        }
    }

    /// @inheritdoc IRecoverable
    function recoverTokens(address token, uint256 tokenId, address receiver, uint256 amount) external auth {
        if (tokenId == 0) {
            recoverTokens(token, receiver, amount);
        } else {
            IERC6909(token).transfer(receiver, tokenId, amount);
        }
    }
}

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

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

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

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

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

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

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

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

        bytes memory bytesArray = new bytes(i);

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

        return string(bytesArray);
    }

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

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

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

    }

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

    uint256 public constant One27 = 10 ** 27;

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

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

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

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, MulDiv_Overflow());

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

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

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

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

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

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

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

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

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

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

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

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

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

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

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

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

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

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

// 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 "src/misc/libraries/MathLib.sol";

using MathLib for uint256;

type PoolId is uint64;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

import {PricingLib} from "src/common/libraries/PricingLib.sol";

library PricingLib {
    using MathLib for *;

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

    //----------------------------------------------------------------------------------------------
    // 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(), "PricingLib/division-by-zero");

        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(), "PricingLib/division-by-zero");

        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 "src/common/types/PoolId.sol";

type ShareClassId is bytes16;

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

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

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

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

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

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

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

import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
import {IRoot} from "src/common/interfaces/IRoot.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
import {IPoolEscrow} from "src/common/interfaces/IPoolEscrow.sol";
import {ISpokeMessageSender} from "src/common/interfaces/IGatewaySenders.sol";
import {IPoolEscrowProvider} from "src/common/factories/interfaces/IPoolEscrowFactory.sol";

import {ISpoke} from "src/spoke/interfaces/ISpoke.sol";

struct ShareQueueAmount {
    // Net queued shares
    uint128 delta;
    // Whether the net queued shares lead to an issuance or revocation
    bool isPositive;
    // Number of queued asset IDs for this share class
    uint32 queuedAssetCounter;
    // Nonce for share + asset messages to the hub
    uint64 nonce;
}

struct AssetQueueAmount {
    uint128 deposits;
    uint128 withdrawals;
}

interface IBalanceSheet {
    // --- Events ---
    event File(bytes32 indexed what, address data);
    event UpdateManager(PoolId indexed poolId, address who, bool canManage);
    event Withdraw(
        PoolId indexed poolId,
        ShareClassId indexed scId,
        address asset,
        uint256 tokenId,
        address receiver,
        uint128 amount,
        D18 pricePoolPerAsset
    );
    event Deposit(PoolId indexed poolId, ShareClassId indexed scId, address asset, uint256 tokenId, uint128 amount);
    event NoteDeposit(
        PoolId indexed poolId,
        ShareClassId indexed scId,
        address asset,
        uint256 tokenId,
        uint128 amount,
        D18 pricePoolPerAsset
    );
    event Issue(PoolId indexed poolId, ShareClassId indexed scId, address to, D18 pricePoolPerShare, uint128 shares);
    event Revoke(PoolId indexed poolId, ShareClassId indexed scId, address from, D18 pricePoolPerShare, uint128 shares);
    event TransferSharesFrom(
        PoolId indexed poolId,
        ShareClassId indexed scId,
        address sender,
        address indexed from,
        address to,
        uint256 amount
    );
    event SubmitQueuedShares(PoolId indexed poolId, ShareClassId indexed scId, ISpokeMessageSender.UpdateData data);
    event SubmitQueuedAssets(
        PoolId indexed poolId,
        ShareClassId indexed scId,
        AssetId indexed assetId,
        ISpokeMessageSender.UpdateData data,
        D18 pricePoolPerAsset
    );

    // --- Errors ---
    error FileUnrecognizedParam();
    error CannotTransferFromEndorsedContract();

    function root() external view returns (IRoot);
    function spoke() external view returns (ISpoke);
    function sender() external view returns (ISpokeMessageSender);
    function poolEscrowProvider() external view returns (IPoolEscrowProvider);

    function manager(PoolId poolId, address manager) external view returns (bool);
    function queuedShares(PoolId poolId, ShareClassId scId)
        external
        view
        returns (uint128 delta, bool isPositive, uint32 queuedAssetCounter, uint64 nonce);
    function queuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId)
        external
        view
        returns (uint128 increase, uint128 decrease);

    function file(bytes32 what, address data) external;

    /// @notice Deposit assets into the escrow of the pool.
    /// @param  tokenId SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported.
    function deposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 amount) external;

    /// @notice Note a deposit of assets into the escrow of the pool.
    /// @dev    Must be followed by a transfer of the equivalent amount of assets to `IBalanceSheet.escrow(poolId)`
    ///         This function is mostly useful to keep higher level integrations CEI adherent.
    /// @param  tokenId SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported.
    function noteDeposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 amount) external;

    /// @notice Withdraw assets from the escrow of the pool.
    /// @param  tokenId SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported.
    function withdraw(
        PoolId poolId,
        ShareClassId scId,
        address asset,
        uint256 tokenId,
        address receiver,
        uint128 amount
    ) external;

    /// @notice Increase the reserved balance of the pool. These assets are removed from the available balance
    ///         and cannot be withdrawn before they are unreserved.
    ///
    ///         It is possible to reserve more than the current balance, to lock future expected assets.
    function reserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 amount) external;

    /// @notice Decrease the reserved balance of the pool. These assets are re-added to the available balance.
    function unreserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 amount) external;

    /// @notice Issue new share tokens. Increases the total issuance.
    function issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) external;

    /// @notice Revoke share tokens. Decreases the total issuance.
    function revoke(PoolId poolId, ShareClassId scId, uint128 shares) external;

    /// @notice Sends the queued updated holding amount to the Hub
    function submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId, uint128 extraGasLimit) external;

    /// @notice Sends the queued updated shares changed to the Hub
    function submitQueuedShares(PoolId poolId, ShareClassId scId, uint128 extraGasLimit) external;

    /// @notice Force-transfers share tokens.
    function transferSharesFrom(
        PoolId poolId,
        ShareClassId scId,
        address sender,
        address from,
        address to,
        uint256 amount
    ) external;

    /// @notice Override the price pool per asset, to be used for any other balance sheet interactions.
    /// @dev    This can be used to note an interaction at a lower/higher price than the current one.
    ///         resetPricePoolPerAsset MUST be called after the balance sheet interactions using this price.
    function overridePricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 value) external;

    /// @notice Reset the price pool per asset.
    function resetPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId) external;

    /// @notice Override the price pool per share, to be used for any other balance sheet interactions.
    /// @dev    This can be used to note an interaction at a lower/higher price than the current one.
    ///         resetPricePoolPerShare MUST be called after the balance sheet interactions using this price.
    function overridePricePoolPerShare(PoolId poolId, ShareClassId scId, D18 value) external;

    /// @notice Reset the price pool per share.
    function resetPricePoolPerShare(PoolId poolId, ShareClassId scId) external;

    /// @notice Returns the pool escrow.
    /// @dev    Assets for pending deposit requests are not held by the pool escrow.
    function escrow(PoolId poolId) external view returns (IPoolEscrow);

    /// @notice Returns the amount of assets that can be withdrawn from the balance sheet.
    /// @dev    Assets that are locked for redemption requests are reserved and not available for withdrawals.
    /// @param  tokenId SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported.
    function availableBalanceOf(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId)
        external
        view
        returns (uint128);
}

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

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

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

import {Price} from "src/spoke/types/Price.sol";
import {IShareToken} from "src/spoke/interfaces/IShareToken.sol";
import {IVault, VaultKind} from "src/spoke/interfaces/IVault.sol";
import {IRequestManager} from "src/spoke/interfaces/IRequestManager.sol";
import {IVaultFactory} from "src/spoke/factories/interfaces/IVaultFactory.sol";

/// @dev Centrifuge pools
struct Pool {
    uint256 createdAt;
    mapping(ShareClassId scId => ShareClassDetails) shareClasses;
}

struct ShareClassAsset {
    /// @dev Manager that can send requests, and handles the request callbacks.
    IRequestManager manager;
    /// @dev Number of linked vaults.
    uint32 numVaults;
}

/// @dev Each Centrifuge pool is associated to 1 or more shar classes
struct ShareClassDetails {
    IShareToken shareToken;
    /// @dev Each share class has an individual price per share class unit in pool denomination (POOL_UNIT/SHARE_UNIT)
    Price pricePoolPerShare;
    mapping(AssetId assetId => ShareClassAsset) asset;
    /// @dev For each share class, we store the price per pool unit in asset denomination (POOL_UNIT/ASSET_UNIT)
    mapping(address asset => mapping(uint256 tokenId => Price)) pricePoolPerAsset;
}

struct VaultDetails {
    /// @dev AssetId of the asset
    AssetId assetId;
    /// @dev Address of the asset
    address asset;
    /// @dev TokenId of the asset - zero if asset is ERC20, non-zero if asset is ERC6909
    uint256 tokenId;
    /// @dev Whether the vault is linked to a share class atm
    bool isLinked;
}

struct AssetIdKey {
    /// @dev The address of the asset
    address asset;
    /// @dev The ERC6909 token id or 0, if the underlying asset is an ERC20
    uint256 tokenId;
}

interface ISpoke {
    event File(bytes32 indexed what, address data);
    event RegisterAsset(
        AssetId indexed assetId,
        address indexed asset,
        uint256 indexed tokenId,
        string name,
        string symbol,
        uint8 decimals,
        bool isInitialization
    );
    event File(bytes32 indexed what, address factory, bool status);
    event AddPool(PoolId indexed poolId);
    event AddShareClass(PoolId indexed poolId, ShareClassId indexed scId, IShareToken token);
    event DeployVault(
        PoolId indexed poolId,
        ShareClassId indexed scId,
        address indexed asset,
        uint256 tokenId,
        IVaultFactory factory,
        IVault vault,
        VaultKind kind
    );
    event SetRequestManager(
        PoolId indexed poolId, ShareClassId indexed scId, AssetId indexed assetId, IRequestManager manager
    );
    event UpdateAssetPrice(
        PoolId indexed poolId,
        ShareClassId indexed scId,
        address indexed asset,
        uint256 tokenId,
        uint256 price,
        uint64 computedAt
    );
    event UpdateSharePrice(PoolId indexed poolId, ShareClassId indexed scId, uint256 price, uint64 computedAt);
    event InitiateTransferShares(
        uint16 centrifugeId,
        PoolId indexed poolId,
        ShareClassId indexed scId,
        address indexed sender,
        bytes32 destinationAddress,
        uint128 amount
    );
    event ExecuteTransferShares(
        PoolId indexed poolId, ShareClassId indexed scId, address indexed receiver, uint128 amount
    );
    event LinkVault(
        PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IVault vault
    );
    event UnlinkVault(
        PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IVault vault
    );
    event UpdateMaxSharePriceAge(PoolId indexed poolId, ShareClassId indexed scId, uint64 maxPriceAge);
    event UpdateMaxAssetPriceAge(
        PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, uint64 maxPriceAge
    );

    error FileUnrecognizedParam();
    error TooFewDecimals();
    error TooManyDecimals();
    error PoolAlreadyAdded();
    error InvalidPool();
    error ShareClassAlreadyRegistered();
    error InvalidHook();
    error OldMetadata();
    error CannotSetOlderPrice();
    error OldHook();
    error UnknownVault();
    error UnknownAsset();
    error MalformedVaultUpdateMessage();
    error UnknownToken();
    error InvalidFactory();
    error InvalidPrice();
    error AssetMissingDecimals();
    error ShareTokenDoesNotExist();
    error LocalTransferNotAllowed();
    error CrossChainTransferNotAllowed();
    error ShareTokenTransferFailed();
    error TransferFromFailed();
    error InvalidRequestManager();
    error MoreThanZeroLinkedVaults();
    error RequestManagerNotSet();
    error InvalidManager();
    error InvalidVault();

    /// @notice Returns the asset address and tokenId associated with a given asset id.
    /// @dev Reverts if asset id does not exist
    ///
    /// @param assetId The underlying internal uint128 assetId.
    /// @return asset The address of the asset linked to the given asset id.
    /// @return tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.
    function idToAsset(AssetId assetId) external view returns (address asset, uint256 tokenId);

    /// @notice Returns assetId given the asset address and tokenId.
    /// @dev Reverts if asset id does not exist
    ///
    /// @param asset The address of the asset linked to the given asset id.
    /// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.
    /// @return assetId The underlying internal uint128 assetId.
    function assetToId(address asset, uint256 tokenId) external view returns (AssetId assetId);

    /// @notice Updates a contract parameter
    /// @param what Accepts a bytes32 representation of 'gateway', 'investmentManager', 'tokenFactory',
    ///                or 'gasService'
    function file(bytes32 what, address data) external;

    /// @notice transfers share class tokens to a cross-chain recipient address
    /// @dev    To transfer to evm chains, pad a 20 byte evm address with 12 bytes of 0
    /// @param  centrifugeId The destination chain id
    /// @param  poolId The centrifuge pool id
    /// @param  scId The share class id
    /// @param  receiver A bytes32 representation of the receiver address
    /// @param  amount The amount of tokens to transfer
    /// @param  remoteExtraGasLimit extra gas limit used for some extra computation that could happen in the chain where
    /// the transfer is executed.
    function crosschainTransferShares(
        uint16 centrifugeId,
        PoolId poolId,
        ShareClassId scId,
        bytes32 receiver,
        uint128 amount,
        uint128 remoteExtraGasLimit
    ) external payable;

    /// @notice Registers an ERC-20 or ERC-6909 asset in another chain.
    /// @dev `decimals()` MUST return a `uint8` value between 2 and 18.
    /// @dev `name()` and `symbol()` MAY return no values.
    ///
    /// @param centrifugeId The centrifuge id of chain to where the shares are transferred
    /// @param asset The address of the asset to be registered
    /// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.
    /// @return assetId The underlying internal uint128 assetId.
    function registerAsset(uint16 centrifugeId, address asset, uint256 tokenId)
        external
        payable
        returns (AssetId assetId);

    function linkToken(PoolId poolId, ShareClassId scId, IShareToken shareToken) external;

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

    /// @notice Deploys a new vault
    ///
    /// @param poolId The pool id
    /// @param scId The share class id
    /// @param assetId The asset id for which we want to deploy a vault
    /// @param factory The address of the corresponding vault factory
    /// @return address The address of the deployed vault
    function deployVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVaultFactory factory)
        external
        returns (IVault);

    /// @notice Register a vault.
    function registerVault(
        PoolId poolId,
        ShareClassId scId,
        AssetId assetId,
        address asset,
        uint256 tokenId,
        IVaultFactory factory,
        IVault vault
    ) external;

    /// @notice Links a deployed vault to the given pool, share class and asset.
    ///
    /// @param poolId The pool id
    /// @param scId The share class id
    /// @param assetId The asset id for which we want to deploy a vault
    /// @param vault The address of the deployed vault
    function linkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVault vault) external;

    /// @notice Removes the link between a vault and the given pool, share class and asset.
    ///
    /// @param poolId The pool id
    /// @param scId The share class id
    /// @param assetId The asset id for which we want to deploy a vault
    /// @param vault The address of the deployed vault
    function unlinkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVault vault) external;

    /// @notice Returns whether the given pool id is active
    function isPoolActive(PoolId poolId) external view returns (bool);

    /// @notice Returns the share class token for a given pool and share class id.
    /// @dev Reverts if share class does not exists
    ///
    /// @param poolId The pool id
    /// @param scId The share class id
    /// @return address The address of the share token
    function shareToken(PoolId poolId, ShareClassId scId) external view returns (IShareToken);

    /// @notice Function to get the details of a vault
    /// @dev    Reverts if vault does not exist
    ///
    /// @param vault The address of the vault to be checked for
    /// @return details The details of the vault including the underlying asset address, token id, asset id
    function vaultDetails(IVault vault) external view returns (VaultDetails memory details);

    /// @notice Checks whether a given vault is eligible for investing into a share class of a pool
    ///
    /// @param vault The address of the vault
    /// @return bool Whether vault is to a share class
    function isLinked(IVault vault) external view returns (bool);

    /// @notice Returns the price per share for a given pool and share class. The Provided price is defined as
    /// POOL_UNIT/SHARE_UNIT.
    /// @dev Conditionally checks if price is valid.
    ///
    /// @param poolId The pool id
    /// @param scId The share class id
    /// @param checkValidity Whether to check if the price is valid
    /// @return price The pool price per share
    function pricePoolPerShare(PoolId poolId, ShareClassId scId, bool checkValidity)
        external
        view
        returns (D18 price);

    /// @notice Returns the price per asset for a given pool, share class and the underlying asset id. The Provided
    /// price is defined as POOL_UNIT/ASSET_UNIT.
    /// @dev Conditionally checks if price is valid.
    ///
    /// @param poolId The pool id
    /// @param scId The share class id
    /// @param assetId The asset id for which we want to know the POOL_UNIT/ASSET_UNIT.
    /// @param checkValidity Whether to check if the price is valid
    /// @return price The pool price per asset unit
    function pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)
        external
        view
        returns (D18 price);

    /// @notice Returns the both prices per pool for a given pool, share class and the underlying asset id. The Provided
    /// prices is defined as POOL_UNIT/ASSET_UNIT and POOL_UNIT/SHARE_UNIT.
    /// @dev Conditionally checks if prices are valid.
    ///
    /// @param poolId The pool id
    /// @param scId The share class id
    /// @param assetId The asset id for which we want to know pool price per asset
    /// @param checkValidity Whether to check if the prices are valid
    /// @return pricePoolPerAsset The pool price per asset unit, i.e. POOL_UNIT/ASSET_UNIT
    /// @return pricePoolPerShare The pool price per share unit, i.e. POOL_UNIT/SHARE_UNIT
    function pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)
        external
        view
        returns (D18 pricePoolPerAsset, D18 pricePoolPerShare);

    /// @notice Returns the age related markers for a share class price
    ///
    /// @param poolId The pool id
    /// @param scId The share class id
    /// @return computedAt The timestamp when this price was computed
    /// @return maxAge The maximum age this price is allowed to have
    /// @return validUntil The timestamp until this price is valid
    function markersPricePoolPerShare(PoolId poolId, ShareClassId scId)
        external
        view
        returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);

    /// @notice Returns the age related markers for an asset price
    ///
    /// @param poolId The pool id
    /// @param scId The share class id
    /// @param assetId The asset id for which we want to know pool price per asset
    /// @return computedAt The timestamp when this price was computed
    /// @return maxAge The maximum age this price is allowed to have
    /// @return validUntil The timestamp until this price is valid
    function markersPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId)
        external
        view
        returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);
}

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

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

interface IUpdateContract {
    error UnknownUpdateContractType();

    /// @notice Triggers an update on the target contract.
    /// @param  poolId The centrifuge pool id
    /// @param  scId The share class id
    /// @param  payload The payload to be processed by the target address
    function update(PoolId poolId, ShareClassId scId, bytes calldata payload) external;
}

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

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

enum UpdateContractType {
    /// @dev Placeholder for null update restriction type
    Invalid,
    Valuation,
    SyncDepositMaxReserve,
    UpdateAddress,
    Policy
}

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

    error UnknownMessageType();

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

    //---------------------------------------
    //   UpdateContract.Valuation (submsg)
    //---------------------------------------

    struct UpdateContractValuation {
        bytes32 valuation;
    }

    function deserializeUpdateContractValuation(bytes memory data)
        internal
        pure
        returns (UpdateContractValuation memory)
    {
        require(updateContractType(data) == UpdateContractType.Valuation, UnknownMessageType());
        return UpdateContractValuation({valuation: data.toBytes32(1)});
    }

    function serialize(UpdateContractValuation memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(UpdateContractType.Valuation, t.valuation);
    }

    //---------------------------------------
    //   UpdateContract.SyncDepositMaxReserve (submsg)
    //---------------------------------------

    struct UpdateContractSyncDepositMaxReserve {
        uint128 assetId;
        uint128 maxReserve;
    }

    function deserializeUpdateContractSyncDepositMaxReserve(bytes memory data)
        internal
        pure
        returns (UpdateContractSyncDepositMaxReserve memory)
    {
        require(updateContractType(data) == UpdateContractType.SyncDepositMaxReserve, UnknownMessageType());
        return UpdateContractSyncDepositMaxReserve({assetId: data.toUint128(1), maxReserve: data.toUint128(17)});
    }

    function serialize(UpdateContractSyncDepositMaxReserve memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(UpdateContractType.SyncDepositMaxReserve, t.assetId, t.maxReserve);
    }

    //---------------------------------------
    //   UpdateContract.UpdateAddress (submsg)
    //---------------------------------------

    struct UpdateContractUpdateAddress {
        bytes32 kind;
        uint128 assetId;
        bytes32 what;
        bool isEnabled;
    }

    function deserializeUpdateContractUpdateAddress(bytes memory data)
        internal
        pure
        returns (UpdateContractUpdateAddress memory)
    {
        require(updateContractType(data) == UpdateContractType.UpdateAddress, UnknownMessageType());

        return UpdateContractUpdateAddress({
            kind: data.toBytes32(1),
            assetId: data.toUint128(33),
            what: data.toBytes32(49),
            isEnabled: data.toBool(81)
        });
    }

    function serialize(UpdateContractUpdateAddress memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(UpdateContractType.UpdateAddress, t.kind, t.assetId, t.what, t.isEnabled);
    }

    //---------------------------------------
    //   UpdateContract.Policy (submsg)
    //---------------------------------------

    struct UpdateContractPolicy {
        bytes32 who;
        bytes32 what;
    }

    function deserializeUpdateContractPolicy(bytes memory data) internal pure returns (UpdateContractPolicy memory) {
        require(updateContractType(data) == UpdateContractType.Policy, UnknownMessageType());

        return UpdateContractPolicy({who: data.toBytes32(1), what: data.toBytes32(33)});
    }

    function serialize(UpdateContractPolicy memory t) internal pure returns (bytes memory) {
        return abi.encodePacked(UpdateContractType.Policy, t.who, t.what);
    }
}

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

import {IERC7575} from "src/misc/interfaces/IERC7575.sol";
import {IRecoverable} from "src/misc/interfaces/IRecoverable.sol";
import {IERC7540Operator, IERC7714, IERC7741} from "src/misc/interfaces/IERC7540.sol";

import {IVault} from "src/spoke/interfaces/IVault.sol";

/// @notice Interface for the all vault contracts
/// @dev Must be implemented by all vaults
interface IBaseVault is IVault, IERC7540Operator, IERC7741, IERC7714, IERC7575, IRecoverable {
    error FileUnrecognizedParam();
    error NotEndorsed();
    error CannotSetSelfAsOperator();
    error ExpiredAuthorization();
    error AlreadyUsedAuthorization();
    error InvalidAuthorization();
    error InvalidController();
    error InsufficientBalance();
    error RequestRedeemFailed();
    error TransferFromFailed();

    event File(bytes32 indexed what, address data);

    /// @notice Set msg.sender as operator of owner, to `approved` status
    /// @dev    MUST be called by endorsed sender
    function setEndorsedOperator(address owner, bool approved) external;
}

File 17 of 40 : IVaultManagers.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;

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

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

import {IUpdateContract} from "src/spoke/interfaces/IUpdateContract.sol";

import {IBaseVault} from "src/vaults/interfaces/IBaseVault.sol";
import {IBaseRequestManager} from "src/vaults/interfaces/IBaseRequestManager.sol";

interface IDepositManager {
    /// @notice Processes owner's asset deposit after the epoch has been executed on the corresponding CP instance and
    /// the deposit order
    ///         has been successfully processed (partial fulfillment possible).
    ///         Shares are transferred from the escrow to the receiver. Amount of shares is computed based of the amount
    ///         of assets and the owner's share price.
    /// @dev    The assets required to fulfill the deposit are already locked in escrow upon calling requestDeposit.
    ///         The shares required to fulfill the deposit have already been minted and transferred to the escrow on
    ///         fulfillDepositRequest.
    ///         Receiver has to pass all the share token restrictions in order to receive the shares.
    function deposit(IBaseVault vault, uint256 assets, address receiver, address owner)
        external
        returns (uint256 shares);

    /// @notice Processes owner's share mint after the epoch has been executed on the corresponding CP instance and the
    /// deposit order has
    ///         been successfully processed (partial fulfillment possible).
    ///         Shares are transferred from the escrow to the receiver. Amount of assets is computed based of the amount
    ///         of shares and the owner's share price.
    /// @dev    The assets required to fulfill the mint are already locked in escrow upon calling requestDeposit.
    ///         The shares required to fulfill the mint have already been minted and transferred to the escrow on
    ///         fulfillDepositRequest.
    ///         Receiver has to pass all the share token restrictions in order to receive the shares.
    function mint(IBaseVault vault, uint256 shares, address receiver, address owner)
        external
        returns (uint256 assets);

    /// @notice Returns the max amount of assets based on the unclaimed amount of shares after at least one successful
    ///         deposit order fulfillment on the corresponding CP instance.
    function maxDeposit(IBaseVault vault, address user) external view returns (uint256);

    /// @notice Returns the max amount of shares a user can claim after at least one successful deposit order
    ///         fulfillment on the corresponding CP instance.
    function maxMint(IBaseVault vault, address user) external view returns (uint256 shares);
}

interface ISyncDepositManager is IDepositManager {
    function previewDeposit(IBaseVault vault, address sender, uint256 assets) external view returns (uint256);
    function previewMint(IBaseVault vault, address sender, uint256 shares) external view returns (uint256);
}

interface IAsyncDepositManager is IDepositManager, IBaseRequestManager {
    /// @notice Requests assets deposit. Vaults have to request investments from Centrifuge before
    ///         shares can be minted. The deposit requests are added to the order book
    ///         on the corresponding CP instance. Once the next epoch is executed on the corresponding CP instance,
    ///         vaults can proceed with share payouts in case the order got fulfilled.
    /// @dev    The assets required to fulfill the deposit request have to be locked and are transferred from the
    ///         owner to the escrow, even though the share payout can only happen after epoch execution.
    ///         The receiver becomes the owner of deposit request fulfillment.
    /// @param  source Deprecated
    function requestDeposit(IBaseVault vault, uint256 assets, address receiver, address owner, address source)
        external
        returns (bool);

    /// @notice Requests the cancellation of a pending deposit request. Vaults have to request the
    ///         cancellation of outstanding requests from Centrifuge before actual assets can be unlocked and
    ///         transferred to the owner.
    ///         While users have outstanding cancellation requests no new deposit requests can be submitted.
    ///         Once the next epoch is executed on the corresponding CP instance, vaults can proceed with asset payouts
    ///         if orders could be cancelled successfully.
    /// @dev    The cancellation request might fail in case the pending deposit order already got fulfilled on
    ///         Centrifuge.
    /// @param  source Deprecated
    function cancelDepositRequest(IBaseVault vault, address owner, address source) external;

    /// @notice Processes owner's deposit request cancellation after the epoch has been executed on the corresponding CP
    ///         instance and the deposit order cancellation has been successfully processed (partial fulfillment
    ///         possible).
    ///         Assets are transferred from the escrow to the receiver.
    /// @dev    The assets required to fulfill the claim have already been reserved for the owner in escrow on
    ///         fulfillDepositRequest with non-zero cancelled asset amount value.
    function claimCancelDepositRequest(IBaseVault vault, address receiver, address owner)
        external
        returns (uint256 assets);

    /// @notice Indicates whether a user has pending deposit requests and returns the total deposit request asset
    /// request value.
    function pendingDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);

    /// @notice Indicates whether a user has pending deposit request cancellations.
    function pendingCancelDepositRequest(IBaseVault vault, address user) external view returns (bool isPending);

    /// @notice Indicates whether a user has claimable deposit request cancellation and returns the total claim
    ///         value in assets.
    function claimableCancelDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);
}

interface IRedeemManager {
    event TriggerRedeemRequest(
        uint64 indexed poolId,
        bytes16 indexed scId,
        address user,
        address indexed asset,
        uint256 tokenId,
        uint128 shares
    );

    /// @notice Processes owner's share redemption after the epoch has been executed on the corresponding CP instance
    /// and the redeem order
    ///         has been successfully processed (partial fulfillment possible).
    ///         Assets are transferred from the escrow to the receiver. Amount of assets is computed based of the amount
    ///         of shares and the owner's share price.
    /// @dev    The shares required to fulfill the redemption were already locked in escrow on requestRedeem and burned
    ///         on fulfillRedeemRequest.
    ///         The assets required to fulfill the redemption have already been reserved in escrow on
    ///         fulfillRedeemtRequest.
    function redeem(IBaseVault vault, uint256 shares, address receiver, address owner)
        external
        returns (uint256 assets);

    /// @notice Processes owner's asset withdrawal after the epoch has been executed on the corresponding CP instance
    /// and the redeem order
    ///         has been successfully processed (partial fulfillment possible).
    ///         Assets are transferred from the escrow to the receiver. Amount of shares is computed based of the amount
    ///         of shares and the owner's share price.
    /// @dev    The shares required to fulfill the withdrawal were already locked in escrow on requestRedeem and burned
    ///         on fulfillRedeemRequest.
    ///         The assets required to fulfill the withdrawal have already been reserved in escrow on
    ///         fulfillRedeemtRequest.
    function withdraw(IBaseVault vault, uint256 assets, address receiver, address owner)
        external
        returns (uint256 shares);

    /// @notice Returns the max amount of shares based on the unclaimed number of assets after at least one successful
    ///         redeem order fulfillment on the corresponding CP instance.
    function maxRedeem(IBaseVault vault, address user) external view returns (uint256 shares);

    /// @notice Returns the max amount of assets a user can claim after at least one successful redeem order fulfillment
    ///         on the corresponding CP instance.
    function maxWithdraw(IBaseVault vault, address user) external view returns (uint256 assets);
}

interface IAsyncRedeemManager is IRedeemManager, IBaseRequestManager {
    /// @notice Requests share redemption. Vaults have to request redemptions
    ///         from Centrifuge before actual asset payouts can be done. The redemption
    ///         requests are added to the order book on the corresponding CP instance. Once the next epoch is
    ///         executed on the corresponding CP instance, vaults can proceed with asset payouts
    ///         in case the order got fulfilled.
    /// @dev    The shares required to fulfill the redemption request have to be locked and are transferred from the
    ///         owner to the escrow, even though the asset payout can only happen after epoch execution.
    ///         The receiver becomes the owner of redeem request fulfillment.
    /// @param  source Deprecated
    /// @param  transfer Set `false` for legacy vaults which already execute the transfer in the vault implementation
    function requestRedeem(
        IBaseVault vault,
        uint256 shares,
        address receiver,
        address owner,
        address source,
        bool transfer
    ) external returns (bool);

    /// @notice Requests the cancellation of an pending redeem request. Vaults have to request the
    ///         cancellation of outstanding requests from Centrifuge before actual shares can be unlocked and
    ///         transferred to the owner.
    ///         While users have outstanding cancellation requests no new redeem requests can be submitted (exception:
    ///         trigger through governance).
    ///         Once the next epoch is executed on the corresponding CP instance, vaults can proceed with share payouts
    ///         if the orders could be cancelled successfully.
    /// @dev    The cancellation request might fail in case the pending redeem order already got fulfilled on
    ///         Centrifuge.
    function cancelRedeemRequest(IBaseVault vault, address owner, address source) external;

    /// @notice Processes owner's redeem request cancellation after the epoch has been executed on the corresponding CP
    ///         instance and the redeem order cancellation has been successfully processed (partial fulfillment
    ///         possible).
    ///         Shares are transferred from the escrow to the receiver.
    /// @dev    The shares required to fulfill the claim have already been reserved for the owner in escrow on
    ///         fulfillRedeemRequest with non-zero cancelled share amount value.
    ///         Receiver has to pass all the share token restrictions in order to receive the shares.
    function claimCancelRedeemRequest(IBaseVault vault, address receiver, address owner)
        external
        returns (uint256 shares);

    /// @notice Indicates whether a user has pending redeem requests and returns the total share request value.
    function pendingRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);

    /// @notice Indicates whether a user has pending redeem request cancellations.
    function pendingCancelRedeemRequest(IBaseVault vault, address user) external view returns (bool isPending);

    /// @notice Indicates whether a user has claimable redeem request cancellation and returns the total claim
    ///         value in shares.
    function claimableCancelRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);
}

/// @dev Solely used locally as protection against stack-too-deep
struct Prices {
    /// @dev Price of 1 asset unit per share unit
    D18 assetPerShare;
    /// @dev Price of 1 pool unit per asset unit
    D18 poolPerAsset;
    /// @dev Price of 1 pool unit per share unit
    D18 poolPerShare;
}

interface ISyncDepositValuation {
    /// @notice Returns the pool price per share for a given pool and share class, asset, and asset id.
    // The provided price is defined as POOL_UNIT/SHARE_UNIT.
    ///
    /// @param poolId The pool id
    /// @param scId The share class id
    /// @return price The pool price per share
    function pricePoolPerShare(PoolId poolId, ShareClassId scId) external view returns (D18 price);
}

interface ISyncManager is ISyncDepositManager, ISyncDepositValuation, IUpdateContract {
    event SetValuation(PoolId indexed poolId, ShareClassId indexed scId, address valuation);
    event SetMaxReserve(
        PoolId indexed poolId, ShareClassId indexed scId, address asset, uint256 tokenId, uint128 maxReserve
    );
    event File(bytes32 indexed what, address data);

    error ExceedsMaxDeposit();
    error FileUnrecognizedParam();
    error ExceedsMaxMint();
    error ShareTokenDoesNotExist();
    error SecondaryManagerDoesNotExist();

    /// @notice Updates contract parameters of type address.
    /// @param what The bytes32 representation of 'gateway' or 'spoke'.
    /// @param data The new contract address.
    function file(bytes32 what, address data) external;

    /// @notice Converts the assets value to share decimals.
    function convertToShares(IBaseVault vault, uint256 _assets) external view returns (uint256 shares);

    /// @notice Converts the shares value to assets decimals.
    function convertToAssets(IBaseVault vault, uint256 _shares) external view returns (uint256 assets);

    /// @notice Sets the valuation for a specific pool and share class.
    ///
    /// @param poolId The id of the pool
    /// @param scId The id of the share class
    /// @param valuation The address of the valuation contract
    function setValuation(PoolId poolId, ShareClassId scId, address valuation) external;

    /// @notice Sets the max reserve for a specific pool, share class and asset.
    ///
    /// @param poolId The id of the pool
    /// @param scId The id of the share class
    /// @param asset The address of the asset
    /// @param tokenId The asset token id, i.e. 0 for ERC20, or the token id for ERC6909
    /// @param maxReserve The amount of maximum reserve
    function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve)
        external;
}

/// @dev Vault requests and deposit/redeem bookkeeping per user
struct AsyncInvestmentState {
    /// @dev Shares that can be claimed using `mint()`
    uint128 maxMint;
    /// @dev Assets that can be claimed using `withdraw()`
    uint128 maxWithdraw;
    /// @dev Weighted average price of deposits, used to convert maxMint to maxDeposit
    /// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT
    D18 depositPrice;
    /// @dev Weighted average price of redemptions, used to convert maxWithdraw to maxRedeem
    /// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT
    D18 redeemPrice;
    /// @dev Remaining deposit request in assets
    uint128 pendingDepositRequest;
    /// @dev Remaining redeem request in shares
    uint128 pendingRedeemRequest;
    /// @dev Assets that can be claimed using `claimCancelDepositRequest()`
    uint128 claimableCancelDepositRequest;
    /// @dev Shares that can be claimed using `claimCancelRedeemRequest()`
    uint128 claimableCancelRedeemRequest;
    /// @dev Indicates whether the depositRequest was requested to be cancelled
    bool pendingCancelDepositRequest;
    /// @dev Indicates whether the redeemRequest was requested to be cancelled
    bool pendingCancelRedeemRequest;
}

interface IAsyncRequestManager is IAsyncDepositManager, IAsyncRedeemManager {
    error AssetNotAllowed();
    error ExceedsMaxDeposit();
    error AssetMismatch();
    error ZeroAmountNotAllowed();
    error TransferNotAllowed();
    error CancellationIsPending();
    error NoPendingRequest();
    error ShareTokenAmountIsZero();
    error FailedRedeemRequest();
    error ExceedsDepositLimits();
    error ShareTokenTransferFailed();
    error ExceedsMaxRedeem();
    error ExceedsRedeemLimits();

    /// @notice Returns the investment state
    function investments(IBaseVault vaultAddr, address investor)
        external
        view
        returns (
            uint128 maxMint,
            uint128 maxWithdraw,
            D18 depositPrice,
            D18 redeemPrice,
            uint128 pendingDepositRequest,
            uint128 pendingRedeemRequest,
            uint128 claimableCancelDepositRequest,
            uint128 claimableCancelRedeemRequest,
            bool pendingCancelDepositRequest,
            bool pendingCancelRedeemRequest
        );

    /// @notice Signal from the Hub that an asynchronous investment order has been approved
    ///
    /// @dev This message needs to trigger making the asset amounts available to the pool-share-class.
    function approvedDeposits(
        PoolId poolId,
        ShareClassId scId,
        AssetId assetId,
        uint128 assetAmount,
        D18 pricePoolPerAsset
    ) external;

    /// @notice Signal from the Hub that an asynchronous investment order has been finalized. Shares have been issued.
    ///
    /// @dev This message needs to trigger minting the new amount of shares.
    function issuedShares(PoolId poolId, ShareClassId scId, uint128 shareAmount, D18 pricePoolPerShare) external;

    /// @notice Signal from the Hub that an asynchronous redeem order has been finalized.
    ///
    /// @dev This messages needs to trigger reserving the asset amount for claims of redemptions by users.
    function revokedShares(
        PoolId poolId,
        ShareClassId scId,
        AssetId assetId,
        uint128 assetAmount,
        uint128 shareAmount,
        D18 pricePoolPerShare
    ) external;

    // --- Deposits ---
    /// @notice Fulfills pending deposit requests after successful epoch execution on Hub.
    ///         The amount of shares that can be claimed by the user is minted and moved to the escrow contract.
    ///         The maxMint and claimableCancelDepositRequest bookkeeping values are updated.
    ///         The request fulfillment can be partial.
    /// @dev    The shares in the escrow are reserved for the user and are transferred to the user on deposit
    ///         and mint calls.
    /// @dev    The cancelled and fulfilled amounts are both non-zero iff the cancellation was queued.
    ///         Otherwise, either of the two must always be zero.
    function fulfillDepositRequest(
        PoolId poolId,
        ShareClassId scId,
        address user,
        AssetId assetId,
        uint128 fulfilledAssetAmount,
        uint128 fulfilledShareAmount,
        uint128 cancelledAssetAmount
    ) external;

    // --- Redeems ---
    /// @notice Fulfills pending redeem requests after successful epoch execution on Hub.
    ///         The amount of redeemed shares is burned. The amount of assets that can be claimed by the user in
    ///         return is locked in the escrow contract.
    ///         The maxWithdraw and claimableCancelRedeemRequest bookkeeping values are updated.
    ///         The request fulfillment can be partial.
    /// @dev    The assets in the escrow are reserved for the user and are transferred to the user on redeem
    ///         and withdraw calls.
    /// @dev    The cancelled and fulfilled amounts are both non-zero iff the cancellation was queued.
    ///         Otherwise, either of the two must always be zero.
    function fulfillRedeemRequest(
        PoolId poolId,
        ShareClassId scId,
        address user,
        AssetId assetId,
        uint128 fulfilledAssetAmount,
        uint128 fulfilledShareAmount,
        uint128 cancelledShareAmount
    ) external;
}

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

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

    error NotAuthorized();

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

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

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

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.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.8.28;

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

/// @title  Safe Transfer Lib
/// @author Modified from Uniswap v3 Periphery (libraries/TransferHelper.sol)
library SafeTransferLib {
    error NoCode();
    error SafeTransferFromFailed();
    error SafeTransferFailed();
    error SafeApproveFailed();
    error SafeTransferEthFailed();

    /// @notice Transfers tokens from the targeted address to the given destination
    /// @notice Errors if transfer fails
    /// @param token The contract address of the token to be transferred
    /// @param from The originating address from which the tokens will be transferred
    /// @param to The destination address of the transfer
    /// @param value The amount to be transferred
    function safeTransferFrom(address token, address from, address to, uint256 value) internal {
        require(address(token).code.length > 0, NoCode());

        (bool success, bytes memory returnData) = token.call(abi.encodeCall(IERC20.transferFrom, (from, to, value)));
        require(
            success && (returnData.length == 0 || abi.decode(returnData, (bool))),
            IERC7751.WrappedError(
                token, IERC20.transferFrom.selector, returnData, abi.encodeWithSelector(SafeTransferFromFailed.selector)
            )
        );
    }

    /// @notice Transfers tokens from msg.sender to a recipient
    /// @dev Errors if transfer fails
    /// @param token The contract address of the token which will be transferred
    /// @param to The recipient of the transfer
    /// @param value The value of the transfer
    function safeTransfer(address token, address to, uint256 value) internal {
        require(address(token).code.length > 0, NoCode());

        (bool success, bytes memory returnData) = token.call(abi.encodeCall(IERC20.transfer, (to, value)));
        require(
            success && (returnData.length == 0 || abi.decode(returnData, (bool))),
            IERC7751.WrappedError(
                token, IERC20.transfer.selector, returnData, abi.encodeWithSelector(SafeTransferFailed.selector)
            )
        );
    }

    /// @notice Approves the stipulated contract to spend the given allowance in the given token
    /// @dev Errors if approval fails
    /// @param token The contract address of the token to be approved
    /// @param to The target of the approval
    /// @param value The amount of the given token the target will be allowed to spend
    function safeApprove(address token, address to, uint256 value) internal {
        require(address(token).code.length > 0, NoCode());

        (bool success, bytes memory returnData) = token.call(abi.encodeCall(IERC20.approve, (to, value)));
        require(
            success && (returnData.length == 0 || abi.decode(returnData, (bool))),
            IERC7751.WrappedError(
                token, IERC20.approve.selector, returnData, abi.encodeWithSelector(SafeApproveFailed.selector)
            )
        );
    }

    /// @notice Transfers ETH to the recipient address
    /// @dev Fails with `STE`
    /// @dev Make sure that method that is using this function is protected from reentrancy
    /// @param to The destination of the transfer
    /// @param value The value to be transferred
    function safeTransferETH(address to, uint256 value) internal {
        (bool success,) = to.call{value: value}(new bytes(0));
        require(success, SafeTransferEthFailed());
    }
}

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

address constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

struct Holding {
    uint128 total;
    uint128 reserved;
}

/// @title PerPoolEscrow separating funds by pool and share class
interface IPoolEscrow is IEscrow, IRecoverable {
    // --- Events ---
    /// @notice Emitted when a deposit is made
    /// @param asset The address of the deposited asset
    /// @param tokenId The id of the asset - 0 for ERC20
    /// @param poolId The id of the pool
    /// @param scId The id of the share class
    /// @param value The amount deposited
    event Deposit(
        address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value
    );

    /// @notice Emitted when an amount is reserved
    /// @param asset The address of the reserved asset
    /// @param tokenId The id of the asset - 0 for ERC20
    /// @param poolId The id of the pool
    /// @param scId The id of the share class
    /// @param value The delta amount reserved
    /// @param value The new absolute amount reserved
    event IncreaseReserve(
        address indexed asset,
        uint256 indexed tokenId,
        PoolId indexed poolId,
        ShareClassId scId,
        uint256 delta,
        uint128 value
    );

    /// @notice Emitted when an amount is unreserved
    /// @param asset The address of the reserved asset
    /// @param tokenId The id of the asset - 0 for ERC20
    /// @param poolId The id of the pool
    /// @param scId The id of the share class
    /// @param value The delta amount unreserved
    /// @param value The new absolute amount reserved
    event DecreaseReserve(
        address indexed asset,
        uint256 indexed tokenId,
        PoolId indexed poolId,
        ShareClassId scId,
        uint256 delta,
        uint128 value
    );

    /// @notice Emitted when a withdraw is made
    /// @param asset The address of the withdrawn asset
    /// @param tokenId The id of the asset - 0 for ERC20
    /// @param poolId The id of the pool
    /// @param scId The id of the share class
    /// @param value The amount withdrawn
    event Withdraw(
        address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value
    );

    /// @notice Emmitted when ETH is transfered to the escrow
    /// @param amount transfered
    event ReceiveNativeTokens(address who, uint256 amount);

    // --- Errors ---
    /// @notice Dispatched when the balance of the escrow did not increase sufficiently
    error InsufficientDeposit();

    /// @notice Dispatched when the outstanding reserved amount is insufficient for the decrease
    error InsufficientReservedAmount();

    // --- Functions ---
    /// @notice Deposits `value` of `asset` in underlying `poolId` and given `scId`
    ///
    /// @dev NOTE: Must ensure balance sufficiency, i.e. that the depositing amount does not exceed the balance of
    /// escrow
    ///
    /// @param scId The id of the share class
    /// @param asset The address of the asset to be deposited
    /// @param tokenId The id of the asset - 0 for ERC20
    /// @param value The amount to deposit
    function deposit(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;

    /// @notice Withdraws `value` of `asset` in underlying `poolId` and given `scId`
    /// @dev MUST ensure that reserved amounts are not withdrawn
    /// @param scId The id of the share class
    /// @param asset The address of the asset to be withdrawn
    /// @param tokenId The id of the asset - 0 for ERC20
    /// @param value The amount to withdraw
    function withdraw(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;

    /// @notice Increases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`
    /// @dev MUST prevent the reserved amount from being withdrawn
    /// @param scId The id of the share class
    /// @param asset The address of the asset to be reserved
    /// @param tokenId The id of the asset - 0 for ERC20
    /// @param value The amount to reserve
    function reserve(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;

    /// @notice Decreases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`
    /// @dev MUST fail if `value` is greater than the current reserved amount
    /// @param scId The id of the share class
    /// @param asset The address of the asset to be reserved
    /// @param tokenId The id of the asset - 0 for ERC20
    /// @param value The amount to decrease
    function unreserve(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;

    /// @notice Provides the available balance of `asset` in underlying `poolId` and given `scId`
    /// @dev MUST return the balance minus the reserved amount
    /// @param scId The id of the share class
    /// @param asset The address of the asset to be checked
    /// @param tokenId The id of the asset - 0 for ERC20
    /// @return The available balance
    function availableBalanceOf(ShareClassId scId, address asset, uint256 tokenId) external view returns (uint128);
}

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

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

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

interface ILocalCentrifugeId {
    function localCentrifugeId() external view returns (uint16);
}

/// @notice Interface for dispatch-only gateway
interface IRootMessageSender {
    /// @notice Creates and send the message
    function sendScheduleUpgrade(uint16 centrifugeId, bytes32 target) external;

    /// @notice Creates and send the message
    function sendCancelUpgrade(uint16 centrifugeId, bytes32 target) external;

    /// @notice Creates and send the message
    function sendRecoverTokens(
        uint16 centrifugeId,
        bytes32 target,
        bytes32 token,
        uint256 tokenId,
        bytes32 to,
        uint256 amount
    ) external;
}

/// @notice Interface for dispatch-only gateway
interface IHubMessageSender is ILocalCentrifugeId {
    /// @notice Creates and send the message
    function sendNotifyPool(uint16 centrifugeId, PoolId poolId) external;

    /// @notice Creates and send the message
    function sendNotifyShareClass(
        uint16 centrifugeId,
        PoolId poolId,
        ShareClassId scId,
        string memory name,
        string memory symbol,
        uint8 decimals,
        bytes32 salt,
        bytes32 hook
    ) external;

    /// @notice Creates and send the message
    function sendNotifyShareMetadata(
        uint16 centrifugeId,
        PoolId poolId,
        ShareClassId scId,
        string memory name,
        string memory symbol
    ) external;

    /// @notice Creates and send the message
    function sendUpdateShareHook(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 hook) external;

    /// @notice Creates and send the message
    function sendNotifyPricePoolPerShare(uint16 chainId, PoolId poolId, ShareClassId scId, D18 pricePerShare)
        external;

    /// @notice Creates and send the message
    function sendNotifyPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePerShare)
        external;

    /// @notice Creates and send the message
    function sendUpdateRestriction(
        uint16 centrifugeId,
        PoolId poolId,
        ShareClassId scId,
        bytes calldata payload,
        uint128 extraGasLimit
    ) external;

    /// @notice Creates and send the message
    function sendUpdateContract(
        uint16 centrifugeId,
        PoolId poolId,
        ShareClassId scId,
        bytes32 target,
        bytes calldata payload,
        uint128 extraGasLimit
    ) external;

    /// @notice Creates and send the message
    function sendUpdateVault(
        PoolId poolId,
        ShareClassId scId,
        AssetId assetId,
        bytes32 vaultOrFactory,
        VaultUpdateKind kind,
        uint128 extraGasLimit
    ) external;

    /// @notice Creates and send the message
    function sendSetRequestManager(PoolId poolId, ShareClassId scId, AssetId assetId, bytes32 manager) external;

    /// @notice Creates and send the message
    function sendUpdateBalanceSheetManager(uint16 centrifugeId, PoolId poolId, bytes32 who, bool canManage) external;

    /// @notice Creates and send the message
    function sendExecuteTransferShares(
        uint16 centrifugeId,
        PoolId poolId,
        ShareClassId scId,
        bytes32 receiver,
        uint128 amount,
        uint128 extraGasLimit
    ) external;

    /// @notice Creates and send the message
    function sendMaxAssetPriceAge(PoolId poolId, ShareClassId scId, AssetId assetId, uint64 maxPriceAge) external;

    /// @notice Creates and send the message
    function sendMaxSharePriceAge(uint16 centrifugeId, PoolId poolId, ShareClassId scId, uint64 maxPriceAge) external;

    /// @notice Creates and send the message
    function sendRequestCallback(
        PoolId poolId,
        ShareClassId scId,
        AssetId assetId,
        bytes calldata payload,
        uint128 extraGasLimit
    ) external;
}

/// @notice Interface for dispatch-only gateway
interface ISpokeMessageSender is ILocalCentrifugeId {
    struct UpdateData {
        uint128 netAmount;
        bool isIncrease;
        bool isSnapshot;
        uint64 nonce;
    }

    /// @notice Creates and send the message
    function sendInitiateTransferShares(
        uint16 centrifugeId,
        PoolId poolId,
        ShareClassId scId,
        bytes32 receiver,
        uint128 amount,
        uint128 remoteExtraGasLimit
    ) external;

    /// @notice Creates and send the message
    function sendRegisterAsset(uint16 centrifugeId, AssetId assetId, uint8 decimals) external;

    /// @notice Creates and send the message
    function sendUpdateHoldingAmount(
        PoolId poolId,
        ShareClassId scId,
        AssetId assetId,
        UpdateData calldata data,
        D18 pricePoolPerAsset,
        uint128 extraGasLimit
    ) external;

    /// @notice Creates and send the message
    function sendUpdateShares(PoolId poolId, ShareClassId scId, UpdateData calldata data, uint128 extraGasLimit)
        external;

    /// @notice Creates and send the message
    function sendRequest(PoolId poolId, ShareClassId scId, AssetId assetId, bytes calldata payload) external;
}

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

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

interface IPoolEscrowProvider {
    /// @notice Returns the deterministic address of an escrow contract based on a given pool id wrapped into the
    /// corresponding interface.
    ///
    /// @dev Does not check, whether the escrow was already deployed.
    function escrow(PoolId poolId) external view returns (IPoolEscrow);
}

interface IPoolEscrowFactory is IPoolEscrowProvider {
    event DeployPoolEscrow(PoolId indexed poolId, address indexed escrow);
    event File(bytes32 what, address data);

    error FileUnrecognizedParam();
    error EscrowAlreadyDeployed();

    /// @notice Deploys new escrow and returns it.
    /// @dev All share classes of a pool are represented by the same escrow contract.
    ///
    /// @param poolId Id of the pool this escrow is deployed for
    /// @return IPoolEscrow The the newly deployed escrow contract
    function newEscrow(PoolId poolId) external returns (IPoolEscrow);

    /// @notice Updates contract parameters of type address.
    function file(bytes32 what, address data) external;
}

File 27 of 40 : Price.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

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

/// @dev Price struct that contains a price, the timestamp at which it was computed and the max age of the price.
struct Price {
    uint128 price;
    uint64 computedAt;
    uint64 maxAge;
}

/// @dev Checks if a price is valid. Returns false if computedAt is 0. Otherwise checks for block
/// timestamp <= computedAt + maxAge
function isValid(Price memory price) view returns (bool) {
    if (price.computedAt != 0) {
        return block.timestamp <= price.validUntil();
    } else {
        return false;
    }
}

/// @dev Computes the timestamp until the price is valid. Saturates at uint64.MAX.
function validUntil(Price memory price) pure returns (uint64) {
    unchecked {
        uint64 validUntil_ = price.computedAt + price.maxAge;
        if (validUntil_ < price.computedAt) {
            return type(uint64).max;
        }
        return validUntil_;
    }
}

/// @dev Retrieves the price as an D18 from the struct
function asPrice(Price memory price) pure returns (D18) {
    return d18(price.price);
}

using {isValid, asPrice, validUntil} for Price global;

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

import {IERC20Metadata} from "src/misc/interfaces/IERC20.sol";
import {IERC7575Share} from "src/misc/interfaces/IERC7575.sol";

interface IERC1404 {
    /// @notice Detects if a transfer will be reverted and if so returns an appropriate reference code
    /// @param from Sending address
    /// @param to Receiving address
    /// @param value Amount of tokens being transferred
    /// @return Code by which to reference message for rejection reasoning
    /// @dev Overwrite with your custom transfer restriction logic
    function detectTransferRestriction(address from, address to, uint256 value) external view returns (uint8);

    /// @notice Returns a human-readable message for a given restriction code
    /// @param restrictionCode Identifier for looking up a message
    /// @return Text showing the restriction's reasoning
    /// @dev Overwrite with your custom message and restrictionCode handling
    function messageForTransferRestriction(uint8 restrictionCode) external view returns (string memory);
}

interface IShareToken is IERC20Metadata, IERC7575Share, IERC1404 {
    // --- Events ---
    event File(bytes32 indexed what, address data);
    event SetHookData(address indexed user, bytes16 data);

    // --- Errors ---
    error NotAuthorizedOrHook();
    error ExceedsMaxSupply();
    error RestrictionsFailed();

    struct Balance {
        /// @dev The user balance is limited to uint128. This is safe because the decimals are limited to 18,
        ///      thus the max balance is 2^128-1 / 10**18 = 3.40 * 10**20. This is also enforced on mint.
        uint128 amount;
        /// @dev There are 16 bytes that are used to store hook data (e.g. restrictions for users).
        bytes16 hookData;
    }

    // --- Administration ---
    /// @notice returns the hook that transfers perform callbacks to
    /// @dev    MUST comply to `ITransferHook` interface
    function hook() external view returns (address);

    /// @notice Updates a contract parameter
    /// @param what Accepts a bytes32 representation of 'name', 'symbol'
    function file(bytes32 what, string memory data) external;

    /// @notice Updates a contract parameter
    /// @param what Accepts a bytes32 representation of 'hook'
    function file(bytes32 what, address data) external;

    /// @notice updates the vault for a given `asset`
    function updateVault(address asset, address vault_) external;

    // --- ERC20 overrides ---
    /// @notice returns the 16 byte hook data of the given `user`.
    /// @dev    Stored in the 128 most significant bits of the user balance
    function hookDataOf(address user) external view returns (bytes16);

    /// @notice update the 16 byte hook data of the given `user`
    function setHookData(address user, bytes16 hookData) external;

    /// @notice Function to mint tokens
    function mint(address user, uint256 value) external;

    /// @notice Function to burn tokens
    function burn(address user, uint256 value) external;

    /// @notice Checks if the tokens can be transferred given the input values
    function checkTransferRestriction(address from, address to, uint256 value) external view returns (bool);

    /// @notice Performs an authorized transfer, with `sender` as the given sender.
    /// @dev    Requires allowance if `sender` != `from`
    function authTransferFrom(address sender, address from, address to, uint256 amount) external returns (bool);
}

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

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

import {IVaultManager} from "src/spoke/interfaces/IVaultManager.sol";

enum VaultKind {
    /// @dev Refers to AsyncVault
    Async,
    /// @dev not yet supported
    Sync,
    /// @dev Refers to SyncDepositVault
    SyncDepositAsyncRedeem
}

/// @notice Interface for the all vault contracts
/// @dev Must be implemented by all vaults
interface IVault {
    /// @notice Identifier of the Centrifuge pool
    function poolId() external view returns (PoolId);

    /// @notice Identifier of the share class of the Centrifuge pool
    function scId() external view returns (ShareClassId);

    /// @notice Returns the associated manager.
    function manager() external view returns (IVaultManager);

    /// @notice Checks whether the vault is partially (a)synchronous.
    ///
    /// @return vaultKind_ The kind of the vault
    function vaultKind() external view returns (VaultKind vaultKind_);
}

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

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

interface IRequestManager {
    error UnknownRequestCallbackType();

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

File 31 of 40 : IVaultFactory.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

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

import {IVault} from "src/spoke/interfaces/IVault.sol";
import {IShareToken} from "src/spoke/interfaces/IShareToken.sol";

interface IVaultFactory {
    error UnsupportedTokenId();

    /// @notice Deploys new vault for `poolId`, `scId` and `asset`.
    ///
    /// @param poolId Id of the pool. Id is one of the already supported pools.
    /// @param scId Id of the share class token. Id is one of the already supported share class tokens.
    /// @param asset Address of the underlying asset that is getting deposited inside the pool.
    /// @param asset Token id of the underlying asset that is getting deposited inside the pool. I.e. zero if asset
    /// corresponds to ERC20 or non-zero if asset corresponds to ERC6909.
    /// @param token Address of the share class token that is getting issues against the deposited asset.
    /// @param wards_ Address which can call methods behind authorized only.
    function newVault(
        PoolId poolId,
        ShareClassId scId,
        address asset,
        uint256 tokenId,
        IShareToken token,
        address[] calldata wards_
    ) external returns (IVault);
}

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

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

interface IERC7575 is IERC165 {
    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
    event Withdraw(
        address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares
    );

    /**
     * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
     *
     * - MUST be an ERC-20 token contract.
     * - MUST NOT revert.
     */
    function asset() external view returns (address assetTokenAddress);

    /**
     * @dev Returns the address of the share token
     *
     * - MUST be an ERC-20 token contract.
     * - MUST NOT revert.
     */
    function share() external view returns (address shareTokenAddress);

    /**
     * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToShares(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToAssets(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.
     *
     * - SHOULD include any compounding that occurs from yield.
     * - MUST be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT revert.
     */
    function totalAssets() external view returns (uint256 totalManagedAssets);

    /**
     * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
     * through a deposit call.
     *
     * - MUST return a limited value if receiver is subject to some deposit limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
     * - MUST NOT revert.
     */
    function maxDeposit(address receiver) external view returns (uint256 maxAssets);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
     * current on-chain conditions.
     *
     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
     *   in the same transaction.
     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.
     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewDeposit(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
     *
     * - MUST emit the Deposit event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   deposit execution, and are accounted for during deposit.
     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
     *   approving enough underlying tokens to the Vault contract, etc).
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function deposit(uint256 assets, address receiver) external returns (uint256 shares);

    /**
     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
     * - MUST return a limited value if receiver is subject to some mint limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
     * - MUST NOT revert.
     */
    function maxMint(address receiver) external view returns (uint256 maxShares);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
     * current on-chain conditions.
     *
     * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
     *   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
     *   same transaction.
     * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
     *   would be accepted, regardless if the user has enough tokens approved, etc.
     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by minting.
     */
    function previewMint(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
     *
     * - MUST emit the Deposit event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
     *   execution, and are accounted for during mint.
     * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
     *   approving enough underlying tokens to the Vault contract, etc).
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function mint(uint256 shares, address receiver) external returns (uint256 assets);

    /**
     * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
     * Vault, through a withdraw call.
     *
     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
     * - MUST NOT revert.
     */
    function maxWithdraw(address owner) external view returns (uint256 maxAssets);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
     * given current on-chain conditions.
     *
     * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
     *   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
     *   called
     *   in the same transaction.
     * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
     *   the withdrawal would be accepted, regardless if the user has enough shares, etc.
     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewWithdraw(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
     *
     * - MUST emit the Withdraw event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   withdraw execution, and are accounted for during withdraw.
     * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
     *   not having enough shares, etc).
     *
     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     * Those methods should be performed separately.
     */
    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);

    /**
     * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
     * through a redeem call.
     *
     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
     * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
     * - MUST NOT revert.
     */
    function maxRedeem(address owner) external view returns (uint256 maxShares);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
     * given current on-chain conditions.
     *
     * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
     *   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
     *   same transaction.
     * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
     *   redemption would be accepted, regardless if the user has enough shares, etc.
     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by redeeming.
     */
    function previewRedeem(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
     *
     * - MUST emit the Withdraw event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   redeem execution, and are accounted for during redeem.
     * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
     *   not having enough shares, etc).
     *
     * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     * Those methods should be performed separately.
     */
    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}

interface IERC7575Share is IERC165 {
    event VaultUpdate(address indexed asset, address vault);

    /**
     * @dev Returns the address of the Vault for the given asset.
     *
     * @param asset the ERC-20 token to deposit with into the Vault
     */
    function vault(address asset) external view returns (address);
}

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

interface IERC7540Operator {
    /**
     * @dev The event emitted when an operator is set.
     *
     * @param controller The address of the controller.
     * @param operator The address of the operator.
     * @param approved The approval status.
     */
    event OperatorSet(address indexed controller, address indexed operator, bool approved);

    /**
     * @dev Sets or removes an operator for the caller.
     *
     * @param operator The address of the operator.
     * @param approved The approval status.
     * @return Whether the call was executed successfully or not
     */
    function setOperator(address operator, bool approved) external returns (bool);

    /**
     * @dev Returns `true` if the `operator` is approved as an operator for an `controller`.
     *
     * @param controller The address of the controller.
     * @param operator The address of the operator.
     * @return status The approval status
     */
    function isOperator(address controller, address operator) external view returns (bool status);
}

interface IERC7540Deposit is IERC7540Operator {
    event DepositRequest(
        address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets
    );
    /**
     * @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.
     *
     * - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow.
     * - MUST revert if all of assets cannot be requested for deposit.
     * - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller,
     *    approval of ERC-20 tokens from owner to sender is NOT enough.
     *
     * @param assets the amount of deposit assets to transfer from owner
     * @param controller the controller of the request who will be able to operate the request
     * @param owner the source of the deposit assets
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.
     */

    function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId);

    /**
     * @dev Returns the amount of requested assets in Pending state.
     *
     * - MUST NOT include any assets in Claimable state for deposit or mint.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
     */
    function pendingDepositRequest(uint256 requestId, address controller)
        external
        view
        returns (uint256 pendingAssets);

    /**
     * @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint.
     *
     * - MUST NOT include any assets in Pending state.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
     */
    function claimableDepositRequest(uint256 requestId, address controller)
        external
        view
        returns (uint256 claimableAssets);

    /**
     * @dev Mints shares Vault shares to receiver by claiming the Request of the controller.
     *
     * - MUST emit the Deposit event.
     * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.
     */
    function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares);

    /**
     * @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller.
     *
     * - MUST emit the Deposit event.
     * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.
     */
    function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets);
}

interface IERC7540Redeem is IERC7540Operator {
    event RedeemRequest(
        address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 shares
    );

    /**
     * @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem.
     *
     * - MUST support a redeem Request flow where the control of shares is taken from sender directly
     *   where msg.sender has ERC-20 approval over the shares of owner.
     * - MUST revert if all of shares cannot be requested for redeem.
     *
     * @param shares the amount of shares to be redeemed to transfer from owner
     * @param controller the controller of the request who will be able to operate the request
     * @param owner the source of the shares to be redeemed
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault's share token.
     */
    function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId);

    /**
     * @dev Returns the amount of requested shares in Pending state.
     *
     * - MUST NOT include any shares in Claimable state for redeem or withdraw.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
     */
    function pendingRedeemRequest(uint256 requestId, address controller)
        external
        view
        returns (uint256 pendingShares);

    /**
     * @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw.
     *
     * - MUST NOT include any shares in Pending state for redeem or withdraw.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
     */
    function claimableRedeemRequest(uint256 requestId, address controller)
        external
        view
        returns (uint256 claimableShares);
}

interface IERC7887Deposit {
    event CancelDepositRequest(address indexed controller, uint256 indexed requestId, address sender);
    event CancelDepositClaim(
        address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 assets
    );

    /**
     * @dev Submits a Request for cancelling the pending deposit Request
     *
     * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,
     *    approval of ERC-20 tokens from controller to sender is NOT enough.
     * - MUST set pendingCancelDepositRequest to `true` for the returned requestId after request
     * - MUST increase claimableCancelDepositRequest for the returned requestId after fulfillment
     * - SHOULD be claimable using `claimCancelDepositRequest`
     * Note: while `pendingCancelDepositRequest` is `true`, `requestDeposit` cannot be called
     */
    function cancelDepositRequest(uint256 requestId, address controller) external;

    /**
     * @dev Returns whether the deposit Request is pending cancelation
     *
     * - MUST NOT show any variations depending on the caller.
     */
    function pendingCancelDepositRequest(uint256 requestId, address controller)
        external
        view
        returns (bool isPending);

    /**
     * @dev Returns the amount of assets that were canceled from a deposit Request, and can now be claimed.
     *
     * - MUST NOT show any variations depending on the caller.
     */
    function claimableCancelDepositRequest(uint256 requestId, address controller)
        external
        view
        returns (uint256 claimableAssets);

    /**
     * @dev Claims the canceled deposit assets, and removes the pending cancelation Request
     *
     * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,
     *    approval of ERC-20 tokens from controller to sender is NOT enough.
     * - MUST set pendingCancelDepositRequest to `false` for the returned requestId after request
     * - MUST set claimableCancelDepositRequest to 0 for the returned requestId after fulfillment
     */
    function claimCancelDepositRequest(uint256 requestId, address receiver, address controller)
        external
        returns (uint256 assets);
}

interface IERC7887Redeem {
    event CancelRedeemRequest(address indexed controller, uint256 indexed requestId, address sender);
    event CancelRedeemClaim(
        address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 shares
    );

    /**
     * @dev Submits a Request for cancelling the pending redeem Request
     *
     * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,
     *    approval of ERC-20 tokens from controller to sender is NOT enough.
     * - MUST set pendingCancelRedeemRequest to `true` for the returned requestId after request
     * - MUST increase claimableCancelRedeemRequest for the returned requestId after fulfillment
     * - SHOULD be claimable using `claimCancelRedeemRequest`
     * Note: while `pendingCancelRedeemRequest` is `true`, `requestRedeem` cannot be called
     */
    function cancelRedeemRequest(uint256 requestId, address controller) external;

    /**
     * @dev Returns whether the redeem Request is pending cancelation
     *
     * - MUST NOT show any variations depending on the caller.
     */
    function pendingCancelRedeemRequest(uint256 requestId, address controller) external view returns (bool isPending);

    /**
     * @dev Returns the amount of shares that were canceled from a redeem Request, and can now be claimed.
     *
     * - MUST NOT show any variations depending on the caller.
     */
    function claimableCancelRedeemRequest(uint256 requestId, address controller)
        external
        view
        returns (uint256 claimableShares);

    /**
     * @dev Claims the canceled redeem shares, and removes the pending cancelation Request
     *
     * - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,
     *    approval of ERC-20 tokens from controller to sender is NOT enough.
     * - MUST set pendingCancelRedeemRequest to `false` for the returned requestId after request
     * - MUST set claimableCancelRedeemRequest to 0 for the returned requestId after fulfillment
     */
    function claimCancelRedeemRequest(uint256 requestId, address receiver, address controller)
        external
        returns (uint256 shares);
}

interface IERC7741 {
    /**
     * @dev Grants or revokes permissions for `operator` to manage Requests on behalf of the
     *      `msg.sender`, using an [EIP-712](./eip-712.md) signature.
     */
    function authorizeOperator(
        address controller,
        address operator,
        bool approved,
        bytes32 nonce,
        uint256 deadline,
        bytes memory signature
    ) external returns (bool);

    /**
     * @dev Revokes the given `nonce` for `msg.sender` as the `owner`.
     */
    function invalidateNonce(bytes32 nonce) external;

    /**
     * @dev Returns whether the given `nonce` has been used for the `controller`.
     */
    function authorizations(address controller, bytes32 nonce) external view returns (bool used);

    /**
     * @dev Returns the `DOMAIN_SEPARATOR` as defined according to EIP-712. The `DOMAIN_SEPARATOR
     *      should be unique to the contract and chain to prevent replay attacks from other domains,
     *      and satisfy the requirements of EIP-712, but is otherwise unconstrained.
     */
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

interface IERC7714 {
    /**
     * @dev Returns `true` if the `user` is permissioned to interact with the contract.
     */
    function isPermissioned(address controller) external view returns (bool);
}

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

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

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

import {ISpoke} from "src/spoke/interfaces/ISpoke.sol";
import {IVaultManager} from "src/spoke/interfaces/IVaultManager.sol";
import {IRequestManager} from "src/spoke/interfaces/IRequestManager.sol";

import {IBaseVault} from "src/vaults/interfaces/IBaseVault.sol";

interface IBaseRequestManager is IVaultManager, IRequestManager {
    event File(bytes32 indexed what, address data);

    error FileUnrecognizedParam();

    /// @notice Updates contract parameters of type address.
    /// @param what The bytes32 representation of 'gateway' or 'spoke'.
    /// @param data The new contract address.
    function file(bytes32 what, address data) external;

    /// @notice Converts the assets value to share decimals.
    function convertToShares(IBaseVault vault, uint256 _assets) external view returns (uint256 shares);

    /// @notice Converts the shares value to assets decimals.
    function convertToAssets(IBaseVault vault, uint256 _shares) external view returns (uint256 assets);

    /// @notice Returns the timestamp of the last share price update for a vaultAddr.
    function priceLastUpdated(IBaseVault vault) external view returns (uint64 lastUpdated);

    /// @notice Returns the Spoke contract address.
    function spoke() external view returns (ISpoke spoke);

    /// @notice The global escrow used for funds that are not yet free to be used for a specific pool
    function globalEscrow() external view returns (IEscrow escrow);

    /// @notice Escrow per pool. Funds are associated to a specific pool
    function poolEscrow(PoolId poolId) external view returns (IPoolEscrow);
}

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

File 36 of 40 : IERC7751.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// [ERC-7751](https://eips.ethereum.org/EIPS/eip-7751): Wrapping of bubbled up reverts
/// Handling bubbled up reverts using custom errors with additional context.
interface IERC7751 {
    error WrappedError(address target, bytes4 selector, bytes reason, bytes details);
}

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

/// @title  Escrow for holding assets
interface IEscrow {
    // --- Events ---
    /// @notice Emitted when an authTransferTo is made
    /// @dev Needed as allowances increase attack surface
    event AuthTransferTo(address indexed asset, uint256 indexed tokenId, address receiver, uint256 value);

    /// @notice Emitted when the escrow has insufficient balance for an action - virtual or actual balance
    error InsufficientBalance(address asset, uint256 tokenId, uint256 value, uint256 balance);

    /// @notice
    function authTransferTo(address asset, uint256 tokenId, address receiver, uint256 value) external;
}

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

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

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

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

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

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

    error UnknownMessageType();

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

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

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

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

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

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

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

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

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

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

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

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

    struct ScheduleUpgrade {
        bytes32 target;
    }

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

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

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

    struct CancelUpgrade {
        bytes32 target;
    }

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

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

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

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

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

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

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

    struct RegisterAsset {
        uint128 assetId;
        uint8 decimals;
    }

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

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

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

    struct NotifyPool {
        uint64 poolId;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

import {IVault} from "src/spoke/interfaces/IVault.sol";

interface IVaultManager {
    error VaultAlreadyExists();
    error VaultDoesNotExist();

    /// @notice Emitted when a new vault is added
    /// @param poolId The pool ID
    /// @param scId The share class ID
    /// @param assetId The asset ID
    /// @param vault The address of the vault being added
    event AddVault(PoolId indexed poolId, ShareClassId indexed scId, AssetId indexed assetId, IVault vault);

    /// @notice Emitted when a vault is removed
    /// @param poolId The pool ID
    /// @param scId The share class ID
    /// @param assetId The asset ID
    /// @param vault The address of the vault being removed
    event RemoveVault(PoolId indexed poolId, ShareClassId indexed scId, AssetId indexed assetId, IVault vault);

    /// @notice Adds new vault for `poolId`, `scId` and `assetId`.
    function addVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVault vault, address asset, uint256 tokenId)
        external;

    /// @notice Removes `vault` from `who`'s authorized callers
    function removeVault(
        PoolId poolId,
        ShareClassId scId,
        AssetId assetId,
        IVault vault,
        address asset,
        uint256 tokenId
    ) external;

    /// @notice Returns the address of the vault for a given pool, share class and asset
    function vaultByAssetId(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (IVault vault);
}

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

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"deployer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ExceedsMaxDeposit","type":"error"},{"inputs":[],"name":"ExceedsMaxMint","type":"error"},{"inputs":[],"name":"FileUnrecognizedParam","type":"error"},{"inputs":[],"name":"MulDiv_Overflow","type":"error"},{"inputs":[],"name":"NoCode","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"SafeTransferEthFailed","type":"error"},{"inputs":[],"name":"SecondaryManagerDoesNotExist","type":"error"},{"inputs":[],"name":"ShareTokenDoesNotExist","type":"error"},{"inputs":[],"name":"SliceOutOfBounds","type":"error"},{"inputs":[],"name":"Uint128_Overflow","type":"error"},{"inputs":[],"name":"UnknownMessageType","type":"error"},{"inputs":[],"name":"UnknownUpdateContractType","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"bytes","name":"reason","type":"bytes"},{"internalType":"bytes","name":"details","type":"bytes"}],"name":"WrappedError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Deny","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"what","type":"bytes32"},{"indexed":false,"internalType":"address","name":"data","type":"address"}],"name":"File","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":"scId","type":"bytes16"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"maxReserve","type":"uint128"}],"name":"SetMaxReserve","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"indexed":false,"internalType":"address","name":"valuation","type":"address"}],"name":"SetValuation","type":"event"},{"inputs":[],"name":"balanceSheet","outputs":[{"internalType":"contract IBalanceSheet","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"what","type":"bytes32"},{"internalType":"address","name":"data","type":"address"}],"name":"file","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"maxReserve","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"}],"name":"pricePoolPerShare","outputs":[{"internalType":"D18","name":"price","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverTokens","outputs":[],"stateMutability":"nonpayable","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":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint128","name":"maxReserve_","type":"uint128"}],"name":"setMaxReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"address","name":"valuation_","type":"address"}],"name":"setValuation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"spoke","outputs":[{"internalType":"contract ISpoke","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"update","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"}],"name":"valuation","outputs":[{"internalType":"contract ISyncDepositValuation","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

6080604052348015600e575f5ffd5b50604051612b90380380612b90833981016040819052602b916074565b6001600160a01b0381165f8181526020819052604080822060019055518392917fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a6091a25050609f565b5f602082840312156083575f5ffd5b81516001600160a01b03811681146098575f5ffd5b9392505050565b612ae4806100ac5f395ff3fe608060405234801561000f575f5ffd5b5060043610610110575f3560e01c806306932fcb1461011457806322285cf61461012957806323c5b7ed1461015257806332de5d3c14610173578063340ab91d146101a65780633a4d2cd1146101b95780633e5541f1146101cc57806347bfbcc6146101df57806350603df3146101f25780635f3e849f146102055780636179ab011461021857806365fae35e1461022b578063760168701461023e5780637cd878eb14610251578063947b330a146102645780639c52a7f114610277578063bd80f7c41461028a578063bf353dbb146102d9578063c6f1649f146102f8578063d4e8be831461030b578063d72e42851461031e578063f2e586db14610331575b5f5ffd5b610127610122366004612335565b610344565b005b60025461013c906001600160a01b031681565b604051610149919061237d565b60405180910390f35b610165610160366004612391565b6103f9565b604051908152602001610149565b61013c6101813660046123cf565b600360209081525f92835260408084209091529082529020546001600160a01b031681565b6101276101b436600461244a565b610410565b6101656101c7366004612500565b610686565b6101656101da366004612550565b610710565b60015461013c906001600160a01b031681565b610165610200366004612550565b610a48565b610127610213366004612391565b610a54565b61012761022636600461258e565b610ac2565b6101276102393660046125f2565b610b96565b61016561024c36600461260d565b610c09565b61016561025f366004612391565b610d62565b610127610272366004612639565b610d6d565b6101276102853660046125f2565b610e31565b6102cc61029836600461267e565b600460209081525f94855260408086208252938552838520815291845282842090915282529020546001600160801b031681565b60405161014991906126bc565b6101656102e73660046125f2565b5f6020819052908152604090205481565b610165610306366004612500565b610ea3565b6101276103193660046126d0565b610f20565b6102cc61032c3660046123cf565b611009565b61016561033f36600461260d565b61114c565b335f908152602081905260409020546001146103735760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0383165f8181526003602090815260408083206001600160801b0319871680855292529182902080546001600160a01b0319166001600160a01b03861617905590519091907ff4930db4239d7c3f044b38dbe35777d82b713760fcaf0067537eb8d0d0446b2e906103ec90859061237d565b60405180910390a3505050565b5f610406848360016112b3565b90505b9392505050565b335f9081526020819052604090205460011461043f5760405163ea8e4eb560e01b815260040160405180910390fd5b5f610449826115c6565b600481111561045a5761045a6126f3565b90505f1960ff821601610525575f610471836115e5565b60015460405163602ff8a960e11b81529192505f916001600160a01b039091169063c05ff152906104a89089908990600401612707565b602060405180830381865afa1580156104c3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104e7919061272a565b6001600160a01b03160361050e57604051630344039160e61b815260040160405180910390fd5b61051f8585610122845f015161164c565b50610680565b60011960ff821601610667575f61053b836116ab565b60015460405163602ff8a960e11b81529192505f916001600160a01b039091169063c05ff152906105729089908990600401612707565b602060405180830381865afa15801561058d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105b1919061272a565b6001600160a01b0316036105d857604051630344039160e61b815260040160405180910390fd5b600154815160405163cee8983d60e01b81525f9283926001600160a01b039091169163cee8983d9161060c916004016126bc565b6040805180830381865afa158015610626573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061064a9190612745565b9150915061065f878784848760200151610ac2565b505050610680565b604051638f0997cd60e01b815260040160405180910390fd5b50505050565b335f908152602081905260408120546001146106b55760405163ea8e4eb560e01b815260040160405180910390fd5b836106c0868461114c565b10156106df576040516352f7657b60e01b815260040160405180910390fd5b6106ea8583866103f9565b9050610708856106f986611738565b8561070385611738565b611765565b949350505050565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff1539061074490879060040161237d565b608060405180830381865afa15801561075f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107839190612785565b90505f610849856001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e991906127fe565b866001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610825573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061032c9190612819565b90505f60015f9054906101000a90046001600160a01b03166001600160a01b031663fd6906ed876001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ab573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108cf91906127fe565b886001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561090b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061092f9190612819565b86516040516001600160e01b031960e086901b16815261095793929190600190600401612834565b602060405180830381865afa158015610972573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610996919061286f565b90506109aa826001600160801b0316611aba565b610a3157610a2c866001600160a01b031663a8d5fd656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109ed573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a11919061272a565b84602001518560400151610a2489611738565b85875f611ac7565b610a33565b5f5b6001600160801b031693505050505b92915050565b5f61040983835f6112b3565b335f90815260208190526040902054600114610a835760405163ea8e4eb560e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601610ab757610ab28282611b9f565b505050565b610ab2838383611c29565b335f90815260208190526040902054600114610af15760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0385165f8181526004602090815260408083206001600160801b03198981168086529184528285206001600160a01b038a1680875290855283862089875285529483902080546001600160801b03891692168217905582519485529284018790529083019190915291907ffece2f0a4e9094e6d87c0f7c8d9a7b92988c81690bcdd1be82e35ef3d7338ab09060600160405180910390a35050505050565b335f90815260208190526040902054600114610bc55760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff15390610c3d90879060040161237d565b608060405180830381865afa158015610c58573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c7c9190612785565b9050610d51846001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cbd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ce191906127fe565b856001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d1d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d419190612819565b8360200151846040015188611d76565b6001600160801b0316949350505050565b5f6104068483610710565b335f90815260208190526040902054600114610d9c5760405163ea8e4eb560e01b815260040160405180910390fd5b825f03610db357610dae848383610a54565b610680565b6040516304ade6db60e11b81526001600160a01b038381166004830152602482018590526044820183905285169063095bcdb6906064016020604051808303815f875af1158015610e06573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e2a919061288a565b5050505050565b335f90815260208190526040902054600114610e605760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b335f90815260208190526040812054600114610ed25760405163ea8e4eb560e01b815260040160405180910390fd5b83610edd8684610c09565b1015610efc5760405163e4bac01b60e01b815260040160405180910390fd5b610f07858386610d62565b905061070885610f1683611738565b8561070388611738565b335f90815260208190526040902054600114610f4f5760405163ea8e4eb560e01b815260040160405180910390fd5b816473706f6b6560d81b03610f7e57600180546001600160a01b0319166001600160a01b038316179055610fcd565b816b18985b185b98d954da19595d60a21b03610fb457600280546001600160a01b0319166001600160a01b038316179055610fcd565b604051633db0d5b960e01b815260040160405180910390fd5b817f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba82604051610ffd919061237d565b60405180910390a25050565b6001600160401b0382165f9081526003602090815260408083206001600160801b0319851684529091528120546001600160a01b0316806110d55760018054604051635274887b60e01b81526001600160401b03871660048201526001600160801b03198616602482015260448101929092526001600160a01b031690635274887b90606401602060405180830381865afa1580156110aa573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110ce919061286f565b9150611145565b60405163d72e428560e01b81526001600160a01b0382169063d72e4285906111039087908790600401612707565b602060405180830381865afa15801561111e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611142919061286f565b91505b5092915050565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff1539061118090879060040161237d565b608060405180830381865afa15801561119b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111bf9190612785565b90505f611295856001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611201573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061122591906127fe565b866001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611261573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112859190612819565b8460200151856040015189611d76565b90506112aa85826001600160801b0316610710565b95945050505050565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff153906112e790889060040161237d565b608060405180830381865afa158015611302573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113269190612785565b90505f6113c8866001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611368573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061138c91906127fe565b876001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610825573d5f5f3e3d5ffd5b90505f60015f9054906101000a90046001600160a01b03166001600160a01b031663fd6906ed886001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561142a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061144e91906127fe565b896001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561148a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114ae9190612819565b86516040516001600160e01b031960e086901b1681526114d693929190600190600401612834565b602060405180830381865afa1580156114f1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611515919061286f565b9050611529816001600160801b0316611aba565b6115b0576115ab876001600160a01b031663a8d5fd656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561156c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611590919061272a565b61159988611738565b8560200151866040015186868b611f00565b6115b2565b5f5b6001600160801b0316979650505050505050565b5f6115d18282611fba565b60ff166004811115610a4257610a426126f3565b60408051602081019091525f815260016115fe836115c6565b600481111561160f5761160f6126f3565b1461162d576040516304c735eb60e11b815260040160405180910390fd5b604080516020810190915280611644846001611ff0565b905292915050565b5f6001600160601b038216156116a45760405162461bcd60e51b8152602060048201526018602482015277496e7075742073686f756c6420626520323020627974657360401b60448201526064015b60405180910390fd5b5060601c90565b604080518082019091525f808252602082015260026116c9836115c6565b60048111156116da576116da6126f3565b146116f8576040516304c735eb60e11b815260040160405180910390fd5b604080518082019091528061170e846001612026565b6001600160801b03168152602001611727846011612026565b6001600160801b0316905292915050565b5f6001600160801b038211156117615760405163e999826d60e01b815260040160405180910390fd5b5090565b5f846001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117a2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117c691906127fe565b90505f856001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611805573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118299190612819565b600154604051632a7ff15360e01b81529192505f916001600160a01b0390911690632a7ff1539061185e908a9060040161237d565b608060405180830381865afa158015611879573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061189d9190612785565b6002546020820151604080840151905163fec8f5eb60e01b81526001600160401b03881660048201526001600160801b0319871660248201526001600160a01b03928316604482015260648101919091526001600160801b0388166084820152929350169063fec8f5eb9060a4015f604051808303815f87803b158015611922575f5ffd5b505af1158015611934573d5f5f3e3d5ffd5b50506002546001600160a01b03169150635c76ada4905084846119578282611009565b6040516001600160e01b031960e086901b1681526001600160401b0390931660048401526001600160801b031990911660248301526001600160801b031660448201526064015f604051808303815f87803b1580156119b4575f5ffd5b505af11580156119c6573d5f5f3e3d5ffd5b5050600254604051630365020f60e41b81526001600160401b03871660048201526001600160801b0319861660248201526001600160a01b0389811660448301526001600160801b038b166064830152909116925063365020f091506084015f604051808303815f87803b158015611a3c575f5ffd5b505af1158015611a4e573d5f5f3e3d5ffd5b5050600254604051639f8ddc4f60e01b81526001600160a01b039091169250639f8ddc4f9150611a849086908690600401612707565b5f604051808303815f87803b158015611a9b575f5ffd5b505af1158015611aad573d5f5f3e3d5ffd5b5050505050505050505050565b6001600160801b03161590565b5f6001600160801b0385161580611aeb5750611aeb846001600160801b0316611aba565b15611af757505f611b94565b5f611b02888861205c565b90505f896001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b41573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b6591906128a3565b9050611b8f611b81886001600160801b031684848a8a8a61212f565b6001600160801b0316611738565b925050505b979650505050505050565b604080515f808252602082019092526001600160a01b038416908390604051611bc891906128c3565b5f6040518083038185875af1925050503d805f8114611c02576040519150601f19603f3d011682016040523d82523d5f602084013e611c07565b606091505b5050905080610ab257604051630d2fa21160e31b815260040160405180910390fd5b5f836001600160a01b03163b11611c5357604051633c11a9c560e21b815260040160405180910390fd5b6040516001600160a01b038381166024830152604482018390525f91829186169060640160408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b17905251611cac91906128c3565b5f604051808303815f865af19150503d805f8114611ce5576040519150601f19603f3d011682016040523d82523d5f602084013e611cea565b606091505b5091509150818015611d14575080511580611d14575080806020019051810190611d14919061288a565b6040805160048152602481019091526020810180516001600160e01b031663fb7f507960e01b179052869163a9059cbb60e01b918491611d6b576040516390bfb86560e01b815260040161169b9493929190612907565b505050505050505050565b60015460405163fb1afbd760e01b81525f916001600160a01b03169063fb1afbd790611da690859060040161237d565b602060405180830381865afa158015611dc1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611de5919061288a565b611df057505f6112aa565b60025460405163188cfd6d60e21b81526001600160401b03881660048201526001600160801b0319871660248201526001600160a01b038681166044830152606482018690525f921690636233f5b490608401602060405180830381865afa158015611e5e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e82919061286f565b6001600160401b0388165f9081526004602090815260408083206001600160801b03198b16845282528083206001600160a01b038a16845282528083208884529091529020549091506001600160801b03908116908216811015611ee8575f9250611ef5565b611ef28282612960565b92505b505095945050505050565b5f6001600160801b0387161580611f245750611f24846001600160801b0316611aba565b15611f3057505f611b94565b5f611f3b878761205c565b90505f896001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f7a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f9e91906128a3565b9050611b8f611b818a6001600160801b031683858a8a8a61212f565b5f611fc682600161297f565b83511015611fe757604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f611ffc82602061297f565b8351101561201d57604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f61203282601061297f565b8351101561205357604051633b99b53d60e01b815260040160405180910390fd5b50016010015190565b5f81156120cf57604051631fa3f33160e11b8152600481018390526001600160a01b03841690633f47e66290602401602060405180830381865afa1580156120a6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120ca91906128a3565b610409565b826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561210b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061040991906128a3565b5f611b948787878787875f6001600160801b03831661218e5760405162461bcd60e51b815260206004820152601b60248201527a50726963696e674c69622f6469766973696f6e2d62792d7a65726f60281b604482015260640161169b565b611b946121d96001600160801b038616896121aa89600a612a75565b6121b49190612a83565b6001600160801b0387166121c98b600a612a75565b6121d39190612a83565b866121de565b611738565b5f5f6121eb868686612237565b90506001836002811115612201576122016126f3565b14801561221d57505f848061221857612218612a9a565b868809115b156112aa5761222d60018261297f565b9695505050505050565b5f80805f19858709858702925082811083820303915050805f0361226e5783828161226457612264612a9a565b0492505050610409565b80841161228e57604051637ee8242b60e01b815260040160405180910390fd5b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b6001600160401b0381168114612309575f5ffd5b50565b6001600160801b031981168114612309575f5ffd5b6001600160a01b0381168114612309575f5ffd5b5f5f5f60608486031215612347575f5ffd5b8335612352816122f5565b925060208401356123628161230c565b9150604084013561237281612321565b809150509250925092565b6001600160a01b0391909116815260200190565b5f5f5f606084860312156123a3575f5ffd5b83356123ae81612321565b925060208401356123be81612321565b929592945050506040919091013590565b5f5f604083850312156123e0575f5ffd5b82356123eb816122f5565b915060208301356123fb8161230c565b809150509250929050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b038111828210171561244257612442612406565b604052919050565b5f5f5f6060848603121561245c575f5ffd5b8335612467816122f5565b925060208401356124778161230c565b915060408401356001600160401b03811115612491575f5ffd5b8401601f810186136124a1575f5ffd5b80356001600160401b038111156124ba576124ba612406565b6124cd601f8201601f191660200161241a565b8181528760208385010111156124e1575f5ffd5b816020840160208301375f602083830101528093505050509250925092565b5f5f5f5f60808587031215612513575f5ffd5b843561251e81612321565b935060208501359250604085013561253581612321565b9150606085013561254581612321565b939692955090935050565b5f5f60408385031215612561575f5ffd5b823561256c81612321565b946020939093013593505050565b6001600160801b0381168114612309575f5ffd5b5f5f5f5f5f60a086880312156125a2575f5ffd5b85356125ad816122f5565b945060208601356125bd8161230c565b935060408601356125cd81612321565b92506060860135915060808601356125e48161257a565b809150509295509295909350565b5f60208284031215612602575f5ffd5b813561040981612321565b5f5f6040838503121561261e575f5ffd5b823561262981612321565b915060208301356123fb81612321565b5f5f5f5f6080858703121561264c575f5ffd5b843561265781612321565b935060208501359250604085013561266e81612321565b9396929550929360600135925050565b5f5f5f5f60808587031215612691575f5ffd5b843561269c816122f5565b935060208501356126ac8161230c565b9250604085013561266e81612321565b6001600160801b0391909116815260200190565b5f5f604083850312156126e1575f5ffd5b8235915060208301356123fb81612321565b634e487b7160e01b5f52602160045260245ffd5b6001600160401b039290921682526001600160801b031916602082015260400190565b5f6020828403121561273a575f5ffd5b815161040981612321565b5f5f60408385031215612756575f5ffd5b825161276181612321565b6020939093015192949293505050565b80518015158114612780575f5ffd5b919050565b5f6080828403128015612796575f5ffd5b50604051608081016001600160401b03811182821017156127b9576127b9612406565b60405282516127c78161257a565b815260208301516127d781612321565b6020820152604083810151908201526127f260608401612771565b60608201529392505050565b5f6020828403121561280e575f5ffd5b8151610409816122f5565b5f60208284031215612829575f5ffd5b81516104098161230c565b6001600160401b039490941684526001600160801b03199290921660208401526001600160801b031660408301521515606082015260800190565b5f6020828403121561287f575f5ffd5b81516104098161257a565b5f6020828403121561289a575f5ffd5b61040982612771565b5f602082840312156128b3575f5ffd5b815160ff81168114610409575f5ffd5b5f82518060208501845e5f920191825250919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03851681526001600160e01b0319841660208201526080604082018190525f9061293a908301856128d9565b8281036060840152611b9481856128d9565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b038281168282160390811115610a4257610a4261294c565b80820180821115610a4257610a4261294c565b6001815b60018411156129cd578085048111156129b1576129b161294c565b60018416156129bf57908102905b60019390931c928002612996565b935093915050565b5f826129e357506001610a42565b816129ef57505f610a42565b8160018114612a055760028114612a0f57612a2b565b6001915050610a42565b60ff841115612a2057612a2061294c565b50506001821b610a42565b5060208310610133831016604e8410600b8410161715612a4e575081810a610a42565b612a5a5f198484612992565b805f1904821115612a6d57612a6d61294c565b029392505050565b5f61040960ff8416836129d5565b8082028115828204841417610a4257610a4261294c565b634e487b7160e01b5f52601260045260245ffdfea26469706673582212206f8216cece949aacb9ec22ee209e09adabf93438543dca216aaebe3122dbf7ca64736f6c634300081c00330000000000000000000000005f3f8ea3b54bff7795de7754866e0eac52e0881d

Deployed Bytecode

0x608060405234801561000f575f5ffd5b5060043610610110575f3560e01c806306932fcb1461011457806322285cf61461012957806323c5b7ed1461015257806332de5d3c14610173578063340ab91d146101a65780633a4d2cd1146101b95780633e5541f1146101cc57806347bfbcc6146101df57806350603df3146101f25780635f3e849f146102055780636179ab011461021857806365fae35e1461022b578063760168701461023e5780637cd878eb14610251578063947b330a146102645780639c52a7f114610277578063bd80f7c41461028a578063bf353dbb146102d9578063c6f1649f146102f8578063d4e8be831461030b578063d72e42851461031e578063f2e586db14610331575b5f5ffd5b610127610122366004612335565b610344565b005b60025461013c906001600160a01b031681565b604051610149919061237d565b60405180910390f35b610165610160366004612391565b6103f9565b604051908152602001610149565b61013c6101813660046123cf565b600360209081525f92835260408084209091529082529020546001600160a01b031681565b6101276101b436600461244a565b610410565b6101656101c7366004612500565b610686565b6101656101da366004612550565b610710565b60015461013c906001600160a01b031681565b610165610200366004612550565b610a48565b610127610213366004612391565b610a54565b61012761022636600461258e565b610ac2565b6101276102393660046125f2565b610b96565b61016561024c36600461260d565b610c09565b61016561025f366004612391565b610d62565b610127610272366004612639565b610d6d565b6101276102853660046125f2565b610e31565b6102cc61029836600461267e565b600460209081525f94855260408086208252938552838520815291845282842090915282529020546001600160801b031681565b60405161014991906126bc565b6101656102e73660046125f2565b5f6020819052908152604090205481565b610165610306366004612500565b610ea3565b6101276103193660046126d0565b610f20565b6102cc61032c3660046123cf565b611009565b61016561033f36600461260d565b61114c565b335f908152602081905260409020546001146103735760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0383165f8181526003602090815260408083206001600160801b0319871680855292529182902080546001600160a01b0319166001600160a01b03861617905590519091907ff4930db4239d7c3f044b38dbe35777d82b713760fcaf0067537eb8d0d0446b2e906103ec90859061237d565b60405180910390a3505050565b5f610406848360016112b3565b90505b9392505050565b335f9081526020819052604090205460011461043f5760405163ea8e4eb560e01b815260040160405180910390fd5b5f610449826115c6565b600481111561045a5761045a6126f3565b90505f1960ff821601610525575f610471836115e5565b60015460405163602ff8a960e11b81529192505f916001600160a01b039091169063c05ff152906104a89089908990600401612707565b602060405180830381865afa1580156104c3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104e7919061272a565b6001600160a01b03160361050e57604051630344039160e61b815260040160405180910390fd5b61051f8585610122845f015161164c565b50610680565b60011960ff821601610667575f61053b836116ab565b60015460405163602ff8a960e11b81529192505f916001600160a01b039091169063c05ff152906105729089908990600401612707565b602060405180830381865afa15801561058d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105b1919061272a565b6001600160a01b0316036105d857604051630344039160e61b815260040160405180910390fd5b600154815160405163cee8983d60e01b81525f9283926001600160a01b039091169163cee8983d9161060c916004016126bc565b6040805180830381865afa158015610626573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061064a9190612745565b9150915061065f878784848760200151610ac2565b505050610680565b604051638f0997cd60e01b815260040160405180910390fd5b50505050565b335f908152602081905260408120546001146106b55760405163ea8e4eb560e01b815260040160405180910390fd5b836106c0868461114c565b10156106df576040516352f7657b60e01b815260040160405180910390fd5b6106ea8583866103f9565b9050610708856106f986611738565b8561070385611738565b611765565b949350505050565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff1539061074490879060040161237d565b608060405180830381865afa15801561075f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107839190612785565b90505f610849856001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e991906127fe565b866001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610825573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061032c9190612819565b90505f60015f9054906101000a90046001600160a01b03166001600160a01b031663fd6906ed876001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ab573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108cf91906127fe565b886001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561090b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061092f9190612819565b86516040516001600160e01b031960e086901b16815261095793929190600190600401612834565b602060405180830381865afa158015610972573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610996919061286f565b90506109aa826001600160801b0316611aba565b610a3157610a2c866001600160a01b031663a8d5fd656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109ed573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a11919061272a565b84602001518560400151610a2489611738565b85875f611ac7565b610a33565b5f5b6001600160801b031693505050505b92915050565b5f61040983835f6112b3565b335f90815260208190526040902054600114610a835760405163ea8e4eb560e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601610ab757610ab28282611b9f565b505050565b610ab2838383611c29565b335f90815260208190526040902054600114610af15760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0385165f8181526004602090815260408083206001600160801b03198981168086529184528285206001600160a01b038a1680875290855283862089875285529483902080546001600160801b03891692168217905582519485529284018790529083019190915291907ffece2f0a4e9094e6d87c0f7c8d9a7b92988c81690bcdd1be82e35ef3d7338ab09060600160405180910390a35050505050565b335f90815260208190526040902054600114610bc55760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff15390610c3d90879060040161237d565b608060405180830381865afa158015610c58573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c7c9190612785565b9050610d51846001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cbd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ce191906127fe565b856001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d1d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d419190612819565b8360200151846040015188611d76565b6001600160801b0316949350505050565b5f6104068483610710565b335f90815260208190526040902054600114610d9c5760405163ea8e4eb560e01b815260040160405180910390fd5b825f03610db357610dae848383610a54565b610680565b6040516304ade6db60e11b81526001600160a01b038381166004830152602482018590526044820183905285169063095bcdb6906064016020604051808303815f875af1158015610e06573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e2a919061288a565b5050505050565b335f90815260208190526040902054600114610e605760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b335f90815260208190526040812054600114610ed25760405163ea8e4eb560e01b815260040160405180910390fd5b83610edd8684610c09565b1015610efc5760405163e4bac01b60e01b815260040160405180910390fd5b610f07858386610d62565b905061070885610f1683611738565b8561070388611738565b335f90815260208190526040902054600114610f4f5760405163ea8e4eb560e01b815260040160405180910390fd5b816473706f6b6560d81b03610f7e57600180546001600160a01b0319166001600160a01b038316179055610fcd565b816b18985b185b98d954da19595d60a21b03610fb457600280546001600160a01b0319166001600160a01b038316179055610fcd565b604051633db0d5b960e01b815260040160405180910390fd5b817f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba82604051610ffd919061237d565b60405180910390a25050565b6001600160401b0382165f9081526003602090815260408083206001600160801b0319851684529091528120546001600160a01b0316806110d55760018054604051635274887b60e01b81526001600160401b03871660048201526001600160801b03198616602482015260448101929092526001600160a01b031690635274887b90606401602060405180830381865afa1580156110aa573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110ce919061286f565b9150611145565b60405163d72e428560e01b81526001600160a01b0382169063d72e4285906111039087908790600401612707565b602060405180830381865afa15801561111e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611142919061286f565b91505b5092915050565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff1539061118090879060040161237d565b608060405180830381865afa15801561119b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111bf9190612785565b90505f611295856001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611201573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061122591906127fe565b866001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611261573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112859190612819565b8460200151856040015189611d76565b90506112aa85826001600160801b0316610710565b95945050505050565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff153906112e790889060040161237d565b608060405180830381865afa158015611302573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113269190612785565b90505f6113c8866001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611368573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061138c91906127fe565b876001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610825573d5f5f3e3d5ffd5b90505f60015f9054906101000a90046001600160a01b03166001600160a01b031663fd6906ed886001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561142a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061144e91906127fe565b896001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561148a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114ae9190612819565b86516040516001600160e01b031960e086901b1681526114d693929190600190600401612834565b602060405180830381865afa1580156114f1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611515919061286f565b9050611529816001600160801b0316611aba565b6115b0576115ab876001600160a01b031663a8d5fd656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561156c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611590919061272a565b61159988611738565b8560200151866040015186868b611f00565b6115b2565b5f5b6001600160801b0316979650505050505050565b5f6115d18282611fba565b60ff166004811115610a4257610a426126f3565b60408051602081019091525f815260016115fe836115c6565b600481111561160f5761160f6126f3565b1461162d576040516304c735eb60e11b815260040160405180910390fd5b604080516020810190915280611644846001611ff0565b905292915050565b5f6001600160601b038216156116a45760405162461bcd60e51b8152602060048201526018602482015277496e7075742073686f756c6420626520323020627974657360401b60448201526064015b60405180910390fd5b5060601c90565b604080518082019091525f808252602082015260026116c9836115c6565b60048111156116da576116da6126f3565b146116f8576040516304c735eb60e11b815260040160405180910390fd5b604080518082019091528061170e846001612026565b6001600160801b03168152602001611727846011612026565b6001600160801b0316905292915050565b5f6001600160801b038211156117615760405163e999826d60e01b815260040160405180910390fd5b5090565b5f846001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117a2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117c691906127fe565b90505f856001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611805573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118299190612819565b600154604051632a7ff15360e01b81529192505f916001600160a01b0390911690632a7ff1539061185e908a9060040161237d565b608060405180830381865afa158015611879573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061189d9190612785565b6002546020820151604080840151905163fec8f5eb60e01b81526001600160401b03881660048201526001600160801b0319871660248201526001600160a01b03928316604482015260648101919091526001600160801b0388166084820152929350169063fec8f5eb9060a4015f604051808303815f87803b158015611922575f5ffd5b505af1158015611934573d5f5f3e3d5ffd5b50506002546001600160a01b03169150635c76ada4905084846119578282611009565b6040516001600160e01b031960e086901b1681526001600160401b0390931660048401526001600160801b031990911660248301526001600160801b031660448201526064015f604051808303815f87803b1580156119b4575f5ffd5b505af11580156119c6573d5f5f3e3d5ffd5b5050600254604051630365020f60e41b81526001600160401b03871660048201526001600160801b0319861660248201526001600160a01b0389811660448301526001600160801b038b166064830152909116925063365020f091506084015f604051808303815f87803b158015611a3c575f5ffd5b505af1158015611a4e573d5f5f3e3d5ffd5b5050600254604051639f8ddc4f60e01b81526001600160a01b039091169250639f8ddc4f9150611a849086908690600401612707565b5f604051808303815f87803b158015611a9b575f5ffd5b505af1158015611aad573d5f5f3e3d5ffd5b5050505050505050505050565b6001600160801b03161590565b5f6001600160801b0385161580611aeb5750611aeb846001600160801b0316611aba565b15611af757505f611b94565b5f611b02888861205c565b90505f896001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b41573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b6591906128a3565b9050611b8f611b81886001600160801b031684848a8a8a61212f565b6001600160801b0316611738565b925050505b979650505050505050565b604080515f808252602082019092526001600160a01b038416908390604051611bc891906128c3565b5f6040518083038185875af1925050503d805f8114611c02576040519150601f19603f3d011682016040523d82523d5f602084013e611c07565b606091505b5050905080610ab257604051630d2fa21160e31b815260040160405180910390fd5b5f836001600160a01b03163b11611c5357604051633c11a9c560e21b815260040160405180910390fd5b6040516001600160a01b038381166024830152604482018390525f91829186169060640160408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b17905251611cac91906128c3565b5f604051808303815f865af19150503d805f8114611ce5576040519150601f19603f3d011682016040523d82523d5f602084013e611cea565b606091505b5091509150818015611d14575080511580611d14575080806020019051810190611d14919061288a565b6040805160048152602481019091526020810180516001600160e01b031663fb7f507960e01b179052869163a9059cbb60e01b918491611d6b576040516390bfb86560e01b815260040161169b9493929190612907565b505050505050505050565b60015460405163fb1afbd760e01b81525f916001600160a01b03169063fb1afbd790611da690859060040161237d565b602060405180830381865afa158015611dc1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611de5919061288a565b611df057505f6112aa565b60025460405163188cfd6d60e21b81526001600160401b03881660048201526001600160801b0319871660248201526001600160a01b038681166044830152606482018690525f921690636233f5b490608401602060405180830381865afa158015611e5e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e82919061286f565b6001600160401b0388165f9081526004602090815260408083206001600160801b03198b16845282528083206001600160a01b038a16845282528083208884529091529020549091506001600160801b03908116908216811015611ee8575f9250611ef5565b611ef28282612960565b92505b505095945050505050565b5f6001600160801b0387161580611f245750611f24846001600160801b0316611aba565b15611f3057505f611b94565b5f611f3b878761205c565b90505f896001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f7a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f9e91906128a3565b9050611b8f611b818a6001600160801b031683858a8a8a61212f565b5f611fc682600161297f565b83511015611fe757604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f611ffc82602061297f565b8351101561201d57604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f61203282601061297f565b8351101561205357604051633b99b53d60e01b815260040160405180910390fd5b50016010015190565b5f81156120cf57604051631fa3f33160e11b8152600481018390526001600160a01b03841690633f47e66290602401602060405180830381865afa1580156120a6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120ca91906128a3565b610409565b826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561210b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061040991906128a3565b5f611b948787878787875f6001600160801b03831661218e5760405162461bcd60e51b815260206004820152601b60248201527a50726963696e674c69622f6469766973696f6e2d62792d7a65726f60281b604482015260640161169b565b611b946121d96001600160801b038616896121aa89600a612a75565b6121b49190612a83565b6001600160801b0387166121c98b600a612a75565b6121d39190612a83565b866121de565b611738565b5f5f6121eb868686612237565b90506001836002811115612201576122016126f3565b14801561221d57505f848061221857612218612a9a565b868809115b156112aa5761222d60018261297f565b9695505050505050565b5f80805f19858709858702925082811083820303915050805f0361226e5783828161226457612264612a9a565b0492505050610409565b80841161228e57604051637ee8242b60e01b815260040160405180910390fd5b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b6001600160401b0381168114612309575f5ffd5b50565b6001600160801b031981168114612309575f5ffd5b6001600160a01b0381168114612309575f5ffd5b5f5f5f60608486031215612347575f5ffd5b8335612352816122f5565b925060208401356123628161230c565b9150604084013561237281612321565b809150509250925092565b6001600160a01b0391909116815260200190565b5f5f5f606084860312156123a3575f5ffd5b83356123ae81612321565b925060208401356123be81612321565b929592945050506040919091013590565b5f5f604083850312156123e0575f5ffd5b82356123eb816122f5565b915060208301356123fb8161230c565b809150509250929050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b038111828210171561244257612442612406565b604052919050565b5f5f5f6060848603121561245c575f5ffd5b8335612467816122f5565b925060208401356124778161230c565b915060408401356001600160401b03811115612491575f5ffd5b8401601f810186136124a1575f5ffd5b80356001600160401b038111156124ba576124ba612406565b6124cd601f8201601f191660200161241a565b8181528760208385010111156124e1575f5ffd5b816020840160208301375f602083830101528093505050509250925092565b5f5f5f5f60808587031215612513575f5ffd5b843561251e81612321565b935060208501359250604085013561253581612321565b9150606085013561254581612321565b939692955090935050565b5f5f60408385031215612561575f5ffd5b823561256c81612321565b946020939093013593505050565b6001600160801b0381168114612309575f5ffd5b5f5f5f5f5f60a086880312156125a2575f5ffd5b85356125ad816122f5565b945060208601356125bd8161230c565b935060408601356125cd81612321565b92506060860135915060808601356125e48161257a565b809150509295509295909350565b5f60208284031215612602575f5ffd5b813561040981612321565b5f5f6040838503121561261e575f5ffd5b823561262981612321565b915060208301356123fb81612321565b5f5f5f5f6080858703121561264c575f5ffd5b843561265781612321565b935060208501359250604085013561266e81612321565b9396929550929360600135925050565b5f5f5f5f60808587031215612691575f5ffd5b843561269c816122f5565b935060208501356126ac8161230c565b9250604085013561266e81612321565b6001600160801b0391909116815260200190565b5f5f604083850312156126e1575f5ffd5b8235915060208301356123fb81612321565b634e487b7160e01b5f52602160045260245ffd5b6001600160401b039290921682526001600160801b031916602082015260400190565b5f6020828403121561273a575f5ffd5b815161040981612321565b5f5f60408385031215612756575f5ffd5b825161276181612321565b6020939093015192949293505050565b80518015158114612780575f5ffd5b919050565b5f6080828403128015612796575f5ffd5b50604051608081016001600160401b03811182821017156127b9576127b9612406565b60405282516127c78161257a565b815260208301516127d781612321565b6020820152604083810151908201526127f260608401612771565b60608201529392505050565b5f6020828403121561280e575f5ffd5b8151610409816122f5565b5f60208284031215612829575f5ffd5b81516104098161230c565b6001600160401b039490941684526001600160801b03199290921660208401526001600160801b031660408301521515606082015260800190565b5f6020828403121561287f575f5ffd5b81516104098161257a565b5f6020828403121561289a575f5ffd5b61040982612771565b5f602082840312156128b3575f5ffd5b815160ff81168114610409575f5ffd5b5f82518060208501845e5f920191825250919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03851681526001600160e01b0319841660208201526080604082018190525f9061293a908301856128d9565b8281036060840152611b9481856128d9565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b038281168282160390811115610a4257610a4261294c565b80820180821115610a4257610a4261294c565b6001815b60018411156129cd578085048111156129b1576129b161294c565b60018416156129bf57908102905b60019390931c928002612996565b935093915050565b5f826129e357506001610a42565b816129ef57505f610a42565b8160018114612a055760028114612a0f57612a2b565b6001915050610a42565b60ff841115612a2057612a2061294c565b50506001821b610a42565b5060208310610133831016604e8410600b8410161715612a4e575081810a610a42565b612a5a5f198484612992565b805f1904821115612a6d57612a6d61294c565b029392505050565b5f61040960ff8416836129d5565b8082028115828204841417610a4257610a4261294c565b634e487b7160e01b5f52601260045260245ffdfea26469706673582212206f8216cece949aacb9ec22ee209e09adabf93438543dca216aaebe3122dbf7ca64736f6c634300081c0033

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

0000000000000000000000005f3f8ea3b54bff7795de7754866e0eac52e0881d

-----Decoded View---------------
Arg [0] : deployer (address): 0x5f3f8ea3b54BFF7795dE7754866e0Eac52e0881d

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000005f3f8ea3b54bff7795de7754866e0eac52e0881d


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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