Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 32901439 | 194 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SyncManager
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 {Auth} from "src/misc/Auth.sol";
import {D18} from "src/misc/types/D18.sol";
import {Recoverable} from "src/misc/Recoverable.sol";
import {CastLib} from "src/misc/libraries/CastLib.sol";
import {MathLib} from "src/misc/libraries/MathLib.sol";
import {BytesLib} from "src/misc/libraries/BytesLib.sol";
import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
import {PricingLib} from "src/common/libraries/PricingLib.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
import {IBalanceSheet} from "src/spoke/interfaces/IBalanceSheet.sol";
import {ISpoke, VaultDetails} from "src/spoke/interfaces/ISpoke.sol";
import {IUpdateContract} from "src/spoke/interfaces/IUpdateContract.sol";
import {UpdateContractMessageLib, UpdateContractType} from "src/spoke/libraries/UpdateContractMessageLib.sol";
import {IBaseVault} from "src/vaults/interfaces/IBaseVault.sol";
import {IDepositManager} from "src/vaults/interfaces/IVaultManagers.sol";
import {ISyncDepositManager} from "src/vaults/interfaces/IVaultManagers.sol";
import {ISyncManager, ISyncDepositValuation} from "src/vaults/interfaces/IVaultManagers.sol";
/// @title Sync Manager
/// @notice This is the main contract for synchronous ERC-4626 deposits.
contract SyncManager is Auth, Recoverable, ISyncManager {
using MathLib for *;
using CastLib for *;
using BytesLib for bytes;
using UpdateContractMessageLib for *;
ISpoke public spoke;
IBalanceSheet public balanceSheet;
mapping(PoolId => mapping(ShareClassId scId => ISyncDepositValuation)) public valuation;
mapping(PoolId => mapping(ShareClassId scId => mapping(address asset => mapping(uint256 tokenId => uint128))))
public maxReserve;
constructor(address deployer) Auth(deployer) {}
//----------------------------------------------------------------------------------------------
// Administration
//----------------------------------------------------------------------------------------------
/// @inheritdoc ISyncManager
function file(bytes32 what, address data) external auth {
if (what == "spoke") spoke = ISpoke(data);
else if (what == "balanceSheet") balanceSheet = IBalanceSheet(data);
else revert FileUnrecognizedParam();
emit File(what, data);
}
/// @inheritdoc IUpdateContract
function update(PoolId poolId, ShareClassId scId, bytes memory payload) external auth {
uint8 kind = uint8(UpdateContractMessageLib.updateContractType(payload));
if (kind == uint8(UpdateContractType.Valuation)) {
UpdateContractMessageLib.UpdateContractValuation memory m =
UpdateContractMessageLib.deserializeUpdateContractValuation(payload);
require(address(spoke.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());
setValuation(poolId, scId, m.valuation.toAddress());
} else if (kind == uint8(UpdateContractType.SyncDepositMaxReserve)) {
UpdateContractMessageLib.UpdateContractSyncDepositMaxReserve memory m =
UpdateContractMessageLib.deserializeUpdateContractSyncDepositMaxReserve(payload);
require(address(spoke.shareToken(poolId, scId)) != address(0), ShareTokenDoesNotExist());
(address asset, uint256 tokenId) = spoke.idToAsset(AssetId.wrap(m.assetId));
setMaxReserve(poolId, scId, asset, tokenId, m.maxReserve);
} else {
revert UnknownUpdateContractType();
}
}
/// @inheritdoc ISyncManager
function setValuation(PoolId poolId, ShareClassId scId, address valuation_) public auth {
valuation[poolId][scId] = ISyncDepositValuation(valuation_);
emit SetValuation(poolId, scId, address(valuation_));
}
/// @inheritdoc ISyncManager
function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve_)
public
auth
{
maxReserve[poolId][scId][asset][tokenId] = maxReserve_;
emit SetMaxReserve(poolId, scId, asset, tokenId, maxReserve_);
}
//----------------------------------------------------------------------------------------------
// Deposit handlers
//----------------------------------------------------------------------------------------------
/// @inheritdoc IDepositManager
function mint(IBaseVault vault_, uint256 shares, address receiver, address owner)
external
auth
returns (uint256 assets)
{
require(maxMint(vault_, owner) >= shares, ExceedsMaxMint());
assets = previewMint(vault_, owner, shares);
_issueShares(vault_, shares.toUint128(), receiver, assets.toUint128());
}
/// @inheritdoc IDepositManager
function deposit(IBaseVault vault_, uint256 assets, address receiver, address owner)
external
auth
returns (uint256 shares)
{
require(maxDeposit(vault_, owner) >= assets, ExceedsMaxDeposit());
shares = previewDeposit(vault_, owner, assets);
_issueShares(vault_, shares.toUint128(), receiver, assets.toUint128());
}
//----------------------------------------------------------------------------------------------
// View methods
//----------------------------------------------------------------------------------------------
/// @inheritdoc ISyncDepositManager
function previewMint(IBaseVault vault_, address, /* sender */ uint256 shares)
public
view
returns (uint256 assets)
{
return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Up);
}
/// @inheritdoc ISyncDepositManager
function previewDeposit(IBaseVault vault_, address, /* sender */ uint256 assets)
public
view
returns (uint256 shares)
{
return convertToShares(vault_, assets);
}
/// @inheritdoc IDepositManager
function maxMint(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {
VaultDetails memory vaultDetails = spoke.vaultDetails(vault_);
uint128 maxAssets =
_maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId, vault_);
return convertToShares(vault_, maxAssets);
}
/// @inheritdoc IDepositManager
function maxDeposit(IBaseVault vault_, address /* owner */ ) public view returns (uint256) {
VaultDetails memory vaultDetails = spoke.vaultDetails(vault_);
return _maxDeposit(vault_.poolId(), vault_.scId(), vaultDetails.asset, vaultDetails.tokenId, vault_);
}
/// @inheritdoc ISyncManager
function convertToShares(IBaseVault vault_, uint256 assets) public view returns (uint256 shares) {
VaultDetails memory vaultDetails = spoke.vaultDetails(vault_);
D18 poolPerShare = pricePoolPerShare(vault_.poolId(), vault_.scId());
D18 poolPerAsset = spoke.pricePoolPerAsset(vault_.poolId(), vault_.scId(), vaultDetails.assetId, true);
return poolPerShare.isZero()
? 0
: PricingLib.assetToShareAmount(
vault_.share(),
vaultDetails.asset,
vaultDetails.tokenId,
assets.toUint128(),
poolPerAsset,
poolPerShare,
MathLib.Rounding.Down
);
}
/// @inheritdoc ISyncManager
function convertToAssets(IBaseVault vault_, uint256 shares) public view returns (uint256 assets) {
return _shareToAssetAmount(vault_, shares, MathLib.Rounding.Down);
}
/// @inheritdoc ISyncDepositValuation
function pricePoolPerShare(PoolId poolId, ShareClassId scId) public view returns (D18 price) {
ISyncDepositValuation valuation_ = valuation[poolId][scId];
if (address(valuation_) == address(0)) {
price = spoke.pricePoolPerShare(poolId, scId, true);
} else {
price = valuation_.pricePoolPerShare(poolId, scId);
}
}
//----------------------------------------------------------------------------------------------
// Internal
//----------------------------------------------------------------------------------------------
/// @dev Issues shares to the receiver and instruct the balance sheet
// to react on the issuance and the updated holding.
function _issueShares(IBaseVault vault_, uint128 shares, address receiver, uint128 assets) internal {
PoolId poolId = vault_.poolId();
ShareClassId scId = vault_.scId();
VaultDetails memory vaultDetails = spoke.vaultDetails(vault_);
// Note deposit into the pool escrow, to make assets available for managers of the balance sheet.
// ERC-20 transfer is handled by the vault to the pool escrow afterwards.
balanceSheet.noteDeposit(poolId, scId, vaultDetails.asset, vaultDetails.tokenId, assets);
// Mint shares to the receiver.
balanceSheet.overridePricePoolPerShare(poolId, scId, pricePoolPerShare(poolId, scId));
balanceSheet.issue(poolId, scId, receiver, shares);
balanceSheet.resetPricePoolPerShare(poolId, scId);
}
function _maxDeposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, IBaseVault vault_)
internal
view
returns (uint128 maxDeposit_)
{
if (!spoke.isLinked(vault_)) return 0;
uint128 availableBalance = balanceSheet.availableBalanceOf(poolId, scId, asset, tokenId);
uint128 maxReserve_ = maxReserve[poolId][scId][asset][tokenId];
if (maxReserve_ < availableBalance) {
maxDeposit_ = 0;
} else {
maxDeposit_ = maxReserve_ - availableBalance;
}
}
function _shareToAssetAmount(IBaseVault vault_, uint256 shares, MathLib.Rounding rounding)
internal
view
returns (uint256 assets)
{
VaultDetails memory vaultDetails = spoke.vaultDetails(vault_);
D18 poolPerShare = pricePoolPerShare(vault_.poolId(), vault_.scId());
D18 poolPerAsset = spoke.pricePoolPerAsset(vault_.poolId(), vault_.scId(), vaultDetails.assetId, true);
return poolPerAsset.isZero()
? 0
: PricingLib.shareToAssetAmount(
vault_.share(),
shares.toUint128(),
vaultDetails.asset,
vaultDetails.tokenId,
poolPerShare,
poolPerAsset,
rounding
);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {IAuth} from "src/misc/interfaces/IAuth.sol";
/// @title Auth
/// @notice Simple authentication pattern
/// @author Based on code from https://github.com/makerdao/dss
abstract contract Auth is IAuth {
/// @inheritdoc IAuth
mapping(address => uint256) public wards;
constructor(address initialWard) {
wards[initialWard] = 1;
emit Rely(initialWard);
}
/// @dev Check if the msg.sender has permissions
modifier auth() {
require(wards[msg.sender] == 1, NotAuthorized());
_;
}
/// @inheritdoc IAuth
function rely(address user) public auth {
wards[user] = 1;
emit Rely(user);
}
/// @inheritdoc IAuth
function deny(address user) public auth {
wards[user] = 0;
emit Deny(user);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
// Small library to handle fixed point number operations with 18 decimals with static typing support.
import {MathLib} from "src/misc/libraries/MathLib.sol";
type D18 is uint128;
using MathLib for uint256;
/// @dev add two D18 types
function add(D18 d1, D18 d2) pure returns (D18) {
return D18.wrap(D18.unwrap(d1) + D18.unwrap(d2));
}
/// @dev substract two D18 types
function sub(D18 d1, D18 d2) pure returns (D18) {
return D18.wrap(D18.unwrap(d1) - D18.unwrap(d2));
}
/// @dev Divides one D18 by another one while retaining precision:
/// - nominator (decimal): 50e18
/// - denominator (decimal): 2e19
/// - result (decimal): 25e17
function divD18(D18 d1, D18 d2) pure returns (D18) {
return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), 1e18, D18.unwrap(d2)).toUint128());
}
/// @dev Multiplies one D18 with another one while retaining precision:
/// - value1 (decimal): 50e18
/// - value2 (decimal): 2e19
/// - result (decimal): 100e19
function mulD18(D18 d1, D18 d2) pure returns (D18) {
return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), D18.unwrap(d2), 1e18).toUint128());
}
/// @dev Returns the reciprocal of a D18 decimal, i.e. 1 / d.
/// Example: if d = 2.0 (2e18 internally), reciprocal(d) = 0.5 (5e17 internally).
function reciprocal(D18 d) pure returns (D18) {
uint128 val = D18.unwrap(d);
require(val != 0, "D18/division-by-zero");
return d18(1e18, val);
}
/// @dev Multiplies a decimal by an integer. i.e:
/// - d (decimal): 1_500_000_000_000_000_000
/// - value (integer): 4_000_000_000_000_000_000
/// - result (integer): 6_000_000_000_000_000_000
function mulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {
return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding).toUint128();
}
/// @dev Multiplies a decimal by an integer. i.e:
/// - d (decimal): 1_500_000_000_000_000_000
/// - value (integer): 4_000_000_000_000_000_000
/// - result (integer): 6_000_000_000_000_000_000
function mulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {
return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding);
}
/// @dev Divides an integer by a decimal, i.e.
/// @dev Same as mulDiv for integers, i.e:
/// - d (decimal): 2_000_000_000_000_000_000
/// - value (integer): 100_000_000_000_000_000_000
/// - result (integer): 50_000_000_000_000_000_000
function reciprocalMulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {
return MathLib.mulDiv(value, 1e18, d.raw(), rounding).toUint128();
}
/// @dev Divides an integer by a decimal, i.e.
/// @dev Same as mulDiv for integers, i.e:
/// - d (decimal): 2_000_000_000_000_000_000
/// - value (integer): 100_000_000_000_000_000_000
/// - result (integer): 50_000_000_000_000_000_000
function reciprocalMulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {
return MathLib.mulDiv(value, 1e18, d.raw(), rounding);
}
/// @dev Easy way to construct a decimal number
function d18(uint128 value) pure returns (D18) {
return D18.wrap(value);
}
/// @dev Easy way to construct a decimal number
function d18(uint128 num, uint128 den) pure returns (D18) {
return D18.wrap(MathLib.mulDiv(num, 1e18, den).toUint128());
}
function eq(D18 a, D18 b) pure returns (bool) {
return D18.unwrap(a) == D18.unwrap(b);
}
function isZero(D18 a) pure returns (bool) {
return D18.unwrap(a) == 0;
}
function isNotZero(D18 a) pure returns (bool) {
return D18.unwrap(a) != 0;
}
function raw(D18 d) pure returns (uint128) {
return D18.unwrap(d);
}
using {
add as +,
sub as -,
divD18 as /,
eq,
mulD18 as *,
mulUint128,
mulUint256,
reciprocalMulUint128,
reciprocalMulUint256,
reciprocal,
raw,
isZero,
isNotZero
} for D18 global;// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {Auth} from "src/misc/Auth.sol";
import {IERC6909} from "src/misc/interfaces/IERC6909.sol";
import {SafeTransferLib} from "src/misc/libraries/SafeTransferLib.sol";
import {IRecoverable, ETH_ADDRESS} from "src/misc/interfaces/IRecoverable.sol";
abstract contract Recoverable is Auth, IRecoverable {
/// @inheritdoc IRecoverable
function recoverTokens(address token, address receiver, uint256 amount) public auth {
if (token == ETH_ADDRESS) {
SafeTransferLib.safeTransferETH(receiver, amount);
} else {
SafeTransferLib.safeTransfer(token, receiver, amount);
}
}
/// @inheritdoc IRecoverable
function recoverTokens(address token, uint256 tokenId, address receiver, uint256 amount) external auth {
if (tokenId == 0) {
recoverTokens(token, receiver, amount);
} else {
IERC6909(token).transfer(receiver, tokenId, amount);
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
/// @title CastLib
library CastLib {
function toAddressLeftPadded(bytes32 addr) internal pure returns (address) {
require(bytes12(addr) == 0, "First 12 bytes should be zero");
return address(uint160(uint256(addr)));
}
function toBytes32LeftPadded(address addr) internal pure returns (bytes32) {
return bytes32(uint256(uint160(addr)));
}
function toAddress(bytes32 addr) internal pure returns (address) {
require(uint96(uint256(addr)) == 0, "Input should be 20 bytes");
return address(bytes20(addr));
}
function toBytes32(address addr) internal pure returns (bytes32) {
return bytes32(bytes20(addr));
}
/// @dev Adds zero padding
function toBytes32(string memory source) internal pure returns (bytes32) {
return bytes32(bytes(source));
}
/// @dev Removes zero padding
function bytes128ToString(bytes memory _bytes128) internal pure returns (string memory) {
require(_bytes128.length == 128, "Input should be 128 bytes");
uint8 i = 0;
while (i < 128 && _bytes128[i] != 0) {
i++;
}
bytes memory bytesArray = new bytes(i);
for (uint8 j; j < i; j++) {
bytesArray[j] = _bytes128[j];
}
return string(bytesArray);
}
function toString(bytes32 _bytes32) internal pure returns (string memory) {
uint8 i = 0;
while (i < 32 && _bytes32[i] != 0) {
i++;
}
bytes memory bytesArray = new bytes(i);
for (i = 0; i < 32 && _bytes32[i] != 0; i++) {
bytesArray[i] = _bytes32[i];
}
return string(bytesArray);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
library MathLib {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
error MulDiv_Overflow();
error Uint8_Overflow();
error Uint32_Overflow();
error Uint64_Overflow();
error Uint128_Overflow();
error Int128_Overflow();
uint256 public constant One27 = 10 ** 27;
/// @notice Returns x^n with rounding precision of base
///
/// @dev Source: https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/jug.sol#L62
///
/// @param x The base value which should be exponentiated
/// @param n The exponent
/// @param base The scaling base, typically used for fix-point calculations
function rpow(uint256 x, uint256 n, uint256 base) public pure returns (uint256 z) {
assembly {
switch x
case 0 {
switch n
case 0 { z := base }
default { z := 0 }
}
default {
switch mod(n, 2)
case 0 { z := base }
default { z := x }
let half := div(base, 2) // for rounding.
for { n := div(n, 2) } n { n := div(n, 2) } {
let xx := mul(x, x)
if iszero(eq(div(xx, x), x)) { revert(0, 0) }
let xxRound := add(xx, half)
if lt(xxRound, xx) { revert(0, 0) }
x := div(xxRound, base)
if mod(n, 2) {
let zx := mul(z, x)
if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) }
let zxRound := add(zx, half)
if lt(zxRound, zx) { revert(0, 0) }
z := div(zxRound, base)
}
}
}
}
}
/// @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
/// denominator == 0
/// @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
/// with further edits by Uniswap Labs also under MIT license.
// slither-disable-start divide-before-multiply
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, MulDiv_Overflow());
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
// slither-disable-end divide-before-multiply
/// @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/// @notice Safe type conversion from uint256 to uint8.
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, Uint8_Overflow());
return uint8(value);
}
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, Uint32_Overflow());
return uint32(value);
}
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, Uint64_Overflow());
return uint64(value);
}
/// @notice Safe type conversion from uint256 to uint128.
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, Uint128_Overflow());
return uint128(value);
}
/// @notice Returns the smallest of two numbers.
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? b : a;
}
/// @notice Returns the largest of two numbers.
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
/// @title Bytes Lib
/// @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
/// The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
/// @author Modified from Solidity Bytes Arrays Utils v0.8.0
library BytesLib {
error SliceOverflow();
error SliceOutOfBounds();
function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {
unchecked {
require(_length + 31 >= _length, SliceOverflow());
}
require(_bytes.length >= _start + _length, SliceOutOfBounds());
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)
// The first word of the slice result is potentially a partial
// word read from the original array. To read it, we calculate
// the length of that partial word and start copying that many
// bytes into the array. The first word we copy will start with
// data we don't care about, but the last `lengthmod` bytes will
// land at the beginning of the contents of the new array. When
// we're done copying, we overwrite the full first word with
// the actual length of the slice.
let lengthmod := and(_length, 31)
// The multiplication in the next line is necessary
// because when slicing multiples of 32 bytes (lengthmod == 0)
// the following copy loop was copying the origin's length
// and then ending prematurely not copying everything it should.
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
// The multiplication in the next line has the same exact purpose
// as the one above.
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} { mstore(mc, mload(cc)) }
mstore(tempBytes, _length)
//update free-memory pointer
//allocating the array padded to 32 bytes like the compiler does now
mstore(0x40, and(add(mc, 31), not(31)))
}
//if we want a zero-length slice let's just return a zero-length array
default {
tempBytes := mload(0x40)
//zero out the 32 bytes slice we are about to return
//we need to do it because Solidity does not garbage collect
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function sliceZeroPadded(bytes memory _bytes, uint256 _start, uint256 _length)
internal
pure
returns (bytes memory)
{
bool needsPad = _bytes.length < _start + _length;
if (!needsPad) return slice(_bytes, _start, _length);
bytes memory slice_ = slice(_bytes, _start, _bytes.length - _start);
bytes memory padding = new bytes(_length + _start - _bytes.length);
return bytes.concat(slice_, padding);
}
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_bytes.length >= _start + 20, SliceOutOfBounds());
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
require(_bytes.length >= _start + 1, SliceOutOfBounds());
uint8 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x1), _start))
}
return tempUint;
}
function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
require(_bytes.length >= _start + 2, SliceOutOfBounds());
uint16 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x2), _start))
}
return tempUint;
}
function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
require(_bytes.length >= _start + 4, SliceOutOfBounds());
uint32 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x4), _start))
}
return tempUint;
}
function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
require(_bytes.length >= _start + 8, SliceOutOfBounds());
uint64 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x8), _start))
}
return tempUint;
}
function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
require(_bytes.length >= _start + 16, SliceOutOfBounds());
uint128 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x10), _start))
}
return tempUint;
}
function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
require(_bytes.length >= _start + 32, SliceOutOfBounds());
uint256 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x20), _start))
}
return tempUint;
}
function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
require(_bytes.length >= _start + 32, SliceOutOfBounds());
bytes32 tempBytes32;
assembly {
tempBytes32 := mload(add(add(_bytes, 0x20), _start))
}
return tempBytes32;
}
function toBytes16(bytes memory _bytes, uint256 _start) internal pure returns (bytes16) {
require(_bytes.length >= _start + 16, SliceOutOfBounds());
bytes16 tempBytes16;
assembly {
tempBytes16 := mload(add(add(_bytes, 0x20), _start))
}
return tempBytes16;
}
function toBool(bytes memory _bytes, uint256 _start) internal pure returns (bool) {
require(_bytes.length > _start, SliceOutOfBounds());
return _bytes[_start] != 0;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {MathLib} from "src/misc/libraries/MathLib.sol";
using MathLib for uint256;
type PoolId is uint64;
function centrifugeId(PoolId poolId) pure returns (uint16) {
return uint16(PoolId.unwrap(poolId) >> 48);
}
function newPoolId(uint16 centrifugeId_, uint48 localPoolId) pure returns (PoolId) {
return PoolId.wrap((uint64(centrifugeId_) << 48) | uint64(localPoolId));
}
function isNull(PoolId poolId) pure returns (bool) {
return PoolId.unwrap(poolId) == 0;
}
function isEqual(PoolId a, PoolId b) pure returns (bool) {
return PoolId.unwrap(a) == PoolId.unwrap(b);
}
function raw(PoolId poolId) pure returns (uint64) {
return PoolId.unwrap(poolId);
}
using {centrifugeId, isNull, raw, isEqual as ==} for PoolId global;// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
/// @dev Composite Id of the centrifugeId (uint16) where the asset resides
/// and a local counter (uint64) that is part of the contract that registers the asset.
type AssetId is uint128;
function isNull(AssetId assetId) pure returns (bool) {
return AssetId.unwrap(assetId) == 0;
}
function raw(AssetId assetId) pure returns (uint128) {
return AssetId.unwrap(assetId);
}
function centrifugeId(AssetId assetId) pure returns (uint16) {
return uint16(AssetId.unwrap(assetId) >> 112);
}
function newAssetId(uint16 centrifugeId_, uint64 counter) pure returns (AssetId) {
return AssetId.wrap((uint128(centrifugeId_) << 112) + counter);
}
function newAssetId(uint32 isoCode) pure returns (AssetId) {
return AssetId.wrap(isoCode);
}
function eq(AssetId a, AssetId b) pure returns (bool) {
return a.raw() == b.raw();
}
using {isNull, raw, centrifugeId, eq} for AssetId global;// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {D18, d18} from "src/misc/types/D18.sol";
import {MathLib} from "src/misc/libraries/MathLib.sol";
import {IERC20Metadata} from "src/misc/interfaces/IERC20.sol";
import {IERC6909MetadataExt} from "src/misc/interfaces/IERC6909.sol";
import {PricingLib} from "src/common/libraries/PricingLib.sol";
library PricingLib {
using MathLib for *;
/// @dev Prices are fixed-point integers with 18 decimals
uint8 internal constant PRICE_DECIMALS = 18;
//----------------------------------------------------------------------------------------------
// View methods
//----------------------------------------------------------------------------------------------
/// @dev Converts the given asset amount to share amount. Returned value is in share decimals.
/// @dev Assumes handling of zero denominator price (priceAssetPerShare_) by consumer.
///
/// NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from
/// Fulfilled* message amounts. Any other codepath must use the variant with pricePoolPerAsset
/// and pricePoolPerShare
function assetToShareAmount(
address shareToken,
address asset,
uint256 tokenId,
uint128 assetAmount,
D18 priceAssetPerShare_,
MathLib.Rounding rounding
) internal view returns (uint128 shares) {
if (assetAmount == 0) {
return 0;
}
uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
uint8 shareDecimals = IERC20Metadata(shareToken).decimals();
return PricingLib.convertWithReciprocalPrice(
assetAmount, assetDecimals, shareDecimals, priceAssetPerShare_, rounding
).toUint128();
}
/// @dev Converts the given asset amount to share amount. Returned value is in share decimals.
/// @dev Assumes handling of zero denominator price (pricePoolPerShare) by consumer.
function assetToShareAmount(
address shareToken,
address asset,
uint256 tokenId,
uint128 assetAmount,
D18 pricePoolPerAsset,
D18 pricePoolPerShare,
MathLib.Rounding rounding
) internal view returns (uint128 shares) {
if (assetAmount == 0 || pricePoolPerAsset.isZero()) {
return 0;
}
uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
uint8 shareDecimals = IERC20Metadata(shareToken).decimals();
return PricingLib.assetToShareAmount(
assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, pricePoolPerShare, rounding
).toUint128();
}
/// @dev Converts the given share amount to asset amount. Returned value is in share decimals.
///
/// NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from
/// Fulfilled* message amounts. Any other codepath must use the variant with pricePoolPerAsset and
/// pricePoolPerShare
function shareToAssetAmount(
address shareToken,
uint128 shareAmount,
address asset,
uint256 tokenId,
D18 priceAssetPerShare_,
MathLib.Rounding rounding
) internal view returns (uint128 assets) {
if (shareAmount == 0 || priceAssetPerShare_.isZero()) {
return 0;
}
uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
uint8 shareDecimals = IERC20Metadata(shareToken).decimals();
return PricingLib.convertWithPrice(shareAmount, shareDecimals, assetDecimals, priceAssetPerShare_, rounding);
}
/// @dev Converts the given share amount to asset amount. Returned value is in share decimals.
/// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
function shareToAssetAmount(
address shareToken,
uint128 shareAmount,
address asset,
uint256 tokenId,
D18 pricePoolPerShare,
D18 pricePoolPerAsset,
MathLib.Rounding rounding
) internal view returns (uint128 shares) {
if (shareAmount == 0 || pricePoolPerShare.isZero()) {
return 0;
}
uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
uint8 shareDecimals = IERC20Metadata(shareToken).decimals();
// NOTE: Pool and share denomination are always equal by design
return PricingLib.shareToAssetAmount(
shareAmount, shareDecimals, assetDecimals, pricePoolPerShare, pricePoolPerAsset, rounding
).toUint128();
}
/// @dev Calculates the asset price per share returns the value in price decimals
/// Denominated in ASSET_UNIT/SHARE_UNIT
/// @dev Assumes handling of zero denominator (shares == 0) by consumer.
function calculatePriceAssetPerShare(
address shareToken,
uint128 shares,
address asset,
uint256 tokenId,
uint128 assets,
MathLib.Rounding rounding
) internal view returns (D18 priceAssetPerShare_) {
if (assets == 0) {
return d18(0);
}
uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
uint8 shareDecimals = IERC20Metadata(shareToken).decimals();
// NOTE: More precise than utilizing D18
return d18(
_toPriceDecimals(assets, assetDecimals).mulDiv(
10 ** PRICE_DECIMALS, _toPriceDecimals(shares, shareDecimals), rounding
).toUint128()
);
}
//----------------------------------------------------------------------------------------------
// Pure methods
//----------------------------------------------------------------------------------------------
/// @dev Converts an amount using decimals and price with implicit rounding down
function convertWithPrice(uint256 baseAmount, uint8 baseDecimals, uint8 quoteDecimals, D18 priceQuotePerBase)
internal
pure
returns (uint128 quoteAmount)
{
return convertWithPrice(baseAmount, baseDecimals, quoteDecimals, priceQuotePerBase, MathLib.Rounding.Down);
}
/// @dev Converts an amount using decimals and price with explicit rounding.
function convertWithPrice(
uint256 baseAmount,
uint8 baseDecimals,
uint8 quoteDecimals,
D18 priceQuotePerBase,
MathLib.Rounding rounding
) internal pure returns (uint128 quoteAmount) {
if (baseDecimals == quoteDecimals) {
return priceQuotePerBase.mulUint256(baseAmount, rounding).toUint128();
}
return MathLib.mulDiv(
priceQuotePerBase.raw(), baseAmount * 10 ** quoteDecimals, 10 ** (baseDecimals + PRICE_DECIMALS), rounding
) // cancel out exponentiation from D18 multiplication
.toUint128();
}
/// @dev Converts an amount using decimals and reciprocal price.
/// @dev Assumes handling of zero denominator price (priceBasePerQuote) by consumer.
///
/// NOTE: More precise than convertWithPrice(,,,price.reciprocal,)
function convertWithReciprocalPrice(
uint256 baseAmount,
uint8 baseDecimals,
uint8 quoteDecimals,
D18 priceBasePerQuote,
MathLib.Rounding rounding
) internal pure returns (uint128 quoteAmount) {
require(priceBasePerQuote.isNotZero(), "PricingLib/division-by-zero");
if (baseDecimals == quoteDecimals) {
return priceBasePerQuote.reciprocalMulUint256(baseAmount, rounding).toUint128();
}
return MathLib.mulDiv(
10 ** quoteDecimals * baseAmount,
10 ** PRICE_DECIMALS,
10 ** baseDecimals * priceBasePerQuote.raw(),
rounding
).toUint128();
}
/// @dev Converts an amount using decimals and two prices.
/// @dev Assumes handling of zero denominator price (priceDenominator) by consumer.
///
/// NOTE: More precise than custom math with one price and convertWith{Reciprocal}Price for the other
function convertWithPrices(
uint256 baseAmount,
uint8 baseDecimals,
uint8 quoteDecimals,
D18 priceNumerator,
D18 priceDenominator,
MathLib.Rounding rounding
) internal pure returns (uint128 quoteAmount) {
require(priceDenominator.isNotZero(), "PricingLib/division-by-zero");
return MathLib.mulDiv(
priceNumerator.raw(),
10 ** quoteDecimals * baseAmount,
10 ** baseDecimals * priceDenominator.raw(),
rounding
).toUint128();
}
/// @dev Converts asset amount to share amount.
/// @dev Assumes handling of zero denominator price (pricePoolPerShare) by consumer.
///
/// NOTE: Pool and share denomination are always equal by design
function assetToShareAmount(
uint256 assetAmount,
uint8 assetDecimals,
uint8 shareDecimals,
D18 pricePoolPerAsset,
D18 pricePoolPerShare,
MathLib.Rounding rounding
) internal pure returns (uint128 shareAmount) {
return
convertWithPrices(assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, pricePoolPerShare, rounding);
}
/// @dev Converts share amount to asset asset amount.
/// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
///
/// NOTE: Pool and share denomination are always equal by design
function shareToAssetAmount(
uint256 shareAmount,
uint8 shareDecimals,
uint8 assetDecimals,
D18 pricePoolPerShare,
D18 pricePoolPerAsset,
MathLib.Rounding rounding
) internal pure returns (uint128 assetAmount) {
return
convertWithPrices(shareAmount, shareDecimals, assetDecimals, pricePoolPerShare, pricePoolPerAsset, rounding);
}
/// @dev Converts pool amount to asset amount.
/// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
function poolToAssetAmount(
uint256 poolAmount,
uint8 poolDecimals,
uint8 assetDecimals,
D18 pricePoolPerAsset,
MathLib.Rounding rounding
) internal pure returns (uint128 assetAmount) {
return convertWithReciprocalPrice(poolAmount, poolDecimals, assetDecimals, pricePoolPerAsset, rounding);
}
/// @dev Converts asset amount to pool amount.
function assetToPoolAmount(
uint128 assetAmount,
uint8 assetDecimals,
uint8 poolDecimals,
D18 pricePoolPerAsset,
MathLib.Rounding rounding
) internal pure returns (uint128 poolAmount) {
return convertWithPrice(assetAmount, assetDecimals, poolDecimals, pricePoolPerAsset, rounding);
}
/// @dev Returns the asset price per share denominated in ASSET_UNIT/SHARE_UNIT
/// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
///
/// NOTE: Should never be used for calculating amounts due to precision loss. Instead, please refer to
/// conversion relying on pricePoolPerShare and pricePoolPerAsset.
function priceAssetPerShare(D18 pricePoolPerShare, D18 pricePoolPerAsset)
internal
pure
returns (D18 priceAssetPerShare_)
{
return pricePoolPerShare / pricePoolPerAsset;
}
//----------------------------------------------------------------------------------------------
// Private methods
//----------------------------------------------------------------------------------------------
/// @dev Returns the asset decimals
function _getAssetDecimals(address asset, uint256 tokenId) private view returns (uint8 assetDecimals) {
return tokenId == 0 ? IERC20Metadata(asset).decimals() : IERC6909MetadataExt(asset).decimals(tokenId);
}
/// @dev When converting assets to shares using the price, all values are normalized to PRICE_DECIMALS
/// NOTE: We require all assets to have 2 <= decimals <= 18, see `Spoke.registerAsset`
function _toPriceDecimals(uint128 _value, uint8 decimals) private pure returns (uint256) {
if (PRICE_DECIMALS == decimals) return uint256(_value);
return uint256(_value) * 10 ** (PRICE_DECIMALS - decimals);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {PoolId} from "src/common/types/PoolId.sol";
type ShareClassId is bytes16;
function isNull(ShareClassId scId) pure returns (bool) {
return ShareClassId.unwrap(scId) == 0;
}
function equals(ShareClassId left, ShareClassId right) pure returns (bool) {
return ShareClassId.unwrap(left) == ShareClassId.unwrap(right);
}
function raw(ShareClassId scId) pure returns (bytes16) {
return ShareClassId.unwrap(scId);
}
function newShareClassId(PoolId poolId, uint32 index) pure returns (ShareClassId scId) {
return ShareClassId.wrap(bytes16((uint128(PoolId.unwrap(poolId)) << 64) + index));
}
using {isNull, raw, equals as ==} for ShareClassId global;// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {D18} from "src/misc/types/D18.sol";
import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
import {IRoot} from "src/common/interfaces/IRoot.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
import {IPoolEscrow} from "src/common/interfaces/IPoolEscrow.sol";
import {ISpokeMessageSender} from "src/common/interfaces/IGatewaySenders.sol";
import {IPoolEscrowProvider} from "src/common/factories/interfaces/IPoolEscrowFactory.sol";
import {ISpoke} from "src/spoke/interfaces/ISpoke.sol";
struct ShareQueueAmount {
// Net queued shares
uint128 delta;
// Whether the net queued shares lead to an issuance or revocation
bool isPositive;
// Number of queued asset IDs for this share class
uint32 queuedAssetCounter;
// Nonce for share + asset messages to the hub
uint64 nonce;
}
struct AssetQueueAmount {
uint128 deposits;
uint128 withdrawals;
}
interface IBalanceSheet {
// --- Events ---
event File(bytes32 indexed what, address data);
event UpdateManager(PoolId indexed poolId, address who, bool canManage);
event Withdraw(
PoolId indexed poolId,
ShareClassId indexed scId,
address asset,
uint256 tokenId,
address receiver,
uint128 amount,
D18 pricePoolPerAsset
);
event Deposit(PoolId indexed poolId, ShareClassId indexed scId, address asset, uint256 tokenId, uint128 amount);
event NoteDeposit(
PoolId indexed poolId,
ShareClassId indexed scId,
address asset,
uint256 tokenId,
uint128 amount,
D18 pricePoolPerAsset
);
event Issue(PoolId indexed poolId, ShareClassId indexed scId, address to, D18 pricePoolPerShare, uint128 shares);
event Revoke(PoolId indexed poolId, ShareClassId indexed scId, address from, D18 pricePoolPerShare, uint128 shares);
event TransferSharesFrom(
PoolId indexed poolId,
ShareClassId indexed scId,
address sender,
address indexed from,
address to,
uint256 amount
);
event SubmitQueuedShares(PoolId indexed poolId, ShareClassId indexed scId, ISpokeMessageSender.UpdateData data);
event SubmitQueuedAssets(
PoolId indexed poolId,
ShareClassId indexed scId,
AssetId indexed assetId,
ISpokeMessageSender.UpdateData data,
D18 pricePoolPerAsset
);
// --- Errors ---
error FileUnrecognizedParam();
error CannotTransferFromEndorsedContract();
function root() external view returns (IRoot);
function spoke() external view returns (ISpoke);
function sender() external view returns (ISpokeMessageSender);
function poolEscrowProvider() external view returns (IPoolEscrowProvider);
function manager(PoolId poolId, address manager) external view returns (bool);
function queuedShares(PoolId poolId, ShareClassId scId)
external
view
returns (uint128 delta, bool isPositive, uint32 queuedAssetCounter, uint64 nonce);
function queuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId)
external
view
returns (uint128 increase, uint128 decrease);
function file(bytes32 what, address data) external;
/// @notice Deposit assets into the escrow of the pool.
/// @param tokenId SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported.
function deposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 amount) external;
/// @notice Note a deposit of assets into the escrow of the pool.
/// @dev Must be followed by a transfer of the equivalent amount of assets to `IBalanceSheet.escrow(poolId)`
/// This function is mostly useful to keep higher level integrations CEI adherent.
/// @param tokenId SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported.
function noteDeposit(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 amount) external;
/// @notice Withdraw assets from the escrow of the pool.
/// @param tokenId SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported.
function withdraw(
PoolId poolId,
ShareClassId scId,
address asset,
uint256 tokenId,
address receiver,
uint128 amount
) external;
/// @notice Increase the reserved balance of the pool. These assets are removed from the available balance
/// and cannot be withdrawn before they are unreserved.
///
/// It is possible to reserve more than the current balance, to lock future expected assets.
function reserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 amount) external;
/// @notice Decrease the reserved balance of the pool. These assets are re-added to the available balance.
function unreserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 amount) external;
/// @notice Issue new share tokens. Increases the total issuance.
function issue(PoolId poolId, ShareClassId scId, address to, uint128 shares) external;
/// @notice Revoke share tokens. Decreases the total issuance.
function revoke(PoolId poolId, ShareClassId scId, uint128 shares) external;
/// @notice Sends the queued updated holding amount to the Hub
function submitQueuedAssets(PoolId poolId, ShareClassId scId, AssetId assetId, uint128 extraGasLimit) external;
/// @notice Sends the queued updated shares changed to the Hub
function submitQueuedShares(PoolId poolId, ShareClassId scId, uint128 extraGasLimit) external;
/// @notice Force-transfers share tokens.
function transferSharesFrom(
PoolId poolId,
ShareClassId scId,
address sender,
address from,
address to,
uint256 amount
) external;
/// @notice Override the price pool per asset, to be used for any other balance sheet interactions.
/// @dev This can be used to note an interaction at a lower/higher price than the current one.
/// resetPricePoolPerAsset MUST be called after the balance sheet interactions using this price.
function overridePricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 value) external;
/// @notice Reset the price pool per asset.
function resetPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId) external;
/// @notice Override the price pool per share, to be used for any other balance sheet interactions.
/// @dev This can be used to note an interaction at a lower/higher price than the current one.
/// resetPricePoolPerShare MUST be called after the balance sheet interactions using this price.
function overridePricePoolPerShare(PoolId poolId, ShareClassId scId, D18 value) external;
/// @notice Reset the price pool per share.
function resetPricePoolPerShare(PoolId poolId, ShareClassId scId) external;
/// @notice Returns the pool escrow.
/// @dev Assets for pending deposit requests are not held by the pool escrow.
function escrow(PoolId poolId) external view returns (IPoolEscrow);
/// @notice Returns the amount of assets that can be withdrawn from the balance sheet.
/// @dev Assets that are locked for redemption requests are reserved and not available for withdrawals.
/// @param tokenId SHOULD be 0 if depositing ERC20 assets. ERC6909 assets with tokenId=0 are not supported.
function availableBalanceOf(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId)
external
view
returns (uint128);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {D18} from "src/misc/types/D18.sol";
import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
import {Price} from "src/spoke/types/Price.sol";
import {IShareToken} from "src/spoke/interfaces/IShareToken.sol";
import {IVault, VaultKind} from "src/spoke/interfaces/IVault.sol";
import {IRequestManager} from "src/spoke/interfaces/IRequestManager.sol";
import {IVaultFactory} from "src/spoke/factories/interfaces/IVaultFactory.sol";
/// @dev Centrifuge pools
struct Pool {
uint256 createdAt;
mapping(ShareClassId scId => ShareClassDetails) shareClasses;
}
struct ShareClassAsset {
/// @dev Manager that can send requests, and handles the request callbacks.
IRequestManager manager;
/// @dev Number of linked vaults.
uint32 numVaults;
}
/// @dev Each Centrifuge pool is associated to 1 or more shar classes
struct ShareClassDetails {
IShareToken shareToken;
/// @dev Each share class has an individual price per share class unit in pool denomination (POOL_UNIT/SHARE_UNIT)
Price pricePoolPerShare;
mapping(AssetId assetId => ShareClassAsset) asset;
/// @dev For each share class, we store the price per pool unit in asset denomination (POOL_UNIT/ASSET_UNIT)
mapping(address asset => mapping(uint256 tokenId => Price)) pricePoolPerAsset;
}
struct VaultDetails {
/// @dev AssetId of the asset
AssetId assetId;
/// @dev Address of the asset
address asset;
/// @dev TokenId of the asset - zero if asset is ERC20, non-zero if asset is ERC6909
uint256 tokenId;
/// @dev Whether the vault is linked to a share class atm
bool isLinked;
}
struct AssetIdKey {
/// @dev The address of the asset
address asset;
/// @dev The ERC6909 token id or 0, if the underlying asset is an ERC20
uint256 tokenId;
}
interface ISpoke {
event File(bytes32 indexed what, address data);
event RegisterAsset(
AssetId indexed assetId,
address indexed asset,
uint256 indexed tokenId,
string name,
string symbol,
uint8 decimals,
bool isInitialization
);
event File(bytes32 indexed what, address factory, bool status);
event AddPool(PoolId indexed poolId);
event AddShareClass(PoolId indexed poolId, ShareClassId indexed scId, IShareToken token);
event DeployVault(
PoolId indexed poolId,
ShareClassId indexed scId,
address indexed asset,
uint256 tokenId,
IVaultFactory factory,
IVault vault,
VaultKind kind
);
event SetRequestManager(
PoolId indexed poolId, ShareClassId indexed scId, AssetId indexed assetId, IRequestManager manager
);
event UpdateAssetPrice(
PoolId indexed poolId,
ShareClassId indexed scId,
address indexed asset,
uint256 tokenId,
uint256 price,
uint64 computedAt
);
event UpdateSharePrice(PoolId indexed poolId, ShareClassId indexed scId, uint256 price, uint64 computedAt);
event InitiateTransferShares(
uint16 centrifugeId,
PoolId indexed poolId,
ShareClassId indexed scId,
address indexed sender,
bytes32 destinationAddress,
uint128 amount
);
event ExecuteTransferShares(
PoolId indexed poolId, ShareClassId indexed scId, address indexed receiver, uint128 amount
);
event LinkVault(
PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IVault vault
);
event UnlinkVault(
PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, IVault vault
);
event UpdateMaxSharePriceAge(PoolId indexed poolId, ShareClassId indexed scId, uint64 maxPriceAge);
event UpdateMaxAssetPriceAge(
PoolId indexed poolId, ShareClassId indexed scId, address indexed asset, uint256 tokenId, uint64 maxPriceAge
);
error FileUnrecognizedParam();
error TooFewDecimals();
error TooManyDecimals();
error PoolAlreadyAdded();
error InvalidPool();
error ShareClassAlreadyRegistered();
error InvalidHook();
error OldMetadata();
error CannotSetOlderPrice();
error OldHook();
error UnknownVault();
error UnknownAsset();
error MalformedVaultUpdateMessage();
error UnknownToken();
error InvalidFactory();
error InvalidPrice();
error AssetMissingDecimals();
error ShareTokenDoesNotExist();
error LocalTransferNotAllowed();
error CrossChainTransferNotAllowed();
error ShareTokenTransferFailed();
error TransferFromFailed();
error InvalidRequestManager();
error MoreThanZeroLinkedVaults();
error RequestManagerNotSet();
error InvalidManager();
error InvalidVault();
/// @notice Returns the asset address and tokenId associated with a given asset id.
/// @dev Reverts if asset id does not exist
///
/// @param assetId The underlying internal uint128 assetId.
/// @return asset The address of the asset linked to the given asset id.
/// @return tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.
function idToAsset(AssetId assetId) external view returns (address asset, uint256 tokenId);
/// @notice Returns assetId given the asset address and tokenId.
/// @dev Reverts if asset id does not exist
///
/// @param asset The address of the asset linked to the given asset id.
/// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.
/// @return assetId The underlying internal uint128 assetId.
function assetToId(address asset, uint256 tokenId) external view returns (AssetId assetId);
/// @notice Updates a contract parameter
/// @param what Accepts a bytes32 representation of 'gateway', 'investmentManager', 'tokenFactory',
/// or 'gasService'
function file(bytes32 what, address data) external;
/// @notice transfers share class tokens to a cross-chain recipient address
/// @dev To transfer to evm chains, pad a 20 byte evm address with 12 bytes of 0
/// @param centrifugeId The destination chain id
/// @param poolId The centrifuge pool id
/// @param scId The share class id
/// @param receiver A bytes32 representation of the receiver address
/// @param amount The amount of tokens to transfer
/// @param remoteExtraGasLimit extra gas limit used for some extra computation that could happen in the chain where
/// the transfer is executed.
function crosschainTransferShares(
uint16 centrifugeId,
PoolId poolId,
ShareClassId scId,
bytes32 receiver,
uint128 amount,
uint128 remoteExtraGasLimit
) external payable;
/// @notice Registers an ERC-20 or ERC-6909 asset in another chain.
/// @dev `decimals()` MUST return a `uint8` value between 2 and 18.
/// @dev `name()` and `symbol()` MAY return no values.
///
/// @param centrifugeId The centrifuge id of chain to where the shares are transferred
/// @param asset The address of the asset to be registered
/// @param tokenId The token id corresponding to the asset, i.e. zero if ERC20 or non-zero if ERC6909.
/// @return assetId The underlying internal uint128 assetId.
function registerAsset(uint16 centrifugeId, address asset, uint256 tokenId)
external
payable
returns (AssetId assetId);
function linkToken(PoolId poolId, ShareClassId scId, IShareToken shareToken) external;
/// @notice Handles a request originating from the Spoke side.
/// @param poolId The pool id
/// @param scId The share class id
/// @param assetId The asset id
/// @param payload The request payload to be processed
function request(PoolId poolId, ShareClassId scId, AssetId assetId, bytes memory payload) external;
/// @notice Deploys a new vault
///
/// @param poolId The pool id
/// @param scId The share class id
/// @param assetId The asset id for which we want to deploy a vault
/// @param factory The address of the corresponding vault factory
/// @return address The address of the deployed vault
function deployVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVaultFactory factory)
external
returns (IVault);
/// @notice Register a vault.
function registerVault(
PoolId poolId,
ShareClassId scId,
AssetId assetId,
address asset,
uint256 tokenId,
IVaultFactory factory,
IVault vault
) external;
/// @notice Links a deployed vault to the given pool, share class and asset.
///
/// @param poolId The pool id
/// @param scId The share class id
/// @param assetId The asset id for which we want to deploy a vault
/// @param vault The address of the deployed vault
function linkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVault vault) external;
/// @notice Removes the link between a vault and the given pool, share class and asset.
///
/// @param poolId The pool id
/// @param scId The share class id
/// @param assetId The asset id for which we want to deploy a vault
/// @param vault The address of the deployed vault
function unlinkVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVault vault) external;
/// @notice Returns whether the given pool id is active
function isPoolActive(PoolId poolId) external view returns (bool);
/// @notice Returns the share class token for a given pool and share class id.
/// @dev Reverts if share class does not exists
///
/// @param poolId The pool id
/// @param scId The share class id
/// @return address The address of the share token
function shareToken(PoolId poolId, ShareClassId scId) external view returns (IShareToken);
/// @notice Function to get the details of a vault
/// @dev Reverts if vault does not exist
///
/// @param vault The address of the vault to be checked for
/// @return details The details of the vault including the underlying asset address, token id, asset id
function vaultDetails(IVault vault) external view returns (VaultDetails memory details);
/// @notice Checks whether a given vault is eligible for investing into a share class of a pool
///
/// @param vault The address of the vault
/// @return bool Whether vault is to a share class
function isLinked(IVault vault) external view returns (bool);
/// @notice Returns the price per share for a given pool and share class. The Provided price is defined as
/// POOL_UNIT/SHARE_UNIT.
/// @dev Conditionally checks if price is valid.
///
/// @param poolId The pool id
/// @param scId The share class id
/// @param checkValidity Whether to check if the price is valid
/// @return price The pool price per share
function pricePoolPerShare(PoolId poolId, ShareClassId scId, bool checkValidity)
external
view
returns (D18 price);
/// @notice Returns the price per asset for a given pool, share class and the underlying asset id. The Provided
/// price is defined as POOL_UNIT/ASSET_UNIT.
/// @dev Conditionally checks if price is valid.
///
/// @param poolId The pool id
/// @param scId The share class id
/// @param assetId The asset id for which we want to know the POOL_UNIT/ASSET_UNIT.
/// @param checkValidity Whether to check if the price is valid
/// @return price The pool price per asset unit
function pricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)
external
view
returns (D18 price);
/// @notice Returns the both prices per pool for a given pool, share class and the underlying asset id. The Provided
/// prices is defined as POOL_UNIT/ASSET_UNIT and POOL_UNIT/SHARE_UNIT.
/// @dev Conditionally checks if prices are valid.
///
/// @param poolId The pool id
/// @param scId The share class id
/// @param assetId The asset id for which we want to know pool price per asset
/// @param checkValidity Whether to check if the prices are valid
/// @return pricePoolPerAsset The pool price per asset unit, i.e. POOL_UNIT/ASSET_UNIT
/// @return pricePoolPerShare The pool price per share unit, i.e. POOL_UNIT/SHARE_UNIT
function pricesPoolPer(PoolId poolId, ShareClassId scId, AssetId assetId, bool checkValidity)
external
view
returns (D18 pricePoolPerAsset, D18 pricePoolPerShare);
/// @notice Returns the age related markers for a share class price
///
/// @param poolId The pool id
/// @param scId The share class id
/// @return computedAt The timestamp when this price was computed
/// @return maxAge The maximum age this price is allowed to have
/// @return validUntil The timestamp until this price is valid
function markersPricePoolPerShare(PoolId poolId, ShareClassId scId)
external
view
returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);
/// @notice Returns the age related markers for an asset price
///
/// @param poolId The pool id
/// @param scId The share class id
/// @param assetId The asset id for which we want to know pool price per asset
/// @return computedAt The timestamp when this price was computed
/// @return maxAge The maximum age this price is allowed to have
/// @return validUntil The timestamp until this price is valid
function markersPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId)
external
view
returns (uint64 computedAt, uint64 maxAge, uint64 validUntil);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {PoolId} from "src/common/types/PoolId.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
interface IUpdateContract {
error UnknownUpdateContractType();
/// @notice Triggers an update on the target contract.
/// @param poolId The centrifuge pool id
/// @param scId The share class id
/// @param payload The payload to be processed by the target address
function update(PoolId poolId, ShareClassId scId, bytes calldata payload) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {CastLib} from "src/misc/libraries/CastLib.sol";
import {BytesLib} from "src/misc/libraries/BytesLib.sol";
enum UpdateContractType {
/// @dev Placeholder for null update restriction type
Invalid,
Valuation,
SyncDepositMaxReserve,
UpdateAddress,
Policy
}
library UpdateContractMessageLib {
using UpdateContractMessageLib for bytes;
using BytesLib for bytes;
using CastLib for *;
error UnknownMessageType();
function updateContractType(bytes memory message) internal pure returns (UpdateContractType) {
return UpdateContractType(message.toUint8(0));
}
//---------------------------------------
// UpdateContract.Valuation (submsg)
//---------------------------------------
struct UpdateContractValuation {
bytes32 valuation;
}
function deserializeUpdateContractValuation(bytes memory data)
internal
pure
returns (UpdateContractValuation memory)
{
require(updateContractType(data) == UpdateContractType.Valuation, UnknownMessageType());
return UpdateContractValuation({valuation: data.toBytes32(1)});
}
function serialize(UpdateContractValuation memory t) internal pure returns (bytes memory) {
return abi.encodePacked(UpdateContractType.Valuation, t.valuation);
}
//---------------------------------------
// UpdateContract.SyncDepositMaxReserve (submsg)
//---------------------------------------
struct UpdateContractSyncDepositMaxReserve {
uint128 assetId;
uint128 maxReserve;
}
function deserializeUpdateContractSyncDepositMaxReserve(bytes memory data)
internal
pure
returns (UpdateContractSyncDepositMaxReserve memory)
{
require(updateContractType(data) == UpdateContractType.SyncDepositMaxReserve, UnknownMessageType());
return UpdateContractSyncDepositMaxReserve({assetId: data.toUint128(1), maxReserve: data.toUint128(17)});
}
function serialize(UpdateContractSyncDepositMaxReserve memory t) internal pure returns (bytes memory) {
return abi.encodePacked(UpdateContractType.SyncDepositMaxReserve, t.assetId, t.maxReserve);
}
//---------------------------------------
// UpdateContract.UpdateAddress (submsg)
//---------------------------------------
struct UpdateContractUpdateAddress {
bytes32 kind;
uint128 assetId;
bytes32 what;
bool isEnabled;
}
function deserializeUpdateContractUpdateAddress(bytes memory data)
internal
pure
returns (UpdateContractUpdateAddress memory)
{
require(updateContractType(data) == UpdateContractType.UpdateAddress, UnknownMessageType());
return UpdateContractUpdateAddress({
kind: data.toBytes32(1),
assetId: data.toUint128(33),
what: data.toBytes32(49),
isEnabled: data.toBool(81)
});
}
function serialize(UpdateContractUpdateAddress memory t) internal pure returns (bytes memory) {
return abi.encodePacked(UpdateContractType.UpdateAddress, t.kind, t.assetId, t.what, t.isEnabled);
}
//---------------------------------------
// UpdateContract.Policy (submsg)
//---------------------------------------
struct UpdateContractPolicy {
bytes32 who;
bytes32 what;
}
function deserializeUpdateContractPolicy(bytes memory data) internal pure returns (UpdateContractPolicy memory) {
require(updateContractType(data) == UpdateContractType.Policy, UnknownMessageType());
return UpdateContractPolicy({who: data.toBytes32(1), what: data.toBytes32(33)});
}
function serialize(UpdateContractPolicy memory t) internal pure returns (bytes memory) {
return abi.encodePacked(UpdateContractType.Policy, t.who, t.what);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IERC7575} from "src/misc/interfaces/IERC7575.sol";
import {IRecoverable} from "src/misc/interfaces/IRecoverable.sol";
import {IERC7540Operator, IERC7714, IERC7741} from "src/misc/interfaces/IERC7540.sol";
import {IVault} from "src/spoke/interfaces/IVault.sol";
/// @notice Interface for the all vault contracts
/// @dev Must be implemented by all vaults
interface IBaseVault is IVault, IERC7540Operator, IERC7741, IERC7714, IERC7575, IRecoverable {
error FileUnrecognizedParam();
error NotEndorsed();
error CannotSetSelfAsOperator();
error ExpiredAuthorization();
error AlreadyUsedAuthorization();
error InvalidAuthorization();
error InvalidController();
error InsufficientBalance();
error RequestRedeemFailed();
error TransferFromFailed();
event File(bytes32 indexed what, address data);
/// @notice Set msg.sender as operator of owner, to `approved` status
/// @dev MUST be called by endorsed sender
function setEndorsedOperator(address owner, bool approved) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {D18} from "src/misc/types/D18.sol";
import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
import {IUpdateContract} from "src/spoke/interfaces/IUpdateContract.sol";
import {IBaseVault} from "src/vaults/interfaces/IBaseVault.sol";
import {IBaseRequestManager} from "src/vaults/interfaces/IBaseRequestManager.sol";
interface IDepositManager {
/// @notice Processes owner's asset deposit after the epoch has been executed on the corresponding CP instance and
/// the deposit order
/// has been successfully processed (partial fulfillment possible).
/// Shares are transferred from the escrow to the receiver. Amount of shares is computed based of the amount
/// of assets and the owner's share price.
/// @dev The assets required to fulfill the deposit are already locked in escrow upon calling requestDeposit.
/// The shares required to fulfill the deposit have already been minted and transferred to the escrow on
/// fulfillDepositRequest.
/// Receiver has to pass all the share token restrictions in order to receive the shares.
function deposit(IBaseVault vault, uint256 assets, address receiver, address owner)
external
returns (uint256 shares);
/// @notice Processes owner's share mint after the epoch has been executed on the corresponding CP instance and the
/// deposit order has
/// been successfully processed (partial fulfillment possible).
/// Shares are transferred from the escrow to the receiver. Amount of assets is computed based of the amount
/// of shares and the owner's share price.
/// @dev The assets required to fulfill the mint are already locked in escrow upon calling requestDeposit.
/// The shares required to fulfill the mint have already been minted and transferred to the escrow on
/// fulfillDepositRequest.
/// Receiver has to pass all the share token restrictions in order to receive the shares.
function mint(IBaseVault vault, uint256 shares, address receiver, address owner)
external
returns (uint256 assets);
/// @notice Returns the max amount of assets based on the unclaimed amount of shares after at least one successful
/// deposit order fulfillment on the corresponding CP instance.
function maxDeposit(IBaseVault vault, address user) external view returns (uint256);
/// @notice Returns the max amount of shares a user can claim after at least one successful deposit order
/// fulfillment on the corresponding CP instance.
function maxMint(IBaseVault vault, address user) external view returns (uint256 shares);
}
interface ISyncDepositManager is IDepositManager {
function previewDeposit(IBaseVault vault, address sender, uint256 assets) external view returns (uint256);
function previewMint(IBaseVault vault, address sender, uint256 shares) external view returns (uint256);
}
interface IAsyncDepositManager is IDepositManager, IBaseRequestManager {
/// @notice Requests assets deposit. Vaults have to request investments from Centrifuge before
/// shares can be minted. The deposit requests are added to the order book
/// on the corresponding CP instance. Once the next epoch is executed on the corresponding CP instance,
/// vaults can proceed with share payouts in case the order got fulfilled.
/// @dev The assets required to fulfill the deposit request have to be locked and are transferred from the
/// owner to the escrow, even though the share payout can only happen after epoch execution.
/// The receiver becomes the owner of deposit request fulfillment.
/// @param source Deprecated
function requestDeposit(IBaseVault vault, uint256 assets, address receiver, address owner, address source)
external
returns (bool);
/// @notice Requests the cancellation of a pending deposit request. Vaults have to request the
/// cancellation of outstanding requests from Centrifuge before actual assets can be unlocked and
/// transferred to the owner.
/// While users have outstanding cancellation requests no new deposit requests can be submitted.
/// Once the next epoch is executed on the corresponding CP instance, vaults can proceed with asset payouts
/// if orders could be cancelled successfully.
/// @dev The cancellation request might fail in case the pending deposit order already got fulfilled on
/// Centrifuge.
/// @param source Deprecated
function cancelDepositRequest(IBaseVault vault, address owner, address source) external;
/// @notice Processes owner's deposit request cancellation after the epoch has been executed on the corresponding CP
/// instance and the deposit order cancellation has been successfully processed (partial fulfillment
/// possible).
/// Assets are transferred from the escrow to the receiver.
/// @dev The assets required to fulfill the claim have already been reserved for the owner in escrow on
/// fulfillDepositRequest with non-zero cancelled asset amount value.
function claimCancelDepositRequest(IBaseVault vault, address receiver, address owner)
external
returns (uint256 assets);
/// @notice Indicates whether a user has pending deposit requests and returns the total deposit request asset
/// request value.
function pendingDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);
/// @notice Indicates whether a user has pending deposit request cancellations.
function pendingCancelDepositRequest(IBaseVault vault, address user) external view returns (bool isPending);
/// @notice Indicates whether a user has claimable deposit request cancellation and returns the total claim
/// value in assets.
function claimableCancelDepositRequest(IBaseVault vault, address user) external view returns (uint256 assets);
}
interface IRedeemManager {
event TriggerRedeemRequest(
uint64 indexed poolId,
bytes16 indexed scId,
address user,
address indexed asset,
uint256 tokenId,
uint128 shares
);
/// @notice Processes owner's share redemption after the epoch has been executed on the corresponding CP instance
/// and the redeem order
/// has been successfully processed (partial fulfillment possible).
/// Assets are transferred from the escrow to the receiver. Amount of assets is computed based of the amount
/// of shares and the owner's share price.
/// @dev The shares required to fulfill the redemption were already locked in escrow on requestRedeem and burned
/// on fulfillRedeemRequest.
/// The assets required to fulfill the redemption have already been reserved in escrow on
/// fulfillRedeemtRequest.
function redeem(IBaseVault vault, uint256 shares, address receiver, address owner)
external
returns (uint256 assets);
/// @notice Processes owner's asset withdrawal after the epoch has been executed on the corresponding CP instance
/// and the redeem order
/// has been successfully processed (partial fulfillment possible).
/// Assets are transferred from the escrow to the receiver. Amount of shares is computed based of the amount
/// of shares and the owner's share price.
/// @dev The shares required to fulfill the withdrawal were already locked in escrow on requestRedeem and burned
/// on fulfillRedeemRequest.
/// The assets required to fulfill the withdrawal have already been reserved in escrow on
/// fulfillRedeemtRequest.
function withdraw(IBaseVault vault, uint256 assets, address receiver, address owner)
external
returns (uint256 shares);
/// @notice Returns the max amount of shares based on the unclaimed number of assets after at least one successful
/// redeem order fulfillment on the corresponding CP instance.
function maxRedeem(IBaseVault vault, address user) external view returns (uint256 shares);
/// @notice Returns the max amount of assets a user can claim after at least one successful redeem order fulfillment
/// on the corresponding CP instance.
function maxWithdraw(IBaseVault vault, address user) external view returns (uint256 assets);
}
interface IAsyncRedeemManager is IRedeemManager, IBaseRequestManager {
/// @notice Requests share redemption. Vaults have to request redemptions
/// from Centrifuge before actual asset payouts can be done. The redemption
/// requests are added to the order book on the corresponding CP instance. Once the next epoch is
/// executed on the corresponding CP instance, vaults can proceed with asset payouts
/// in case the order got fulfilled.
/// @dev The shares required to fulfill the redemption request have to be locked and are transferred from the
/// owner to the escrow, even though the asset payout can only happen after epoch execution.
/// The receiver becomes the owner of redeem request fulfillment.
/// @param source Deprecated
/// @param transfer Set `false` for legacy vaults which already execute the transfer in the vault implementation
function requestRedeem(
IBaseVault vault,
uint256 shares,
address receiver,
address owner,
address source,
bool transfer
) external returns (bool);
/// @notice Requests the cancellation of an pending redeem request. Vaults have to request the
/// cancellation of outstanding requests from Centrifuge before actual shares can be unlocked and
/// transferred to the owner.
/// While users have outstanding cancellation requests no new redeem requests can be submitted (exception:
/// trigger through governance).
/// Once the next epoch is executed on the corresponding CP instance, vaults can proceed with share payouts
/// if the orders could be cancelled successfully.
/// @dev The cancellation request might fail in case the pending redeem order already got fulfilled on
/// Centrifuge.
function cancelRedeemRequest(IBaseVault vault, address owner, address source) external;
/// @notice Processes owner's redeem request cancellation after the epoch has been executed on the corresponding CP
/// instance and the redeem order cancellation has been successfully processed (partial fulfillment
/// possible).
/// Shares are transferred from the escrow to the receiver.
/// @dev The shares required to fulfill the claim have already been reserved for the owner in escrow on
/// fulfillRedeemRequest with non-zero cancelled share amount value.
/// Receiver has to pass all the share token restrictions in order to receive the shares.
function claimCancelRedeemRequest(IBaseVault vault, address receiver, address owner)
external
returns (uint256 shares);
/// @notice Indicates whether a user has pending redeem requests and returns the total share request value.
function pendingRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);
/// @notice Indicates whether a user has pending redeem request cancellations.
function pendingCancelRedeemRequest(IBaseVault vault, address user) external view returns (bool isPending);
/// @notice Indicates whether a user has claimable redeem request cancellation and returns the total claim
/// value in shares.
function claimableCancelRedeemRequest(IBaseVault vault, address user) external view returns (uint256 shares);
}
/// @dev Solely used locally as protection against stack-too-deep
struct Prices {
/// @dev Price of 1 asset unit per share unit
D18 assetPerShare;
/// @dev Price of 1 pool unit per asset unit
D18 poolPerAsset;
/// @dev Price of 1 pool unit per share unit
D18 poolPerShare;
}
interface ISyncDepositValuation {
/// @notice Returns the pool price per share for a given pool and share class, asset, and asset id.
// The provided price is defined as POOL_UNIT/SHARE_UNIT.
///
/// @param poolId The pool id
/// @param scId The share class id
/// @return price The pool price per share
function pricePoolPerShare(PoolId poolId, ShareClassId scId) external view returns (D18 price);
}
interface ISyncManager is ISyncDepositManager, ISyncDepositValuation, IUpdateContract {
event SetValuation(PoolId indexed poolId, ShareClassId indexed scId, address valuation);
event SetMaxReserve(
PoolId indexed poolId, ShareClassId indexed scId, address asset, uint256 tokenId, uint128 maxReserve
);
event File(bytes32 indexed what, address data);
error ExceedsMaxDeposit();
error FileUnrecognizedParam();
error ExceedsMaxMint();
error ShareTokenDoesNotExist();
error SecondaryManagerDoesNotExist();
/// @notice Updates contract parameters of type address.
/// @param what The bytes32 representation of 'gateway' or 'spoke'.
/// @param data The new contract address.
function file(bytes32 what, address data) external;
/// @notice Converts the assets value to share decimals.
function convertToShares(IBaseVault vault, uint256 _assets) external view returns (uint256 shares);
/// @notice Converts the shares value to assets decimals.
function convertToAssets(IBaseVault vault, uint256 _shares) external view returns (uint256 assets);
/// @notice Sets the valuation for a specific pool and share class.
///
/// @param poolId The id of the pool
/// @param scId The id of the share class
/// @param valuation The address of the valuation contract
function setValuation(PoolId poolId, ShareClassId scId, address valuation) external;
/// @notice Sets the max reserve for a specific pool, share class and asset.
///
/// @param poolId The id of the pool
/// @param scId The id of the share class
/// @param asset The address of the asset
/// @param tokenId The asset token id, i.e. 0 for ERC20, or the token id for ERC6909
/// @param maxReserve The amount of maximum reserve
function setMaxReserve(PoolId poolId, ShareClassId scId, address asset, uint256 tokenId, uint128 maxReserve)
external;
}
/// @dev Vault requests and deposit/redeem bookkeeping per user
struct AsyncInvestmentState {
/// @dev Shares that can be claimed using `mint()`
uint128 maxMint;
/// @dev Assets that can be claimed using `withdraw()`
uint128 maxWithdraw;
/// @dev Weighted average price of deposits, used to convert maxMint to maxDeposit
/// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT
D18 depositPrice;
/// @dev Weighted average price of redemptions, used to convert maxWithdraw to maxRedeem
/// @dev Represents priceAssetPerShare, i.e. ASSET_UNIT/SHARE_UNIT
D18 redeemPrice;
/// @dev Remaining deposit request in assets
uint128 pendingDepositRequest;
/// @dev Remaining redeem request in shares
uint128 pendingRedeemRequest;
/// @dev Assets that can be claimed using `claimCancelDepositRequest()`
uint128 claimableCancelDepositRequest;
/// @dev Shares that can be claimed using `claimCancelRedeemRequest()`
uint128 claimableCancelRedeemRequest;
/// @dev Indicates whether the depositRequest was requested to be cancelled
bool pendingCancelDepositRequest;
/// @dev Indicates whether the redeemRequest was requested to be cancelled
bool pendingCancelRedeemRequest;
}
interface IAsyncRequestManager is IAsyncDepositManager, IAsyncRedeemManager {
error AssetNotAllowed();
error ExceedsMaxDeposit();
error AssetMismatch();
error ZeroAmountNotAllowed();
error TransferNotAllowed();
error CancellationIsPending();
error NoPendingRequest();
error ShareTokenAmountIsZero();
error FailedRedeemRequest();
error ExceedsDepositLimits();
error ShareTokenTransferFailed();
error ExceedsMaxRedeem();
error ExceedsRedeemLimits();
/// @notice Returns the investment state
function investments(IBaseVault vaultAddr, address investor)
external
view
returns (
uint128 maxMint,
uint128 maxWithdraw,
D18 depositPrice,
D18 redeemPrice,
uint128 pendingDepositRequest,
uint128 pendingRedeemRequest,
uint128 claimableCancelDepositRequest,
uint128 claimableCancelRedeemRequest,
bool pendingCancelDepositRequest,
bool pendingCancelRedeemRequest
);
/// @notice Signal from the Hub that an asynchronous investment order has been approved
///
/// @dev This message needs to trigger making the asset amounts available to the pool-share-class.
function approvedDeposits(
PoolId poolId,
ShareClassId scId,
AssetId assetId,
uint128 assetAmount,
D18 pricePoolPerAsset
) external;
/// @notice Signal from the Hub that an asynchronous investment order has been finalized. Shares have been issued.
///
/// @dev This message needs to trigger minting the new amount of shares.
function issuedShares(PoolId poolId, ShareClassId scId, uint128 shareAmount, D18 pricePoolPerShare) external;
/// @notice Signal from the Hub that an asynchronous redeem order has been finalized.
///
/// @dev This messages needs to trigger reserving the asset amount for claims of redemptions by users.
function revokedShares(
PoolId poolId,
ShareClassId scId,
AssetId assetId,
uint128 assetAmount,
uint128 shareAmount,
D18 pricePoolPerShare
) external;
// --- Deposits ---
/// @notice Fulfills pending deposit requests after successful epoch execution on Hub.
/// The amount of shares that can be claimed by the user is minted and moved to the escrow contract.
/// The maxMint and claimableCancelDepositRequest bookkeeping values are updated.
/// The request fulfillment can be partial.
/// @dev The shares in the escrow are reserved for the user and are transferred to the user on deposit
/// and mint calls.
/// @dev The cancelled and fulfilled amounts are both non-zero iff the cancellation was queued.
/// Otherwise, either of the two must always be zero.
function fulfillDepositRequest(
PoolId poolId,
ShareClassId scId,
address user,
AssetId assetId,
uint128 fulfilledAssetAmount,
uint128 fulfilledShareAmount,
uint128 cancelledAssetAmount
) external;
// --- Redeems ---
/// @notice Fulfills pending redeem requests after successful epoch execution on Hub.
/// The amount of redeemed shares is burned. The amount of assets that can be claimed by the user in
/// return is locked in the escrow contract.
/// The maxWithdraw and claimableCancelRedeemRequest bookkeeping values are updated.
/// The request fulfillment can be partial.
/// @dev The assets in the escrow are reserved for the user and are transferred to the user on redeem
/// and withdraw calls.
/// @dev The cancelled and fulfilled amounts are both non-zero iff the cancellation was queued.
/// Otherwise, either of the two must always be zero.
function fulfillRedeemRequest(
PoolId poolId,
ShareClassId scId,
address user,
AssetId assetId,
uint128 fulfilledAssetAmount,
uint128 fulfilledShareAmount,
uint128 cancelledShareAmount
) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IAuth {
event Rely(address indexed user);
event Deny(address indexed user);
error NotAuthorized();
/// @notice Returns whether the target is a ward (has admin access)
function wards(address target) external view returns (uint256);
/// @notice Make user a ward (give them admin access)
function rely(address user) external;
/// @notice Remove user as a ward (remove admin access)
function deny(address user) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IERC165} from "forge-std/interfaces/IERC165.sol";
interface IERC6909 is IERC165 {
error EmptyOwner();
error EmptyAmount();
error InvalidTokenId();
error InsufficientBalance(address owner, uint256 tokenId);
error InsufficientAllowance(address sender, uint256 tokenId);
event OperatorSet(address indexed owner, address indexed operator, bool approved);
event Approval(address indexed owner, address indexed spender, uint256 indexed tokenId, uint256 amount);
event Transfer(address caller, address indexed from, address indexed to, uint256 indexed tokenId, uint256 amount);
/// @notice Owner balance of a tokenId.
/// @param owner The address of the owner.
/// @param tokenId The id of the token.
/// @return amount The balance of the token.
function balanceOf(address owner, uint256 tokenId) external view returns (uint256 amount);
/// @notice Spender allowance of a tokenId.
/// @param owner The address of the owner.
/// @param spender The address of the spender.
/// @param tokenId The id of the token.
/// @return amount The allowance of the token.
function allowance(address owner, address spender, uint256 tokenId) external view returns (uint256 amount);
/// @notice Checks if a spender is approved by an owner as an operator.
/// @param owner The address of the owner.
/// @param spender The address of the spender.
/// @return approved The approval status.
function isOperator(address owner, address spender) external view returns (bool approved);
/// @notice Transfers an amount of a tokenId from the caller to a receiver.
/// @param receiver The address of the receiver.
/// @param tokenId The id of the token.
/// @param amount The amount of the token.
/// @return bool True, always, unless the function reverts.
function transfer(address receiver, uint256 tokenId, uint256 amount) external returns (bool);
/// @notice Transfers an amount of a tokenId from a sender to a receiver.
/// @param sender The address of the sender.
/// @param receiver The address of the receiver.
/// @param tokenId The id of the token.
/// @param amount The amount of the token.
/// @return bool True, always, unless the function reverts.
function transferFrom(address sender, address receiver, uint256 tokenId, uint256 amount) external returns (bool);
/// @notice Approves an amount of a tokenId to a spender.
/// @param spender The address of the spender.
/// @param tokenId The id of the token.
/// @param amount The amount of the token.
/// @return bool True, always.
function approve(address spender, uint256 tokenId, uint256 amount) external returns (bool);
/// @notice Sets or removes an operator for the caller.
/// @param operator The address of the operator.
/// @param approved The approval status.
/// @return bool True, always.
function setOperator(address operator, bool approved) external returns (bool);
}
interface IERC6909URIExt {
event TokenURISet(uint256 indexed tokenId, string uri);
event ContractURISet(address indexed target, string uri);
error EmptyURI();
/// @return uri Returns the common token URI.
function contractURI() external view returns (string memory);
/// @dev Returns empty string if tokenId does not exist.
/// MAY implemented to throw MissingURI(tokenId) error.
/// @param tokenId The token to query URI for.
/// @return uri A string representing the uri for the specific tokenId.
function tokenURI(uint256 tokenId) external view returns (string memory);
}
interface IERC6909NFT is IERC6909, IERC6909URIExt {
error UnknownTokenId(address owner, uint256 tokenId);
error LessThanMinimalDecimal(uint8 minimal, uint8 actual);
/// @notice Provide URI for a specific tokenId.
/// @param tokenId Token Id.
/// @param URI URI to a document defining the collection as a whole.
function setTokenURI(uint256 tokenId, string memory URI) external;
/// @dev Optional method to set up the contract URI if needed.
/// @param URI URI to a document defining the collection as a whole.
function setContractURI(string memory URI) external;
/// @notice Mint new tokens for a given owner and sets tokenURI.
/// @dev For non-fungible tokens, call with amount = 1, for fungible it could be any amount.
/// TokenId is auto incremented by one.
///
/// @param owner Creates supply of a given tokenId by amount for owner.
/// @param tokenURI URI fortestBurningToken the newly minted token.
/// @return tokenId Id of the newly minted token.
function mint(address owner, string memory tokenURI) external returns (uint256 tokenId);
/// @notice Destroy supply of a given tokenId by amount.
/// @dev The msg.sender MUST be the owner.
///
/// @param tokenId Item which have reduced supply.
function burn(uint256 tokenId) external;
}
/// @notice Extension of ERC6909 Standard for tracking total supply
interface IERC6909TotalSupplyExt {
/// @notice The totalSupply for a token id.
///
/// @param tokenId Id of the token
/// @return supply Total supply for a given `tokenId`
function totalSupply(uint256 tokenId) external returns (uint256 supply);
}
interface IERC6909Decimals {
/// @notice Used to retrieve the decimals of an asset
/// @dev address is used but the value corresponds to a AssetId
function decimals(uint256 assetId) external view returns (uint8);
}
interface IERC6909MetadataExt is IERC6909Decimals {
/// @notice Used to retrieve the decimals of an asset
/// @dev address is used but the value corresponds to a AssetId
function decimals(uint256 assetId) external view returns (uint8);
/// @notice Used to retrieve the name of an asset
/// @dev address is used but the value corresponds to a AssetId
function name(uint256 assetId) external view returns (string memory);
/// @notice Used to retrieve the symbol of an asset
/// @dev address is used but the value corresponds to a AssetId
function symbol(uint256 assetId) external view returns (string memory);
}
interface IERC6909Fungible is IERC6909 {
/// @notice Mint new tokens for a specific tokenid and assign them to an owner
///
/// @param owner Creates supply of a given `tokenId` by `amount` for owner.
/// @param tokenId Id of the item
/// @param amount Adds `amount` to the total supply of the given `tokenId`
function mint(address owner, uint256 tokenId, uint256 amount) external;
/// @notice Destroy supply of a given tokenId by amount.
/// @dev The msg.sender MUST be the owner.
///
/// @param owner Owner of the `tokenId`
/// @param tokenId Id of the item.
/// @param amount Subtract `amount` from the total supply of the given `tokenId`
function burn(address owner, uint256 tokenId, uint256 amount) external;
/// @notice Enforces a transfer from `spender` point of view.
///
///
/// @param sender The owner of the `tokenId`
/// @param receiver Address of the receiving party
/// @param tokenId Token Id
/// @param amount Amount to be transferred
function authTransferFrom(address sender, address receiver, uint256 tokenId, uint256 amount)
external
returns (bool);
}
/// @dev A factory contract to deploy new collateral contracts implementing IERC6909.
interface IERC6909Factory {
/// Events
event NewTokenDeployment(address indexed owner, address instance);
/// @notice Deploys new install of a contract that implements IERC6909.
/// @dev Factory should deploy deterministically if possible.
///
/// @param owner Owner of the deployed collateral contract which has initial full rights.
/// @param salt Used to make a deterministic deployment.
/// @return An address of the newly deployed contract.
function deploy(address owner, bytes32 salt) external returns (address);
/// @notice Generates a new deterministic address based on the owner and the salt.
///
/// @param owner Owner of the deployed collateral contract which has initial full rights.
/// @param salt Used to make a deterministic deployment.
/// @return An address of the newly deployed contract.
function previewAddress(address owner, bytes32 salt) external returns (address);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {IERC20} from "src/misc/interfaces/IERC20.sol";
import {IERC7751} from "src/misc/interfaces/IERC7751.sol";
/// @title Safe Transfer Lib
/// @author Modified from Uniswap v3 Periphery (libraries/TransferHelper.sol)
library SafeTransferLib {
error NoCode();
error SafeTransferFromFailed();
error SafeTransferFailed();
error SafeApproveFailed();
error SafeTransferEthFailed();
/// @notice Transfers tokens from the targeted address to the given destination
/// @notice Errors if transfer fails
/// @param token The contract address of the token to be transferred
/// @param from The originating address from which the tokens will be transferred
/// @param to The destination address of the transfer
/// @param value The amount to be transferred
function safeTransferFrom(address token, address from, address to, uint256 value) internal {
require(address(token).code.length > 0, NoCode());
(bool success, bytes memory returnData) = token.call(abi.encodeCall(IERC20.transferFrom, (from, to, value)));
require(
success && (returnData.length == 0 || abi.decode(returnData, (bool))),
IERC7751.WrappedError(
token, IERC20.transferFrom.selector, returnData, abi.encodeWithSelector(SafeTransferFromFailed.selector)
)
);
}
/// @notice Transfers tokens from msg.sender to a recipient
/// @dev Errors if transfer fails
/// @param token The contract address of the token which will be transferred
/// @param to The recipient of the transfer
/// @param value The value of the transfer
function safeTransfer(address token, address to, uint256 value) internal {
require(address(token).code.length > 0, NoCode());
(bool success, bytes memory returnData) = token.call(abi.encodeCall(IERC20.transfer, (to, value)));
require(
success && (returnData.length == 0 || abi.decode(returnData, (bool))),
IERC7751.WrappedError(
token, IERC20.transfer.selector, returnData, abi.encodeWithSelector(SafeTransferFailed.selector)
)
);
}
/// @notice Approves the stipulated contract to spend the given allowance in the given token
/// @dev Errors if approval fails
/// @param token The contract address of the token to be approved
/// @param to The target of the approval
/// @param value The amount of the given token the target will be allowed to spend
function safeApprove(address token, address to, uint256 value) internal {
require(address(token).code.length > 0, NoCode());
(bool success, bytes memory returnData) = token.call(abi.encodeCall(IERC20.approve, (to, value)));
require(
success && (returnData.length == 0 || abi.decode(returnData, (bool))),
IERC7751.WrappedError(
token, IERC20.approve.selector, returnData, abi.encodeWithSelector(SafeApproveFailed.selector)
)
);
}
/// @notice Transfers ETH to the recipient address
/// @dev Fails with `STE`
/// @dev Make sure that method that is using this function is protected from reentrancy
/// @param to The destination of the transfer
/// @param value The value to be transferred
function safeTransferETH(address to, uint256 value) internal {
(bool success,) = to.call{value: value}(new bytes(0));
require(success, SafeTransferEthFailed());
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
address constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
interface IRecoverable {
/// @notice Used to recover any ERC-20 token.
/// @dev This method is called only by authorized entities
/// @param token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
/// to recover locked native ETH or token compatible with ERC20.
/// @param to Receiver of the funds
/// @param amount Amount to send to the receiver.
function recoverTokens(address token, address to, uint256 amount) external;
/// @notice Used to recover any ERC-20 or ERC-6909 token.
/// @dev This method is called only by authorized entities
/// @param token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
/// to recover locked native ETH or token compatible with ERC20 or ERC6909.
/// @param tokenId The token id, i.e. non-zero if the underlying token is ERC6909 and else zero.
/// @param to Receiver of the funds
/// @param amount Amount to send to the receiver.
function recoverTokens(address token, uint256 tokenId, address to, uint256 amount) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title IERC20
/// @dev Interface of the ERC20 standard as defined in the EIP.
/// @author Modified from OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
interface IERC20 {
error InvalidAddress();
error InsufficientBalance();
error InsufficientAllowance();
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
error PermitExpired();
error InvalidPermit();
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
interface IERC20Wrapper {
/**
* @dev Returns the address of the underlying ERC-20 token that is being wrapped.
*/
function underlying() external view returns (address);
/**
* @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens.
*/
function depositFor(address account, uint256 value) external returns (bool);
/**
* @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens.
*/
function withdrawTo(address account, uint256 value) external returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IRoot {
// --- Events ---
event File(bytes32 indexed what, uint256 data);
event Pause();
event Unpause();
event ScheduleRely(address indexed target, uint256 indexed scheduledTime);
event CancelRely(address indexed target);
event RelyContract(address indexed target, address indexed user);
event DenyContract(address indexed target, address indexed user);
event Endorse(address indexed user);
event Veto(address indexed user);
error DelayTooLong();
error FileUnrecognizedParam();
error TargetNotScheduled();
error TargetNotReady();
/// @notice Returns whether the root is paused
function paused() external view returns (bool);
/// @notice Returns the current timelock for adding new wards
function delay() external view returns (uint256);
/// @notice Trusted contracts within the system
function endorsements(address target) external view returns (uint256);
/// @notice Returns when `relyTarget` has passed the timelock
function schedule(address relyTarget) external view returns (uint256 timestamp);
// --- Administration ---
/// @notice Updates a contract parameter
/// @param what Accepts a bytes32 representation of 'delay'
function file(bytes32 what, uint256 data) external;
/// --- Endorsements ---
/// @notice Endorses the `user`
/// @dev Endorsed users are trusted contracts in the system. They are allowed to bypass
/// token restrictions (e.g. the Escrow can automatically receive share class tokens by being endorsed), and
/// can automatically set operators in ERC-7540 vaults (e.g. the VaultRouter) is always an operator.
function endorse(address user) external;
/// @notice Removes the endorsed user
function veto(address user) external;
/// @notice Returns whether the user is endorsed
function endorsed(address user) external view returns (bool);
// --- Pause management ---
/// @notice Pause any contracts that depend on `Root.paused()`
function pause() external;
/// @notice Unpause any contracts that depend on `Root.paused()`
function unpause() external;
/// --- Timelocked ward management ---
/// @notice Schedule relying a new ward after the delay has passed
function scheduleRely(address target) external;
/// @notice Cancel a pending scheduled rely
function cancelRely(address target) external;
/// @notice Execute a scheduled rely
/// @dev Can be triggered by anyone since the scheduling is protected
function executeScheduledRely(address target) external;
/// --- External contract ward management ---
/// @notice Make an address a ward on any contract that Root is a ward on
function relyContract(address target, address user) external;
/// @notice Removes an address as a ward on any contract that Root is a ward on
function denyContract(address target, address user) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IRecoverable} from "src/misc/Recoverable.sol";
import {IEscrow} from "src/misc/interfaces/IEscrow.sol";
import {PoolId} from "src/common/types/PoolId.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
struct Holding {
uint128 total;
uint128 reserved;
}
/// @title PerPoolEscrow separating funds by pool and share class
interface IPoolEscrow is IEscrow, IRecoverable {
// --- Events ---
/// @notice Emitted when a deposit is made
/// @param asset The address of the deposited asset
/// @param tokenId The id of the asset - 0 for ERC20
/// @param poolId The id of the pool
/// @param scId The id of the share class
/// @param value The amount deposited
event Deposit(
address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value
);
/// @notice Emitted when an amount is reserved
/// @param asset The address of the reserved asset
/// @param tokenId The id of the asset - 0 for ERC20
/// @param poolId The id of the pool
/// @param scId The id of the share class
/// @param value The delta amount reserved
/// @param value The new absolute amount reserved
event IncreaseReserve(
address indexed asset,
uint256 indexed tokenId,
PoolId indexed poolId,
ShareClassId scId,
uint256 delta,
uint128 value
);
/// @notice Emitted when an amount is unreserved
/// @param asset The address of the reserved asset
/// @param tokenId The id of the asset - 0 for ERC20
/// @param poolId The id of the pool
/// @param scId The id of the share class
/// @param value The delta amount unreserved
/// @param value The new absolute amount reserved
event DecreaseReserve(
address indexed asset,
uint256 indexed tokenId,
PoolId indexed poolId,
ShareClassId scId,
uint256 delta,
uint128 value
);
/// @notice Emitted when a withdraw is made
/// @param asset The address of the withdrawn asset
/// @param tokenId The id of the asset - 0 for ERC20
/// @param poolId The id of the pool
/// @param scId The id of the share class
/// @param value The amount withdrawn
event Withdraw(
address indexed asset, uint256 indexed tokenId, PoolId indexed poolId, ShareClassId scId, uint128 value
);
/// @notice Emmitted when ETH is transfered to the escrow
/// @param amount transfered
event ReceiveNativeTokens(address who, uint256 amount);
// --- Errors ---
/// @notice Dispatched when the balance of the escrow did not increase sufficiently
error InsufficientDeposit();
/// @notice Dispatched when the outstanding reserved amount is insufficient for the decrease
error InsufficientReservedAmount();
// --- Functions ---
/// @notice Deposits `value` of `asset` in underlying `poolId` and given `scId`
///
/// @dev NOTE: Must ensure balance sufficiency, i.e. that the depositing amount does not exceed the balance of
/// escrow
///
/// @param scId The id of the share class
/// @param asset The address of the asset to be deposited
/// @param tokenId The id of the asset - 0 for ERC20
/// @param value The amount to deposit
function deposit(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;
/// @notice Withdraws `value` of `asset` in underlying `poolId` and given `scId`
/// @dev MUST ensure that reserved amounts are not withdrawn
/// @param scId The id of the share class
/// @param asset The address of the asset to be withdrawn
/// @param tokenId The id of the asset - 0 for ERC20
/// @param value The amount to withdraw
function withdraw(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;
/// @notice Increases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`
/// @dev MUST prevent the reserved amount from being withdrawn
/// @param scId The id of the share class
/// @param asset The address of the asset to be reserved
/// @param tokenId The id of the asset - 0 for ERC20
/// @param value The amount to reserve
function reserve(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;
/// @notice Decreases the reserved amount of `value` for `asset` in underlying `poolId` and given `scId`
/// @dev MUST fail if `value` is greater than the current reserved amount
/// @param scId The id of the share class
/// @param asset The address of the asset to be reserved
/// @param tokenId The id of the asset - 0 for ERC20
/// @param value The amount to decrease
function unreserve(ShareClassId scId, address asset, uint256 tokenId, uint128 value) external;
/// @notice Provides the available balance of `asset` in underlying `poolId` and given `scId`
/// @dev MUST return the balance minus the reserved amount
/// @param scId The id of the share class
/// @param asset The address of the asset to be checked
/// @param tokenId The id of the asset - 0 for ERC20
/// @return The available balance
function availableBalanceOf(ShareClassId scId, address asset, uint256 tokenId) external view returns (uint128);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {D18} from "src/misc/types/D18.sol";
import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
import {VaultUpdateKind} from "src/common/libraries/MessageLib.sol";
interface ILocalCentrifugeId {
function localCentrifugeId() external view returns (uint16);
}
/// @notice Interface for dispatch-only gateway
interface IRootMessageSender {
/// @notice Creates and send the message
function sendScheduleUpgrade(uint16 centrifugeId, bytes32 target) external;
/// @notice Creates and send the message
function sendCancelUpgrade(uint16 centrifugeId, bytes32 target) external;
/// @notice Creates and send the message
function sendRecoverTokens(
uint16 centrifugeId,
bytes32 target,
bytes32 token,
uint256 tokenId,
bytes32 to,
uint256 amount
) external;
}
/// @notice Interface for dispatch-only gateway
interface IHubMessageSender is ILocalCentrifugeId {
/// @notice Creates and send the message
function sendNotifyPool(uint16 centrifugeId, PoolId poolId) external;
/// @notice Creates and send the message
function sendNotifyShareClass(
uint16 centrifugeId,
PoolId poolId,
ShareClassId scId,
string memory name,
string memory symbol,
uint8 decimals,
bytes32 salt,
bytes32 hook
) external;
/// @notice Creates and send the message
function sendNotifyShareMetadata(
uint16 centrifugeId,
PoolId poolId,
ShareClassId scId,
string memory name,
string memory symbol
) external;
/// @notice Creates and send the message
function sendUpdateShareHook(uint16 centrifugeId, PoolId poolId, ShareClassId scId, bytes32 hook) external;
/// @notice Creates and send the message
function sendNotifyPricePoolPerShare(uint16 chainId, PoolId poolId, ShareClassId scId, D18 pricePerShare)
external;
/// @notice Creates and send the message
function sendNotifyPricePoolPerAsset(PoolId poolId, ShareClassId scId, AssetId assetId, D18 pricePerShare)
external;
/// @notice Creates and send the message
function sendUpdateRestriction(
uint16 centrifugeId,
PoolId poolId,
ShareClassId scId,
bytes calldata payload,
uint128 extraGasLimit
) external;
/// @notice Creates and send the message
function sendUpdateContract(
uint16 centrifugeId,
PoolId poolId,
ShareClassId scId,
bytes32 target,
bytes calldata payload,
uint128 extraGasLimit
) external;
/// @notice Creates and send the message
function sendUpdateVault(
PoolId poolId,
ShareClassId scId,
AssetId assetId,
bytes32 vaultOrFactory,
VaultUpdateKind kind,
uint128 extraGasLimit
) external;
/// @notice Creates and send the message
function sendSetRequestManager(PoolId poolId, ShareClassId scId, AssetId assetId, bytes32 manager) external;
/// @notice Creates and send the message
function sendUpdateBalanceSheetManager(uint16 centrifugeId, PoolId poolId, bytes32 who, bool canManage) external;
/// @notice Creates and send the message
function sendExecuteTransferShares(
uint16 centrifugeId,
PoolId poolId,
ShareClassId scId,
bytes32 receiver,
uint128 amount,
uint128 extraGasLimit
) external;
/// @notice Creates and send the message
function sendMaxAssetPriceAge(PoolId poolId, ShareClassId scId, AssetId assetId, uint64 maxPriceAge) external;
/// @notice Creates and send the message
function sendMaxSharePriceAge(uint16 centrifugeId, PoolId poolId, ShareClassId scId, uint64 maxPriceAge) external;
/// @notice Creates and send the message
function sendRequestCallback(
PoolId poolId,
ShareClassId scId,
AssetId assetId,
bytes calldata payload,
uint128 extraGasLimit
) external;
}
/// @notice Interface for dispatch-only gateway
interface ISpokeMessageSender is ILocalCentrifugeId {
struct UpdateData {
uint128 netAmount;
bool isIncrease;
bool isSnapshot;
uint64 nonce;
}
/// @notice Creates and send the message
function sendInitiateTransferShares(
uint16 centrifugeId,
PoolId poolId,
ShareClassId scId,
bytes32 receiver,
uint128 amount,
uint128 remoteExtraGasLimit
) external;
/// @notice Creates and send the message
function sendRegisterAsset(uint16 centrifugeId, AssetId assetId, uint8 decimals) external;
/// @notice Creates and send the message
function sendUpdateHoldingAmount(
PoolId poolId,
ShareClassId scId,
AssetId assetId,
UpdateData calldata data,
D18 pricePoolPerAsset,
uint128 extraGasLimit
) external;
/// @notice Creates and send the message
function sendUpdateShares(PoolId poolId, ShareClassId scId, UpdateData calldata data, uint128 extraGasLimit)
external;
/// @notice Creates and send the message
function sendRequest(PoolId poolId, ShareClassId scId, AssetId assetId, bytes calldata payload) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {PoolId} from "src/common/types/PoolId.sol";
import {IPoolEscrow} from "src/common/interfaces/IPoolEscrow.sol";
interface IPoolEscrowProvider {
/// @notice Returns the deterministic address of an escrow contract based on a given pool id wrapped into the
/// corresponding interface.
///
/// @dev Does not check, whether the escrow was already deployed.
function escrow(PoolId poolId) external view returns (IPoolEscrow);
}
interface IPoolEscrowFactory is IPoolEscrowProvider {
event DeployPoolEscrow(PoolId indexed poolId, address indexed escrow);
event File(bytes32 what, address data);
error FileUnrecognizedParam();
error EscrowAlreadyDeployed();
/// @notice Deploys new escrow and returns it.
/// @dev All share classes of a pool are represented by the same escrow contract.
///
/// @param poolId Id of the pool this escrow is deployed for
/// @return IPoolEscrow The the newly deployed escrow contract
function newEscrow(PoolId poolId) external returns (IPoolEscrow);
/// @notice Updates contract parameters of type address.
function file(bytes32 what, address data) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {D18, d18} from "src/misc/types/D18.sol";
/// @dev Price struct that contains a price, the timestamp at which it was computed and the max age of the price.
struct Price {
uint128 price;
uint64 computedAt;
uint64 maxAge;
}
/// @dev Checks if a price is valid. Returns false if computedAt is 0. Otherwise checks for block
/// timestamp <= computedAt + maxAge
function isValid(Price memory price) view returns (bool) {
if (price.computedAt != 0) {
return block.timestamp <= price.validUntil();
} else {
return false;
}
}
/// @dev Computes the timestamp until the price is valid. Saturates at uint64.MAX.
function validUntil(Price memory price) pure returns (uint64) {
unchecked {
uint64 validUntil_ = price.computedAt + price.maxAge;
if (validUntil_ < price.computedAt) {
return type(uint64).max;
}
return validUntil_;
}
}
/// @dev Retrieves the price as an D18 from the struct
function asPrice(Price memory price) pure returns (D18) {
return d18(price.price);
}
using {isValid, asPrice, validUntil} for Price global;// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {IERC20Metadata} from "src/misc/interfaces/IERC20.sol";
import {IERC7575Share} from "src/misc/interfaces/IERC7575.sol";
interface IERC1404 {
/// @notice Detects if a transfer will be reverted and if so returns an appropriate reference code
/// @param from Sending address
/// @param to Receiving address
/// @param value Amount of tokens being transferred
/// @return Code by which to reference message for rejection reasoning
/// @dev Overwrite with your custom transfer restriction logic
function detectTransferRestriction(address from, address to, uint256 value) external view returns (uint8);
/// @notice Returns a human-readable message for a given restriction code
/// @param restrictionCode Identifier for looking up a message
/// @return Text showing the restriction's reasoning
/// @dev Overwrite with your custom message and restrictionCode handling
function messageForTransferRestriction(uint8 restrictionCode) external view returns (string memory);
}
interface IShareToken is IERC20Metadata, IERC7575Share, IERC1404 {
// --- Events ---
event File(bytes32 indexed what, address data);
event SetHookData(address indexed user, bytes16 data);
// --- Errors ---
error NotAuthorizedOrHook();
error ExceedsMaxSupply();
error RestrictionsFailed();
struct Balance {
/// @dev The user balance is limited to uint128. This is safe because the decimals are limited to 18,
/// thus the max balance is 2^128-1 / 10**18 = 3.40 * 10**20. This is also enforced on mint.
uint128 amount;
/// @dev There are 16 bytes that are used to store hook data (e.g. restrictions for users).
bytes16 hookData;
}
// --- Administration ---
/// @notice returns the hook that transfers perform callbacks to
/// @dev MUST comply to `ITransferHook` interface
function hook() external view returns (address);
/// @notice Updates a contract parameter
/// @param what Accepts a bytes32 representation of 'name', 'symbol'
function file(bytes32 what, string memory data) external;
/// @notice Updates a contract parameter
/// @param what Accepts a bytes32 representation of 'hook'
function file(bytes32 what, address data) external;
/// @notice updates the vault for a given `asset`
function updateVault(address asset, address vault_) external;
// --- ERC20 overrides ---
/// @notice returns the 16 byte hook data of the given `user`.
/// @dev Stored in the 128 most significant bits of the user balance
function hookDataOf(address user) external view returns (bytes16);
/// @notice update the 16 byte hook data of the given `user`
function setHookData(address user, bytes16 hookData) external;
/// @notice Function to mint tokens
function mint(address user, uint256 value) external;
/// @notice Function to burn tokens
function burn(address user, uint256 value) external;
/// @notice Checks if the tokens can be transferred given the input values
function checkTransferRestriction(address from, address to, uint256 value) external view returns (bool);
/// @notice Performs an authorized transfer, with `sender` as the given sender.
/// @dev Requires allowance if `sender` != `from`
function authTransferFrom(address sender, address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {PoolId} from "src/common/types/PoolId.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
import {IVaultManager} from "src/spoke/interfaces/IVaultManager.sol";
enum VaultKind {
/// @dev Refers to AsyncVault
Async,
/// @dev not yet supported
Sync,
/// @dev Refers to SyncDepositVault
SyncDepositAsyncRedeem
}
/// @notice Interface for the all vault contracts
/// @dev Must be implemented by all vaults
interface IVault {
/// @notice Identifier of the Centrifuge pool
function poolId() external view returns (PoolId);
/// @notice Identifier of the share class of the Centrifuge pool
function scId() external view returns (ShareClassId);
/// @notice Returns the associated manager.
function manager() external view returns (IVaultManager);
/// @notice Checks whether the vault is partially (a)synchronous.
///
/// @return vaultKind_ The kind of the vault
function vaultKind() external view returns (VaultKind vaultKind_);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
interface IRequestManager {
error UnknownRequestCallbackType();
/// @notice Handles a request callback originating from the Hub side.
/// @param poolId The pool id
/// @param scId The share class id
/// @param assetId The asset id
/// @param payload The payload to be processed by the request callback
function callback(PoolId poolId, ShareClassId scId, AssetId assetId, bytes calldata payload) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {PoolId} from "src/common/types/PoolId.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
import {IVault} from "src/spoke/interfaces/IVault.sol";
import {IShareToken} from "src/spoke/interfaces/IShareToken.sol";
interface IVaultFactory {
error UnsupportedTokenId();
/// @notice Deploys new vault for `poolId`, `scId` and `asset`.
///
/// @param poolId Id of the pool. Id is one of the already supported pools.
/// @param scId Id of the share class token. Id is one of the already supported share class tokens.
/// @param asset Address of the underlying asset that is getting deposited inside the pool.
/// @param asset Token id of the underlying asset that is getting deposited inside the pool. I.e. zero if asset
/// corresponds to ERC20 or non-zero if asset corresponds to ERC6909.
/// @param token Address of the share class token that is getting issues against the deposited asset.
/// @param wards_ Address which can call methods behind authorized only.
function newVault(
PoolId poolId,
ShareClassId scId,
address asset,
uint256 tokenId,
IShareToken token,
address[] calldata wards_
) external returns (IVault);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IERC165} from "src/misc/interfaces/IERC165.sol";
interface IERC7575 is IERC165 {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the address of the share token
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function share() external view returns (address shareTokenAddress);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}
interface IERC7575Share is IERC165 {
event VaultUpdate(address indexed asset, address vault);
/**
* @dev Returns the address of the Vault for the given asset.
*
* @param asset the ERC-20 token to deposit with into the Vault
*/
function vault(address asset) external view returns (address);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IERC7540Operator {
/**
* @dev The event emitted when an operator is set.
*
* @param controller The address of the controller.
* @param operator The address of the operator.
* @param approved The approval status.
*/
event OperatorSet(address indexed controller, address indexed operator, bool approved);
/**
* @dev Sets or removes an operator for the caller.
*
* @param operator The address of the operator.
* @param approved The approval status.
* @return Whether the call was executed successfully or not
*/
function setOperator(address operator, bool approved) external returns (bool);
/**
* @dev Returns `true` if the `operator` is approved as an operator for an `controller`.
*
* @param controller The address of the controller.
* @param operator The address of the operator.
* @return status The approval status
*/
function isOperator(address controller, address operator) external view returns (bool status);
}
interface IERC7540Deposit is IERC7540Operator {
event DepositRequest(
address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets
);
/**
* @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.
*
* - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow.
* - MUST revert if all of assets cannot be requested for deposit.
* - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller,
* approval of ERC-20 tokens from owner to sender is NOT enough.
*
* @param assets the amount of deposit assets to transfer from owner
* @param controller the controller of the request who will be able to operate the request
* @param owner the source of the deposit assets
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.
*/
function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId);
/**
* @dev Returns the amount of requested assets in Pending state.
*
* - MUST NOT include any assets in Claimable state for deposit or mint.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
*/
function pendingDepositRequest(uint256 requestId, address controller)
external
view
returns (uint256 pendingAssets);
/**
* @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint.
*
* - MUST NOT include any assets in Pending state.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
*/
function claimableDepositRequest(uint256 requestId, address controller)
external
view
returns (uint256 claimableAssets);
/**
* @dev Mints shares Vault shares to receiver by claiming the Request of the controller.
*
* - MUST emit the Deposit event.
* - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.
*/
function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares);
/**
* @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller.
*
* - MUST emit the Deposit event.
* - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.
*/
function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets);
}
interface IERC7540Redeem is IERC7540Operator {
event RedeemRequest(
address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 shares
);
/**
* @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem.
*
* - MUST support a redeem Request flow where the control of shares is taken from sender directly
* where msg.sender has ERC-20 approval over the shares of owner.
* - MUST revert if all of shares cannot be requested for redeem.
*
* @param shares the amount of shares to be redeemed to transfer from owner
* @param controller the controller of the request who will be able to operate the request
* @param owner the source of the shares to be redeemed
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault's share token.
*/
function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId);
/**
* @dev Returns the amount of requested shares in Pending state.
*
* - MUST NOT include any shares in Claimable state for redeem or withdraw.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
*/
function pendingRedeemRequest(uint256 requestId, address controller)
external
view
returns (uint256 pendingShares);
/**
* @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw.
*
* - MUST NOT include any shares in Pending state for redeem or withdraw.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
*/
function claimableRedeemRequest(uint256 requestId, address controller)
external
view
returns (uint256 claimableShares);
}
interface IERC7887Deposit {
event CancelDepositRequest(address indexed controller, uint256 indexed requestId, address sender);
event CancelDepositClaim(
address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 assets
);
/**
* @dev Submits a Request for cancelling the pending deposit Request
*
* - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,
* approval of ERC-20 tokens from controller to sender is NOT enough.
* - MUST set pendingCancelDepositRequest to `true` for the returned requestId after request
* - MUST increase claimableCancelDepositRequest for the returned requestId after fulfillment
* - SHOULD be claimable using `claimCancelDepositRequest`
* Note: while `pendingCancelDepositRequest` is `true`, `requestDeposit` cannot be called
*/
function cancelDepositRequest(uint256 requestId, address controller) external;
/**
* @dev Returns whether the deposit Request is pending cancelation
*
* - MUST NOT show any variations depending on the caller.
*/
function pendingCancelDepositRequest(uint256 requestId, address controller)
external
view
returns (bool isPending);
/**
* @dev Returns the amount of assets that were canceled from a deposit Request, and can now be claimed.
*
* - MUST NOT show any variations depending on the caller.
*/
function claimableCancelDepositRequest(uint256 requestId, address controller)
external
view
returns (uint256 claimableAssets);
/**
* @dev Claims the canceled deposit assets, and removes the pending cancelation Request
*
* - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,
* approval of ERC-20 tokens from controller to sender is NOT enough.
* - MUST set pendingCancelDepositRequest to `false` for the returned requestId after request
* - MUST set claimableCancelDepositRequest to 0 for the returned requestId after fulfillment
*/
function claimCancelDepositRequest(uint256 requestId, address receiver, address controller)
external
returns (uint256 assets);
}
interface IERC7887Redeem {
event CancelRedeemRequest(address indexed controller, uint256 indexed requestId, address sender);
event CancelRedeemClaim(
address indexed controller, address indexed receiver, uint256 indexed requestId, address sender, uint256 shares
);
/**
* @dev Submits a Request for cancelling the pending redeem Request
*
* - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,
* approval of ERC-20 tokens from controller to sender is NOT enough.
* - MUST set pendingCancelRedeemRequest to `true` for the returned requestId after request
* - MUST increase claimableCancelRedeemRequest for the returned requestId after fulfillment
* - SHOULD be claimable using `claimCancelRedeemRequest`
* Note: while `pendingCancelRedeemRequest` is `true`, `requestRedeem` cannot be called
*/
function cancelRedeemRequest(uint256 requestId, address controller) external;
/**
* @dev Returns whether the redeem Request is pending cancelation
*
* - MUST NOT show any variations depending on the caller.
*/
function pendingCancelRedeemRequest(uint256 requestId, address controller) external view returns (bool isPending);
/**
* @dev Returns the amount of shares that were canceled from a redeem Request, and can now be claimed.
*
* - MUST NOT show any variations depending on the caller.
*/
function claimableCancelRedeemRequest(uint256 requestId, address controller)
external
view
returns (uint256 claimableShares);
/**
* @dev Claims the canceled redeem shares, and removes the pending cancelation Request
*
* - controller MUST be msg.sender unless some unspecified explicit approval is given by the caller,
* approval of ERC-20 tokens from controller to sender is NOT enough.
* - MUST set pendingCancelRedeemRequest to `false` for the returned requestId after request
* - MUST set claimableCancelRedeemRequest to 0 for the returned requestId after fulfillment
*/
function claimCancelRedeemRequest(uint256 requestId, address receiver, address controller)
external
returns (uint256 shares);
}
interface IERC7741 {
/**
* @dev Grants or revokes permissions for `operator` to manage Requests on behalf of the
* `msg.sender`, using an [EIP-712](./eip-712.md) signature.
*/
function authorizeOperator(
address controller,
address operator,
bool approved,
bytes32 nonce,
uint256 deadline,
bytes memory signature
) external returns (bool);
/**
* @dev Revokes the given `nonce` for `msg.sender` as the `owner`.
*/
function invalidateNonce(bytes32 nonce) external;
/**
* @dev Returns whether the given `nonce` has been used for the `controller`.
*/
function authorizations(address controller, bytes32 nonce) external view returns (bool used);
/**
* @dev Returns the `DOMAIN_SEPARATOR` as defined according to EIP-712. The `DOMAIN_SEPARATOR
* should be unique to the contract and chain to prevent replay attacks from other domains,
* and satisfy the requirements of EIP-712, but is otherwise unconstrained.
*/
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
interface IERC7714 {
/**
* @dev Returns `true` if the `user` is permissioned to interact with the contract.
*/
function isPermissioned(address controller) external view returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {IEscrow} from "src/misc/interfaces/IEscrow.sol";
import {PoolId} from "src/common/types/PoolId.sol";
import {IPoolEscrow} from "src/common/interfaces/IPoolEscrow.sol";
import {ISpoke} from "src/spoke/interfaces/ISpoke.sol";
import {IVaultManager} from "src/spoke/interfaces/IVaultManager.sol";
import {IRequestManager} from "src/spoke/interfaces/IRequestManager.sol";
import {IBaseVault} from "src/vaults/interfaces/IBaseVault.sol";
interface IBaseRequestManager is IVaultManager, IRequestManager {
event File(bytes32 indexed what, address data);
error FileUnrecognizedParam();
/// @notice Updates contract parameters of type address.
/// @param what The bytes32 representation of 'gateway' or 'spoke'.
/// @param data The new contract address.
function file(bytes32 what, address data) external;
/// @notice Converts the assets value to share decimals.
function convertToShares(IBaseVault vault, uint256 _assets) external view returns (uint256 shares);
/// @notice Converts the shares value to assets decimals.
function convertToAssets(IBaseVault vault, uint256 _shares) external view returns (uint256 assets);
/// @notice Returns the timestamp of the last share price update for a vaultAddr.
function priceLastUpdated(IBaseVault vault) external view returns (uint64 lastUpdated);
/// @notice Returns the Spoke contract address.
function spoke() external view returns (ISpoke spoke);
/// @notice The global escrow used for funds that are not yet free to be used for a specific pool
function globalEscrow() external view returns (IEscrow escrow);
/// @notice Escrow per pool. Funds are associated to a specific pool
function poolEscrow(PoolId poolId) external view returns (IPoolEscrow);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
interface IERC165 {
/// @notice Query if a contract implements an interface
/// @param interfaceID The interface identifier, as specified in ERC-165
/// @dev Interface identification is specified in ERC-165. This function
/// uses less than 30,000 gas.
/// @return `true` if the contract implements `interfaceID` and
/// `interfaceID` is not 0xffffffff, `false` otherwise
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// [ERC-7751](https://eips.ethereum.org/EIPS/eip-7751): Wrapping of bubbled up reverts
/// Handling bubbled up reverts using custom errors with additional context.
interface IERC7751 {
error WrappedError(address target, bytes4 selector, bytes reason, bytes details);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Escrow for holding assets
interface IEscrow {
// --- Events ---
/// @notice Emitted when an authTransferTo is made
/// @dev Needed as allowances increase attack surface
event AuthTransferTo(address indexed asset, uint256 indexed tokenId, address receiver, uint256 value);
/// @notice Emitted when the escrow has insufficient balance for an action - virtual or actual balance
error InsufficientBalance(address asset, uint256 tokenId, uint256 value, uint256 balance);
/// @notice
function authTransferTo(address asset, uint256 tokenId, address receiver, uint256 value) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {CastLib} from "src/misc/libraries/CastLib.sol";
import {BytesLib} from "src/misc/libraries/BytesLib.sol";
import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
// NOTE: Should never exceed 254 messages because id == 255 corresponds to message proofs
enum MessageType {
/// @dev Placeholder for null message type
_Invalid,
// -- Pool independent messages
ScheduleUpgrade,
CancelUpgrade,
RecoverTokens,
RegisterAsset,
_Placeholder5,
_Placeholder6,
_Placeholder7,
_Placeholder8,
_Placeholder9,
_Placeholder10,
_Placeholder11,
_Placeholder12,
_Placeholder13,
_Placeholder14,
_Placeholder15,
// -- Pool dependent messages
NotifyPool,
NotifyShareClass,
NotifyPricePoolPerShare,
NotifyPricePoolPerAsset,
NotifyShareMetadata,
UpdateShareHook,
InitiateTransferShares,
ExecuteTransferShares,
UpdateRestriction,
UpdateContract,
UpdateVault,
UpdateBalanceSheetManager,
UpdateHoldingAmount,
UpdateShares,
MaxAssetPriceAge,
MaxSharePriceAge,
Request,
RequestCallback,
SetRequestManager
}
/// @dev Used internally in the UpdateVault message (not represent a submessage)
enum VaultUpdateKind {
DeployAndLink,
Link,
Unlink
}
library MessageLib {
using MessageLib for bytes;
using BytesLib for bytes;
using CastLib for *;
error UnknownMessageType();
/// @dev Encode all message lengths in this constant to avoid a large list of if/elseif checks
/// and reduce generated bytecode.
/// If the message has some dynamic part, will be added later in `messageLength()`.
// forgefmt: disable-next-item
uint256 constant MESSAGE_LENGTHS_1 =
(33 << uint8(MessageType.ScheduleUpgrade) * 8) +
(33 << uint8(MessageType.CancelUpgrade) * 8) +
(161 << uint8(MessageType.RecoverTokens) * 8) +
(18 << uint8(MessageType.RegisterAsset) * 8) +
(0 << uint8(MessageType._Placeholder5) * 8) +
(0 << uint8(MessageType._Placeholder6) * 8) +
(0 << uint8(MessageType._Placeholder7) * 8) +
(0 << uint8(MessageType._Placeholder8) * 8) +
(0 << uint8(MessageType._Placeholder9) * 8) +
(0 << uint8(MessageType._Placeholder10) * 8) +
(0 << uint8(MessageType._Placeholder11) * 8) +
(0 << uint8(MessageType._Placeholder12) * 8) +
(0 << uint8(MessageType._Placeholder13) * 8) +
(0 << uint8(MessageType._Placeholder14) * 8) +
(0 << uint8(MessageType._Placeholder15) * 8) +
(9 << uint8(MessageType.NotifyPool) * 8) +
(250 << uint8(MessageType.NotifyShareClass) * 8) +
(49 << uint8(MessageType.NotifyPricePoolPerShare) * 8) +
(65 << uint8(MessageType.NotifyPricePoolPerAsset) * 8) +
(185 << uint8(MessageType.NotifyShareMetadata) * 8) +
(57 << uint8(MessageType.UpdateShareHook) * 8) +
(91 << uint8(MessageType.InitiateTransferShares) * 8) +
(73 << uint8(MessageType.ExecuteTransferShares) * 8) +
(25 << uint8(MessageType.UpdateRestriction) * 8) +
(57 << uint8(MessageType.UpdateContract) * 8) +
(74 << uint8(MessageType.UpdateVault) * 8) +
(42 << uint8(MessageType.UpdateBalanceSheetManager) * 8) +
(91 << uint8(MessageType.UpdateHoldingAmount) * 8) +
(59 << uint8(MessageType.UpdateShares) * 8) +
(49 << uint8(MessageType.MaxAssetPriceAge) * 8) +
(33 << uint8(MessageType.MaxSharePriceAge) * 8);
// forgefmt: disable-next-item
uint256 constant MESSAGE_LENGTHS_2 =
(41 << (uint8(MessageType.Request) - 32) * 8) +
(41 << (uint8(MessageType.RequestCallback) - 32) * 8) +
(73 << (uint8(MessageType.SetRequestManager) - 32) * 8);
function messageType(bytes memory message) internal pure returns (MessageType) {
return MessageType(message.toUint8(0));
}
function messageCode(bytes memory message) internal pure returns (uint8) {
return message.toUint8(0);
}
function messageLength(bytes memory message) internal pure returns (uint16 length) {
uint8 kind = message.toUint8(0);
require(kind <= uint8(type(MessageType).max), UnknownMessageType());
length = (kind <= 31)
? uint16(uint8(bytes32(MESSAGE_LENGTHS_1)[31 - kind]))
: uint16(uint8(bytes32(MESSAGE_LENGTHS_2)[63 - kind]));
// Special treatment for messages with dynamic size:
if (kind == uint8(MessageType.UpdateRestriction)) {
length += 2 + message.toUint16(length); //payloadLength
} else if (kind == uint8(MessageType.UpdateContract)) {
length += 2 + message.toUint16(length); //payloadLength
} else if (kind == uint8(MessageType.Request)) {
length += 2 + message.toUint16(length); //payloadLength
} else if (kind == uint8(MessageType.RequestCallback)) {
length += 2 + message.toUint16(length); //payloadLength
}
}
function messagePoolId(bytes memory message) internal pure returns (PoolId poolId) {
uint8 kind = message.toUint8(0);
// All messages from NotifyPool to the end contains a PoolId in position 1.
if (kind >= uint8(MessageType.NotifyPool)) {
return PoolId.wrap(message.toUint64(1));
} else {
return PoolId.wrap(0);
}
}
function messageSourceCentrifugeId(bytes memory message) internal pure returns (uint16) {
uint8 kind = message.toUint8(0);
if (kind <= uint8(MessageType.RecoverTokens)) {
return 0; // Non centrifugeId associated
} else if (kind == uint8(MessageType.UpdateShares) || kind == uint8(MessageType.InitiateTransferShares)) {
return 0; // Non centrifugeId associated
} else if (kind == uint8(MessageType.RegisterAsset)) {
return AssetId.wrap(message.toUint128(1)).centrifugeId();
} else if (kind == uint8(MessageType.UpdateHoldingAmount)) {
return AssetId.wrap(message.toUint128(25)).centrifugeId();
} else if (kind == uint8(MessageType.Request)) {
return AssetId.wrap(message.toUint128(25)).centrifugeId();
} else {
return message.messagePoolId().centrifugeId();
}
}
//---------------------------------------
// ScheduleUpgrade
//---------------------------------------
struct ScheduleUpgrade {
bytes32 target;
}
function deserializeScheduleUpgrade(bytes memory data) internal pure returns (ScheduleUpgrade memory) {
require(messageType(data) == MessageType.ScheduleUpgrade, UnknownMessageType());
return ScheduleUpgrade({target: data.toBytes32(1)});
}
function serialize(ScheduleUpgrade memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.ScheduleUpgrade, t.target);
}
//---------------------------------------
// CancelUpgrade
//---------------------------------------
struct CancelUpgrade {
bytes32 target;
}
function deserializeCancelUpgrade(bytes memory data) internal pure returns (CancelUpgrade memory) {
require(messageType(data) == MessageType.CancelUpgrade, UnknownMessageType());
return CancelUpgrade({target: data.toBytes32(1)});
}
function serialize(CancelUpgrade memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.CancelUpgrade, t.target);
}
//---------------------------------------
// RecoverTokens
//---------------------------------------
struct RecoverTokens {
bytes32 target;
bytes32 token;
uint256 tokenId;
bytes32 to;
uint256 amount;
}
function deserializeRecoverTokens(bytes memory data) internal pure returns (RecoverTokens memory) {
require(messageType(data) == MessageType.RecoverTokens, UnknownMessageType());
return RecoverTokens({
target: data.toBytes32(1),
token: data.toBytes32(33),
tokenId: data.toUint256(65),
to: data.toBytes32(97),
amount: data.toUint256(129)
});
}
function serialize(RecoverTokens memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.RecoverTokens, t.target, t.token, t.tokenId, t.to, t.amount);
}
//---------------------------------------
// RegisterAsset
//---------------------------------------
struct RegisterAsset {
uint128 assetId;
uint8 decimals;
}
function deserializeRegisterAsset(bytes memory data) internal pure returns (RegisterAsset memory) {
require(messageType(data) == MessageType.RegisterAsset, UnknownMessageType());
return RegisterAsset({assetId: data.toUint128(1), decimals: data.toUint8(17)});
}
function serialize(RegisterAsset memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.RegisterAsset, t.assetId, t.decimals);
}
//---------------------------------------
// NotifyPool
//---------------------------------------
struct NotifyPool {
uint64 poolId;
}
function deserializeNotifyPool(bytes memory data) internal pure returns (NotifyPool memory) {
require(messageType(data) == MessageType.NotifyPool, UnknownMessageType());
return NotifyPool({poolId: data.toUint64(1)});
}
function serialize(NotifyPool memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.NotifyPool, t.poolId);
}
//---------------------------------------
// NotifyShareClass
//---------------------------------------
struct NotifyShareClass {
uint64 poolId;
bytes16 scId;
string name; // Fixed to 128 bytes
bytes32 symbol; // utf8
uint8 decimals;
bytes32 salt;
bytes32 hook;
}
function deserializeNotifyShareClass(bytes memory data) internal pure returns (NotifyShareClass memory) {
require(messageType(data) == MessageType.NotifyShareClass, UnknownMessageType());
return NotifyShareClass({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
name: data.slice(25, 128).bytes128ToString(),
symbol: data.toBytes32(153),
decimals: data.toUint8(185),
salt: data.toBytes32(186),
hook: data.toBytes32(218)
});
}
function serialize(NotifyShareClass memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.NotifyShareClass,
t.poolId,
t.scId,
bytes(t.name).sliceZeroPadded(0, 128),
t.symbol,
t.decimals,
t.salt,
t.hook
);
}
//---------------------------------------
// NotifyPricePoolPerShare
//---------------------------------------
struct NotifyPricePoolPerShare {
uint64 poolId;
bytes16 scId;
uint128 price;
uint64 timestamp;
}
function deserializeNotifyPricePoolPerShare(bytes memory data)
internal
pure
returns (NotifyPricePoolPerShare memory)
{
require(messageType(data) == MessageType.NotifyPricePoolPerShare, UnknownMessageType());
return NotifyPricePoolPerShare({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
price: data.toUint128(25),
timestamp: data.toUint64(41)
});
}
function serialize(NotifyPricePoolPerShare memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.NotifyPricePoolPerShare, t.poolId, t.scId, t.price, t.timestamp);
}
//---------------------------------------
// NotifyPricePoolPerAsset
//---------------------------------------
struct NotifyPricePoolPerAsset {
uint64 poolId;
bytes16 scId;
uint128 assetId;
uint128 price;
uint64 timestamp;
}
function deserializeNotifyPricePoolPerAsset(bytes memory data)
internal
pure
returns (NotifyPricePoolPerAsset memory)
{
require(messageType(data) == MessageType.NotifyPricePoolPerAsset, UnknownMessageType());
return NotifyPricePoolPerAsset({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
price: data.toUint128(41),
timestamp: data.toUint64(57)
});
}
function serialize(NotifyPricePoolPerAsset memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.NotifyPricePoolPerAsset, t.poolId, t.scId, t.assetId, t.price, t.timestamp);
}
//---------------------------------------
// NotifyShareMetadata
//---------------------------------------
struct NotifyShareMetadata {
uint64 poolId;
bytes16 scId;
string name; // Fixed to 128 bytes
bytes32 symbol; // utf8
}
function deserializeNotifyShareMetadata(bytes memory data) internal pure returns (NotifyShareMetadata memory) {
require(messageType(data) == MessageType.NotifyShareMetadata, UnknownMessageType());
return NotifyShareMetadata({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
name: data.slice(25, 128).bytes128ToString(),
symbol: data.toBytes32(153)
});
}
function serialize(NotifyShareMetadata memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.NotifyShareMetadata, t.poolId, t.scId, bytes(t.name).sliceZeroPadded(0, 128), t.symbol
);
}
//---------------------------------------
// UpdateShareHook
//---------------------------------------
struct UpdateShareHook {
uint64 poolId;
bytes16 scId;
bytes32 hook;
}
function deserializeUpdateShareHook(bytes memory data) internal pure returns (UpdateShareHook memory) {
require(messageType(data) == MessageType.UpdateShareHook, UnknownMessageType());
return UpdateShareHook({poolId: data.toUint64(1), scId: data.toBytes16(9), hook: data.toBytes32(25)});
}
function serialize(UpdateShareHook memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.UpdateShareHook, t.poolId, t.scId, t.hook);
}
//---------------------------------------
// InitiateTransferShares
//---------------------------------------
struct InitiateTransferShares {
uint64 poolId;
bytes16 scId;
uint16 centrifugeId;
bytes32 receiver;
uint128 amount;
uint128 extraGasLimit;
}
function deserializeInitiateTransferShares(bytes memory data)
internal
pure
returns (InitiateTransferShares memory)
{
require(messageType(data) == MessageType.InitiateTransferShares, UnknownMessageType());
return InitiateTransferShares({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
centrifugeId: data.toUint16(25),
receiver: data.toBytes32(27),
amount: data.toUint128(59),
extraGasLimit: data.toUint128(75)
});
}
function serialize(InitiateTransferShares memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.InitiateTransferShares, t.poolId, t.scId, t.centrifugeId, t.receiver, t.amount, t.extraGasLimit
);
}
//---------------------------------------
// ExecuteTransferShares
//---------------------------------------
struct ExecuteTransferShares {
uint64 poolId;
bytes16 scId;
bytes32 receiver;
uint128 amount;
}
function deserializeExecuteTransferShares(bytes memory data) internal pure returns (ExecuteTransferShares memory) {
require(messageType(data) == MessageType.ExecuteTransferShares, UnknownMessageType());
return ExecuteTransferShares({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
receiver: data.toBytes32(25),
amount: data.toUint128(57)
});
}
function serialize(ExecuteTransferShares memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.ExecuteTransferShares, t.poolId, t.scId, t.receiver, t.amount);
}
//---------------------------------------
// UpdateRestriction
//---------------------------------------
struct UpdateRestriction {
uint64 poolId;
bytes16 scId;
bytes payload; // As sequence of bytes
}
function deserializeUpdateRestriction(bytes memory data) internal pure returns (UpdateRestriction memory) {
require(messageType(data) == MessageType.UpdateRestriction, UnknownMessageType());
uint16 payloadLength = data.toUint16(25);
return UpdateRestriction({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
payload: data.slice(27, payloadLength)
});
}
function serialize(UpdateRestriction memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.UpdateRestriction, t.poolId, t.scId, uint16(t.payload.length), t.payload);
}
//---------------------------------------
// UpdateContract
//---------------------------------------
struct UpdateContract {
uint64 poolId;
bytes16 scId;
bytes32 target;
bytes payload; // As sequence of bytes
}
function deserializeUpdateContract(bytes memory data) internal pure returns (UpdateContract memory) {
require(messageType(data) == MessageType.UpdateContract, UnknownMessageType());
uint16 payloadLength = data.toUint16(57);
return UpdateContract({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
target: data.toBytes32(25),
payload: data.slice(59, payloadLength)
});
}
function serialize(UpdateContract memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.UpdateContract, t.poolId, t.scId, t.target, uint16(t.payload.length), t.payload
);
}
//---------------------------------------
// Request
//---------------------------------------
struct Request {
uint64 poolId;
bytes16 scId;
uint128 assetId;
bytes payload; // As sequence of bytes
}
function deserializeRequest(bytes memory data) internal pure returns (Request memory) {
require(messageType(data) == MessageType.Request, UnknownMessageType());
uint16 payloadLength = data.toUint16(41);
return Request({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
payload: data.slice(43, payloadLength)
});
}
function serialize(Request memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.Request, t.poolId, t.scId, t.assetId, uint16(t.payload.length), t.payload);
}
//---------------------------------------
// RequestCallback
//---------------------------------------
struct RequestCallback {
uint64 poolId;
bytes16 scId;
uint128 assetId;
bytes payload; // As sequence of bytes
}
function deserializeRequestCallback(bytes memory data) internal pure returns (RequestCallback memory) {
require(messageType(data) == MessageType.RequestCallback, UnknownMessageType());
uint16 payloadLength = data.toUint16(41);
return RequestCallback({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
payload: data.slice(43, payloadLength)
});
}
function serialize(RequestCallback memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.RequestCallback, t.poolId, t.scId, t.assetId, uint16(t.payload.length), t.payload
);
}
//---------------------------------------
// VaultUpdate
//---------------------------------------
struct UpdateVault {
uint64 poolId;
bytes16 scId;
uint128 assetId;
bytes32 vaultOrFactory;
uint8 kind;
}
function deserializeUpdateVault(bytes memory data) internal pure returns (UpdateVault memory) {
require(messageType(data) == MessageType.UpdateVault, UnknownMessageType());
return UpdateVault({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
vaultOrFactory: data.toBytes32(41),
kind: data.toUint8(73)
});
}
function serialize(UpdateVault memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.UpdateVault, t.poolId, t.scId, t.assetId, t.vaultOrFactory, t.kind);
}
//---------------------------------------
// SetRequestManager
//---------------------------------------
struct SetRequestManager {
uint64 poolId;
bytes16 scId;
uint128 assetId;
bytes32 manager;
}
function deserializeSetRequestManager(bytes memory data) internal pure returns (SetRequestManager memory) {
require(messageType(data) == MessageType.SetRequestManager, UnknownMessageType());
return SetRequestManager({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
manager: data.toBytes32(41)
});
}
function serialize(SetRequestManager memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.SetRequestManager, t.poolId, t.scId, t.assetId, t.manager);
}
//---------------------------------------
// UpdateBalanceSheetManager
//---------------------------------------
struct UpdateBalanceSheetManager {
uint64 poolId;
bytes32 who;
bool canManage;
}
function deserializeUpdateBalanceSheetManager(bytes memory data)
internal
pure
returns (UpdateBalanceSheetManager memory)
{
require(messageType(data) == MessageType.UpdateBalanceSheetManager, UnknownMessageType());
return UpdateBalanceSheetManager({poolId: data.toUint64(1), who: data.toBytes32(9), canManage: data.toBool(41)});
}
function serialize(UpdateBalanceSheetManager memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.UpdateBalanceSheetManager, t.poolId, t.who, t.canManage);
}
//---------------------------------------
// UpdateHoldingAmount
//---------------------------------------
struct UpdateHoldingAmount {
uint64 poolId;
bytes16 scId;
uint128 assetId;
uint128 amount;
uint128 pricePerUnit;
uint64 timestamp;
bool isIncrease;
bool isSnapshot;
uint64 nonce;
}
function deserializeUpdateHoldingAmount(bytes memory data) internal pure returns (UpdateHoldingAmount memory h) {
require(messageType(data) == MessageType.UpdateHoldingAmount, "UnknownMessageType");
return UpdateHoldingAmount({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
amount: data.toUint128(41),
pricePerUnit: data.toUint128(57),
timestamp: data.toUint64(73),
isIncrease: data.toBool(81),
isSnapshot: data.toBool(82),
nonce: data.toUint64(83)
});
}
function serialize(UpdateHoldingAmount memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.UpdateHoldingAmount,
t.poolId,
t.scId,
t.assetId,
t.amount,
t.pricePerUnit,
t.timestamp,
t.isIncrease,
t.isSnapshot,
t.nonce
);
}
//---------------------------------------
// UpdateShares
//---------------------------------------
struct UpdateShares {
uint64 poolId;
bytes16 scId;
uint128 shares;
uint64 timestamp;
bool isIssuance;
bool isSnapshot;
uint64 nonce;
}
function deserializeUpdateShares(bytes memory data) internal pure returns (UpdateShares memory) {
require(messageType(data) == MessageType.UpdateShares, UnknownMessageType());
return UpdateShares({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
shares: data.toUint128(25),
timestamp: data.toUint64(41),
isIssuance: data.toBool(49),
isSnapshot: data.toBool(50),
nonce: data.toUint64(51)
});
}
function serialize(UpdateShares memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.UpdateShares, t.poolId, t.scId, t.shares, t.timestamp, t.isIssuance, t.isSnapshot, t.nonce
);
}
//---------------------------------------
// MaxAssetPriceAge
//---------------------------------------
struct MaxAssetPriceAge {
uint64 poolId;
bytes16 scId;
uint128 assetId;
uint64 maxPriceAge;
}
function deserializeMaxAssetPriceAge(bytes memory data) internal pure returns (MaxAssetPriceAge memory) {
require(messageType(data) == MessageType.MaxAssetPriceAge, UnknownMessageType());
return MaxAssetPriceAge({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
maxPriceAge: data.toUint64(41)
});
}
function serialize(MaxAssetPriceAge memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.MaxAssetPriceAge, t.poolId, t.scId, t.assetId, t.maxPriceAge);
}
//---------------------------------------
// MaxSharePriceAge
//---------------------------------------
struct MaxSharePriceAge {
uint64 poolId;
bytes16 scId;
uint64 maxPriceAge;
}
function deserializeMaxSharePriceAge(bytes memory data) internal pure returns (MaxSharePriceAge memory) {
require(messageType(data) == MessageType.MaxSharePriceAge, UnknownMessageType());
return MaxSharePriceAge({poolId: data.toUint64(1), scId: data.toBytes16(9), maxPriceAge: data.toUint64(25)});
}
function serialize(MaxSharePriceAge memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.MaxSharePriceAge, t.poolId, t.scId, t.maxPriceAge);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
import {IVault} from "src/spoke/interfaces/IVault.sol";
interface IVaultManager {
error VaultAlreadyExists();
error VaultDoesNotExist();
/// @notice Emitted when a new vault is added
/// @param poolId The pool ID
/// @param scId The share class ID
/// @param assetId The asset ID
/// @param vault The address of the vault being added
event AddVault(PoolId indexed poolId, ShareClassId indexed scId, AssetId indexed assetId, IVault vault);
/// @notice Emitted when a vault is removed
/// @param poolId The pool ID
/// @param scId The share class ID
/// @param assetId The asset ID
/// @param vault The address of the vault being removed
event RemoveVault(PoolId indexed poolId, ShareClassId indexed scId, AssetId indexed assetId, IVault vault);
/// @notice Adds new vault for `poolId`, `scId` and `assetId`.
function addVault(PoolId poolId, ShareClassId scId, AssetId assetId, IVault vault, address asset, uint256 tokenId)
external;
/// @notice Removes `vault` from `who`'s authorized callers
function removeVault(
PoolId poolId,
ShareClassId scId,
AssetId assetId,
IVault vault,
address asset,
uint256 tokenId
) external;
/// @notice Returns the address of the vault for a given pool, share class and asset
function vaultByAssetId(PoolId poolId, ShareClassId scId, AssetId assetId) external view returns (IVault vault);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"remappings": [
"forge-std/=lib/forge-std/src/",
"@chimera/=lib/chimera/src/",
"createx-forge/=lib/createx-forge/",
"chimera/=lib/chimera/src/",
"ds-test/=lib/chimera/lib/forge-std/lib/ds-test/src/",
"setup-helpers/=lib/setup-helpers/src/"
],
"optimizer": {
"enabled": true,
"runs": 1
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"deployer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ExceedsMaxDeposit","type":"error"},{"inputs":[],"name":"ExceedsMaxMint","type":"error"},{"inputs":[],"name":"FileUnrecognizedParam","type":"error"},{"inputs":[],"name":"MulDiv_Overflow","type":"error"},{"inputs":[],"name":"NoCode","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"SafeTransferEthFailed","type":"error"},{"inputs":[],"name":"SecondaryManagerDoesNotExist","type":"error"},{"inputs":[],"name":"ShareTokenDoesNotExist","type":"error"},{"inputs":[],"name":"SliceOutOfBounds","type":"error"},{"inputs":[],"name":"Uint128_Overflow","type":"error"},{"inputs":[],"name":"UnknownMessageType","type":"error"},{"inputs":[],"name":"UnknownUpdateContractType","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"bytes","name":"reason","type":"bytes"},{"internalType":"bytes","name":"details","type":"bytes"}],"name":"WrappedError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Deny","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"what","type":"bytes32"},{"indexed":false,"internalType":"address","name":"data","type":"address"}],"name":"File","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Rely","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"maxReserve","type":"uint128"}],"name":"SetMaxReserve","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"indexed":false,"internalType":"address","name":"valuation","type":"address"}],"name":"SetValuation","type":"event"},{"inputs":[],"name":"balanceSheet","outputs":[{"internalType":"contract IBalanceSheet","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"what","type":"bytes32"},{"internalType":"address","name":"data","type":"address"}],"name":"file","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"maxReserve","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBaseVault","name":"vault_","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"}],"name":"pricePoolPerShare","outputs":[{"internalType":"D18","name":"price","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint128","name":"maxReserve_","type":"uint128"}],"name":"setMaxReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"address","name":"valuation_","type":"address"}],"name":"setValuation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"spoke","outputs":[{"internalType":"contract ISpoke","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"update","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"}],"name":"valuation","outputs":[{"internalType":"contract ISyncDepositValuation","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6080604052348015600e575f5ffd5b50604051612b90380380612b90833981016040819052602b916074565b6001600160a01b0381165f8181526020819052604080822060019055518392917fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a6091a25050609f565b5f602082840312156083575f5ffd5b81516001600160a01b03811681146098575f5ffd5b9392505050565b612ae4806100ac5f395ff3fe608060405234801561000f575f5ffd5b5060043610610110575f3560e01c806306932fcb1461011457806322285cf61461012957806323c5b7ed1461015257806332de5d3c14610173578063340ab91d146101a65780633a4d2cd1146101b95780633e5541f1146101cc57806347bfbcc6146101df57806350603df3146101f25780635f3e849f146102055780636179ab011461021857806365fae35e1461022b578063760168701461023e5780637cd878eb14610251578063947b330a146102645780639c52a7f114610277578063bd80f7c41461028a578063bf353dbb146102d9578063c6f1649f146102f8578063d4e8be831461030b578063d72e42851461031e578063f2e586db14610331575b5f5ffd5b610127610122366004612335565b610344565b005b60025461013c906001600160a01b031681565b604051610149919061237d565b60405180910390f35b610165610160366004612391565b6103f9565b604051908152602001610149565b61013c6101813660046123cf565b600360209081525f92835260408084209091529082529020546001600160a01b031681565b6101276101b436600461244a565b610410565b6101656101c7366004612500565b610686565b6101656101da366004612550565b610710565b60015461013c906001600160a01b031681565b610165610200366004612550565b610a48565b610127610213366004612391565b610a54565b61012761022636600461258e565b610ac2565b6101276102393660046125f2565b610b96565b61016561024c36600461260d565b610c09565b61016561025f366004612391565b610d62565b610127610272366004612639565b610d6d565b6101276102853660046125f2565b610e31565b6102cc61029836600461267e565b600460209081525f94855260408086208252938552838520815291845282842090915282529020546001600160801b031681565b60405161014991906126bc565b6101656102e73660046125f2565b5f6020819052908152604090205481565b610165610306366004612500565b610ea3565b6101276103193660046126d0565b610f20565b6102cc61032c3660046123cf565b611009565b61016561033f36600461260d565b61114c565b335f908152602081905260409020546001146103735760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0383165f8181526003602090815260408083206001600160801b0319871680855292529182902080546001600160a01b0319166001600160a01b03861617905590519091907ff4930db4239d7c3f044b38dbe35777d82b713760fcaf0067537eb8d0d0446b2e906103ec90859061237d565b60405180910390a3505050565b5f610406848360016112b3565b90505b9392505050565b335f9081526020819052604090205460011461043f5760405163ea8e4eb560e01b815260040160405180910390fd5b5f610449826115c6565b600481111561045a5761045a6126f3565b90505f1960ff821601610525575f610471836115e5565b60015460405163602ff8a960e11b81529192505f916001600160a01b039091169063c05ff152906104a89089908990600401612707565b602060405180830381865afa1580156104c3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104e7919061272a565b6001600160a01b03160361050e57604051630344039160e61b815260040160405180910390fd5b61051f8585610122845f015161164c565b50610680565b60011960ff821601610667575f61053b836116ab565b60015460405163602ff8a960e11b81529192505f916001600160a01b039091169063c05ff152906105729089908990600401612707565b602060405180830381865afa15801561058d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105b1919061272a565b6001600160a01b0316036105d857604051630344039160e61b815260040160405180910390fd5b600154815160405163cee8983d60e01b81525f9283926001600160a01b039091169163cee8983d9161060c916004016126bc565b6040805180830381865afa158015610626573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061064a9190612745565b9150915061065f878784848760200151610ac2565b505050610680565b604051638f0997cd60e01b815260040160405180910390fd5b50505050565b335f908152602081905260408120546001146106b55760405163ea8e4eb560e01b815260040160405180910390fd5b836106c0868461114c565b10156106df576040516352f7657b60e01b815260040160405180910390fd5b6106ea8583866103f9565b9050610708856106f986611738565b8561070385611738565b611765565b949350505050565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff1539061074490879060040161237d565b608060405180830381865afa15801561075f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107839190612785565b90505f610849856001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e991906127fe565b866001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610825573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061032c9190612819565b90505f60015f9054906101000a90046001600160a01b03166001600160a01b031663fd6906ed876001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ab573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108cf91906127fe565b886001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561090b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061092f9190612819565b86516040516001600160e01b031960e086901b16815261095793929190600190600401612834565b602060405180830381865afa158015610972573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610996919061286f565b90506109aa826001600160801b0316611aba565b610a3157610a2c866001600160a01b031663a8d5fd656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109ed573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a11919061272a565b84602001518560400151610a2489611738565b85875f611ac7565b610a33565b5f5b6001600160801b031693505050505b92915050565b5f61040983835f6112b3565b335f90815260208190526040902054600114610a835760405163ea8e4eb560e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601610ab757610ab28282611b9f565b505050565b610ab2838383611c29565b335f90815260208190526040902054600114610af15760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0385165f8181526004602090815260408083206001600160801b03198981168086529184528285206001600160a01b038a1680875290855283862089875285529483902080546001600160801b03891692168217905582519485529284018790529083019190915291907ffece2f0a4e9094e6d87c0f7c8d9a7b92988c81690bcdd1be82e35ef3d7338ab09060600160405180910390a35050505050565b335f90815260208190526040902054600114610bc55760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff15390610c3d90879060040161237d565b608060405180830381865afa158015610c58573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c7c9190612785565b9050610d51846001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cbd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ce191906127fe565b856001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d1d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d419190612819565b8360200151846040015188611d76565b6001600160801b0316949350505050565b5f6104068483610710565b335f90815260208190526040902054600114610d9c5760405163ea8e4eb560e01b815260040160405180910390fd5b825f03610db357610dae848383610a54565b610680565b6040516304ade6db60e11b81526001600160a01b038381166004830152602482018590526044820183905285169063095bcdb6906064016020604051808303815f875af1158015610e06573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e2a919061288a565b5050505050565b335f90815260208190526040902054600114610e605760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b335f90815260208190526040812054600114610ed25760405163ea8e4eb560e01b815260040160405180910390fd5b83610edd8684610c09565b1015610efc5760405163e4bac01b60e01b815260040160405180910390fd5b610f07858386610d62565b905061070885610f1683611738565b8561070388611738565b335f90815260208190526040902054600114610f4f5760405163ea8e4eb560e01b815260040160405180910390fd5b816473706f6b6560d81b03610f7e57600180546001600160a01b0319166001600160a01b038316179055610fcd565b816b18985b185b98d954da19595d60a21b03610fb457600280546001600160a01b0319166001600160a01b038316179055610fcd565b604051633db0d5b960e01b815260040160405180910390fd5b817f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba82604051610ffd919061237d565b60405180910390a25050565b6001600160401b0382165f9081526003602090815260408083206001600160801b0319851684529091528120546001600160a01b0316806110d55760018054604051635274887b60e01b81526001600160401b03871660048201526001600160801b03198616602482015260448101929092526001600160a01b031690635274887b90606401602060405180830381865afa1580156110aa573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110ce919061286f565b9150611145565b60405163d72e428560e01b81526001600160a01b0382169063d72e4285906111039087908790600401612707565b602060405180830381865afa15801561111e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611142919061286f565b91505b5092915050565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff1539061118090879060040161237d565b608060405180830381865afa15801561119b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111bf9190612785565b90505f611295856001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611201573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061122591906127fe565b866001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611261573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112859190612819565b8460200151856040015189611d76565b90506112aa85826001600160801b0316610710565b95945050505050565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff153906112e790889060040161237d565b608060405180830381865afa158015611302573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113269190612785565b90505f6113c8866001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611368573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061138c91906127fe565b876001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610825573d5f5f3e3d5ffd5b90505f60015f9054906101000a90046001600160a01b03166001600160a01b031663fd6906ed886001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561142a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061144e91906127fe565b896001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561148a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114ae9190612819565b86516040516001600160e01b031960e086901b1681526114d693929190600190600401612834565b602060405180830381865afa1580156114f1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611515919061286f565b9050611529816001600160801b0316611aba565b6115b0576115ab876001600160a01b031663a8d5fd656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561156c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611590919061272a565b61159988611738565b8560200151866040015186868b611f00565b6115b2565b5f5b6001600160801b0316979650505050505050565b5f6115d18282611fba565b60ff166004811115610a4257610a426126f3565b60408051602081019091525f815260016115fe836115c6565b600481111561160f5761160f6126f3565b1461162d576040516304c735eb60e11b815260040160405180910390fd5b604080516020810190915280611644846001611ff0565b905292915050565b5f6001600160601b038216156116a45760405162461bcd60e51b8152602060048201526018602482015277496e7075742073686f756c6420626520323020627974657360401b60448201526064015b60405180910390fd5b5060601c90565b604080518082019091525f808252602082015260026116c9836115c6565b60048111156116da576116da6126f3565b146116f8576040516304c735eb60e11b815260040160405180910390fd5b604080518082019091528061170e846001612026565b6001600160801b03168152602001611727846011612026565b6001600160801b0316905292915050565b5f6001600160801b038211156117615760405163e999826d60e01b815260040160405180910390fd5b5090565b5f846001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117a2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117c691906127fe565b90505f856001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611805573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118299190612819565b600154604051632a7ff15360e01b81529192505f916001600160a01b0390911690632a7ff1539061185e908a9060040161237d565b608060405180830381865afa158015611879573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061189d9190612785565b6002546020820151604080840151905163fec8f5eb60e01b81526001600160401b03881660048201526001600160801b0319871660248201526001600160a01b03928316604482015260648101919091526001600160801b0388166084820152929350169063fec8f5eb9060a4015f604051808303815f87803b158015611922575f5ffd5b505af1158015611934573d5f5f3e3d5ffd5b50506002546001600160a01b03169150635c76ada4905084846119578282611009565b6040516001600160e01b031960e086901b1681526001600160401b0390931660048401526001600160801b031990911660248301526001600160801b031660448201526064015f604051808303815f87803b1580156119b4575f5ffd5b505af11580156119c6573d5f5f3e3d5ffd5b5050600254604051630365020f60e41b81526001600160401b03871660048201526001600160801b0319861660248201526001600160a01b0389811660448301526001600160801b038b166064830152909116925063365020f091506084015f604051808303815f87803b158015611a3c575f5ffd5b505af1158015611a4e573d5f5f3e3d5ffd5b5050600254604051639f8ddc4f60e01b81526001600160a01b039091169250639f8ddc4f9150611a849086908690600401612707565b5f604051808303815f87803b158015611a9b575f5ffd5b505af1158015611aad573d5f5f3e3d5ffd5b5050505050505050505050565b6001600160801b03161590565b5f6001600160801b0385161580611aeb5750611aeb846001600160801b0316611aba565b15611af757505f611b94565b5f611b02888861205c565b90505f896001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b41573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b6591906128a3565b9050611b8f611b81886001600160801b031684848a8a8a61212f565b6001600160801b0316611738565b925050505b979650505050505050565b604080515f808252602082019092526001600160a01b038416908390604051611bc891906128c3565b5f6040518083038185875af1925050503d805f8114611c02576040519150601f19603f3d011682016040523d82523d5f602084013e611c07565b606091505b5050905080610ab257604051630d2fa21160e31b815260040160405180910390fd5b5f836001600160a01b03163b11611c5357604051633c11a9c560e21b815260040160405180910390fd5b6040516001600160a01b038381166024830152604482018390525f91829186169060640160408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b17905251611cac91906128c3565b5f604051808303815f865af19150503d805f8114611ce5576040519150601f19603f3d011682016040523d82523d5f602084013e611cea565b606091505b5091509150818015611d14575080511580611d14575080806020019051810190611d14919061288a565b6040805160048152602481019091526020810180516001600160e01b031663fb7f507960e01b179052869163a9059cbb60e01b918491611d6b576040516390bfb86560e01b815260040161169b9493929190612907565b505050505050505050565b60015460405163fb1afbd760e01b81525f916001600160a01b03169063fb1afbd790611da690859060040161237d565b602060405180830381865afa158015611dc1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611de5919061288a565b611df057505f6112aa565b60025460405163188cfd6d60e21b81526001600160401b03881660048201526001600160801b0319871660248201526001600160a01b038681166044830152606482018690525f921690636233f5b490608401602060405180830381865afa158015611e5e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e82919061286f565b6001600160401b0388165f9081526004602090815260408083206001600160801b03198b16845282528083206001600160a01b038a16845282528083208884529091529020549091506001600160801b03908116908216811015611ee8575f9250611ef5565b611ef28282612960565b92505b505095945050505050565b5f6001600160801b0387161580611f245750611f24846001600160801b0316611aba565b15611f3057505f611b94565b5f611f3b878761205c565b90505f896001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f7a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f9e91906128a3565b9050611b8f611b818a6001600160801b031683858a8a8a61212f565b5f611fc682600161297f565b83511015611fe757604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f611ffc82602061297f565b8351101561201d57604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f61203282601061297f565b8351101561205357604051633b99b53d60e01b815260040160405180910390fd5b50016010015190565b5f81156120cf57604051631fa3f33160e11b8152600481018390526001600160a01b03841690633f47e66290602401602060405180830381865afa1580156120a6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120ca91906128a3565b610409565b826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561210b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061040991906128a3565b5f611b948787878787875f6001600160801b03831661218e5760405162461bcd60e51b815260206004820152601b60248201527a50726963696e674c69622f6469766973696f6e2d62792d7a65726f60281b604482015260640161169b565b611b946121d96001600160801b038616896121aa89600a612a75565b6121b49190612a83565b6001600160801b0387166121c98b600a612a75565b6121d39190612a83565b866121de565b611738565b5f5f6121eb868686612237565b90506001836002811115612201576122016126f3565b14801561221d57505f848061221857612218612a9a565b868809115b156112aa5761222d60018261297f565b9695505050505050565b5f80805f19858709858702925082811083820303915050805f0361226e5783828161226457612264612a9a565b0492505050610409565b80841161228e57604051637ee8242b60e01b815260040160405180910390fd5b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b6001600160401b0381168114612309575f5ffd5b50565b6001600160801b031981168114612309575f5ffd5b6001600160a01b0381168114612309575f5ffd5b5f5f5f60608486031215612347575f5ffd5b8335612352816122f5565b925060208401356123628161230c565b9150604084013561237281612321565b809150509250925092565b6001600160a01b0391909116815260200190565b5f5f5f606084860312156123a3575f5ffd5b83356123ae81612321565b925060208401356123be81612321565b929592945050506040919091013590565b5f5f604083850312156123e0575f5ffd5b82356123eb816122f5565b915060208301356123fb8161230c565b809150509250929050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b038111828210171561244257612442612406565b604052919050565b5f5f5f6060848603121561245c575f5ffd5b8335612467816122f5565b925060208401356124778161230c565b915060408401356001600160401b03811115612491575f5ffd5b8401601f810186136124a1575f5ffd5b80356001600160401b038111156124ba576124ba612406565b6124cd601f8201601f191660200161241a565b8181528760208385010111156124e1575f5ffd5b816020840160208301375f602083830101528093505050509250925092565b5f5f5f5f60808587031215612513575f5ffd5b843561251e81612321565b935060208501359250604085013561253581612321565b9150606085013561254581612321565b939692955090935050565b5f5f60408385031215612561575f5ffd5b823561256c81612321565b946020939093013593505050565b6001600160801b0381168114612309575f5ffd5b5f5f5f5f5f60a086880312156125a2575f5ffd5b85356125ad816122f5565b945060208601356125bd8161230c565b935060408601356125cd81612321565b92506060860135915060808601356125e48161257a565b809150509295509295909350565b5f60208284031215612602575f5ffd5b813561040981612321565b5f5f6040838503121561261e575f5ffd5b823561262981612321565b915060208301356123fb81612321565b5f5f5f5f6080858703121561264c575f5ffd5b843561265781612321565b935060208501359250604085013561266e81612321565b9396929550929360600135925050565b5f5f5f5f60808587031215612691575f5ffd5b843561269c816122f5565b935060208501356126ac8161230c565b9250604085013561266e81612321565b6001600160801b0391909116815260200190565b5f5f604083850312156126e1575f5ffd5b8235915060208301356123fb81612321565b634e487b7160e01b5f52602160045260245ffd5b6001600160401b039290921682526001600160801b031916602082015260400190565b5f6020828403121561273a575f5ffd5b815161040981612321565b5f5f60408385031215612756575f5ffd5b825161276181612321565b6020939093015192949293505050565b80518015158114612780575f5ffd5b919050565b5f6080828403128015612796575f5ffd5b50604051608081016001600160401b03811182821017156127b9576127b9612406565b60405282516127c78161257a565b815260208301516127d781612321565b6020820152604083810151908201526127f260608401612771565b60608201529392505050565b5f6020828403121561280e575f5ffd5b8151610409816122f5565b5f60208284031215612829575f5ffd5b81516104098161230c565b6001600160401b039490941684526001600160801b03199290921660208401526001600160801b031660408301521515606082015260800190565b5f6020828403121561287f575f5ffd5b81516104098161257a565b5f6020828403121561289a575f5ffd5b61040982612771565b5f602082840312156128b3575f5ffd5b815160ff81168114610409575f5ffd5b5f82518060208501845e5f920191825250919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03851681526001600160e01b0319841660208201526080604082018190525f9061293a908301856128d9565b8281036060840152611b9481856128d9565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b038281168282160390811115610a4257610a4261294c565b80820180821115610a4257610a4261294c565b6001815b60018411156129cd578085048111156129b1576129b161294c565b60018416156129bf57908102905b60019390931c928002612996565b935093915050565b5f826129e357506001610a42565b816129ef57505f610a42565b8160018114612a055760028114612a0f57612a2b565b6001915050610a42565b60ff841115612a2057612a2061294c565b50506001821b610a42565b5060208310610133831016604e8410600b8410161715612a4e575081810a610a42565b612a5a5f198484612992565b805f1904821115612a6d57612a6d61294c565b029392505050565b5f61040960ff8416836129d5565b8082028115828204841417610a4257610a4261294c565b634e487b7160e01b5f52601260045260245ffdfea26469706673582212206f8216cece949aacb9ec22ee209e09adabf93438543dca216aaebe3122dbf7ca64736f6c634300081c00330000000000000000000000005f3f8ea3b54bff7795de7754866e0eac52e0881d
Deployed Bytecode
0x608060405234801561000f575f5ffd5b5060043610610110575f3560e01c806306932fcb1461011457806322285cf61461012957806323c5b7ed1461015257806332de5d3c14610173578063340ab91d146101a65780633a4d2cd1146101b95780633e5541f1146101cc57806347bfbcc6146101df57806350603df3146101f25780635f3e849f146102055780636179ab011461021857806365fae35e1461022b578063760168701461023e5780637cd878eb14610251578063947b330a146102645780639c52a7f114610277578063bd80f7c41461028a578063bf353dbb146102d9578063c6f1649f146102f8578063d4e8be831461030b578063d72e42851461031e578063f2e586db14610331575b5f5ffd5b610127610122366004612335565b610344565b005b60025461013c906001600160a01b031681565b604051610149919061237d565b60405180910390f35b610165610160366004612391565b6103f9565b604051908152602001610149565b61013c6101813660046123cf565b600360209081525f92835260408084209091529082529020546001600160a01b031681565b6101276101b436600461244a565b610410565b6101656101c7366004612500565b610686565b6101656101da366004612550565b610710565b60015461013c906001600160a01b031681565b610165610200366004612550565b610a48565b610127610213366004612391565b610a54565b61012761022636600461258e565b610ac2565b6101276102393660046125f2565b610b96565b61016561024c36600461260d565b610c09565b61016561025f366004612391565b610d62565b610127610272366004612639565b610d6d565b6101276102853660046125f2565b610e31565b6102cc61029836600461267e565b600460209081525f94855260408086208252938552838520815291845282842090915282529020546001600160801b031681565b60405161014991906126bc565b6101656102e73660046125f2565b5f6020819052908152604090205481565b610165610306366004612500565b610ea3565b6101276103193660046126d0565b610f20565b6102cc61032c3660046123cf565b611009565b61016561033f36600461260d565b61114c565b335f908152602081905260409020546001146103735760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0383165f8181526003602090815260408083206001600160801b0319871680855292529182902080546001600160a01b0319166001600160a01b03861617905590519091907ff4930db4239d7c3f044b38dbe35777d82b713760fcaf0067537eb8d0d0446b2e906103ec90859061237d565b60405180910390a3505050565b5f610406848360016112b3565b90505b9392505050565b335f9081526020819052604090205460011461043f5760405163ea8e4eb560e01b815260040160405180910390fd5b5f610449826115c6565b600481111561045a5761045a6126f3565b90505f1960ff821601610525575f610471836115e5565b60015460405163602ff8a960e11b81529192505f916001600160a01b039091169063c05ff152906104a89089908990600401612707565b602060405180830381865afa1580156104c3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104e7919061272a565b6001600160a01b03160361050e57604051630344039160e61b815260040160405180910390fd5b61051f8585610122845f015161164c565b50610680565b60011960ff821601610667575f61053b836116ab565b60015460405163602ff8a960e11b81529192505f916001600160a01b039091169063c05ff152906105729089908990600401612707565b602060405180830381865afa15801561058d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105b1919061272a565b6001600160a01b0316036105d857604051630344039160e61b815260040160405180910390fd5b600154815160405163cee8983d60e01b81525f9283926001600160a01b039091169163cee8983d9161060c916004016126bc565b6040805180830381865afa158015610626573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061064a9190612745565b9150915061065f878784848760200151610ac2565b505050610680565b604051638f0997cd60e01b815260040160405180910390fd5b50505050565b335f908152602081905260408120546001146106b55760405163ea8e4eb560e01b815260040160405180910390fd5b836106c0868461114c565b10156106df576040516352f7657b60e01b815260040160405180910390fd5b6106ea8583866103f9565b9050610708856106f986611738565b8561070385611738565b611765565b949350505050565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff1539061074490879060040161237d565b608060405180830381865afa15801561075f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107839190612785565b90505f610849856001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e991906127fe565b866001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610825573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061032c9190612819565b90505f60015f9054906101000a90046001600160a01b03166001600160a01b031663fd6906ed876001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ab573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108cf91906127fe565b886001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561090b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061092f9190612819565b86516040516001600160e01b031960e086901b16815261095793929190600190600401612834565b602060405180830381865afa158015610972573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610996919061286f565b90506109aa826001600160801b0316611aba565b610a3157610a2c866001600160a01b031663a8d5fd656040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109ed573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a11919061272a565b84602001518560400151610a2489611738565b85875f611ac7565b610a33565b5f5b6001600160801b031693505050505b92915050565b5f61040983835f6112b3565b335f90815260208190526040902054600114610a835760405163ea8e4eb560e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601610ab757610ab28282611b9f565b505050565b610ab2838383611c29565b335f90815260208190526040902054600114610af15760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0385165f8181526004602090815260408083206001600160801b03198981168086529184528285206001600160a01b038a1680875290855283862089875285529483902080546001600160801b03891692168217905582519485529284018790529083019190915291907ffece2f0a4e9094e6d87c0f7c8d9a7b92988c81690bcdd1be82e35ef3d7338ab09060600160405180910390a35050505050565b335f90815260208190526040902054600114610bc55760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff15390610c3d90879060040161237d565b608060405180830381865afa158015610c58573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c7c9190612785565b9050610d51846001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cbd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ce191906127fe565b856001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d1d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d419190612819565b8360200151846040015188611d76565b6001600160801b0316949350505050565b5f6104068483610710565b335f90815260208190526040902054600114610d9c5760405163ea8e4eb560e01b815260040160405180910390fd5b825f03610db357610dae848383610a54565b610680565b6040516304ade6db60e11b81526001600160a01b038381166004830152602482018590526044820183905285169063095bcdb6906064016020604051808303815f875af1158015610e06573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e2a919061288a565b5050505050565b335f90815260208190526040902054600114610e605760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b335f90815260208190526040812054600114610ed25760405163ea8e4eb560e01b815260040160405180910390fd5b83610edd8684610c09565b1015610efc5760405163e4bac01b60e01b815260040160405180910390fd5b610f07858386610d62565b905061070885610f1683611738565b8561070388611738565b335f90815260208190526040902054600114610f4f5760405163ea8e4eb560e01b815260040160405180910390fd5b816473706f6b6560d81b03610f7e57600180546001600160a01b0319166001600160a01b038316179055610fcd565b816b18985b185b98d954da19595d60a21b03610fb457600280546001600160a01b0319166001600160a01b038316179055610fcd565b604051633db0d5b960e01b815260040160405180910390fd5b817f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba82604051610ffd919061237d565b60405180910390a25050565b6001600160401b0382165f9081526003602090815260408083206001600160801b0319851684529091528120546001600160a01b0316806110d55760018054604051635274887b60e01b81526001600160401b03871660048201526001600160801b03198616602482015260448101929092526001600160a01b031690635274887b90606401602060405180830381865afa1580156110aa573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110ce919061286f565b9150611145565b60405163d72e428560e01b81526001600160a01b0382169063d72e4285906111039087908790600401612707565b602060405180830381865afa15801561111e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611142919061286f565b91505b5092915050565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff1539061118090879060040161237d565b608060405180830381865afa15801561119b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111bf9190612785565b90505f611295856001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611201573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061122591906127fe565b866001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611261573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112859190612819565b8460200151856040015189611d76565b90506112aa85826001600160801b0316610710565b95945050505050565b600154604051632a7ff15360e01b81525f9182916001600160a01b0390911690632a7ff153906112e790889060040161237d565b608060405180830381865afa158015611302573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113269190612785565b90505f6113c8866001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611368573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061138c91906127fe565b876001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610825573d5f5f3e3d5ffd5b90505f60015f9054906101000a90046001600160a01b03166001600160a01b031663fd6906ed886001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561142a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061144e91906127fe565b896001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561148a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114ae9190612819565b86516040516001600160e01b031960e086901b1681526114d693929190600190600401612834565b602060405180830381865afa1580156114f1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611515919061286f565b9050611529816001600160801b0316611aba565b6115b0576115ab876001600160a01b031663a8d5fd656040518163ffffffff1660e01b8152600401602060405180830381865afa15801561156c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611590919061272a565b61159988611738565b8560200151866040015186868b611f00565b6115b2565b5f5b6001600160801b0316979650505050505050565b5f6115d18282611fba565b60ff166004811115610a4257610a426126f3565b60408051602081019091525f815260016115fe836115c6565b600481111561160f5761160f6126f3565b1461162d576040516304c735eb60e11b815260040160405180910390fd5b604080516020810190915280611644846001611ff0565b905292915050565b5f6001600160601b038216156116a45760405162461bcd60e51b8152602060048201526018602482015277496e7075742073686f756c6420626520323020627974657360401b60448201526064015b60405180910390fd5b5060601c90565b604080518082019091525f808252602082015260026116c9836115c6565b60048111156116da576116da6126f3565b146116f8576040516304c735eb60e11b815260040160405180910390fd5b604080518082019091528061170e846001612026565b6001600160801b03168152602001611727846011612026565b6001600160801b0316905292915050565b5f6001600160801b038211156117615760405163e999826d60e01b815260040160405180910390fd5b5090565b5f846001600160a01b0316633e0dc34e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117a2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117c691906127fe565b90505f856001600160a01b03166328f2930d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611805573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118299190612819565b600154604051632a7ff15360e01b81529192505f916001600160a01b0390911690632a7ff1539061185e908a9060040161237d565b608060405180830381865afa158015611879573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061189d9190612785565b6002546020820151604080840151905163fec8f5eb60e01b81526001600160401b03881660048201526001600160801b0319871660248201526001600160a01b03928316604482015260648101919091526001600160801b0388166084820152929350169063fec8f5eb9060a4015f604051808303815f87803b158015611922575f5ffd5b505af1158015611934573d5f5f3e3d5ffd5b50506002546001600160a01b03169150635c76ada4905084846119578282611009565b6040516001600160e01b031960e086901b1681526001600160401b0390931660048401526001600160801b031990911660248301526001600160801b031660448201526064015f604051808303815f87803b1580156119b4575f5ffd5b505af11580156119c6573d5f5f3e3d5ffd5b5050600254604051630365020f60e41b81526001600160401b03871660048201526001600160801b0319861660248201526001600160a01b0389811660448301526001600160801b038b166064830152909116925063365020f091506084015f604051808303815f87803b158015611a3c575f5ffd5b505af1158015611a4e573d5f5f3e3d5ffd5b5050600254604051639f8ddc4f60e01b81526001600160a01b039091169250639f8ddc4f9150611a849086908690600401612707565b5f604051808303815f87803b158015611a9b575f5ffd5b505af1158015611aad573d5f5f3e3d5ffd5b5050505050505050505050565b6001600160801b03161590565b5f6001600160801b0385161580611aeb5750611aeb846001600160801b0316611aba565b15611af757505f611b94565b5f611b02888861205c565b90505f896001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b41573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b6591906128a3565b9050611b8f611b81886001600160801b031684848a8a8a61212f565b6001600160801b0316611738565b925050505b979650505050505050565b604080515f808252602082019092526001600160a01b038416908390604051611bc891906128c3565b5f6040518083038185875af1925050503d805f8114611c02576040519150601f19603f3d011682016040523d82523d5f602084013e611c07565b606091505b5050905080610ab257604051630d2fa21160e31b815260040160405180910390fd5b5f836001600160a01b03163b11611c5357604051633c11a9c560e21b815260040160405180910390fd5b6040516001600160a01b038381166024830152604482018390525f91829186169060640160408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b17905251611cac91906128c3565b5f604051808303815f865af19150503d805f8114611ce5576040519150601f19603f3d011682016040523d82523d5f602084013e611cea565b606091505b5091509150818015611d14575080511580611d14575080806020019051810190611d14919061288a565b6040805160048152602481019091526020810180516001600160e01b031663fb7f507960e01b179052869163a9059cbb60e01b918491611d6b576040516390bfb86560e01b815260040161169b9493929190612907565b505050505050505050565b60015460405163fb1afbd760e01b81525f916001600160a01b03169063fb1afbd790611da690859060040161237d565b602060405180830381865afa158015611dc1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611de5919061288a565b611df057505f6112aa565b60025460405163188cfd6d60e21b81526001600160401b03881660048201526001600160801b0319871660248201526001600160a01b038681166044830152606482018690525f921690636233f5b490608401602060405180830381865afa158015611e5e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e82919061286f565b6001600160401b0388165f9081526004602090815260408083206001600160801b03198b16845282528083206001600160a01b038a16845282528083208884529091529020549091506001600160801b03908116908216811015611ee8575f9250611ef5565b611ef28282612960565b92505b505095945050505050565b5f6001600160801b0387161580611f245750611f24846001600160801b0316611aba565b15611f3057505f611b94565b5f611f3b878761205c565b90505f896001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f7a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f9e91906128a3565b9050611b8f611b818a6001600160801b031683858a8a8a61212f565b5f611fc682600161297f565b83511015611fe757604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f611ffc82602061297f565b8351101561201d57604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f61203282601061297f565b8351101561205357604051633b99b53d60e01b815260040160405180910390fd5b50016010015190565b5f81156120cf57604051631fa3f33160e11b8152600481018390526001600160a01b03841690633f47e66290602401602060405180830381865afa1580156120a6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120ca91906128a3565b610409565b826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561210b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061040991906128a3565b5f611b948787878787875f6001600160801b03831661218e5760405162461bcd60e51b815260206004820152601b60248201527a50726963696e674c69622f6469766973696f6e2d62792d7a65726f60281b604482015260640161169b565b611b946121d96001600160801b038616896121aa89600a612a75565b6121b49190612a83565b6001600160801b0387166121c98b600a612a75565b6121d39190612a83565b866121de565b611738565b5f5f6121eb868686612237565b90506001836002811115612201576122016126f3565b14801561221d57505f848061221857612218612a9a565b868809115b156112aa5761222d60018261297f565b9695505050505050565b5f80805f19858709858702925082811083820303915050805f0361226e5783828161226457612264612a9a565b0492505050610409565b80841161228e57604051637ee8242b60e01b815260040160405180910390fd5b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b6001600160401b0381168114612309575f5ffd5b50565b6001600160801b031981168114612309575f5ffd5b6001600160a01b0381168114612309575f5ffd5b5f5f5f60608486031215612347575f5ffd5b8335612352816122f5565b925060208401356123628161230c565b9150604084013561237281612321565b809150509250925092565b6001600160a01b0391909116815260200190565b5f5f5f606084860312156123a3575f5ffd5b83356123ae81612321565b925060208401356123be81612321565b929592945050506040919091013590565b5f5f604083850312156123e0575f5ffd5b82356123eb816122f5565b915060208301356123fb8161230c565b809150509250929050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b038111828210171561244257612442612406565b604052919050565b5f5f5f6060848603121561245c575f5ffd5b8335612467816122f5565b925060208401356124778161230c565b915060408401356001600160401b03811115612491575f5ffd5b8401601f810186136124a1575f5ffd5b80356001600160401b038111156124ba576124ba612406565b6124cd601f8201601f191660200161241a565b8181528760208385010111156124e1575f5ffd5b816020840160208301375f602083830101528093505050509250925092565b5f5f5f5f60808587031215612513575f5ffd5b843561251e81612321565b935060208501359250604085013561253581612321565b9150606085013561254581612321565b939692955090935050565b5f5f60408385031215612561575f5ffd5b823561256c81612321565b946020939093013593505050565b6001600160801b0381168114612309575f5ffd5b5f5f5f5f5f60a086880312156125a2575f5ffd5b85356125ad816122f5565b945060208601356125bd8161230c565b935060408601356125cd81612321565b92506060860135915060808601356125e48161257a565b809150509295509295909350565b5f60208284031215612602575f5ffd5b813561040981612321565b5f5f6040838503121561261e575f5ffd5b823561262981612321565b915060208301356123fb81612321565b5f5f5f5f6080858703121561264c575f5ffd5b843561265781612321565b935060208501359250604085013561266e81612321565b9396929550929360600135925050565b5f5f5f5f60808587031215612691575f5ffd5b843561269c816122f5565b935060208501356126ac8161230c565b9250604085013561266e81612321565b6001600160801b0391909116815260200190565b5f5f604083850312156126e1575f5ffd5b8235915060208301356123fb81612321565b634e487b7160e01b5f52602160045260245ffd5b6001600160401b039290921682526001600160801b031916602082015260400190565b5f6020828403121561273a575f5ffd5b815161040981612321565b5f5f60408385031215612756575f5ffd5b825161276181612321565b6020939093015192949293505050565b80518015158114612780575f5ffd5b919050565b5f6080828403128015612796575f5ffd5b50604051608081016001600160401b03811182821017156127b9576127b9612406565b60405282516127c78161257a565b815260208301516127d781612321565b6020820152604083810151908201526127f260608401612771565b60608201529392505050565b5f6020828403121561280e575f5ffd5b8151610409816122f5565b5f60208284031215612829575f5ffd5b81516104098161230c565b6001600160401b039490941684526001600160801b03199290921660208401526001600160801b031660408301521515606082015260800190565b5f6020828403121561287f575f5ffd5b81516104098161257a565b5f6020828403121561289a575f5ffd5b61040982612771565b5f602082840312156128b3575f5ffd5b815160ff81168114610409575f5ffd5b5f82518060208501845e5f920191825250919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03851681526001600160e01b0319841660208201526080604082018190525f9061293a908301856128d9565b8281036060840152611b9481856128d9565b634e487b7160e01b5f52601160045260245ffd5b6001600160801b038281168282160390811115610a4257610a4261294c565b80820180821115610a4257610a4261294c565b6001815b60018411156129cd578085048111156129b1576129b161294c565b60018416156129bf57908102905b60019390931c928002612996565b935093915050565b5f826129e357506001610a42565b816129ef57505f610a42565b8160018114612a055760028114612a0f57612a2b565b6001915050610a42565b60ff841115612a2057612a2061294c565b50506001821b610a42565b5060208310610133831016604e8410600b8410161715612a4e575081810a610a42565b612a5a5f198484612992565b805f1904821115612a6d57612a6d61294c565b029392505050565b5f61040960ff8416836129d5565b8082028115828204841417610a4257610a4261294c565b634e487b7160e01b5f52601260045260245ffdfea26469706673582212206f8216cece949aacb9ec22ee209e09adabf93438543dca216aaebe3122dbf7ca64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005f3f8ea3b54bff7795de7754866e0eac52e0881d
-----Decoded View---------------
Arg [0] : deployer (address): 0x5f3f8ea3b54BFF7795dE7754866e0Eac52e0881d
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000005f3f8ea3b54bff7795de7754866e0eac52e0881d
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.