Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Cross-Chain Transactions
Loading...
Loading
Contract Name:
AsyncVault
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 1 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {BaseVault} from "./BaseVaults.sol";
import {BaseAsyncRedeemVault} from "./BaseVaults.sol";
import {IAsyncVault} from "./interfaces/IAsyncVault.sol";
import {IAsyncRequestManager} from "./interfaces/IVaultManagers.sol";
import "../misc/interfaces/IERC7540.sol";
import "../misc/interfaces/IERC7575.sol";
import {IERC20} from "../misc/interfaces/IERC20.sol";
import {SafeTransferLib} from "../misc/libraries/SafeTransferLib.sol";
import {PoolId} from "../common/types/PoolId.sol";
import {ShareClassId} from "../common/types/ShareClassId.sol";
import {VaultKind} from "../spoke/interfaces/IVault.sol";
import {IShareToken} from "../spoke/interfaces/IShareToken.sol";
/// @title AsyncVault
/// @notice Asynchronous Tokenized Vault standard implementation for Centrifuge pools
///
/// @dev Each vault issues shares of Centrifuge share class tokens as restricted ERC-20 tokens
/// against asset deposits based on the current share price.
///
/// ERC-7540 is an extension of the ERC-4626 standard by 'requestDeposit' & 'requestRedeem' methods, where
/// deposit and redeem orders are submitted to the pools to be included in the execution of the following epoch.
/// After execution users can use the deposit, mint, redeem and withdraw functions to get their shares
/// and/or assets from the pools.
contract AsyncVault is BaseAsyncRedeemVault, IAsyncVault {
constructor(
PoolId poolId_,
ShareClassId scId_,
address asset_,
IShareToken token_,
address root_,
IAsyncRequestManager manager_
) BaseVault(poolId_, scId_, asset_, token_, root_, manager_) BaseAsyncRedeemVault(manager_) {}
//----------------------------------------------------------------------------------------------
// ERC-7540 deposit
//----------------------------------------------------------------------------------------------
/// @inheritdoc IERC7540Deposit
function requestDeposit(uint256 assets, address controller, address owner) public returns (uint256) {
require(owner == msg.sender || isOperator[owner][msg.sender], InvalidOwner());
require(IERC20(asset).balanceOf(owner) >= assets, InsufficientBalance());
require(asyncManager().requestDeposit(this, assets, controller, owner, msg.sender), RequestDepositFailed());
SafeTransferLib.safeTransferFrom(asset, owner, address(baseManager.globalEscrow()), assets);
emit DepositRequest(controller, owner, REQUEST_ID, msg.sender, assets);
return REQUEST_ID;
}
/// @inheritdoc IERC7540Deposit
function pendingDepositRequest(uint256, address controller) public view returns (uint256 pendingAssets) {
pendingAssets = asyncManager().pendingDepositRequest(this, controller);
}
/// @inheritdoc IERC7540Deposit
function claimableDepositRequest(uint256, address controller) external view returns (uint256 claimableAssets) {
claimableAssets = maxDeposit(controller);
}
//----------------------------------------------------------------------------------------------
// ERC-7887
//----------------------------------------------------------------------------------------------
/// @inheritdoc IERC7887Deposit
function cancelDepositRequest(uint256, address controller) external {
_validateController(controller);
asyncManager().cancelDepositRequest(this, controller, msg.sender);
emit CancelDepositRequest(controller, REQUEST_ID, msg.sender);
}
/// @inheritdoc IERC7887Deposit
function pendingCancelDepositRequest(uint256, address controller) public view returns (bool isPending) {
isPending = asyncManager().pendingCancelDepositRequest(this, controller);
}
/// @inheritdoc IERC7887Deposit
function claimableCancelDepositRequest(uint256, address controller) public view returns (uint256 claimableAssets) {
claimableAssets = asyncManager().claimableCancelDepositRequest(this, controller);
}
/// @inheritdoc IERC7887Deposit
function claimCancelDepositRequest(uint256, address receiver, address controller)
external
returns (uint256 assets)
{
_validateController(controller);
assets = asyncManager().claimCancelDepositRequest(this, receiver, controller);
emit CancelDepositClaim(controller, receiver, REQUEST_ID, msg.sender, assets);
}
//----------------------------------------------------------------------------------------------
// ERC-165
//----------------------------------------------------------------------------------------------
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public pure override(BaseAsyncRedeemVault, IERC165) returns (bool) {
return interfaceId == type(IERC7540Deposit).interfaceId || interfaceId == type(IERC7887Deposit).interfaceId
|| super.supportsInterface(interfaceId);
}
//----------------------------------------------------------------------------------------------
// ERC-7540 claim
//----------------------------------------------------------------------------------------------
/// @inheritdoc IERC7575
function maxDeposit(address controller) public view returns (uint256 maxAssets) {
maxAssets = asyncManager().maxDeposit(this, controller);
}
/// @inheritdoc IERC7540Deposit
function deposit(uint256 assets, address receiver, address controller) public returns (uint256 shares) {
_validateController(controller);
shares = asyncManager().deposit(this, assets, receiver, controller);
emit Deposit(controller, receiver, assets, shares);
}
/// @inheritdoc IERC7575
/// @notice When claiming deposit requests using deposit(), there can be some precision loss leading to dust.
/// It is recommended to use mint() to claim deposit requests instead.
function deposit(uint256 assets, address receiver) external returns (uint256 shares) {
shares = deposit(assets, receiver, msg.sender);
}
/// @inheritdoc IERC7575
function maxMint(address controller) public view returns (uint256 maxShares) {
maxShares = asyncManager().maxMint(this, controller);
}
/// @inheritdoc IERC7540Deposit
function mint(uint256 shares, address receiver, address controller) public returns (uint256 assets) {
_validateController(controller);
assets = asyncManager().mint(this, shares, receiver, controller);
emit Deposit(controller, receiver, assets, shares);
}
/// @inheritdoc IERC7575
function mint(uint256 shares, address receiver) public returns (uint256 assets) {
assets = mint(shares, receiver, msg.sender);
}
/// @dev Strongly-typed accessor to the generic async redeem manager
function asyncManager() public view returns (IAsyncRequestManager) {
return IAsyncRequestManager(address(asyncRedeemManager));
}
/// @dev Preview functions for ERC-7540 vaults revert
function previewDeposit(uint256) external pure returns (uint256) {
revert();
}
/// @dev Preview functions for ERC-7540 vaults revert
function previewMint(uint256) external pure returns (uint256) {
revert();
}
//----------------------------------------------------------------------------------------------
// Event emitters
//----------------------------------------------------------------------------------------------
function onDepositClaimable(address controller, uint256 assets, uint256 shares) public virtual auth {
emit DepositClaimable(controller, REQUEST_ID, assets, shares);
}
function onCancelDepositClaimable(address controller, uint256 assets) public virtual auth {
emit CancelDepositClaimable(controller, REQUEST_ID, assets);
}
//----------------------------------------------------------------------------------------------
// IBaseVault view
//----------------------------------------------------------------------------------------------
function vaultKind() public pure returns (VaultKind vaultKind_) {
return VaultKind.Async;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {IBaseVault} from "./interfaces/IBaseVault.sol";
import {IAsyncRedeemVault} from "./interfaces/IAsyncVault.sol";
import {IAsyncRedeemManager} from "./interfaces/IVaultManagers.sol";
import {ISyncDepositManager} from "./interfaces/IVaultManagers.sol";
import {IBaseRequestManager} from "./interfaces/IBaseRequestManager.sol";
import {Auth} from "../misc/Auth.sol";
import "../misc/interfaces/IERC7540.sol";
import "../misc/interfaces/IERC7575.sol";
import {Recoverable} from "../misc/Recoverable.sol";
import {IERC7575} from "../misc/interfaces/IERC7575.sol";
import {EIP712Lib} from "../misc/libraries/EIP712Lib.sol";
import {IERC20Metadata} from "../misc/interfaces/IERC20.sol";
import {SignatureLib} from "../misc/libraries/SignatureLib.sol";
import {SafeTransferLib} from "../misc/libraries/SafeTransferLib.sol";
import {PoolId} from "../common/types/PoolId.sol";
import {IRoot} from "../common/interfaces/IRoot.sol";
import {ShareClassId} from "../common/types/ShareClassId.sol";
import {IVault} from "../spoke/interfaces/IVaultManager.sol";
import {IShareToken} from "../spoke/interfaces/IShareToken.sol";
import {IVaultManager} from "../spoke/interfaces/IVaultManager.sol";
abstract contract BaseVault is Auth, Recoverable, IBaseVault {
/// @dev Requests for Centrifuge pool are non-fungible and all have ID = 0
uint256 internal constant REQUEST_ID = 0;
IRoot public immutable root;
IBaseRequestManager public baseManager;
/// @inheritdoc IVault
PoolId public immutable poolId;
/// @inheritdoc IVault
ShareClassId public immutable scId;
/// @inheritdoc IERC7575
address public immutable asset;
/// @inheritdoc IERC7575
address public immutable share;
uint8 internal immutable _shareDecimals;
/// --- ERC7741 ---
bytes32 private immutable nameHash;
bytes32 private immutable versionHash;
uint256 public immutable deploymentChainId;
bytes32 private immutable _DOMAIN_SEPARATOR;
bytes32 public constant AUTHORIZE_OPERATOR_TYPEHASH =
keccak256("AuthorizeOperator(address controller,address operator,bool approved,bytes32 nonce,uint256 deadline)");
/// @inheritdoc IERC7741
mapping(address controller => mapping(bytes32 nonce => bool used)) public authorizations;
/// @inheritdoc IERC7540Operator
mapping(address => mapping(address => bool)) public isOperator;
constructor(
PoolId poolId_,
ShareClassId scId_,
address asset_,
IShareToken token_,
address root_,
IBaseRequestManager manager_
) Auth(msg.sender) {
poolId = poolId_;
scId = scId_;
asset = asset_;
share = address(token_);
_shareDecimals = IERC20Metadata(share).decimals();
root = IRoot(root_);
baseManager = IBaseRequestManager(manager_);
nameHash = keccak256(bytes("Centrifuge"));
versionHash = keccak256(bytes("1"));
deploymentChainId = block.chainid;
_DOMAIN_SEPARATOR = EIP712Lib.calculateDomainSeparator(nameHash, versionHash);
}
//----------------------------------------------------------------------------------------------
// Administration
//----------------------------------------------------------------------------------------------
function file(bytes32 what, address data) external virtual auth {
if (what == "manager") baseManager = IBaseRequestManager(data);
else revert FileUnrecognizedParam();
emit File(what, data);
}
/// @inheritdoc IERC7540Operator
function setOperator(address operator, bool approved) public virtual returns (bool success) {
require(msg.sender != operator, CannotSetSelfAsOperator());
isOperator[msg.sender][operator] = approved;
emit OperatorSet(msg.sender, operator, approved);
success = true;
}
/// @inheritdoc IBaseVault
function setEndorsedOperator(address owner, bool approved) public virtual {
require(msg.sender != owner, CannotSetSelfAsOperator());
require(root.endorsed(msg.sender), NotEndorsed());
isOperator[owner][msg.sender] = approved;
emit OperatorSet(owner, msg.sender, approved);
}
/// @inheritdoc IERC7741
function DOMAIN_SEPARATOR() public view returns (bytes32) {
return block.chainid == deploymentChainId
? _DOMAIN_SEPARATOR
: EIP712Lib.calculateDomainSeparator(nameHash, versionHash);
}
/// @inheritdoc IERC7741
function authorizeOperator(
address controller,
address operator,
bool approved,
bytes32 nonce,
uint256 deadline,
bytes memory signature
) external returns (bool success) {
require(controller != operator, CannotSetSelfAsOperator());
require(block.timestamp <= deadline, ExpiredAuthorization());
require(!authorizations[controller][nonce], AlreadyUsedAuthorization());
authorizations[controller][nonce] = true;
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(abi.encode(AUTHORIZE_OPERATOR_TYPEHASH, controller, operator, approved, nonce, deadline))
)
);
require(SignatureLib.isValidSignature(controller, digest, signature), InvalidAuthorization());
isOperator[controller][operator] = approved;
emit OperatorSet(controller, operator, approved);
success = true;
}
/// @inheritdoc IERC7741
function invalidateNonce(bytes32 nonce) external {
authorizations[msg.sender][nonce] = true;
}
//----------------------------------------------------------------------------------------------
// ERC-165
//----------------------------------------------------------------------------------------------
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return interfaceId == type(IERC7540Operator).interfaceId || interfaceId == type(IERC7741).interfaceId
|| interfaceId == type(IERC7714).interfaceId || interfaceId == type(IERC7575).interfaceId
|| interfaceId == type(IERC165).interfaceId;
}
//----------------------------------------------------------------------------------------------
// ERC-4626
//----------------------------------------------------------------------------------------------
/// @inheritdoc IERC7575
function totalAssets() external view returns (uint256) {
return convertToAssets(IERC20Metadata(share).totalSupply());
}
/// @inheritdoc IERC7575
/// @notice The calculation is based on the token price from the most recent epoch retrieved from Centrifuge.
/// The actual conversion MAY change between order submission and execution.
function convertToShares(uint256 assets) public view returns (uint256 shares) {
shares = baseManager.convertToShares(this, assets);
}
/// @inheritdoc IERC7575
/// @notice The calculation is based on the token price from the most recent epoch retrieved from Centrifuge.
/// The actual conversion MAY change between order submission and execution.
function convertToAssets(uint256 shares) public view returns (uint256 assets) {
assets = baseManager.convertToAssets(this, shares);
}
//----------------------------------------------------------------------------------------------
// Helpers
//----------------------------------------------------------------------------------------------
/// @inheritdoc IVault
function manager() public view returns (IVaultManager) {
return baseManager;
}
/// @notice Price of 1 unit of share, quoted in the decimals of the asset.
function pricePerShare() external view returns (uint256) {
return convertToAssets(10 ** _shareDecimals);
}
/// @notice Returns timestamp of the last share price update.
function priceLastUpdated() external view returns (uint64) {
return baseManager.priceLastUpdated(this);
}
/// @inheritdoc IERC7714
function isPermissioned(address controller) external view returns (bool) {
return IShareToken(share).checkTransferRestriction(address(0), controller, 0);
}
/// @notice Ensures msg.sender can operate on behalf of controller.
function _validateController(address controller) internal view {
require(controller == msg.sender || isOperator[controller][msg.sender], InvalidController());
}
}
abstract contract BaseAsyncRedeemVault is BaseVault, IAsyncRedeemVault {
IAsyncRedeemManager public asyncRedeemManager;
constructor(IAsyncRedeemManager asyncRequestManager_) {
asyncRedeemManager = asyncRequestManager_;
}
//----------------------------------------------------------------------------------------------
// Administration
//----------------------------------------------------------------------------------------------
function file(bytes32 what, address data) external virtual override auth {
if (what == "manager") baseManager = IBaseRequestManager(data);
else if (what == "asyncRedeemManager") asyncRedeemManager = IAsyncRedeemManager(data);
else revert FileUnrecognizedParam();
emit File(what, data);
}
//----------------------------------------------------------------------------------------------
// ERC-7540 redeem
//----------------------------------------------------------------------------------------------
/// @inheritdoc IERC7540Redeem
function requestRedeem(uint256 shares, address controller, address owner) public returns (uint256) {
require(IShareToken(share).balanceOf(owner) >= shares, InsufficientBalance());
// If msg.sender is operator of owner, the transfer is executed as if
// the sender is the owner, to bypass the allowance check
address sender = isOperator[owner][msg.sender] ? owner : msg.sender;
require(asyncRedeemManager.requestRedeem(this, shares, controller, owner, sender, true), RequestRedeemFailed());
emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);
return REQUEST_ID;
}
/// @inheritdoc IERC7540Redeem
function pendingRedeemRequest(uint256, address controller) public view returns (uint256 pendingShares) {
pendingShares = asyncRedeemManager.pendingRedeemRequest(this, controller);
}
/// @inheritdoc IERC7540Redeem
function claimableRedeemRequest(uint256, address controller) external view returns (uint256 claimableShares) {
claimableShares = maxRedeem(controller);
}
//----------------------------------------------------------------------------------------------
// ERC-7887
//----------------------------------------------------------------------------------------------
/// @inheritdoc IERC7887Redeem
function cancelRedeemRequest(uint256, address controller) external {
_validateController(controller);
asyncRedeemManager.cancelRedeemRequest(this, controller, msg.sender);
emit CancelRedeemRequest(controller, REQUEST_ID, msg.sender);
}
/// @inheritdoc IERC7887Redeem
function pendingCancelRedeemRequest(uint256, address controller) public view returns (bool isPending) {
isPending = asyncRedeemManager.pendingCancelRedeemRequest(this, controller);
}
/// @inheritdoc IERC7887Redeem
function claimableCancelRedeemRequest(uint256, address controller) public view returns (uint256 claimableShares) {
claimableShares = asyncRedeemManager.claimableCancelRedeemRequest(this, controller);
}
/// @inheritdoc IERC7887Redeem
function claimCancelRedeemRequest(uint256, address receiver, address controller)
external
returns (uint256 shares)
{
_validateController(controller);
shares = asyncRedeemManager.claimCancelRedeemRequest(this, receiver, controller);
emit CancelRedeemClaim(controller, receiver, REQUEST_ID, msg.sender, shares);
}
//----------------------------------------------------------------------------------------------
// ERC-7540 claim
//----------------------------------------------------------------------------------------------
/// @inheritdoc IERC7575
/// @notice DOES NOT support controller != msg.sender since shares are already transferred on requestRedeem
function withdraw(uint256 assets, address receiver, address controller) public returns (uint256 shares) {
_validateController(controller);
shares = asyncRedeemManager.withdraw(this, assets, receiver, controller);
emit Withdraw(msg.sender, receiver, controller, assets, shares);
}
/// @inheritdoc IERC7575
/// @notice DOES NOT support controller != msg.sender since shares are already transferred on requestRedeem.
/// When claiming redemption requests using redeem(), there can be some precision loss leading to dust.
/// It is recommended to use withdraw() to claim redemption requests instead.
function redeem(uint256 shares, address receiver, address controller) external returns (uint256 assets) {
_validateController(controller);
assets = asyncRedeemManager.redeem(this, shares, receiver, controller);
emit Withdraw(msg.sender, receiver, controller, assets, shares);
}
//----------------------------------------------------------------------------------------------
// Event emitters
//----------------------------------------------------------------------------------------------
function onRedeemRequest(address controller, address owner, uint256 shares) public virtual auth {
emit RedeemRequest(controller, owner, REQUEST_ID, msg.sender, shares);
}
function onRedeemClaimable(address controller, uint256 assets, uint256 shares) public virtual auth {
emit RedeemClaimable(controller, REQUEST_ID, assets, shares);
}
function onCancelRedeemClaimable(address controller, uint256 shares) public virtual auth {
emit CancelRedeemClaimable(controller, REQUEST_ID, shares);
}
//----------------------------------------------------------------------------------------------
// View methods
//----------------------------------------------------------------------------------------------
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public pure virtual override(BaseVault, IERC165) returns (bool) {
return super.supportsInterface(interfaceId) || interfaceId == type(IERC7540Redeem).interfaceId
|| interfaceId == type(IERC7887Redeem).interfaceId;
}
/// @inheritdoc IERC7575
function maxWithdraw(address controller) public view returns (uint256 maxAssets) {
maxAssets = asyncRedeemManager.maxWithdraw(this, controller);
}
/// @inheritdoc IERC7575
function maxRedeem(address controller) public view returns (uint256 maxShares) {
maxShares = asyncRedeemManager.maxRedeem(this, controller);
}
/// @dev Preview functions for ERC-7540 vaults revert
function previewWithdraw(uint256) external pure returns (uint256) {
revert();
}
/// @dev Preview functions for ERC-7540 vaults revert
function previewRedeem(uint256) external pure returns (uint256) {
revert();
}
}
abstract contract BaseSyncDepositVault is BaseVault {
ISyncDepositManager public syncDepositManager;
constructor(ISyncDepositManager syncManager_) {
syncDepositManager = syncManager_;
}
//----------------------------------------------------------------------------------------------
// ERC-4626
//----------------------------------------------------------------------------------------------
/// @inheritdoc IERC7575
function maxDeposit(address owner) public view returns (uint256 maxAssets) {
maxAssets = syncDepositManager.maxDeposit(this, owner);
}
/// @inheritdoc IERC7575
function previewDeposit(uint256 assets) external view override returns (uint256 shares) {
shares = syncDepositManager.previewDeposit(this, msg.sender, assets);
}
/// @inheritdoc IERC7575
function deposit(uint256 assets, address receiver) external returns (uint256 shares) {
shares = syncDepositManager.deposit(this, assets, receiver, msg.sender);
// NOTE: For security reasons, transfer must stay at end of call despite the fact that it logically should
// happen before depositing in the manager
SafeTransferLib.safeTransferFrom(asset, msg.sender, address(baseManager.poolEscrow(poolId)), assets);
emit Deposit(receiver, msg.sender, assets, shares);
}
/// @inheritdoc IERC7575
function maxMint(address owner) public view returns (uint256 maxShares) {
maxShares = syncDepositManager.maxMint(this, owner);
}
/// @inheritdoc IERC7575
function previewMint(uint256 shares) external view returns (uint256 assets) {
assets = syncDepositManager.previewMint(this, msg.sender, shares);
}
/// @inheritdoc IERC7575
function mint(uint256 shares, address receiver) public returns (uint256 assets) {
assets = syncDepositManager.mint(this, shares, receiver, msg.sender);
// NOTE: For security reasons, transfer must stay at end of call
SafeTransferLib.safeTransferFrom(asset, msg.sender, address(baseManager.poolEscrow(poolId)), assets);
emit Deposit(receiver, msg.sender, assets, shares);
}
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public pure virtual override(BaseVault) returns (bool) {
return super.supportsInterface(interfaceId);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IBaseVault} from "./IBaseVault.sol";
import {IAsyncRedeemManager} from "./IVaultManagers.sol";
import {IERC7540Redeem, IERC7887Redeem, IERC7887Deposit, IERC7540Deposit} from "../../misc/interfaces/IERC7540.sol";
/**
* @title IAsyncRedeemVault
* @dev This is the specific set of interfaces used by the Centrifuge implementation of ERC7540,
* as a fully asynchronous Vault, with cancellation support, and authorize operator signature support.
*/
interface IAsyncRedeemVault is IERC7540Redeem, IERC7887Redeem, IBaseVault {
event RedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);
event CancelRedeemClaimable(address indexed controller, uint256 indexed requestId, uint256 shares);
/// @notice Callback when a redeem Request is triggered externally;
function onRedeemRequest(address controller, address owner, uint256 shares) external;
/// @notice Callback when a redeem Request becomes claimable
function onRedeemClaimable(address owner, uint256 assets, uint256 shares) external;
/// @notice Callback when a claim redeem Request becomes claimable
function onCancelRedeemClaimable(address owner, uint256 shares) external;
/// @notice Retrieve the asynchronous redeem manager
function asyncRedeemManager() external view returns (IAsyncRedeemManager);
}
interface IAsyncVault is IERC7540Deposit, IERC7887Deposit, IAsyncRedeemVault {
event DepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets, uint256 shares);
event CancelDepositClaimable(address indexed controller, uint256 indexed requestId, uint256 assets);
error InvalidOwner();
error RequestDepositFailed();
/// @notice Callback when a deposit Request becomes claimable
function onDepositClaimable(address owner, uint256 assets, uint256 shares) external;
/// @notice Callback when a claim deposit Request becomes claimable
function onCancelDepositClaimable(address owner, uint256 assets) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {IBaseVault} from "./IBaseVault.sol";
import {IBaseRequestManager} from "./IBaseRequestManager.sol";
import {D18} from "../../misc/types/D18.sol";
import {PoolId} from "../../common/types/PoolId.sol";
import {AssetId} from "../../common/types/AssetId.sol";
import {ShareClassId} from "../../common/types/ShareClassId.sol";
import {IUpdateContract} from "../../spoke/interfaces/IUpdateContract.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 ExceedsMaxDeposit();
error AssetMismatch();
error ZeroAmountNotAllowed();
error TransferNotAllowed();
error CancellationIsPending();
error NoPendingRequest();
error ShareTokenAmountIsZero();
error FailedRedeemRequest();
error ExceedsDepositLimits();
error ShareTokenTransferFailed();
error ExceedsMaxRedeem();
error ExceedsRedeemLimits();
error VaultNotLinked();
/// @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 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 cancellation
*
* - 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 cancellation 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 cancellation
*
* - 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 cancellation 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.5.0;
import {IERC165} from "./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;
/// @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.8.28;
import {IERC20} from "../interfaces/IERC20.sol";
import {IERC7751} from "../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: BUSL-1.1
pragma solidity 0.8.28;
import {MathLib} from "../../misc/libraries/MathLib.sol";
using MathLib for uint256;
type PoolId is uint64;
function centrifugeId(PoolId poolId) pure returns (uint16) {
return uint16(PoolId.unwrap(poolId) >> 48);
}
function newPoolId(uint16 centrifugeId_, uint48 localPoolId) pure returns (PoolId) {
return PoolId.wrap((uint64(centrifugeId_) << 48) | uint64(localPoolId));
}
function isNull(PoolId poolId) pure returns (bool) {
return PoolId.unwrap(poolId) == 0;
}
function isEqual(PoolId a, PoolId b) pure returns (bool) {
return PoolId.unwrap(a) == PoolId.unwrap(b);
}
function raw(PoolId poolId) pure returns (uint64) {
return PoolId.unwrap(poolId);
}
using {centrifugeId, isNull, raw, isEqual as ==} for PoolId global;// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {PoolId} from "./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 {IVaultManager} from "./IVaultManager.sol";
import {PoolId} from "../../common/types/PoolId.sol";
import {ShareClassId} from "../../common/types/ShareClassId.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.8.28;
import {IERC20Metadata} from "../../misc/interfaces/IERC20.sol";
import {IERC7575Share} from "../../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 {IERC7575} from "../../misc/interfaces/IERC7575.sol";
import {IRecoverable} from "../../misc/interfaces/IRecoverable.sol";
import {IERC7540Operator, IERC7714, IERC7741} from "../../misc/interfaces/IERC7540.sol";
import {IVault} from "../../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;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {IBaseVault} from "./IBaseVault.sol";
import {IEscrow} from "../../misc/interfaces/IEscrow.sol";
import {PoolId} from "../../common/types/PoolId.sol";
import {IPoolEscrow} from "../../common/interfaces/IPoolEscrow.sol";
import {ISpoke} from "../../spoke/interfaces/ISpoke.sol";
import {IVaultManager} from "../../spoke/interfaces/IVaultManager.sol";
import {IRequestManager} from "../../spoke/interfaces/IRequestManager.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: GPL-2.0-or-later
pragma solidity 0.8.28;
import {IAuth} from "./interfaces/IAuth.sol";
/// @title Auth
/// @notice Simple authentication pattern
/// @author Based on code from https://github.com/makerdao/dss
abstract contract Auth is IAuth {
/// @inheritdoc IAuth
mapping(address => uint256) public wards;
constructor(address initialWard) {
wards[initialWard] = 1;
emit Rely(initialWard);
}
/// @dev Check if the msg.sender has permissions
modifier auth() {
require(wards[msg.sender] == 1, NotAuthorized());
_;
}
/// @inheritdoc IAuth
function rely(address user) public auth {
wards[user] = 1;
emit Rely(user);
}
/// @inheritdoc IAuth
function deny(address user) public auth {
wards[user] = 0;
emit Deny(user);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {Auth} from "./Auth.sol";
import {IERC6909} from "./interfaces/IERC6909.sol";
import {SafeTransferLib} from "./libraries/SafeTransferLib.sol";
import {IRecoverable, ETH_ADDRESS} from "./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 EIP712 Lib
library EIP712Lib {
// keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
bytes32 public constant EIP712_DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;
function calculateDomainSeparator(bytes32 nameHash, bytes32 versionHash) internal view returns (bytes32) {
return keccak256(abi.encode(EIP712_DOMAIN_TYPEHASH, nameHash, versionHash, block.chainid, address(this)));
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
interface IERC1271 {
function isValidSignature(bytes32, bytes memory) external view returns (bytes4);
}
/// @title Signature Lib
library SignatureLib {
error InvalidSigner();
function isValidSignature(address signer, bytes32 digest, bytes memory signature)
internal
view
returns (bool valid)
{
require(signer != address(0), InvalidSigner());
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
if (signer == ecrecover(digest, v, r, s)) {
return true;
}
}
if (signer.code.length > 0) {
(bool success, bytes memory result) =
signer.staticcall(abi.encodeCall(IERC1271.isValidSignature, (digest, signature)));
valid =
(success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271.isValidSignature.selector);
}
}
}// 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 {IVault} from "./IVault.sol";
import {PoolId} from "../../common/types/PoolId.sol";
import {AssetId} from "../../common/types/AssetId.sol";
import {ShareClassId} from "../../common/types/ShareClassId.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.8.28;
// Small library to handle fixed point number operations with 18 decimals with static typing support.
import {MathLib} from "../libraries/MathLib.sol";
type D18 is uint128;
using MathLib for uint256;
/// @dev add two D18 types
function add(D18 d1, D18 d2) pure returns (D18) {
return D18.wrap(D18.unwrap(d1) + D18.unwrap(d2));
}
/// @dev subtract two D18 types
function sub(D18 d1, D18 d2) pure returns (D18) {
return D18.wrap(D18.unwrap(d1) - D18.unwrap(d2));
}
/// @dev Divides one D18 by another one while retaining precision:
/// - nominator (decimal): 50e18
/// - denominator (decimal): 2e19
/// - result (decimal): 25e17
function divD18(D18 d1, D18 d2) pure returns (D18) {
return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), 1e18, D18.unwrap(d2)).toUint128());
}
/// @dev Multiplies one D18 with another one while retaining precision:
/// - value1 (decimal): 50e18
/// - value2 (decimal): 2e19
/// - result (decimal): 100e19
function mulD18(D18 d1, D18 d2) pure returns (D18) {
return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), D18.unwrap(d2), 1e18).toUint128());
}
/// @dev Returns the reciprocal of a D18 decimal, i.e. 1 / d.
/// Example: if d = 2.0 (2e18 internally), reciprocal(d) = 0.5 (5e17 internally).
function reciprocal(D18 d) pure returns (D18) {
uint128 val = D18.unwrap(d);
require(val != 0, "D18/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: BUSL-1.1
pragma solidity 0.8.28;
/// @dev Composite Id of the centrifugeId (uint16) where the asset resides
/// and a local counter (uint64) that is part of the contract that registers the asset.
type AssetId is uint128;
function isNull(AssetId assetId) pure returns (bool) {
return AssetId.unwrap(assetId) == 0;
}
function raw(AssetId assetId) pure returns (uint128) {
return AssetId.unwrap(assetId);
}
function centrifugeId(AssetId assetId) pure returns (uint16) {
return uint16(AssetId.unwrap(assetId) >> 112);
}
function newAssetId(uint16 centrifugeId_, uint64 counter) pure returns (AssetId) {
return AssetId.wrap((uint128(centrifugeId_) << 112) + counter);
}
function newAssetId(uint32 isoCode) pure returns (AssetId) {
return AssetId.wrap(isoCode);
}
function eq(AssetId a, AssetId b) pure returns (bool) {
return a.raw() == b.raw();
}
using {isNull, raw, centrifugeId, eq} for AssetId global;// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {PoolId} from "../../common/types/PoolId.sol";
import {ShareClassId} from "../../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: GPL-2.0-or-later
pragma solidity >=0.5.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.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.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.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 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;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IRecoverable} from "../../misc/Recoverable.sol";
import {IEscrow} from "../../misc/interfaces/IEscrow.sol";
import {PoolId} from "../types/PoolId.sol";
import {ShareClassId} from "../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 Emitted when ETH is transferred to the escrow
/// @param amount transferred
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 {IShareToken} from "./IShareToken.sol";
import {IVault, VaultKind} from "./IVault.sol";
import {IRequestManager} from "./IRequestManager.sol";
import {D18} from "../../misc/types/D18.sol";
import {PoolId} from "../../common/types/PoolId.sol";
import {AssetId} from "../../common/types/AssetId.sol";
import {ShareClassId} from "../../common/types/ShareClassId.sol";
import {Price} from "../types/Price.sol";
import {IVaultFactory} from "../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 "../../common/types/PoolId.sol";
import {AssetId} from "../../common/types/AssetId.sol";
import {ShareClassId} from "../../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;
}// 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: BUSL-1.1
pragma solidity 0.8.28;
import {D18, d18} from "../../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: BUSL-1.1
pragma solidity 0.8.28;
import {PoolId} from "../../../common/types/PoolId.sol";
import {ShareClassId} from "../../../common/types/ShareClassId.sol";
import {IVault} from "../../interfaces/IVault.sol";
import {IShareToken} from "../../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: 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);
}{
"remappings": [
"forge-std/=lib/forge-std/src/",
"@chimera/=lib/chimera/src/",
"createx-forge/=lib/createx-forge/",
"@openzeppelin/contracts/=lib/pigeon/lib/openzeppelin-contracts/contracts/",
"chimera/=lib/chimera/src/",
"ds-test/=lib/pigeon/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/pigeon/lib/openzeppelin-contracts/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/pigeon/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/pigeon/lib/openzeppelin-contracts/",
"pigeon/=lib/pigeon/src/",
"setup-helpers/=lib/setup-helpers/src/",
"solady/=lib/pigeon/lib/solady/"
],
"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
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"PoolId","name":"poolId_","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"address","name":"asset_","type":"address"},{"internalType":"contract IShareToken","name":"token_","type":"address"},{"internalType":"address","name":"root_","type":"address"},{"internalType":"contract IAsyncRequestManager","name":"manager_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyUsedAuthorization","type":"error"},{"inputs":[],"name":"CannotSetSelfAsOperator","type":"error"},{"inputs":[],"name":"ExpiredAuthorization","type":"error"},{"inputs":[],"name":"FileUnrecognizedParam","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidAuthorization","type":"error"},{"inputs":[],"name":"InvalidController","type":"error"},{"inputs":[],"name":"InvalidOwner","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"NoCode","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotEndorsed","type":"error"},{"inputs":[],"name":"RequestDepositFailed","type":"error"},{"inputs":[],"name":"RequestRedeemFailed","type":"error"},{"inputs":[],"name":"SafeTransferEthFailed","type":"error"},{"inputs":[],"name":"TransferFromFailed","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":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"CancelDepositClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"CancelDepositClaimable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"CancelDepositRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"CancelRedeemClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"CancelRedeemClaimable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"CancelRedeemRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Deny","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"DepositClaimable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"DepositRequest","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":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"OperatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"RedeemClaimable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"RedeemRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Rely","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"AUTHORIZE_OPERATOR_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"asyncManager","outputs":[{"internalType":"contract IAsyncRequestManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"asyncRedeemManager","outputs":[{"internalType":"contract IAsyncRedeemManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"},{"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"authorizations","outputs":[{"internalType":"bool","name":"used","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"authorizeOperator","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"baseManager","outputs":[{"internalType":"contract IBaseRequestManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"name":"cancelDepositRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"name":"cancelRedeemRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"controller","type":"address"}],"name":"claimCancelDepositRequest","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"controller","type":"address"}],"name":"claimCancelRedeemRequest","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"name":"claimableCancelDepositRequest","outputs":[{"internalType":"uint256","name":"claimableAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"name":"claimableCancelRedeemRequest","outputs":[{"internalType":"uint256","name":"claimableShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"name":"claimableDepositRequest","outputs":[{"internalType":"uint256","name":"claimableAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"name":"claimableRedeemRequest","outputs":[{"internalType":"uint256","name":"claimableShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"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":[],"name":"deploymentChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"controller","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","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":"bytes32","name":"nonce","type":"bytes32"}],"name":"invalidateNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"}],"name":"isPermissioned","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"manager","outputs":[{"internalType":"contract IVaultManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"controller","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"onCancelDepositClaimable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"onCancelRedeemClaimable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"onDepositClaimable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"onRedeemClaimable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"onRedeemRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"name":"pendingCancelDepositRequest","outputs":[{"internalType":"bool","name":"isPending","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"name":"pendingCancelRedeemRequest","outputs":[{"internalType":"bool","name":"isPending","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"name":"pendingDepositRequest","outputs":[{"internalType":"uint256","name":"pendingAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"controller","type":"address"}],"name":"pendingRedeemRequest","outputs":[{"internalType":"uint256","name":"pendingShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolId","outputs":[{"internalType":"PoolId","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"priceLastUpdated","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"controller","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"controller","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"requestDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"controller","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"requestRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"root","outputs":[{"internalType":"contract IRoot","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"scId","outputs":[{"internalType":"ShareClassId","name":"","type":"bytes16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setEndorsedOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setOperator","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"share","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultKind","outputs":[{"internalType":"enum VaultKind","name":"vaultKind_","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"controller","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6101c0604052348015610010575f5ffd5b5060405161331838038061331883398101604081905261002f91610274565b335f81815260208190526040808220600190555183928992899289928992899288929182917fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a2506001600160401b03861660a0526001600160801b0319851660c0526001600160a01b0380851660e05283166101008190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa1580156100e3573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610107919061030e565b60ff16610120526001600160a01b03828116608052600180546001600160a01b031916918316919091178155604080518082018252600a81526943656e7472696675676560b01b6020918201527fe416b338a274162320c79445ae6604141d1cb08275eb27011b69f002dc094d056101409081528251808401909352928252603160f81b9101527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66101608190524661018052905161022691604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020820152908101839052606081018290524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905092915050565b6101a0525050600480546001600160a01b0319166001600160a01b0396909616959095179094555061033598505050505050505050565b6001600160a01b0381168114610271575f5ffd5b50565b5f5f5f5f5f5f60c08789031215610289575f5ffd5b86516001600160401b038116811461029f575f5ffd5b60208801519096506001600160801b0319811681146102bc575f5ffd5b60408801519095506102cd8161025d565b60608801519094506102de8161025d565b60808801519093506102ef8161025d565b60a08801519092506103008161025d565b809150509295509295509295565b5f6020828403121561031e575f5ffd5b815160ff8116811461032e575f5ffd5b9392505050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a051612f436103d55f395f610f5701525f81816107840152610e8b01525f610f0601525f610ee101525f611b7e01525f818161068401528181610959015281816114d501526115c301525f81816104660152818161187201526119b301525f6103e501525f61049a01525f81816108370152610b4a0152612f435ff3fe608060405234801561000f575f5ffd5b50600436106102e8575f3560e01c8062a06d19146102ec57806301e1d1141461031257806301ffc9a71461031a5780630263704b1461033d57806307a2d13a146103525780630a28a477146103655780630d62c3321461037357806321f075ee14610387578063234f0e3b1461039a57806326c6f96c146103cd57806328f2930d146103e05780632b9d9c1f146104205780632cdfbae5146104335780632e2d2984146104465780633644e5151461045957806338d52e0f146104615780633e0dc34e146104955780633e8c5a70146104d4578063402d267d146104e2578063481c6a75146104f55780634b5fd666146105065780634cdad506146103655780634d44edeb1461051957806352aaead81461052c578063558a7297146105345780635f3e849f1461054757806365fae35e1461055a57806369d77a441461056d5780636e553f6514610580578063711b58ff1461059357806378d77ecb146105a65780637c1b50c4146105b95780637c9448f1146105cc5780637d41c86e146105df57806384ce2bf7146105f257806385b77f4514610605578063947b330a1461061857806394bf804d1461062b57806399530b061461063e578063995ea21a146106465780639c52a7f114610659578063a21ec79f1461066c578063a8d5fd651461067f578063aabb5922146106a6578063b04a5e05146106b9578063b3d7f6b914610365578063b460af94146106cc578063b6363cf2146106df578063b7570e0c1461070c578063b9cf063414610714578063ba08765214610727578063bf353dbb1461073a578063c63d75b614610759578063c6e6f5921461076c578063cd0d00961461077f578063cdf5bba3146107a6578063ce96cb77146107d3578063d4e8be83146107e6578063d905777e146107f9578063da39b3e71461080c578063eaed1d071461081f578063ebf0c71714610832578063ef8b30f714610365578063f15b65b114610859578063f5a23d8d1461086c575b5f5ffd5b6102ff6102fa36600461281a565b61087f565b6040519081526020015b60405180910390f35b6102ff610953565b61032d61032836600461286e565b6109dc565b6040519015158152602001610309565b61035061034b366004612889565b610a21565b005b6102ff6103603660046128bb565b610a99565b6102ff6102e83660046128bb565b6102ff5f516020612ece5f395f51905f5281565b6103506103953660046128df565b610b0a565b6103506103a83660046128bb565b335f90815260026020908152604080832093835292905220805460ff19166001179055565b6102ff6103db366004612916565b610c34565b6104077f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160801b03199091168152602001610309565b61035061042e366004612916565b610cb0565b610350610441366004612939565b610d53565b6102ff61045436600461281a565b610dc2565b6102ff610e88565b6104887f000000000000000000000000000000000000000000000000000000000000000081565b6040516103099190612977565b6104bc7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160401b039091168152602001610309565b5f604051610309919061298b565b6102ff6104f03660046129b1565b610f79565b6001546001600160a01b0316610488565b6103506105143660046129cc565b610faf565b600154610488906001600160a01b031681565b6104bc61101a565b61032d6105423660046128df565b611089565b610350610555366004612939565b611110565b6103506105683660046129b1565b61117e565b6102ff61057b36600461281a565b6111f1565b6102ff61058e366004612916565b6112ba565b61032d6105a1366004612a0a565b6112c6565b61032d6105b43660046129b1565b6114bc565b61032d6105c7366004612916565b61154d565b600454610488906001600160a01b031681565b6102ff6105ed36600461281a565b6115bf565b6103506106003660046129cc565b611797565b6102ff61061336600461281a565b611802565b610350610626366004612b02565b611aa4565b6102ff610639366004612916565b611b69565b6102ff611b75565b6102ff610654366004612916565b611ba4565b6103506106673660046129b1565b611bae565b61035061067a366004612889565b611c20565b6104887f000000000000000000000000000000000000000000000000000000000000000081565b6102ff6106b4366004612916565b611c8b565b6102ff6106c7366004612916565b611cc1565b6102ff6106da36600461281a565b611cf4565b61032d6106ed366004612b47565b600360209081525f928352604080842090915290825290205460ff1681565b610488611db1565b610350610722366004612916565b611dc0565b6102ff61073536600461281a565b611e67565b6102ff6107483660046129b1565b5f6020819052908152604090205481565b6102ff6107673660046129b1565b611f24565b6102ff61077a3660046128bb565b611f5a565b6102ff7f000000000000000000000000000000000000000000000000000000000000000081565b61032d6107b43660046129cc565b600260209081525f928352604080842090915290825290205460ff1681565b6102ff6107e13660046129b1565b611f8c565b6103506107f4366004612916565b611fbf565b6102ff6108073660046129b1565b6120b0565b6102ff61081a36600461281a565b6120e3565b6102ff61082d366004612916565b61219a565b6104887f000000000000000000000000000000000000000000000000000000000000000081565b61032d610867366004612916565b6121a4565b6102ff61087a366004612916565b6121da565b5f6108898261220d565b600480546040516311dcd79160e01b81526001600160a01b03909116916311dcd791916108bc9130918891889101612b73565b6020604051808303815f875af11580156108d8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108fc9190612b96565b90505f836001600160a01b0316836001600160a01b03167f9c133d4657dc9cd12f4c08cef86ef778dbbe03f3ad3b661ff14d36bc3febb1fb3385604051610944929190612bad565b60405180910390a49392505050565b5f6109d77f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109b3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103609190612b96565b905090565b5f6001600160e01b03198216630ce3bbe560e41b1480610a0c57506001600160e01b03198216638bf840e360e01b145b80610a1b5750610a1b82612266565b92915050565b335f90815260208190526040902054600114610a505760405163ea8e4eb560e01b815260040160405180910390fd5b5f836001600160a01b03167f4dd5187225a2ae5f5ea35ca7b1732180f848cc4b6f7dce34b4c5e9f384d77dec8484604051610a8c929190612bc6565b60405180910390a3505050565b6001546040516350603df360e01b81525f916001600160a01b0316906350603df390610acb9030908690600401612bad565b602060405180830381865afa158015610ae6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a1b9190612b96565b6001600160a01b0382163303610b33576040516343588e5760e01b815260040160405180910390fd5b60405163854b89d560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063854b89d590610b7f903390600401612977565b602060405180830381865afa158015610b9a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bbe9190612bd4565b610bdb5760405163175f16a160e01b815260040160405180910390fd5b6001600160a01b0382165f8181526003602090815260408083203380855290835292819020805460ff191686151590811790915590519081529192915f516020612e6e5f395f51905f5291015b60405180910390a35050565b5f610c3d611db1565b6001600160a01b03166337fb2bb830846040518363ffffffff1660e01b8152600401610c6a929190612bef565b602060405180830381865afa158015610c85573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ca99190612b96565b9392505050565b610cb98161220d565b60048054604051638b44deb160e01b81526001600160a01b0390911691638b44deb191610cec9130918691339101612b73565b5f604051808303815f87803b158015610d03575f5ffd5b505af1158015610d15573d5f5f3e3d5ffd5b505050505f816001600160a01b03167fa16c0f2cab616ed5d17cd544655b00d7062a1df7c457960cc8b9bf60770f923633604051610c289190612977565b335f90815260208190526040902054600114610d825760405163ea8e4eb560e01b815260040160405180910390fd5b5f826001600160a01b0316846001600160a01b03165f516020612eae5f395f51905f523385604051610db5929190612bad565b60405180910390a4505050565b5f610dcc8261220d565b610dd4611db1565b6001600160a01b031663c6f1649f308686866040518563ffffffff1660e01b8152600401610e059493929190612c09565b6020604051808303815f875af1158015610e21573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e459190612b96565b9050826001600160a01b0316826001600160a01b03165f516020612eee5f395f51905f528684604051610e79929190612bc6565b60405180910390a39392505050565b5f7f00000000000000000000000000000000000000000000000000000000000000004614610f545750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b507f000000000000000000000000000000000000000000000000000000000000000090565b5f610f82611db1565b6001600160a01b0316637601687030846040518363ffffffff1660e01b8152600401610acb929190612bef565b335f90815260208190526040902054600114610fde5760405163ea8e4eb560e01b815260040160405180910390fd5b5f826001600160a01b03167fe60d0cd4e01ab7d1e0cf1917bddb6779ca8db0fb23138e3b7a4bab6a727b966183604051610c2891815260200190565b6001546040516308332b4560e11b81525f916001600160a01b031690631066568a9061104a903090600401612977565b602060405180830381865afa158015611065573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109d79190612c34565b5f6001600160a01b03831633036110b3576040516343588e5760e01b815260040160405180910390fd5b335f8181526003602090815260408083206001600160a01b03881680855290835292819020805460ff191687151590811790915590519081529192915f516020612e6e5f395f51905f52910160405180910390a350600192915050565b335f9081526020819052604090205460011461113f5760405163ea8e4eb560e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038416016111735761116e82826122ab565b505050565b61116e838383612335565b335f908152602081905260409020546001146111ad5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b5f6111fb8261220d565b611203611db1565b6001600160a01b03166372a2fcca3085856040518463ffffffff1660e01b815260040161123293929190612b73565b6020604051808303815f875af115801561124e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112729190612b96565b90505f836001600160a01b0316836001600160a01b03167f295a9a8b44c0ac92394b0da92ef469784ff064156f08dab8316760c064c6cd2f3385604051610944929190612bad565b5f610ca9838333610dc2565b5f856001600160a01b0316876001600160a01b0316036112f9576040516343588e5760e01b815260040160405180910390fd5b8242111561131a5760405163a899ef9360e01b815260040160405180910390fd5b6001600160a01b0387165f90815260026020908152604080832087845290915290205460ff161561135e57604051638d5b647d60e01b815260040160405180910390fd5b6001600160a01b0387165f9081526002602090815260408083208784529091528120805460ff19166001179055611393610e88565b604080515f516020612ece5f395f51905f5260208201526001600160a01b03808c16928201929092529089166060820152871515608082015260a0810187905260c0810186905260e0016040516020818303038152906040528051906020012060405160200161141a92919061190160f01b81526002810192909252602282015260420190565b60405160208183030381529060405280519060200120905061143d888285612486565b61145a57604051632ce87eeb60e01b815260040160405180910390fd5b6001600160a01b038881165f818152600360209081526040808320948c1680845294825291829020805460ff19168b151590811790915591519182525f516020612e6e5f395f51905f52910160405180910390a3506001979650505050505050565b604051630fa1e71360e41b81525f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fa1e71309061150e90849086908290600401612c5a565b602060405180830381865afa158015611529573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a1b9190612bd4565b6004805460405163010476c960e71b81525f926001600160a01b039092169163823b648091611580913091879101612bef565b602060405180830381865afa15801561159b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ca99190612bd4565b5f837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231846040518263ffffffff1660e01b815260040161160d9190612977565b602060405180830381865afa158015611628573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061164c9190612b96565b101561166b57604051631e9acf1760e31b815260040160405180910390fd5b6001600160a01b0382165f90815260036020908152604080832033845290915281205460ff1661169b573361169d565b825b6004805460405163079731b960e51b81523092810192909252602482018890526001600160a01b03878116604484015286811660648401528084166084840152600160a4840152929350919091169063f2e637209060c4016020604051808303815f875af1158015611711573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117359190612bd4565b611752576040516303be524360e31b815260040160405180910390fd5b5f836001600160a01b0316856001600160a01b03165f516020612eae5f395f51905f523389604051611785929190612bad565b60405180910390a4505f949350505050565b335f908152602081905260409020546001146117c65760405163ea8e4eb560e01b815260040160405180910390fd5b5f826001600160a01b03167f0ede66e1b0b7bef549c7d3a5c885444b371535620c089dc7b92ddf8550edaa1983604051610c2891815260200190565b5f6001600160a01b03821633148061183c57506001600160a01b0382165f90815260036020908152604080832033845290915290205460ff165b611859576040516349e27cff60e01b815260040160405180910390fd5b6040516370a0823160e01b815284906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a08231906118a7908690600401612977565b602060405180830381865afa1580156118c2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118e69190612b96565b101561190557604051631e9acf1760e31b815260040160405180910390fd5b61190d611db1565b604051620bcc0d60e41b8152306004820152602481018690526001600160a01b0385811660448301528481166064830152336084830152919091169062bcc0d09060a4016020604051808303815f875af115801561196d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119919190612bd4565b6119ae576040516312ce515360e21b815260040160405180910390fd5b611a4d7f00000000000000000000000000000000000000000000000000000000000000008360015f9054906101000a90046001600160a01b03166001600160a01b0316634acbc0a96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a23573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a479190612c7e565b87612635565b5f826001600160a01b0316846001600160a01b03167fbb58420bb8ce44e11b84e214cc0de10ce5e7c24d0355b2815c3d758b514cae723388604051611a93929190612bad565b60405180910390a4505f9392505050565b335f90815260208190526040902054600114611ad35760405163ea8e4eb560e01b815260040160405180910390fd5b825f03611aea57611ae5848383611110565b611b63565b6040516304ade6db60e11b81526001600160a01b038381166004830152602482018590526044820183905285169063095bcdb6906064016020604051808303815f875af1158015611b3d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b619190612bd4565b505b50505050565b5f610ca98383336120e3565b5f6109d76103607f0000000000000000000000000000000000000000000000000000000000000000600a612d90565b5f610ca982610f79565b335f90815260208190526040902054600114611bdd5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b335f90815260208190526040902054600114611c4f5760405163ea8e4eb560e01b815260040160405180910390fd5b5f836001600160a01b03167fad23d6d908f14df9b90c8c580954f8a95c4a6e3261e49af08db21e6aaadcd1288484604051610a8c929190612bc6565b5f611c94611db1565b6001600160a01b0316631495d74f30846040518363ffffffff1660e01b8152600401610c6a929190612bef565b600480546040516308a44dc760e21b81525f926001600160a01b0390921691632291371c91610c6a913091879101612bef565b5f611cfe8261220d565b60048054604051636fe6a09760e11b81526001600160a01b039091169163dfcd412e91611d3391309189918991899101612c09565b6020604051808303815f875af1158015611d4f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d739190612b96565b9050816001600160a01b0316836001600160a01b0316336001600160a01b03165f516020612e8e5f395f51905f528785604051610944929190612bc6565b6004546001600160a01b031690565b611dc98161220d565b611dd1611db1565b6001600160a01b0316638c025bdc3083336040518463ffffffff1660e01b8152600401611e0093929190612b73565b5f604051808303815f87803b158015611e17575f5ffd5b505af1158015611e29573d5f5f3e3d5ffd5b505050505f816001600160a01b03167f4ae0134aad5d0e98e82f45680facd628ee6b5aa85ad9a85248a7ef47319f8c5033604051610c289190612977565b5f611e718261220d565b6004805460405163fea53be160e01b81526001600160a01b039091169163fea53be191611ea691309189918991899101612c09565b6020604051808303815f875af1158015611ec2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ee69190612b96565b9050816001600160a01b0316836001600160a01b0316336001600160a01b03165f516020612e8e5f395f51905f528488604051610944929190612bc6565b5f611f2d611db1565b6001600160a01b031663f2e586db30846040518363ffffffff1660e01b8152600401610acb929190612bef565b600154604051633e5541f160e01b81525f916001600160a01b031690633e5541f190610acb9030908690600401612bad565b600480546040516308c22e9b60e41b81525f926001600160a01b0390921691638c22e9b091610acb913091879101612bef565b335f90815260208190526040902054600114611fee5760405163ea8e4eb560e01b815260040160405180910390fd5b816636b0b730b3b2b960c91b0361201f57600180546001600160a01b0319166001600160a01b038316179055612074565b817130b9bcb731a932b232b2b6a6b0b730b3b2b960711b0361205b57600480546001600160a01b0319166001600160a01b038316179055612074565b604051633db0d5b960e01b815260040160405180910390fd5b817f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba826040516120a49190612977565b60405180910390a25050565b600480546040516395b734fb60e01b81525f926001600160a01b03909216916395b734fb91610acb913091879101612bef565b5f6120ed8261220d565b6120f5611db1565b6001600160a01b0316633a4d2cd1308686866040518563ffffffff1660e01b81526004016121269493929190612c09565b6020604051808303815f875af1158015612142573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121669190612b96565b9050826001600160a01b0316826001600160a01b03165f516020612eee5f395f51905f528387604051610e79929190612bc6565b5f610ca9826120b0565b5f6121ad611db1565b6001600160a01b0316636d7e837c30846040518363ffffffff1660e01b8152600401611580929190612bef565b60048054604051638ae5ecff60e01b81525f926001600160a01b0390921691638ae5ecff91610c6a913091879101612bef565b6001600160a01b03811633148061224657506001600160a01b0381165f90815260036020908152604080832033845290915290205460ff165b612263576040516336abb4df60e11b815260040160405180910390fd5b50565b5f61227082612780565b8061228b57506001600160e01b03198216631883ba3960e21b145b80610a1b57506001600160e01b0319821663e76cffc760e01b1492915050565b604080515f808252602082019092526001600160a01b0384169083906040516122d49190612d9e565b5f6040518083038185875af1925050503d805f811461230e576040519150601f19603f3d011682016040523d82523d5f602084013e612313565b606091505b505090508061116e57604051630d2fa21160e31b815260040160405180910390fd5b5f836001600160a01b03163b1161235f57604051633c11a9c560e21b815260040160405180910390fd5b5f5f846001600160a01b0316848460405160240161237e929190612bad565b60408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b179052516123b39190612d9e565b5f604051808303815f865af19150503d805f81146123ec576040519150601f19603f3d011682016040523d82523d5f602084013e6123f1565b606091505b509150915081801561241b57508051158061241b57508080602001905181019061241b9190612bd4565b6040805160048152602481019091526020810180516001600160e01b031663fb7f507960e01b179052869163a9059cbb60e01b91849161247b576040516390bfb86560e01b81526004016124729493929190612de2565b60405180910390fd5b505050505050505050565b5f6001600160a01b0384166124ae57604051632057875960e21b815260040160405180910390fd5b81516041036125465760208281015160408085015160608087015183515f8082529681018086528a9052951a928501839052840183905260808401819052919260019060a0016020604051602081039080840390855afa158015612514573d5f5f3e3d5ffd5b505050602060405103516001600160a01b0316876001600160a01b0316036125425760019350505050610ca9565b5050505b6001600160a01b0384163b15610ca9575f5f856001600160a01b03168585604051602401612575929190612e32565b60408051601f198184030181529181526020820180516001600160e01b0316630b135d3f60e11b179052516125aa9190612d9e565b5f60405180830381855afa9150503d805f81146125e2576040519150601f19603f3d011682016040523d82523d5f602084013e6125e7565b606091505b50915091508180156125fa575080516020145b801561262b57508051630b135d3f60e11b9061261f9083016020908101908401612e52565b6001600160e01b031916145b9695505050505050565b5f846001600160a01b03163b1161265f57604051633c11a9c560e21b815260040160405180910390fd5b5f5f856001600160a01b031685858560405160240161268093929190612c5a565b60408051601f198184030181529181526020820180516001600160e01b03166323b872dd60e01b179052516126b59190612d9e565b5f604051808303815f865af19150503d805f81146126ee576040519150601f19603f3d011682016040523d82523d5f602084013e6126f3565b606091505b509150915081801561271d57508051158061271d57508080602001905181019061271d9190612bd4565b6040805160048152602481019091526020810180516001600160e01b031663f405907160e01b17905287916323b872dd60e01b918491612774576040516390bfb86560e01b81526004016124729493929190612de2565b50505050505050505050565b5f6001600160e01b0319821663e3bc4e6560e01b14806127b057506001600160e01b031982166354f2843960e11b145b806127cb57506001600160e01b031982166378d77ecb60e01b145b806127e657506001600160e01b03198216632f0a18c560e01b145b80610a1b57506001600160e01b031982166301ffc9a760e01b1492915050565b6001600160a01b0381168114612263575f5ffd5b5f5f5f6060848603121561282c575f5ffd5b83359250602084013561283e81612806565b9150604084013561284e81612806565b809150509250925092565b6001600160e01b031981168114612263575f5ffd5b5f6020828403121561287e575f5ffd5b8135610ca981612859565b5f5f5f6060848603121561289b575f5ffd5b83356128a681612806565b95602085013595506040909401359392505050565b5f602082840312156128cb575f5ffd5b5035919050565b8015158114612263575f5ffd5b5f5f604083850312156128f0575f5ffd5b82356128fb81612806565b9150602083013561290b816128d2565b809150509250929050565b5f5f60408385031215612927575f5ffd5b82359150602083013561290b81612806565b5f5f5f6060848603121561294b575f5ffd5b833561295681612806565b9250602084013561296681612806565b929592945050506040919091013590565b6001600160a01b0391909116815260200190565b60208101600383106129ab57634e487b7160e01b5f52602160045260245ffd5b91905290565b5f602082840312156129c1575f5ffd5b8135610ca981612806565b5f5f604083850312156129dd575f5ffd5b82356129e881612806565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b5f5f5f5f5f5f60c08789031215612a1f575f5ffd5b8635612a2a81612806565b95506020870135612a3a81612806565b94506040870135612a4a816128d2565b9350606087013592506080870135915060a08701356001600160401b03811115612a72575f5ffd5b8701601f81018913612a82575f5ffd5b80356001600160401b03811115612a9b57612a9b6129f6565b604051601f8201601f19908116603f011681016001600160401b0381118282101715612ac957612ac96129f6565b6040528181528282016020018b1015612ae0575f5ffd5b816020840160208301375f602083830101528093505050509295509295509295565b5f5f5f5f60808587031215612b15575f5ffd5b8435612b2081612806565b9350602085013592506040850135612b3781612806565b9396929550929360600135925050565b5f5f60408385031215612b58575f5ffd5b8235612b6381612806565b9150602083013561290b81612806565b6001600160a01b0393841681529183166020830152909116604082015260600190565b5f60208284031215612ba6575f5ffd5b5051919050565b6001600160a01b03929092168252602082015260400190565b918252602082015260400190565b5f60208284031215612be4575f5ffd5b8151610ca9816128d2565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b5f60208284031215612c44575f5ffd5b81516001600160401b0381168114610ca9575f5ffd5b6001600160a01b039384168152919092166020820152604081019190915260600190565b5f60208284031215612c8e575f5ffd5b8151610ca981612806565b634e487b7160e01b5f52601160045260245ffd5b6001815b6001841115612ce857808504811115612ccc57612ccc612c99565b6001841615612cda57908102905b60019390931c928002612cb1565b935093915050565b5f82612cfe57506001610a1b565b81612d0a57505f610a1b565b8160018114612d205760028114612d2a57612d46565b6001915050610a1b565b60ff841115612d3b57612d3b612c99565b50506001821b610a1b565b5060208310610133831016604e8410600b8410161715612d69575081810a610a1b565b612d755f198484612cad565b805f1904821115612d8857612d88612c99565b029392505050565b5f610ca960ff841683612cf0565b5f82518060208501845e5f920191825250919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03851681526001600160e01b0319841660208201526080604082018190525f90612e1590830185612db4565b8281036060840152612e278185612db4565b979650505050505050565b828152604060208201525f612e4a6040830184612db4565b949350505050565b5f60208284031215612e62575f5ffd5b8151610ca98161285956feceb576d9f15e4e200fdb5096d64d5dfd667e16def20c1eefd14256d8e3faa267fbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db1fdc681a13d8c5da54e301c7ce6542dcde4581e4725043fdab2db12ddc574506a3efcf8cb518126a85cdfd1c1102ee539e0700189f80926e1ac37144450473fadcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7a2646970667358221220a80581730e05b85c38be7ffac68b1cd0a70cd2bef5c4fdeabf18328a8b0e579364736f6c634300081c003300000000000000000000000000000000000000000000000000010000000000060001000000000006000000000000000100000000000000000000000000000000000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e58310000000000000000000000008c213ee79581ff4984583c6a801e5263418c4b860000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f000000000000000000000000f06f89a1b6c601235729a689595571b7455dd433
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106102e8575f3560e01c8062a06d19146102ec57806301e1d1141461031257806301ffc9a71461031a5780630263704b1461033d57806307a2d13a146103525780630a28a477146103655780630d62c3321461037357806321f075ee14610387578063234f0e3b1461039a57806326c6f96c146103cd57806328f2930d146103e05780632b9d9c1f146104205780632cdfbae5146104335780632e2d2984146104465780633644e5151461045957806338d52e0f146104615780633e0dc34e146104955780633e8c5a70146104d4578063402d267d146104e2578063481c6a75146104f55780634b5fd666146105065780634cdad506146103655780634d44edeb1461051957806352aaead81461052c578063558a7297146105345780635f3e849f1461054757806365fae35e1461055a57806369d77a441461056d5780636e553f6514610580578063711b58ff1461059357806378d77ecb146105a65780637c1b50c4146105b95780637c9448f1146105cc5780637d41c86e146105df57806384ce2bf7146105f257806385b77f4514610605578063947b330a1461061857806394bf804d1461062b57806399530b061461063e578063995ea21a146106465780639c52a7f114610659578063a21ec79f1461066c578063a8d5fd651461067f578063aabb5922146106a6578063b04a5e05146106b9578063b3d7f6b914610365578063b460af94146106cc578063b6363cf2146106df578063b7570e0c1461070c578063b9cf063414610714578063ba08765214610727578063bf353dbb1461073a578063c63d75b614610759578063c6e6f5921461076c578063cd0d00961461077f578063cdf5bba3146107a6578063ce96cb77146107d3578063d4e8be83146107e6578063d905777e146107f9578063da39b3e71461080c578063eaed1d071461081f578063ebf0c71714610832578063ef8b30f714610365578063f15b65b114610859578063f5a23d8d1461086c575b5f5ffd5b6102ff6102fa36600461281a565b61087f565b6040519081526020015b60405180910390f35b6102ff610953565b61032d61032836600461286e565b6109dc565b6040519015158152602001610309565b61035061034b366004612889565b610a21565b005b6102ff6103603660046128bb565b610a99565b6102ff6102e83660046128bb565b6102ff5f516020612ece5f395f51905f5281565b6103506103953660046128df565b610b0a565b6103506103a83660046128bb565b335f90815260026020908152604080832093835292905220805460ff19166001179055565b6102ff6103db366004612916565b610c34565b6104077f000100000000000600000000000000010000000000000000000000000000000081565b6040516001600160801b03199091168152602001610309565b61035061042e366004612916565b610cb0565b610350610441366004612939565b610d53565b6102ff61045436600461281a565b610dc2565b6102ff610e88565b6104887f000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e583181565b6040516103099190612977565b6104bc7f000000000000000000000000000000000000000000000000000100000000000681565b6040516001600160401b039091168152602001610309565b5f604051610309919061298b565b6102ff6104f03660046129b1565b610f79565b6001546001600160a01b0316610488565b6103506105143660046129cc565b610faf565b600154610488906001600160a01b031681565b6104bc61101a565b61032d6105423660046128df565b611089565b610350610555366004612939565b611110565b6103506105683660046129b1565b61117e565b6102ff61057b36600461281a565b6111f1565b6102ff61058e366004612916565b6112ba565b61032d6105a1366004612a0a565b6112c6565b61032d6105b43660046129b1565b6114bc565b61032d6105c7366004612916565b61154d565b600454610488906001600160a01b031681565b6102ff6105ed36600461281a565b6115bf565b6103506106003660046129cc565b611797565b6102ff61061336600461281a565b611802565b610350610626366004612b02565b611aa4565b6102ff610639366004612916565b611b69565b6102ff611b75565b6102ff610654366004612916565b611ba4565b6103506106673660046129b1565b611bae565b61035061067a366004612889565b611c20565b6104887f0000000000000000000000008c213ee79581ff4984583c6a801e5263418c4b8681565b6102ff6106b4366004612916565b611c8b565b6102ff6106c7366004612916565b611cc1565b6102ff6106da36600461281a565b611cf4565b61032d6106ed366004612b47565b600360209081525f928352604080842090915290825290205460ff1681565b610488611db1565b610350610722366004612916565b611dc0565b6102ff61073536600461281a565b611e67565b6102ff6107483660046129b1565b5f6020819052908152604090205481565b6102ff6107673660046129b1565b611f24565b6102ff61077a3660046128bb565b611f5a565b6102ff7f000000000000000000000000000000000000000000000000000000000000a4b181565b61032d6107b43660046129cc565b600260209081525f928352604080842090915290825290205460ff1681565b6102ff6107e13660046129b1565b611f8c565b6103506107f4366004612916565b611fbf565b6102ff6108073660046129b1565b6120b0565b6102ff61081a36600461281a565b6120e3565b6102ff61082d366004612916565b61219a565b6104887f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f81565b61032d610867366004612916565b6121a4565b6102ff61087a366004612916565b6121da565b5f6108898261220d565b600480546040516311dcd79160e01b81526001600160a01b03909116916311dcd791916108bc9130918891889101612b73565b6020604051808303815f875af11580156108d8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108fc9190612b96565b90505f836001600160a01b0316836001600160a01b03167f9c133d4657dc9cd12f4c08cef86ef778dbbe03f3ad3b661ff14d36bc3febb1fb3385604051610944929190612bad565b60405180910390a49392505050565b5f6109d77f0000000000000000000000008c213ee79581ff4984583c6a801e5263418c4b866001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109b3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103609190612b96565b905090565b5f6001600160e01b03198216630ce3bbe560e41b1480610a0c57506001600160e01b03198216638bf840e360e01b145b80610a1b5750610a1b82612266565b92915050565b335f90815260208190526040902054600114610a505760405163ea8e4eb560e01b815260040160405180910390fd5b5f836001600160a01b03167f4dd5187225a2ae5f5ea35ca7b1732180f848cc4b6f7dce34b4c5e9f384d77dec8484604051610a8c929190612bc6565b60405180910390a3505050565b6001546040516350603df360e01b81525f916001600160a01b0316906350603df390610acb9030908690600401612bad565b602060405180830381865afa158015610ae6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a1b9190612b96565b6001600160a01b0382163303610b33576040516343588e5760e01b815260040160405180910390fd5b60405163854b89d560e01b81526001600160a01b037f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f169063854b89d590610b7f903390600401612977565b602060405180830381865afa158015610b9a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bbe9190612bd4565b610bdb5760405163175f16a160e01b815260040160405180910390fd5b6001600160a01b0382165f8181526003602090815260408083203380855290835292819020805460ff191686151590811790915590519081529192915f516020612e6e5f395f51905f5291015b60405180910390a35050565b5f610c3d611db1565b6001600160a01b03166337fb2bb830846040518363ffffffff1660e01b8152600401610c6a929190612bef565b602060405180830381865afa158015610c85573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ca99190612b96565b9392505050565b610cb98161220d565b60048054604051638b44deb160e01b81526001600160a01b0390911691638b44deb191610cec9130918691339101612b73565b5f604051808303815f87803b158015610d03575f5ffd5b505af1158015610d15573d5f5f3e3d5ffd5b505050505f816001600160a01b03167fa16c0f2cab616ed5d17cd544655b00d7062a1df7c457960cc8b9bf60770f923633604051610c289190612977565b335f90815260208190526040902054600114610d825760405163ea8e4eb560e01b815260040160405180910390fd5b5f826001600160a01b0316846001600160a01b03165f516020612eae5f395f51905f523385604051610db5929190612bad565b60405180910390a4505050565b5f610dcc8261220d565b610dd4611db1565b6001600160a01b031663c6f1649f308686866040518563ffffffff1660e01b8152600401610e059493929190612c09565b6020604051808303815f875af1158015610e21573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e459190612b96565b9050826001600160a01b0316826001600160a01b03165f516020612eee5f395f51905f528684604051610e79929190612bc6565b60405180910390a39392505050565b5f7f000000000000000000000000000000000000000000000000000000000000a4b14614610f545750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527fe416b338a274162320c79445ae6604141d1cb08275eb27011b69f002dc094d05828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b507fc2ebadbb37fa71bd3b258508d4823a00d5360fb9390d45d8b32c13947255135a90565b5f610f82611db1565b6001600160a01b0316637601687030846040518363ffffffff1660e01b8152600401610acb929190612bef565b335f90815260208190526040902054600114610fde5760405163ea8e4eb560e01b815260040160405180910390fd5b5f826001600160a01b03167fe60d0cd4e01ab7d1e0cf1917bddb6779ca8db0fb23138e3b7a4bab6a727b966183604051610c2891815260200190565b6001546040516308332b4560e11b81525f916001600160a01b031690631066568a9061104a903090600401612977565b602060405180830381865afa158015611065573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109d79190612c34565b5f6001600160a01b03831633036110b3576040516343588e5760e01b815260040160405180910390fd5b335f8181526003602090815260408083206001600160a01b03881680855290835292819020805460ff191687151590811790915590519081529192915f516020612e6e5f395f51905f52910160405180910390a350600192915050565b335f9081526020819052604090205460011461113f5760405163ea8e4eb560e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038416016111735761116e82826122ab565b505050565b61116e838383612335565b335f908152602081905260409020546001146111ad5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b5f6111fb8261220d565b611203611db1565b6001600160a01b03166372a2fcca3085856040518463ffffffff1660e01b815260040161123293929190612b73565b6020604051808303815f875af115801561124e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112729190612b96565b90505f836001600160a01b0316836001600160a01b03167f295a9a8b44c0ac92394b0da92ef469784ff064156f08dab8316760c064c6cd2f3385604051610944929190612bad565b5f610ca9838333610dc2565b5f856001600160a01b0316876001600160a01b0316036112f9576040516343588e5760e01b815260040160405180910390fd5b8242111561131a5760405163a899ef9360e01b815260040160405180910390fd5b6001600160a01b0387165f90815260026020908152604080832087845290915290205460ff161561135e57604051638d5b647d60e01b815260040160405180910390fd5b6001600160a01b0387165f9081526002602090815260408083208784529091528120805460ff19166001179055611393610e88565b604080515f516020612ece5f395f51905f5260208201526001600160a01b03808c16928201929092529089166060820152871515608082015260a0810187905260c0810186905260e0016040516020818303038152906040528051906020012060405160200161141a92919061190160f01b81526002810192909252602282015260420190565b60405160208183030381529060405280519060200120905061143d888285612486565b61145a57604051632ce87eeb60e01b815260040160405180910390fd5b6001600160a01b038881165f818152600360209081526040808320948c1680845294825291829020805460ff19168b151590811790915591519182525f516020612e6e5f395f51905f52910160405180910390a3506001979650505050505050565b604051630fa1e71360e41b81525f906001600160a01b037f0000000000000000000000008c213ee79581ff4984583c6a801e5263418c4b86169063fa1e71309061150e90849086908290600401612c5a565b602060405180830381865afa158015611529573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a1b9190612bd4565b6004805460405163010476c960e71b81525f926001600160a01b039092169163823b648091611580913091879101612bef565b602060405180830381865afa15801561159b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ca99190612bd4565b5f837f0000000000000000000000008c213ee79581ff4984583c6a801e5263418c4b866001600160a01b03166370a08231846040518263ffffffff1660e01b815260040161160d9190612977565b602060405180830381865afa158015611628573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061164c9190612b96565b101561166b57604051631e9acf1760e31b815260040160405180910390fd5b6001600160a01b0382165f90815260036020908152604080832033845290915281205460ff1661169b573361169d565b825b6004805460405163079731b960e51b81523092810192909252602482018890526001600160a01b03878116604484015286811660648401528084166084840152600160a4840152929350919091169063f2e637209060c4016020604051808303815f875af1158015611711573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117359190612bd4565b611752576040516303be524360e31b815260040160405180910390fd5b5f836001600160a01b0316856001600160a01b03165f516020612eae5f395f51905f523389604051611785929190612bad565b60405180910390a4505f949350505050565b335f908152602081905260409020546001146117c65760405163ea8e4eb560e01b815260040160405180910390fd5b5f826001600160a01b03167f0ede66e1b0b7bef549c7d3a5c885444b371535620c089dc7b92ddf8550edaa1983604051610c2891815260200190565b5f6001600160a01b03821633148061183c57506001600160a01b0382165f90815260036020908152604080832033845290915290205460ff165b611859576040516349e27cff60e01b815260040160405180910390fd5b6040516370a0823160e01b815284906001600160a01b037f000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e583116906370a08231906118a7908690600401612977565b602060405180830381865afa1580156118c2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118e69190612b96565b101561190557604051631e9acf1760e31b815260040160405180910390fd5b61190d611db1565b604051620bcc0d60e41b8152306004820152602481018690526001600160a01b0385811660448301528481166064830152336084830152919091169062bcc0d09060a4016020604051808303815f875af115801561196d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119919190612bd4565b6119ae576040516312ce515360e21b815260040160405180910390fd5b611a4d7f000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e58318360015f9054906101000a90046001600160a01b03166001600160a01b0316634acbc0a96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a23573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a479190612c7e565b87612635565b5f826001600160a01b0316846001600160a01b03167fbb58420bb8ce44e11b84e214cc0de10ce5e7c24d0355b2815c3d758b514cae723388604051611a93929190612bad565b60405180910390a4505f9392505050565b335f90815260208190526040902054600114611ad35760405163ea8e4eb560e01b815260040160405180910390fd5b825f03611aea57611ae5848383611110565b611b63565b6040516304ade6db60e11b81526001600160a01b038381166004830152602482018590526044820183905285169063095bcdb6906064016020604051808303815f875af1158015611b3d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b619190612bd4565b505b50505050565b5f610ca98383336120e3565b5f6109d76103607f0000000000000000000000000000000000000000000000000000000000000006600a612d90565b5f610ca982610f79565b335f90815260208190526040902054600114611bdd5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b335f90815260208190526040902054600114611c4f5760405163ea8e4eb560e01b815260040160405180910390fd5b5f836001600160a01b03167fad23d6d908f14df9b90c8c580954f8a95c4a6e3261e49af08db21e6aaadcd1288484604051610a8c929190612bc6565b5f611c94611db1565b6001600160a01b0316631495d74f30846040518363ffffffff1660e01b8152600401610c6a929190612bef565b600480546040516308a44dc760e21b81525f926001600160a01b0390921691632291371c91610c6a913091879101612bef565b5f611cfe8261220d565b60048054604051636fe6a09760e11b81526001600160a01b039091169163dfcd412e91611d3391309189918991899101612c09565b6020604051808303815f875af1158015611d4f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d739190612b96565b9050816001600160a01b0316836001600160a01b0316336001600160a01b03165f516020612e8e5f395f51905f528785604051610944929190612bc6565b6004546001600160a01b031690565b611dc98161220d565b611dd1611db1565b6001600160a01b0316638c025bdc3083336040518463ffffffff1660e01b8152600401611e0093929190612b73565b5f604051808303815f87803b158015611e17575f5ffd5b505af1158015611e29573d5f5f3e3d5ffd5b505050505f816001600160a01b03167f4ae0134aad5d0e98e82f45680facd628ee6b5aa85ad9a85248a7ef47319f8c5033604051610c289190612977565b5f611e718261220d565b6004805460405163fea53be160e01b81526001600160a01b039091169163fea53be191611ea691309189918991899101612c09565b6020604051808303815f875af1158015611ec2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ee69190612b96565b9050816001600160a01b0316836001600160a01b0316336001600160a01b03165f516020612e8e5f395f51905f528488604051610944929190612bc6565b5f611f2d611db1565b6001600160a01b031663f2e586db30846040518363ffffffff1660e01b8152600401610acb929190612bef565b600154604051633e5541f160e01b81525f916001600160a01b031690633e5541f190610acb9030908690600401612bad565b600480546040516308c22e9b60e41b81525f926001600160a01b0390921691638c22e9b091610acb913091879101612bef565b335f90815260208190526040902054600114611fee5760405163ea8e4eb560e01b815260040160405180910390fd5b816636b0b730b3b2b960c91b0361201f57600180546001600160a01b0319166001600160a01b038316179055612074565b817130b9bcb731a932b232b2b6a6b0b730b3b2b960711b0361205b57600480546001600160a01b0319166001600160a01b038316179055612074565b604051633db0d5b960e01b815260040160405180910390fd5b817f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba826040516120a49190612977565b60405180910390a25050565b600480546040516395b734fb60e01b81525f926001600160a01b03909216916395b734fb91610acb913091879101612bef565b5f6120ed8261220d565b6120f5611db1565b6001600160a01b0316633a4d2cd1308686866040518563ffffffff1660e01b81526004016121269493929190612c09565b6020604051808303815f875af1158015612142573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121669190612b96565b9050826001600160a01b0316826001600160a01b03165f516020612eee5f395f51905f528387604051610e79929190612bc6565b5f610ca9826120b0565b5f6121ad611db1565b6001600160a01b0316636d7e837c30846040518363ffffffff1660e01b8152600401611580929190612bef565b60048054604051638ae5ecff60e01b81525f926001600160a01b0390921691638ae5ecff91610c6a913091879101612bef565b6001600160a01b03811633148061224657506001600160a01b0381165f90815260036020908152604080832033845290915290205460ff165b612263576040516336abb4df60e11b815260040160405180910390fd5b50565b5f61227082612780565b8061228b57506001600160e01b03198216631883ba3960e21b145b80610a1b57506001600160e01b0319821663e76cffc760e01b1492915050565b604080515f808252602082019092526001600160a01b0384169083906040516122d49190612d9e565b5f6040518083038185875af1925050503d805f811461230e576040519150601f19603f3d011682016040523d82523d5f602084013e612313565b606091505b505090508061116e57604051630d2fa21160e31b815260040160405180910390fd5b5f836001600160a01b03163b1161235f57604051633c11a9c560e21b815260040160405180910390fd5b5f5f846001600160a01b0316848460405160240161237e929190612bad565b60408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b179052516123b39190612d9e565b5f604051808303815f865af19150503d805f81146123ec576040519150601f19603f3d011682016040523d82523d5f602084013e6123f1565b606091505b509150915081801561241b57508051158061241b57508080602001905181019061241b9190612bd4565b6040805160048152602481019091526020810180516001600160e01b031663fb7f507960e01b179052869163a9059cbb60e01b91849161247b576040516390bfb86560e01b81526004016124729493929190612de2565b60405180910390fd5b505050505050505050565b5f6001600160a01b0384166124ae57604051632057875960e21b815260040160405180910390fd5b81516041036125465760208281015160408085015160608087015183515f8082529681018086528a9052951a928501839052840183905260808401819052919260019060a0016020604051602081039080840390855afa158015612514573d5f5f3e3d5ffd5b505050602060405103516001600160a01b0316876001600160a01b0316036125425760019350505050610ca9565b5050505b6001600160a01b0384163b15610ca9575f5f856001600160a01b03168585604051602401612575929190612e32565b60408051601f198184030181529181526020820180516001600160e01b0316630b135d3f60e11b179052516125aa9190612d9e565b5f60405180830381855afa9150503d805f81146125e2576040519150601f19603f3d011682016040523d82523d5f602084013e6125e7565b606091505b50915091508180156125fa575080516020145b801561262b57508051630b135d3f60e11b9061261f9083016020908101908401612e52565b6001600160e01b031916145b9695505050505050565b5f846001600160a01b03163b1161265f57604051633c11a9c560e21b815260040160405180910390fd5b5f5f856001600160a01b031685858560405160240161268093929190612c5a565b60408051601f198184030181529181526020820180516001600160e01b03166323b872dd60e01b179052516126b59190612d9e565b5f604051808303815f865af19150503d805f81146126ee576040519150601f19603f3d011682016040523d82523d5f602084013e6126f3565b606091505b509150915081801561271d57508051158061271d57508080602001905181019061271d9190612bd4565b6040805160048152602481019091526020810180516001600160e01b031663f405907160e01b17905287916323b872dd60e01b918491612774576040516390bfb86560e01b81526004016124729493929190612de2565b50505050505050505050565b5f6001600160e01b0319821663e3bc4e6560e01b14806127b057506001600160e01b031982166354f2843960e11b145b806127cb57506001600160e01b031982166378d77ecb60e01b145b806127e657506001600160e01b03198216632f0a18c560e01b145b80610a1b57506001600160e01b031982166301ffc9a760e01b1492915050565b6001600160a01b0381168114612263575f5ffd5b5f5f5f6060848603121561282c575f5ffd5b83359250602084013561283e81612806565b9150604084013561284e81612806565b809150509250925092565b6001600160e01b031981168114612263575f5ffd5b5f6020828403121561287e575f5ffd5b8135610ca981612859565b5f5f5f6060848603121561289b575f5ffd5b83356128a681612806565b95602085013595506040909401359392505050565b5f602082840312156128cb575f5ffd5b5035919050565b8015158114612263575f5ffd5b5f5f604083850312156128f0575f5ffd5b82356128fb81612806565b9150602083013561290b816128d2565b809150509250929050565b5f5f60408385031215612927575f5ffd5b82359150602083013561290b81612806565b5f5f5f6060848603121561294b575f5ffd5b833561295681612806565b9250602084013561296681612806565b929592945050506040919091013590565b6001600160a01b0391909116815260200190565b60208101600383106129ab57634e487b7160e01b5f52602160045260245ffd5b91905290565b5f602082840312156129c1575f5ffd5b8135610ca981612806565b5f5f604083850312156129dd575f5ffd5b82356129e881612806565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b5f5f5f5f5f5f60c08789031215612a1f575f5ffd5b8635612a2a81612806565b95506020870135612a3a81612806565b94506040870135612a4a816128d2565b9350606087013592506080870135915060a08701356001600160401b03811115612a72575f5ffd5b8701601f81018913612a82575f5ffd5b80356001600160401b03811115612a9b57612a9b6129f6565b604051601f8201601f19908116603f011681016001600160401b0381118282101715612ac957612ac96129f6565b6040528181528282016020018b1015612ae0575f5ffd5b816020840160208301375f602083830101528093505050509295509295509295565b5f5f5f5f60808587031215612b15575f5ffd5b8435612b2081612806565b9350602085013592506040850135612b3781612806565b9396929550929360600135925050565b5f5f60408385031215612b58575f5ffd5b8235612b6381612806565b9150602083013561290b81612806565b6001600160a01b0393841681529183166020830152909116604082015260600190565b5f60208284031215612ba6575f5ffd5b5051919050565b6001600160a01b03929092168252602082015260400190565b918252602082015260400190565b5f60208284031215612be4575f5ffd5b8151610ca9816128d2565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b5f60208284031215612c44575f5ffd5b81516001600160401b0381168114610ca9575f5ffd5b6001600160a01b039384168152919092166020820152604081019190915260600190565b5f60208284031215612c8e575f5ffd5b8151610ca981612806565b634e487b7160e01b5f52601160045260245ffd5b6001815b6001841115612ce857808504811115612ccc57612ccc612c99565b6001841615612cda57908102905b60019390931c928002612cb1565b935093915050565b5f82612cfe57506001610a1b565b81612d0a57505f610a1b565b8160018114612d205760028114612d2a57612d46565b6001915050610a1b565b60ff841115612d3b57612d3b612c99565b50506001821b610a1b565b5060208310610133831016604e8410600b8410161715612d69575081810a610a1b565b612d755f198484612cad565b805f1904821115612d8857612d88612c99565b029392505050565b5f610ca960ff841683612cf0565b5f82518060208501845e5f920191825250919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03851681526001600160e01b0319841660208201526080604082018190525f90612e1590830185612db4565b8281036060840152612e278185612db4565b979650505050505050565b828152604060208201525f612e4a6040830184612db4565b949350505050565b5f60208284031215612e62575f5ffd5b8151610ca98161285956feceb576d9f15e4e200fdb5096d64d5dfd667e16def20c1eefd14256d8e3faa267fbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db1fdc681a13d8c5da54e301c7ce6542dcde4581e4725043fdab2db12ddc574506a3efcf8cb518126a85cdfd1c1102ee539e0700189f80926e1ac37144450473fadcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7a2646970667358221220a80581730e05b85c38be7ffac68b1cd0a70cd2bef5c4fdeabf18328a8b0e579364736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000010000000000060001000000000006000000000000000100000000000000000000000000000000000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e58310000000000000000000000008c213ee79581ff4984583c6a801e5263418c4b860000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f000000000000000000000000f06f89a1b6c601235729a689595571b7455dd433
-----Decoded View---------------
Arg [0] : poolId_ (uint64): 281474976710662
Arg [1] : scId_ (bytes16): 0x00010000000000060000000000000001
Arg [2] : asset_ (address): 0xaf88d065e77c8cC2239327C5EDb3A432268e5831
Arg [3] : token_ (address): 0x8c213ee79581Ff4984583C6a801e5263418C4b86
Arg [4] : root_ (address): 0x7Ed48C31f2fdC40d37407cBaBf0870B2b688368f
Arg [5] : manager_ (address): 0xf06f89A1b6C601235729A689595571B7455Dd433
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000001000000000006
Arg [1] : 0001000000000006000000000000000100000000000000000000000000000000
Arg [2] : 000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831
Arg [3] : 0000000000000000000000008c213ee79581ff4984583c6a801e5263418c4b86
Arg [4] : 0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f
Arg [5] : 000000000000000000000000f06f89a1b6c601235729a689595571b7455dd433
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.