Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 18368978 | 403 days ago | IN | 0 ETH | 0.03359244 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Native20
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/types/mapping.sol"; import "utils.sol/types/string.sol"; import "utils.sol/Implementation.sol"; import "utils.sol/Initializable.sol"; import "./MultiPool20.sol"; import "./interfaces/INative20.sol"; /// @title Native20 (V1) /// @author 0xvv @ Kiln /// @notice This contract allows users to stake any amount of ETH in the vPool(s) /// @notice Users are given non transferable ERC-20 type shares to track their stake contract Native20 is MultiPool20, INative20, Implementation, Initializable { using LMapping for types.Mapping; using LString for types.String; using LUint256 for types.Uint256; /// @dev The name of the shares. /// @dev Slot: keccak256(bytes("native20.1.name")) - 1 types.String internal constant $name = types.String.wrap(0xeee152275d096301850a53ae85c6991c818bc6bac8a2174c268aa94ed7cf06f1); /// @dev The symbol of the shares. /// @dev Slot: keccak256(bytes("native20.1.symbol")) - 1 types.String internal constant $symbol = types.String.wrap(0x4a8b3e24ebc795477af927068865c6fcc26e359a994edca2492e515a46aad711); /// @inheritdoc INative20 function initialize(Native20Configuration calldata args) external init(0) { $name.set(args.name); emit SetName(args.name); $symbol.set(args.symbol); emit SetSymbol(args.symbol); Administrable._setAdmin(args.admin); if (args.pools.length == 0) { revert EmptyPoolList(); } if (args.pools.length != args.poolFees.length) { revert UnequalLengths(args.pools.length, args.poolFees.length); } for (uint256 i = 0; i < args.pools.length;) { _addPool(args.pools[i], args.poolFees[i]); unchecked { i++; } } _setPoolPercentages(args.poolPercentages); _initFeeDispatcher(args.commissionRecipients, args.commissionDistribution); _setMaxCommission(args.maxCommissionBps); _setMonoTicketThreshold(args.monoTicketThreshold); } /// @inheritdoc INative20 function name() external view returns (string memory) { return string(abi.encodePacked($name.get())); } /// @inheritdoc INative20 function symbol() external view returns (string memory) { return string(abi.encodePacked($symbol.get())); } /// @inheritdoc INative20 function decimals() external view virtual override returns (uint8) { return 18; } /// @inheritdoc INative20 function balanceOf(address account) external view virtual returns (uint256) { return _balanceOf(account); } /// @inheritdoc INative20 function balanceOfUnderlying(address account) external view virtual returns (uint256) { return _balanceOfUnderlying(account); } /// @inheritdoc INative20 function totalSupply() external view virtual returns (uint256) { return _totalSupply(); } /// @inheritdoc INative20 function totalUnderlyingSupply() external view virtual returns (uint256) { return _totalUnderlyingSupply(); } /// @inheritdoc INative20 function stake() external payable { LibSanitize.notNullValue(msg.value); _stake(msg.value); } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types.sol"; library LMapping { // slither-disable-next-line dead-code function get(types.Mapping position) internal pure returns (mapping(uint256 => uint256) storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types.sol"; library LString { struct StringStorage { string value; } // slither-disable-next-line dead-code function get(types.String position) internal view returns (string memory) { StringStorage storage ss; // slither-disable-next-line assembly assembly { ss.slot := position } return ss.value; } // slither-disable-next-line dead-code function set(types.String position, string memory value) internal { StringStorage storage ss; // slither-disable-next-line assembly assembly { ss.slot := position } ss.value = value; } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types/uint256.sol"; /// @title Implementation /// @author mortimr @ Kiln /// @dev Unstructured Storage Friendly /// @notice This contracts must be used on all implementation contracts. It ensures that the initializers are only callable through the proxy. /// This will brick the implementation and make it unusable directly without using delegatecalls. abstract contract Implementation { using LUint256 for types.Uint256; /// @dev The version number in storage in the initializable contract. /// @dev Slot: keccak256(bytes("initializable.version"))) - 1 types.Uint256 internal constant $initializableVersion = types.Uint256.wrap(0xc4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a76); constructor() { $initializableVersion.set(type(uint256).max); } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types/uint256.sol"; /// @title Initializable /// @author mortimr @ Kiln /// @dev Unstructured Storage Friendly /// @notice This contracts helps upgradeable contracts handle an internal /// version value to prevent initializer replays. abstract contract Initializable { using LUint256 for types.Uint256; /// @notice The version has been initialized. /// @param version The version number initialized /// @param cdata The calldata used for the call event Initialized(uint256 version, bytes cdata); /// @notice The init modifier has already been called on the given version number. /// @param version The provided version number /// @param currentVersion The stored version number error AlreadyInitialized(uint256 version, uint256 currentVersion); /// @dev The version number in storage. /// @dev Slot: keccak256(bytes("initializable.version"))) - 1 types.Uint256 internal constant $version = types.Uint256.wrap(0xc4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a76); /// @dev The modifier to use on initializers. /// @dev Do not provide _version dynamically, make sure the value is hard-coded each /// time the modifier is used. /// @param _version The version to initialize // slither-disable-next-line incorrect-modifier modifier init(uint256 _version) { if (_version == $version.get()) { $version.set(_version + 1); emit Initialized(_version, msg.data); _; } else { revert AlreadyInitialized(_version, $version.get()); } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "vsuite/ctypes/ctypes.sol"; import "vsuite/ctypes/approvals_mapping.sol"; import "./MultiPool.sol"; import "./interfaces/IMultiPool20.sol"; import "./victypes/victypes.sol"; import "./victypes/balance.sol"; uint256 constant MIN_SUPPLY = 1e14; // If there is only dust in the pool, we mint 1:1 uint256 constant COMMISSION_MAX = 10; // 0.1% / 10 bps ~= 12 days of accrued commission at 3% GRR /// @title MultiPool-20 (v1) /// @author 0xvv @ Kiln /// @notice This contract contains the internal logic for an ERC-20 token based on one or multiple pools. abstract contract MultiPool20 is MultiPool, IMultiPool20 { using LArray for types.Array; using LMapping for types.Mapping; using LUint256 for types.Uint256; using LBalance for victypes.BalanceMapping; using LApprovalsMapping for ctypes.ApprovalsMapping; using CUint256 for uint256; using CBool for bool; /// @dev The total supply of ERC 20. /// @dev Slot: keccak256(bytes("multiPool20.1.totalSupply")) - 1 types.Uint256 internal constant $totalSupply = types.Uint256.wrap(0xb24a0f21470b6927dcbaaf5b1f54865bd687f4a2ce4c43edf1e20339a4c05bae); /// @dev The list containing the percentages of ETH to route to each pool, in basis points, must add up to 10 000. /// @dev Slot: keccak256(bytes("multiPool20.1.poolRoutingList")) - 1 types.Array internal constant $poolRoutingList = types.Array.wrap(0x3803482dd7707d12238e38a3b1b5e55fa6e13d81c36ce29ec5c267cc02c53fe3); /// @dev Stores the balances : mapping(address => uint256). /// @dev Slot: keccak256(bytes("multiPool20.1.balances")) - 1 victypes.BalanceMapping internal constant $balances = victypes.BalanceMapping.wrap(0x4f74125ce1aafb5d1699fc2e5e8f96929ff1a99170dc9bda82c8944acc5c7286); /// @dev Stores the approvals /// @dev Type: mapping(address => mapping(address => bool). /// @dev Slot: keccak256(bytes("multiPool20.1.approvals")) - 1 ctypes.ApprovalsMapping internal constant $approvals = ctypes.ApprovalsMapping.wrap(0xebc1e0a04bae59eb2e2b17f55cd491aec28c349ae4f6b6fe9be28a72f9c6b202); /// @dev The threshold below which we try to issue only one exit ticket /// @dev Slot: keccak256(bytes("multiPool20.1.monoTicketThreshold")) - 1 types.Uint256 internal constant $monoTicketThreshold = types.Uint256.wrap(0x900053b761278bb5de4eeaea5ed9000b89943edad45dcf64a9dab96d0ce29c2e); /// @inheritdoc IMultiPool20 function setPoolPercentages(uint256[] calldata split) external onlyAdmin { _setPoolPercentages(split); } /// @notice Sets the threshold below which we try to issue only one exit ticket /// @param minTicketEthValue The threshold function setMonoTicketThreshold(uint256 minTicketEthValue) external onlyAdmin { _setMonoTicketThreshold(minTicketEthValue); } /// @inheritdoc IMultiPool20 function requestExit(uint256 amount) external virtual { _requestExit(amount); } /// @inheritdoc IMultiPool20 function rate() external view returns (uint256) { uint256 currentTotalSupply = _totalSupply(); return currentTotalSupply > 0 ? LibUint256.mulDiv(_totalUnderlyingSupply(), 1e18, currentTotalSupply) : 1e18; } /// Private functions /// @dev Internal function to requestExit /// @param amount The amount of shares to exit // slither-disable-next-line reentrancy-events function _requestExit(uint256 amount) internal { uint256 totalSupply = $totalSupply.get(); uint256 totalUnderlyingSupply = _totalUnderlyingSupply(); _burn(msg.sender, amount); uint256 ethValue = LibUint256.mulDiv(amount, totalUnderlyingSupply, totalSupply); uint256 poolCount_ = $poolCount.get(); // Early return in case of mono pool operation if (poolCount_ == 1) { PoolExitDetails[] memory detail = new PoolExitDetails[](1); _sendToExitQueue(0, ethValue, detail[0]); _checkCommissionRatio(0); emit Exit(msg.sender, uint128(amount), detail); return; } uint256[] memory splits = $poolRoutingList.toUintA(); // If the amount is below the set threshold we exit via the most imabalanced pool to print only 1 ticket if (ethValue < $monoTicketThreshold.get()) { int256 maxImbalance = 0; uint256 exitPoolId = 0; for (uint256 id = 0; id < poolCount_;) { uint256 expectedValue = LibUint256.mulDiv(totalUnderlyingSupply, splits[id], LibConstant.BASIS_POINTS_MAX); uint256 poolValue = _ethAfterCommission(id); int256 imbalance = int256(poolValue) - int256(expectedValue); if (poolValue >= ethValue && imbalance > maxImbalance) { maxImbalance = imbalance; exitPoolId = id; } unchecked { id++; } } if (maxImbalance > 0) { PoolExitDetails[] memory detail = new PoolExitDetails[](1); _sendToExitQueue(exitPoolId, ethValue, detail[0]); _checkCommissionRatio(exitPoolId); emit Exit(msg.sender, uint128(amount), detail); return; } } // If the the amount is over the threshold or no pool has enough value to cover the exit // We exit proportionally to maintain the balance PoolExitDetails[] memory details = new PoolExitDetails[](poolCount_); for (uint256 id = 0; id < poolCount_;) { uint256 ethForPool = LibUint256.mulDiv(ethValue, splits[id], LibConstant.BASIS_POINTS_MAX); if (ethForPool > 0) _sendToExitQueue(id, ethForPool, details[id]); _checkCommissionRatio(id); unchecked { id++; } } emit Exit(msg.sender, uint128(amount), details); } /// @dev Internal function to exit the commission shares if needed /// @param id The pool id function _checkCommissionRatio(uint256 id) internal { // If the commission shares / all shares ratio go over the limit we exit them if (_poolSharesOfIntegrator(id) > LibUint256.mulDiv($poolShares.get()[id], COMMISSION_MAX, LibConstant.BASIS_POINTS_MAX)) { _exitCommissionShares(id); } } /// @dev Utility function to send a given ETH amount of shares to the exit queue of a pool // slither-disable-next-line calls-loop function _sendToExitQueue(uint256 poolId, uint256 ethAmount, PoolExitDetails memory details) internal { IvPool pool = _getPool(poolId); uint256 shares = LibUint256.mulDiv(ethAmount, pool.totalSupply(), pool.totalUnderlyingSupply()); uint256 stakedValueBefore = _stakedEthValue(poolId); details.exitedPoolShares = uint128(shares); details.poolId = uint128(poolId); _sendSharesToExitQueue(poolId, shares, pool, msg.sender); $exitedEth.get()[poolId] += stakedValueBefore - _stakedEthValue(poolId); } /// @dev Internal function to stake in one or more pools with arbitrary amounts to each one /// @param totalAmount The amount of ETH to stake // slither-disable-next-line reentrancy-events,unused-return,dead-code function _stake(uint256 totalAmount) internal notPaused returns (bool) { uint256[] memory splits = $poolRoutingList.toUintA(); PoolStakeDetails[] memory stakeDetails = new PoolStakeDetails[](splits.length); uint256 tokensBoughtTotal = 0; for (uint256 id = 0; id < $poolCount.get();) { if (splits[id] > 0) { stakeDetails[id].poolId = uint128(id); uint256 remainingEth = LibUint256.mulDiv(totalAmount, splits[id], LibConstant.BASIS_POINTS_MAX); _checkPoolIsEnabled(id); IvPool pool = _getPool(id); uint256 totalSupply = _totalSupply(); // we can use these values because the ratio of shares to underlying is constant in this function uint256 totalUnderlyingSupply = _totalUnderlyingSupply(); if (totalSupply < MIN_SUPPLY) { $injectedEth.get()[id] += remainingEth; uint256 sharesAcquired = pool.deposit{value: remainingEth}(); tokensBoughtTotal += sharesAcquired; _mint(msg.sender, sharesAcquired); stakeDetails[id].ethToPool = uint128(remainingEth); stakeDetails[id].pSharesFromPool = uint128(sharesAcquired); } else { uint256 comOwed = _integratorCommissionOwed(id); uint256 tokensBoughtPool = 0; // If there is enough commission we sell it first // This avoids wasting gas to sell infinitesimal amounts of commission + a potential DoS vector if (comOwed > MIN_COMMISSION_TO_SELL) { uint256 ethForCommission = LibUint256.min(comOwed, remainingEth); remainingEth -= ethForCommission; uint256 pSharesBought = LibUint256.mulDiv( ethForCommission, $poolShares.get()[id] - _poolSharesOfIntegrator(id), _ethAfterCommission(id) ); $commissionPaid.get()[id] += ethForCommission; stakeDetails[id].ethToIntegrator = uint128(ethForCommission); stakeDetails[id].pSharesFromIntegrator = uint128(pSharesBought); emit CommissionSharesSold(pSharesBought, id, ethForCommission); uint256 tokensAcquired = LibUint256.mulDiv(ethForCommission, totalSupply, totalUnderlyingSupply); if (tokensAcquired == 0) revert ZeroSharesMint(); tokensBoughtPool += tokensAcquired; } if (remainingEth > 0) { $injectedEth.get()[id] += remainingEth; uint256 pShares = pool.deposit{value: remainingEth}(); uint256 tokensAcquired = LibUint256.mulDiv(remainingEth, totalSupply, totalUnderlyingSupply); if (tokensAcquired == 0) revert ZeroSharesMint(); stakeDetails[id].ethToPool += uint128(remainingEth); stakeDetails[id].pSharesFromPool += uint128(pShares); tokensBoughtPool += tokensAcquired; } _mint(msg.sender, tokensBoughtPool); tokensBoughtTotal += tokensBoughtPool; } } unchecked { id++; } } emit Stake(msg.sender, uint128(totalAmount), uint128(tokensBoughtTotal), stakeDetails); return true; } /// @dev Internal function to set the pool percentages /// @param percentages The new percentages function _setPoolPercentages(uint256[] calldata percentages) internal { if (percentages.length != $poolCount.get()) { revert UnequalLengths(percentages.length, $poolCount.get()); } uint256 total = 0; $poolRoutingList.del(); uint256[] storage percentagesList = $poolRoutingList.toUintA(); for (uint256 i = 0; i < percentages.length;) { bool enabled = $poolActivation.get()[i].toBool(); uint256 percentage = percentages[i]; if (!enabled && percentage != 0) { revert NonZeroPercentageOnDeactivatedPool(i); } else { total += percentages[i]; percentagesList.push(percentages[i]); } unchecked { i++; } } if (total != LibConstant.BASIS_POINTS_MAX) { revert LibErrors.InvalidBPSValue(); } emit SetPoolPercentages(percentages); } /// @inheritdoc IMultiPool20 function setPoolActivation(uint256 poolId, bool status, uint256[] calldata newPoolPercentages) external onlyAdmin { $poolActivation.get()[poolId] = status.v(); _setPoolPercentages(newPoolPercentages); } /// @dev Internal function to retrieve the balance of a given account /// @param account The account to retrieve the balance of // slither-disable-next-line dead-code function _balanceOf(address account) internal view returns (uint256) { return $balances.get()[account]; } /// @dev Internal function to retrieve the balance of a given account in underlying /// @param account The account to retrieve the balance of in underlying // slither-disable-next-line dead-code function _balanceOfUnderlying(address account) internal view returns (uint256) { uint256 tUnderlyingSupply = _totalUnderlyingSupply(); uint256 tSupply = _totalSupply(); if (tUnderlyingSupply == 0 || tSupply == 0) { return 0; } return LibUint256.mulDiv($balances.get()[account], tUnderlyingSupply, tSupply); } /// @dev Internal function retrieve the total underlying supply // slither-disable-next-line naming-convention function _totalUnderlyingSupply() internal view returns (uint256) { uint256 ethValue = 0; for (uint256 i = 0; i < $poolCount.get();) { unchecked { ethValue += _ethAfterCommission(i); i++; } } return ethValue; } /// @dev Internal function to retrieve the total supply // slither-disable-next-line naming-convention function _totalSupply() internal view returns (uint256) { return $totalSupply.get(); } /// @dev Internal function to transfer tokens from one account to another /// @param from The account to transfer from /// @param to The account to transfer to /// @param amount The amount to transfer // slither-disable-next-line dead-code function _transfer(address from, address to, uint256 amount) internal virtual { uint256 fromBalance = $balances.get()[from]; if (amount > fromBalance) { revert InsufficientBalance(amount, fromBalance); } unchecked { $balances.get()[from] = fromBalance - amount; } $balances.get()[to] += amount; emit Transfer(from, to, amount); } /// @dev Internal function to retrieve the allowance of a given spender /// @param owner The owner of the allowance /// @param spender The spender of the allowance // slither-disable-next-line dead-code function _allowance(address owner, address spender) internal view returns (uint256) { return $approvals.get()[owner][spender]; } /// @dev Internal function to approve a spender /// @param owner The owner of the allowance /// @param spender The spender of the allowance /// @param amount The amount to approve // slither-disable-next-line dead-code function _approve(address owner, address spender, uint256 amount) internal { $approvals.get()[owner][spender] = amount; emit Approval(owner, spender, amount); } /// @dev Internal function to transfer tokens from one account to another /// @param spender The spender of the allowance /// @param from The account to transfer from /// @param to The account to transfer to /// @param amount The amount to transfer // slither-disable-next-line dead-code function _transferFrom(address spender, address from, address to, uint256 amount) internal virtual { uint256 currentAllowance = $approvals.get()[from][spender]; if (amount > currentAllowance) { revert InsufficientAllowance(amount, currentAllowance); } unchecked { $approvals.get()[from][spender] = currentAllowance - amount; } _transfer(from, to, amount); } /// @dev Internal function for minting /// @param account The address to mint to /// @param amount The amount to mint // slither-disable-next-line dead-code function _mint(address account, uint256 amount) internal { $totalSupply.set($totalSupply.get() + amount); unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, checked above $balances.get()[account] += amount; } emit Transfer(address(0), account, amount); } /// @dev Internal function to burn tokens /// @param account The account to burn from /// @param amount The amount to burn // slither-disable-next-line dead-code function _burn(address account, uint256 amount) internal { uint256 accountBalance = $balances.get()[account]; if (amount > accountBalance) { revert InsufficientBalance(amount, accountBalance); } $totalSupply.set($totalSupply.get() - amount); unchecked { $balances.get()[account] = accountBalance - amount; } emit Transfer(account, address(0), amount); } /// @dev Internal function to set the mono ticket threshold /// @param minTicketEthValue The minimum ticket value function _setMonoTicketThreshold(uint256 minTicketEthValue) internal { $monoTicketThreshold.set(minTicketEthValue); } }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; /// @notice Configuration parameters for the Native20 contract. /// @param admin The address of the admin. /// @param name ERC-20 style display name. /// @param symbol ERC-20 style display symbol. /// @param pools List of pool addresses. /// @param poolFees List of fee for each pool, in basis points. /// @param commissionRecipients List of recipients among which the withdrawn fees are shared. /// @param commissionDistribution Share of each fee recipient, in basis points, must add up to 10 000. /// @param poolPercentages The amount of ETH to route to each pool when staking, in basis points, must add up to 10 000. struct Native20Configuration { string name; string symbol; address admin; address[] pools; uint256[] poolFees; address[] commissionRecipients; uint256[] commissionDistribution; uint256[] poolPercentages; uint256 maxCommissionBps; uint256 monoTicketThreshold; } /// @title Native20 (V1) Interface /// @author 0xvv @ Kiln /// @notice This contract allows users to stake any amount of ETH in the vPool(s). /// Users are given non transferable ERC-20 type shares to track their stake. interface INative20 { /// @notice Initializes the contract with the given parameters. /// @param args The initialization arguments. function initialize(Native20Configuration calldata args) external; /// @notice Returns the name of the token. function name() external view returns (string memory); /// @notice Returns the symbol of the token, usually a shorter version of the name. function symbol() external view returns (string memory); /// @notice Returns the number of decimals used to get its user representation. function decimals() external view returns (uint8); /// @notice Returns the total amount of staking shares. /// @return Total amount of shares. function totalSupply() external view returns (uint256); /// @notice Returns the amount of ETH owned by the users in the pool(s). /// @return Total amount of shares. function totalUnderlyingSupply() external view returns (uint256); /// @notice Returns the amount of staking shares for an account. /// @param account The address of the account. /// @return amount of staking shares. function balanceOf(address account) external view returns (uint256); /// @notice Returns the ETH value of the account balance. /// @param account The address of the account. /// @return amount of ETH. function balanceOfUnderlying(address account) external view returns (uint256); /// @notice Function to stake ETH. function stake() external payable; }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; /// @dev Library holding bytes32 custom types // slither-disable-next-line naming-convention library types { type Uint256 is bytes32; type Address is bytes32; type Bytes32 is bytes32; type Bool is bytes32; type String is bytes32; type Mapping is bytes32; type Array is bytes32; }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types.sol"; library LUint256 { // slither-disable-next-line dead-code function get(types.Uint256 position) internal view returns (uint256 data) { // slither-disable-next-line assembly assembly { data := sload(position) } } // slither-disable-next-line dead-code function set(types.Uint256 position, uint256 data) internal { // slither-disable-next-line assembly assembly { sstore(position, data) } } // slither-disable-next-line dead-code function del(types.Uint256 position) internal { // slither-disable-next-line assembly assembly { sstore(position, 0) } } } library CUint256 { // slither-disable-next-line dead-code function toBytes32(uint256 val) internal pure returns (bytes32) { return bytes32(val); } // slither-disable-next-line dead-code function toAddress(uint256 val) internal pure returns (address) { return address(uint160(val)); } // slither-disable-next-line dead-code function toBool(uint256 val) internal pure returns (bool) { return (val & 1) == 1; } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/libs/LibPublicKey.sol"; import "utils.sol/libs/LibSignature.sol"; /// @title Custom Types // slither-disable-next-line naming-convention library ctypes { /// @notice Structure representing a validator in the factory /// @param publicKey The public key of the validator /// @param signature The signature used for the deposit /// @param feeRecipient The address receiving the exec layer fees struct Validator { LibPublicKey.PublicKey publicKey; LibSignature.Signature signature; address feeRecipient; } /// @notice Structure representing a withdrawal channel in the factory /// @param validators The validators in the channel /// @param lastEdit The last time the channel was edited (in blocks) /// @param limit The staking limit of the channel. Always <= validators.length /// @param funded The amount of funded validators in the channel struct WithdrawalChannel { Validator[] validators; uint256 lastEdit; uint32 limit; uint32 funded; } /// @notice Structure representing a deposit in the factory /// @param index The index of the deposit in the withdrawal channel /// @param withdrawalChannel The withdrawal channel of the validator /// @param owner The owner of the deposited validator struct Deposit { uint256 index; bytes32 withdrawalChannel; address owner; } /// @notice Structure representing the operator metadata in the factory /// @param name The name of the operator /// @param url The url of the operator /// @param iconUrl The icon url of the operator struct Metadata { string name; string url; string iconUrl; } /// @notice Structure representing the global consensus layer spec held in the global consensus layer spec holder /// @param genesisTimestamp The timestamp of the genesis of the consensus layer (slot 0 timestamp) /// @param epochsUntilFinal The number of epochs until a block is considered final by the vsuite /// @param slotsPerEpoch The number of slots per epoch (32 on mainnet) /// @param secondsPerSlot The number of seconds per slot (12 on mainnet) struct ConsensusLayerSpec { uint64 genesisTimestamp; uint64 epochsUntilFinal; uint64 slotsPerEpoch; uint64 secondsPerSlot; } /// @notice Structure representing the report bounds held in the pools /// @param maxAPRUpperBound The maximum APR upper bound, representing the maximum increase in underlying balance checked at each oracle report /// @param maxAPRUpperCoverageBoost The maximum APR upper coverage boost, representing the additional increase allowed when pulling coverage funds /// @param maxRelativeLowerBound The maximum relative lower bound, representing the maximum decrease in underlying balance checked at each oracle report struct ReportBounds { uint64 maxAPRUpperBound; uint64 maxAPRUpperCoverageBoost; uint64 maxRelativeLowerBound; } /// @notice Structure representing the consensus layer report submitted by oracle members /// @param balanceSum sum of all the balances of all validators that have been activated by the vPool /// this means that as long as the validator was activated, no matter its current status, its balance is taken /// into account /// @param exitedSum sum of all the ether that has been exited by the validators that have been activated by the vPool /// to compute this value, we look for withdrawal events inside the block bodies that have happened at an epoch /// that is greater or equal to the withdrawable epoch of a validator purchased by the pool /// when we detect any, we take min(amount,32 eth) into account as exited balance /// @param skimmedSum sum of all the ether that has been skimmed by the validators that have been activated by the vPool /// similar to the exitedSum, we look for withdrawal events. If the epochs is lower than the withdrawable epoch /// we take into account the full withdrawal amount, otherwise we take amount - min(amount, 32 eth) into account /// @param slashedSum sum of all the ether that has been slashed by the validators that have been activated by the vPool /// to compute this value, we look for validators that are of have been in the slashed state /// then we take the balance of the validator at the epoch prior to its slashing event /// we then add the delta between this old balance and the current balance (or balance just before withdrawal) /// @param exiting amount of currently exiting eth, that will soon hit the withdrawal recipient /// this value is computed by taking the balance of any validator in the exit or slashed state or after /// @param maxExitable maximum amount that can get requested for exits during report processing /// this value is determined by the oracle. its calculation logic can be updated but all members need to agree and reach /// consensus on the new calculation logic. Its role is to control the rate at which exit requests are performed /// @param maxCommittable maximum amount that can get committed for deposits during report processing /// positive value means commit happens before possible exit boosts, negative after /// similar to the mexExitable, this value is determined by the oracle. its calculation logic can be updated but all /// members need to agree and reach consensus on the new calculation logic. Its role is to control the rate at which /// deposit are made. Committed funds are funds that are always a multiple of 32 eth and that cannot be used for /// anything else than purchasing validator, as opposed to the deposited funds that can still be used to fuel the /// exit queue in some cases. /// @param epoch epoch at which the report was crafter /// @param activatedCount current count of validators that have been activated by the vPool /// no matter the current state of the validator, if it has been activated, it has to be accounted inside this value /// @param stoppedCount current count of validators that have been stopped (being in the exit queue, exited or slashed) struct ValidatorsReport { uint128 balanceSum; uint128 exitedSum; uint128 skimmedSum; uint128 slashedSum; uint128 exiting; uint128 maxExitable; int256 maxCommittable; uint64 epoch; uint32 activatedCount; uint32 stoppedCount; } /// @notice Structure representing the ethers held in the pools /// @param deposited The amount of deposited ethers, that can either be used to boost exits or get committed /// @param committed The amount of committed ethers, that can only be used to purchase validators struct Ethers { uint128 deposited; uint128 committed; } /// @notice Structure representing a ticket in the exit queue /// @param position The position of the ticket in the exit queue (equal to the position + size of the previous ticket) /// @param size The size of the ticket in the exit queue (in pool shares) /// @param maxExitable The maximum amount of ethers that can be exited by the ticket owner (no more rewards in the exit queue, losses are still mutualized) struct Ticket { uint128 position; uint128 size; uint128 maxExitable; } /// @notice Structure representing a cask in the exit queue. This entity is created by the pool upon oracle reports, when exit liquidity is available to feed the exit queue /// @param position The position of the cask in the exit queue (equal to the position + size of the previous cask) /// @param size The size of the cask in the exit queue (in pool shares) /// @param value The value of the cask in the exit queue (in ethers) struct Cask { uint128 position; uint128 size; uint128 value; } type DepositMapping is bytes32; type WithdrawalChannelMapping is bytes32; type BalanceMapping is bytes32; type MetadataStruct is bytes32; type ConsensusLayerSpecStruct is bytes32; type ReportBoundsStruct is bytes32; type ApprovalsMapping is bytes32; type ValidatorsReportStruct is bytes32; type EthersStruct is bytes32; type TicketArray is bytes32; type CaskArray is bytes32; type FactoryDepositorMapping is bytes32; }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "./ctypes.sol"; /// @title Approval Mapping Custom Type library LApprovalsMapping { function get(ctypes.ApprovalsMapping position) internal pure returns (mapping(address => mapping(address => uint256)) storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/Administrable.sol"; import "utils.sol/types/mapping.sol"; import "utils.sol/types/uint256.sol"; import "utils.sol/types/bool.sol"; import "utils.sol/types/address.sol"; import "vsuite/interfaces/IvPool.sol"; import "./interfaces/IMultiPool.sol"; import "./FeeDispatcher.sol"; import "./ExitQueueClaimHelper.sol"; uint256 constant MIN_COMMISSION_TO_SELL = 1e9; // If there is less than a gwei of commission to sell, we don't sell it /// @title MultiPool (v1) /// @author 0xvv @ Kiln /// @notice This contract contains the common functions to all integration contracts /// @notice Contains the functions to add pools, activate/deactivate a pool, change the fee of a pool and change the commission distribution abstract contract MultiPool is IMultiPool, FeeDispatcher, Administrable, ExitQueueClaimHelper { using LArray for types.Array; using LMapping for types.Mapping; using LUint256 for types.Uint256; using LBool for types.Bool; using CAddress for address; using CBool for bool; using CUint256 for uint256; /// @dev The mapping of pool addresses /// @dev Type: mapping(uint256 => address) /// @dev Slot: keccak256(bytes("multiPool.1.poolMap")) - 1 types.Mapping internal constant $poolMap = types.Mapping.wrap(0xbbbff6eb43d00812703825948233d51219dc930ada33999d17cf576c509bebe5); /// @dev The mapping of fee amounts in basis point to be applied on rewards from different pools /// @dev Type: mapping(uint256 => uint256) /// @dev Slot: keccak256(bytes("multiPool.1.fees")) - 1 types.Mapping internal constant $fees = types.Mapping.wrap(0x725bc5812d869f51ca713008babaeead3e54db7feab7d4cb185136396950f0e3); /// @dev The mapping of commission paid for different pools /// @dev Type: mapping(uint256 => uint256) /// @dev Slot: keccak256(bytes("multiPool.1.commissionPaid")) - 1 types.Mapping internal constant $commissionPaid = types.Mapping.wrap(0x6c8f9259db4f6802ea7a1e0a01ddb54668b622f1e8d6b610ad7ba4d95f59da29); /// @dev The mapping of injected Eth for different pools /// @dev Type: mapping(uint256 => uint256) /// @dev Slot: keccak256(bytes("multiPool.1.injectedEth")) - 1 types.Mapping internal constant $injectedEth = types.Mapping.wrap(0x03abd4c14227eca60c6fecceef3797455c352f43ab35128096ea0ac0d9b2170a); /// @dev The mapping of exited Eth for different pools /// @dev Type: mapping(uint256 => uint256) /// @dev Slot: keccak256(bytes("multiPool.1.exitedEth")) - 1 types.Mapping internal constant $exitedEth = types.Mapping.wrap(0x76a0ecda094c6ccf2a55f6f1ef41b98d3c1f2dfcb9c1970701fe842ce778ff9b); /// @dev The mapping storing whether users can deposit or not to each pool /// @dev Type: mapping(uint256 => bool) /// @dev Slot: keccak256(bytes("multiPool.1.poolActivation")) - 1 types.Mapping internal constant $poolActivation = types.Mapping.wrap(0x17b1774c0811229612ec3762023ccd209d6a131e52cdd22f3427eaa8005bcb2f); /// @dev The mapping of pool shares owned for each pools /// @dev Type: mapping(uint256 => uint256) /// @dev Slot: keccak256(bytes("multiPool.1.poolShares")) - 1 types.Mapping internal constant $poolShares = types.Mapping.wrap(0x357e26a850dc4edaa8b82b6511eec141075372c9c551d3ddb37c35a301f00018); /// @dev The number of pools. /// @dev Slot: keccak256(bytes("multiPool.1.poolCount")) - 1 types.Uint256 internal constant $poolCount = types.Uint256.wrap(0xce6dbdcc28927f6ed428550e539c70c9145bd20fc6e3d7611bd20e170e9b1840); /// @dev True if deposits are paused /// @dev Slot: keccak256(bytes("multiPool.1.depositsPaused")) - 1 types.Bool internal constant $depositPaused = types.Bool.wrap(0xa030c45ae387079bc9a34aa1365121b47b8ef2d06c04682ce63b90b7c06843e7); /// @dev The maximum commission that can be set for a pool, in basis points, to be set at initialization /// @dev Slot: keccak256(bytes("multiPool.1.maxCommission")) - 1 types.Uint256 internal constant $maxCommission = types.Uint256.wrap(0x70be78e680b682a5a3c38e305d79e28594fd0c62048cca29ef1bd1d746ca8785); /// @notice This modifier reverts if the deposit is paused modifier notPaused() { if ($depositPaused.get()) { revert DepositsPaused(); } _; } /// @inheritdoc IMultiPool function pools() public view returns (address[] memory) { uint256 length = $poolCount.get(); address[] memory poolAddresses = new address[](length); for (uint256 i = 0; i < length;) { poolAddresses[i] = $poolMap.get()[i].toAddress(); unchecked { i++; } } return poolAddresses; } /// @inheritdoc IMultiPool function pauseDeposits(bool isPaused) external onlyAdmin { emit SetDepositsPaused(isPaused); $depositPaused.set(isPaused); } /// @inheritdoc IMultiPool function depositsPaused() external view returns (bool) { return $depositPaused.get(); } /// @inheritdoc IMultiPool function getFee(uint256 poolId) public view returns (uint256) { return $fees.get()[poolId]; } /// @inheritdoc IMultiPool // slither-disable-next-line reentrancy-events function changeFee(uint256 poolId, uint256 newFeeBps) external onlyAdmin { uint256 earnedBeforeFeeUpdate = _integratorCommissionEarned(poolId); _setFee(newFeeBps, poolId); uint256 earnedAfterFeeUpdate = _integratorCommissionEarned(poolId); uint256 paid = $commissionPaid.get()[poolId]; uint256 paidAndEarnedAfter = paid + earnedAfterFeeUpdate; if (paidAndEarnedAfter < earnedBeforeFeeUpdate) { revert CommissionPaidUnderflow(); } $commissionPaid.get()[poolId] = paidAndEarnedAfter - earnedBeforeFeeUpdate; } /// @inheritdoc IMultiPool function changeSplit(address[] calldata recipients, uint256[] calldata splits) external onlyAdmin { _setFeeSplit(recipients, splits); } /// @inheritdoc IMultiPool function addPool(address pool, uint256 feeBps) external onlyAdmin { _addPool(pool, feeBps); } /// @inheritdoc IMultiPool function getPoolActivation(uint256 poolId) external view returns (bool) { return $poolActivation.get()[poolId].toBool(); } /// @inheritdoc IMultiPool function integratorCommissionOwed(uint256 poolId) external view returns (uint256) { return _integratorCommissionOwed(poolId); } /// @inheritdoc IMultiPool function exitCommissionShares(uint256 poolId) external onlyAdmin { _exitCommissionShares(poolId); } /// @inheritdoc IvPoolSharesReceiver function onvPoolSharesReceived(address operator, address from, uint256 amount, bytes memory) external returns (bytes4) { uint256 poolId = _findPoolIdOrRevert(msg.sender); if (!$poolActivation.get()[poolId].toBool()) revert PoolDisabled(poolId); // Check this callback is from minting, we can only receive shares from the pool when depositing if ($poolMap.get()[poolId].toAddress() != operator || from != address(0)) { revert CallbackNotFromMinting(); } $poolShares.get()[poolId] += amount; emit VPoolSharesReceived(msg.sender, poolId, amount); return IvPoolSharesReceiver.onvPoolSharesReceived.selector; } /// PRIVATE METHODS /// @dev Internal utility to exit commission shares /// @param poolId The vPool id // slither-disable-next-line reentrancy-events function _exitCommissionShares(uint256 poolId) internal { if (poolId >= $poolCount.get()) revert InvalidPoolId(poolId); uint256 shares = _poolSharesOfIntegrator(poolId); if (shares == 0) revert NoSharesToExit(poolId); address[] memory recipients = $feeRecipients.toAddressA(); uint256[] memory weights = $feeSplits.toUintA(); IvPool pool = _getPool(poolId); for (uint256 i = 0; i < recipients.length;) { uint256 share = LibUint256.mulDiv(shares, weights[i], LibConstant.BASIS_POINTS_MAX); if (share > 0) { _sendSharesToExitQueue(poolId, share, pool, recipients[i]); } unchecked { ++i; } } $exitedEth.get()[poolId] += LibUint256.mulDiv(shares, pool.totalUnderlyingSupply(), pool.totalSupply()); $commissionPaid.get()[poolId] = _integratorCommissionEarned(poolId); emit ExitedCommissionShares(poolId, shares, weights, recipients); } /// @dev Internal utility to send pool shares to the exit queue // slither-disable-next-line calls-loop function _sendSharesToExitQueue(uint256 poolId, uint256 shares, IvPool pool, address ticketOwner) internal { $poolShares.get()[poolId] -= shares; bool result = pool.transferShares(pool.exitQueue(), shares, abi.encodePacked(ticketOwner)); if (!result) { revert PoolTransferFailed(poolId); } } /// @notice Internal utility to find the id of a pool using its address /// @dev Reverts if the address is not found /// @param poolAddress address of the pool to look up function _findPoolIdOrRevert(address poolAddress) internal view returns (uint256) { for (uint256 id = 0; id < $poolCount.get();) { if (poolAddress == $poolMap.get()[id].toAddress()) { return id; } unchecked { id++; } } revert NotARegisteredPool(poolAddress); } /// @dev Internal utility to set the integrator fee value /// @param integratorFeeBps The new integrator fee in bps /// @param poolId The vPool id function _setFee(uint256 integratorFeeBps, uint256 poolId) internal { if (integratorFeeBps > $maxCommission.get()) { revert FeeOverMax($maxCommission.get()); } $fees.get()[poolId] = integratorFeeBps; emit SetFee(poolId, integratorFeeBps); } /// @dev Internal utility to get get the pool address /// @param poolId The index of the pool /// @return The pool // slither-disable-next-line naming-convention function _getPool(uint256 poolId) public view returns (IvPool) { if (poolId >= $poolCount.get()) { revert InvalidPoolId(poolId); } return IvPool($poolMap.get()[poolId].toAddress()); } /// @dev Add a pool to the list. /// @param newPool new pool address. /// @param fee fees in basis points of ETH. // slither-disable-next-line dead-code function _addPool(address newPool, uint256 fee) internal { LibSanitize.notInvalidBps(fee); LibSanitize.notZeroAddress(newPool); uint256 poolId = $poolCount.get(); for (uint256 i = 0; i < poolId;) { if (newPool == $poolMap.get()[i].toAddress()) { revert PoolAlreadyRegistered(newPool); } unchecked { i++; } } $poolMap.get()[poolId] = newPool.v(); $fees.get()[poolId] = fee; $poolActivation.get()[poolId] = true.v(); $poolCount.set(poolId + 1); emit PoolAdded(newPool, poolId); emit SetFee(poolId, fee); } /// @dev Reverts if the given pool is not enabled. /// @param poolId pool id. // slither-disable-next-line dead-code function _checkPoolIsEnabled(uint256 poolId) internal view { if (poolId >= $poolCount.get()) { revert InvalidPoolId(poolId); } bool status = $poolActivation.get()[poolId].toBool(); if (!status) { revert PoolDisabled(poolId); } } /// @dev Returns the ETH value of the vPool shares in the contract. /// @return amount of ETH. // slither-disable-next-line calls-loop function _stakedEthValue(uint256 poolId) internal view returns (uint256) { IvPool pool = _getPool(poolId); uint256 poolTotalSupply = pool.totalSupply(); if (poolTotalSupply == 0) { return 0; } return LibUint256.mulDiv($poolShares.get()[poolId], pool.totalUnderlyingSupply(), poolTotalSupply); } /// @dev Returns the amount of ETH earned by the integrator. /// @return amount of ETH. function _integratorCommissionEarned(uint256 poolId) internal view returns (uint256) { uint256 staked = _stakedEthValue(poolId); uint256 injected = $injectedEth.get()[poolId]; uint256 exited = $exitedEth.get()[poolId]; if (injected >= staked + exited) { // Can happen right after staking due to rounding error return 0; } uint256 rewardsEarned = staked + exited - injected; return LibUint256.mulDiv(rewardsEarned, $fees.get()[poolId], LibConstant.BASIS_POINTS_MAX); } /// @dev Returns the amount of ETH owed to the integrator. /// @return amount of ETH. // slither-disable-next-line dead-code function _integratorCommissionOwed(uint256 poolId) internal view returns (uint256) { uint256 earned = _integratorCommissionEarned(poolId); uint256 paid = $commissionPaid.get()[poolId]; if (earned > paid) { return earned - paid; } else { return 0; } } /// @dev Returns the ETH value of the vPool shares after subtracting integrator commission. /// @return amount of ETH. // slither-disable-next-line dead-code function _ethAfterCommission(uint256 poolId) internal view returns (uint256) { return _stakedEthValue(poolId) - _integratorCommissionOwed(poolId); } /// @dev Returns the number of vPool shares owed as commission. /// @return amount of shares. // slither-disable-next-line calls-loop,dead-code function _poolSharesOfIntegrator(uint256 poolId) internal view returns (uint256) { IvPool pool = IvPool($poolMap.get()[poolId].toAddress()); uint256 poolTotalUnderlying = pool.totalUnderlyingSupply(); return poolTotalUnderlying == 0 ? 0 : LibUint256.mulDiv(_integratorCommissionOwed(poolId), pool.totalSupply(), poolTotalUnderlying); } /// @dev Internal utility to set the max commission value /// @param maxCommission The new max commission in bps // slither-disable-next-line dead-code function _setMaxCommission(uint256 maxCommission) internal { LibSanitize.notInvalidBps(maxCommission); $maxCommission.set(maxCommission); emit SetMaxCommission(maxCommission); } }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; /// @title MultiPool-20 (V1) Interface /// @author 0xvv @ Kiln /// @notice This contract contains the internal logic for an ERC-20 token based on one or multiple pools. interface IMultiPool20 { /// @notice Emitted when a stake is transferred. /// @param from The address sending the stake /// @param to The address receiving the stake /// @param value The transfer amount event Transfer(address indexed from, address indexed to, uint256 value); /// @notice Emitted when an allowance is created. /// @param owner The owner of the shares /// @param spender The address that can spend /// @param value The allowance amount event Approval(address indexed owner, address indexed spender, uint256 value); /// @notice Emitted when some integrator shares are sold /// @param pSharesSold ETH amount of vPool shares sold /// @param id Id of the pool /// @param amountSold ETH amount of shares sold event CommissionSharesSold(uint256 pSharesSold, uint256 id, uint256 amountSold); /// @notice Emitted when new split is set. /// @param split Array of value in basis points to route to each pool event SetPoolPercentages(uint256[] split); /// @notice Thrown when a transfer is attempted but the sender does not have enough balance. /// @param amount The token amount. /// @param balance The balance of user. error InsufficientBalance(uint256 amount, uint256 balance); /// @notice Thrown when a transferFrom is attempted but the spender does not have enough allowance. error InsufficientAllowance(uint256 amount, uint256 allowance); /// @notice Thrown when trying to set a pool percentage != 0 to a deactivated pool error NonZeroPercentageOnDeactivatedPool(uint256 id); /// @notice Set the percentage of new stakes to route to each pool /// @notice If a pool is disabled it needs to be set to 0 in the array /// @param split Array of values in basis points to route to each pool function setPoolPercentages(uint256[] calldata split) external; /// @notice Burns the sender's shares and sends the exitQueue tickets to the caller. /// @param amount Amount of shares to add to the exit queue function requestExit(uint256 amount) external; /// @notice Returns the share to ETH conversion rate /// @return ETH value of a share function rate() external returns (uint256); /// @notice Allows the integrator to prevent users from depositing to a vPool. /// @param poolId The id of the vPool. /// @param status Whether the users can deposit to the pool. /// @param newPoolPercentages Array of value in basis points to route to each pool after the change function setPoolActivation(uint256 poolId, bool status, uint256[] calldata newPoolPercentages) external; }
//SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import "utils.sol/libs/LibPublicKey.sol"; import "utils.sol/libs/LibSignature.sol"; /// @title Custom Types // slither-disable-next-line naming-convention library victypes { struct User4907 { address user; uint64 expiration; } type BalanceMapping is bytes32; type User4907Mapping is bytes32; }
//SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import "./victypes.sol"; /// @title Balance mappings Custom Type library LBalance { // slither-disable-next-line dead-code function get(victypes.BalanceMapping position) internal pure returns (mapping(address => uint256) storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; library LibPublicKey { // slither-disable-next-line unused-state uint256 constant PUBLIC_KEY_LENGTH = 48; // slither-disable-next-line unused-state bytes constant PADDING = hex"00000000000000000000000000000000"; struct PublicKey { bytes32 A; bytes16 B; } // slither-disable-next-line dead-code function toBytes(PublicKey memory publicKey) internal pure returns (bytes memory) { return abi.encodePacked(publicKey.A, publicKey.B); } // slither-disable-next-line dead-code function fromBytes(bytes memory publicKey) internal pure returns (PublicKey memory ret) { publicKey = bytes.concat(publicKey, PADDING); (bytes32 A, bytes32 B_prime) = abi.decode(publicKey, (bytes32, bytes32)); bytes16 B = bytes16(uint128(uint256(B_prime) >> 128)); ret.A = A; ret.B = B; } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; library LibSignature { // slither-disable-next-line unused-state uint256 constant SIGNATURE_LENGTH = 96; struct Signature { bytes32 A; bytes32 B; bytes32 C; } // slither-disable-next-line dead-code function toBytes(Signature memory signature) internal pure returns (bytes memory) { return abi.encodePacked(signature.A, signature.B, signature.C); } // slither-disable-next-line dead-code function fromBytes(bytes memory signature) internal pure returns (Signature memory ret) { (ret) = abi.decode(signature, (Signature)); } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./libs/LibSanitize.sol"; import "./types/address.sol"; import "./interfaces/IAdministrable.sol"; /// @title Administrable /// @author mortimr @ Kiln /// @dev Unstructured Storage Friendly /// @notice This contract provides all the utilities to handle the administration and its transfer. abstract contract Administrable is IAdministrable { using LAddress for types.Address; /// @dev The admin address in storage. /// @dev Slot: keccak256(bytes("administrable.admin")) - 1 types.Address internal constant $admin = types.Address.wrap(0x927a17e5ea75d9461748062a2652f4d3698a628896c9832f8488fa0d2846af09); /// @dev The pending admin address in storage. /// @dev Slot: keccak256(bytes("administrable.pendingAdmin")) - 1 types.Address internal constant $pendingAdmin = types.Address.wrap(0x3c1eebcc225c6cc7f5f8765767af6eff617b4139dc3624923a2db67dbca7b68e); /// @dev This modifier ensures that only the admin is able to call the method. modifier onlyAdmin() { if (msg.sender != _getAdmin()) { revert LibErrors.Unauthorized(msg.sender, _getAdmin()); } _; } /// @dev This modifier ensures that only the pending admin is able to call the method. modifier onlyPendingAdmin() { if (msg.sender != _getPendingAdmin()) { revert LibErrors.Unauthorized(msg.sender, _getPendingAdmin()); } _; } /// @inheritdoc IAdministrable function admin() external view returns (address) { return _getAdmin(); } /// @inheritdoc IAdministrable function pendingAdmin() external view returns (address) { return _getPendingAdmin(); } /// @notice Propose a new admin. /// @dev Only callable by the admin. /// @param newAdmin The new admin to propose function transferAdmin(address newAdmin) external onlyAdmin { _setPendingAdmin(newAdmin); } /// @notice Accept an admin transfer. /// @dev Only callable by the pending admin. function acceptAdmin() external onlyPendingAdmin { _setAdmin(msg.sender); _setPendingAdmin(address(0)); } /// @dev Retrieve the admin address. /// @return The admin address function _getAdmin() internal view returns (address) { return $admin.get(); } /// @dev Change the admin address. /// @param newAdmin The new admin address function _setAdmin(address newAdmin) internal { LibSanitize.notZeroAddress(newAdmin); emit SetAdmin(newAdmin); $admin.set(newAdmin); } /// @dev Retrieve the pending admin address. /// @return The pending admin address function _getPendingAdmin() internal view returns (address) { return $pendingAdmin.get(); } /// @dev Change the pending admin address. /// @param newPendingAdmin The new pending admin address function _setPendingAdmin(address newPendingAdmin) internal { emit SetPendingAdmin(newPendingAdmin); $pendingAdmin.set(newPendingAdmin); } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types.sol"; library LBool { // slither-disable-next-line dead-code function get(types.Bool position) internal view returns (bool data) { // slither-disable-next-line assembly assembly { data := sload(position) } } // slither-disable-next-line dead-code function set(types.Bool position, bool data) internal { // slither-disable-next-line assembly assembly { sstore(position, data) } } // slither-disable-next-line dead-code function del(types.Bool position) internal { // slither-disable-next-line assembly assembly { sstore(position, 0) } } } library CBool { // slither-disable-next-line dead-code function toBytes32(bool val) internal pure returns (bytes32) { return bytes32(toUint256(val)); } // slither-disable-next-line dead-code function toAddress(bool val) internal pure returns (address) { return address(uint160(toUint256(val))); } // slither-disable-next-line dead-code function toUint256(bool val) internal pure returns (uint256 converted) { // slither-disable-next-line assembly assembly { converted := iszero(iszero(val)) } } /// @dev This method should be used to convert a bool to a uint256 when used as a key in a mapping. // slither-disable-next-line dead-code function k(bool val) internal pure returns (uint256) { return toUint256(val); } /// @dev This method should be used to convert a bool to a uint256 when used as a value in a mapping. // slither-disable-next-line dead-code function v(bool val) internal pure returns (uint256) { return toUint256(val); } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types.sol"; /// @notice Library Address - Address slot utilities. library LAddress { // slither-disable-next-line dead-code, assembly function get(types.Address position) internal view returns (address data) { // slither-disable-next-line assembly assembly { data := sload(position) } } // slither-disable-next-line dead-code function set(types.Address position, address data) internal { // slither-disable-next-line assembly assembly { sstore(position, data) } } // slither-disable-next-line dead-code function del(types.Address position) internal { // slither-disable-next-line assembly assembly { sstore(position, 0) } } } library CAddress { // slither-disable-next-line dead-code function toUint256(address val) internal pure returns (uint256) { return uint256(uint160(val)); } // slither-disable-next-line dead-code function toBytes32(address val) internal pure returns (bytes32) { return bytes32(uint256(uint160(val))); } // slither-disable-next-line dead-code function toBool(address val) internal pure returns (bool converted) { // slither-disable-next-line assembly assembly { converted := gt(val, 0) } } /// @notice This method should be used to convert an address to a uint256 when used as a key in a mapping. // slither-disable-next-line dead-code function k(address val) internal pure returns (uint256) { return toUint256(val); } /// @notice This method should be used to convert an address to a uint256 when used as a value in a mapping. // slither-disable-next-line dead-code function v(address val) internal pure returns (uint256) { return toUint256(val); } }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/interfaces/IFixable.sol"; import "../ctypes/ctypes.sol"; /// @title Pool Interface /// @author mortimr @ Kiln /// @notice The vPool contract is in charge of pool funds and fund validators from the vFactory interface IvPool is IFixable { /// @notice Emitted at construction time when all contract addresses are set /// @param factory The address of the vFactory contract /// @param withdrawalRecipient The address of the withdrawal recipient contract /// @param execLayerRecipient The address of the execution layer recipient contract /// @param coverageRecipient The address of the coverage recipient contract /// @param oracleAggregator The address of the oracle aggregator contract /// @param exitQueue The address of the exit queue contract event SetContractLinks( address factory, address withdrawalRecipient, address execLayerRecipient, address coverageRecipient, address oracleAggregator, address exitQueue ); /// @notice Emitted when the global validator extra data is changed /// @param extraData New extra data used on validator purchase event SetValidatorGlobalExtraData(string extraData); /// @notice Emitted when a depositor authorization changed /// @param depositor The address of the depositor /// @param allowed True if allowed to deposit event ApproveDepositor(address depositor, bool allowed); /// @notice Emitted when a depositor performs a deposit /// @param sender The transaction sender /// @param amount The deposit amount /// @param mintedShares The amount of shares created event Deposit(address indexed sender, uint256 amount, uint256 mintedShares); /// @notice Emitted when the vPool purchases validators to the vFactory /// @param validators The list of IDs (not BLS Public keys) event PurchasedValidators(uint256[] validators); /// @notice Emitted when new shares are created /// @param account The account receiving the new shares /// @param amount The amount of shares created /// @param totalSupply The new totalSupply value event Mint(address indexed account, uint256 amount, uint256 totalSupply); /// @notice Emitted when shares are burned /// @param burner The account burning shares /// @param amount The amount of burned shares /// @param totalSupply The new totalSupply value event Burn(address burner, uint256 amount, uint256 totalSupply); /// @notice Emitted when shares are transfered /// @param from The account sending the shares /// @param to The account receiving the shares /// @param value The value transfered event Transfer(address indexed from, address indexed to, uint256 value); /// @notice Emitted when shares are approved for a spender /// @param owner The account approving the shares /// @param spender The account receiving the spending rights /// @param value The value of the approval. Max uint256 means infinite (will never decrease) event Approval(address indexed owner, address indexed spender, uint256 value); /// @notice Emitted when shares are voided (action of burning without redeeming anything on purpose) /// @param voider The account voiding the shares /// @param amount The amount of voided shares event VoidedShares(address voider, uint256 amount); /// @notice Emitted when ether is injected into the system (outside of the deposit flow) /// @param injecter The account injecting the ETH /// @param amount The amount of injected ETH event InjectedEther(address injecter, uint256 amount); /// @notice Emitted when the report processing is finished /// @param epoch The epoch number /// @param report The received report structure /// @param traces Internal traces with key figures event ProcessedReport(uint256 indexed epoch, ctypes.ValidatorsReport report, ReportTraces traces); /// @notice Emitted when rewards are distributed to the node operator /// @param operatorTreasury The address receiving the rewards /// @param sharesCount The amount of shares created to pay the rewards /// @param sharesValue The value in ETH of the newly minted shares /// @param totalSupply The updated totalSupply value /// @param totalUnderlyingSupply The updated totalUnderlyingSupply value event DistributedOperatorRewards( address indexed operatorTreasury, uint256 sharesCount, uint256 sharesValue, uint256 totalSupply, uint256 totalUnderlyingSupply ); /// @notice Emitted when the report bounds are updated /// @param maxAPRUpperBound The maximum APR allowed during oracle reports /// @param maxAPRUpperCoverageBoost The APR boost allowed only for coverage funds /// @param maxRelativeLowerBound The max relative delta in underlying supply authorized during losses of funds event SetReportBounds(uint64 maxAPRUpperBound, uint64 maxAPRUpperCoverageBoost, uint64 maxRelativeLowerBound); /// @notice Emitted when the epochs per frame value is updated /// @param epochsPerFrame The new epochs per frame value event SetEpochsPerFrame(uint256 epochsPerFrame); /// @notice Emitted when the consensus layer spec is updated /// @param consensusLayerSpec The new consensus layer spec event SetConsensusLayerSpec(ctypes.ConsensusLayerSpec consensusLayerSpec); /// @notice Emitted when the operator fee is updated /// @param operatorFeeBps The new operator fee value event SetOperatorFee(uint256 operatorFeeBps); /// @notice Emitted when the deposited ether buffer is updated /// @param depositedEthers The new deposited ethers value event SetDepositedEthers(uint256 depositedEthers); /// @notice Emitted when the committed ether buffer is updated /// @param committedEthers The new committed ethers value event SetCommittedEthers(uint256 committedEthers); /// @notice Emitted when the requested exits is updated /// @param newRequestedExits The new requested exits count event SetRequestedExits(uint32 newRequestedExits); /// @notice The balance was too low for the requested operation /// @param account The account trying to perform the operation /// @param currentBalance The current account balance /// @param requiredAmount The amount that was required to perform the operation error BalanceTooLow(address account, uint256 currentBalance, uint256 requiredAmount); /// @notice The allowance was too low for the requested operation /// @param account The account trying to perform the operation /// @param operator The account triggering the operation on behalf of the account /// @param currentApproval The current account approval towards the operator /// @param requiredAmount The amount that was required to perform the operation error AllowanceTooLow(address account, address operator, uint256 currentApproval, uint256 requiredAmount); /// @notice Thrown when approval for an account and spender is already zero. /// @param account The account for which approval was attempted to be set to zero. /// @param spender The spender for which approval was attempted to be set to zero. error ApprovalAlreadyZero(address account, address spender); /// @notice Thrown when there is an error with a share receiver. /// @param err The error message. error ShareReceiverError(string err); /// @notice Thrown when there is no validator available to purchase. error NoValidatorToPurchase(); /// @notice Thrown when the epoch of a report is too old. /// @param epoch The epoch of the report. /// @param expectEpoch The expected epoch for the operation. error EpochTooOld(uint256 epoch, uint256 expectEpoch); /// @notice Thrown when an epoch is not the first epoch of a frame. /// @param epoch The epoch that was not the first epoch of a frame. error EpochNotFrameFirst(uint256 epoch); /// @notice Thrown when an epoch is not final. /// @param epoch The epoch that was not final. /// @param currentTimestamp The current timestamp. /// @param finalTimestamp The final timestamp of the frame. error EpochNotFinal(uint256 epoch, uint256 currentTimestamp, uint256 finalTimestamp); /// @notice Thrown when the validator count is decreasing. /// @param previousValidatorCount The previous validator count. /// @param validatorCount The current validator count. error DecreasingValidatorCount(uint256 previousValidatorCount, uint256 validatorCount); /// @notice Thrown when the stopped validator count is decreasing. /// @param previousStoppedValidatorCount The previous stopped validator count. /// @param stoppedValidatorCount The current stopped validator count. error DecreasingStoppedValidatorCount(uint256 previousStoppedValidatorCount, uint256 stoppedValidatorCount); /// @notice Thrown when the slashed balance sum is decreasing. /// @param reportedSlashedBalanceSum The reported slashed balance sum. /// @param lastReportedSlashedBalanceSum The last reported slashed balance sum. error DecreasingSlashedBalanceSum(uint256 reportedSlashedBalanceSum, uint256 lastReportedSlashedBalanceSum); /// @notice Thrown when the exited balance sum is decreasing. /// @param reportedExitedBalanceSum The reported exited balance sum. /// @param lastReportedExitedBalanceSum The last reported exited balance sum. error DecreasingExitedBalanceSum(uint256 reportedExitedBalanceSum, uint256 lastReportedExitedBalanceSum); /// @notice Thrown when the skimmed balance sum is decreasing. /// @param reportedSkimmedBalanceSum The reported skimmed balance sum. /// @param lastReportedSkimmedBalanceSum The last reported skimmed balance sum. error DecreasingSkimmedBalanceSum(uint256 reportedSkimmedBalanceSum, uint256 lastReportedSkimmedBalanceSum); /// @notice Thrown when the reported validator count is higher than the total activated validators /// @param stoppedValidatorsCount The reported stopped validator count. /// @param maxStoppedValidatorsCount The maximum allowed stopped validator count. error StoppedValidatorCountTooHigh(uint256 stoppedValidatorsCount, uint256 maxStoppedValidatorsCount); /// @notice Thrown when the reported exiting balance exceeds the total validator balance on the cl /// @param exiting The reported exiting balance. /// @param balance The total validator balance on the cl. error ExitingBalanceTooHigh(uint256 exiting, uint256 balance); /// @notice Thrown when the reported validator count is higher than the deposited validator count. /// @param reportedValidatorCount The reported validator count. /// @param depositedValidatorCount The deposited validator count. error ValidatorCountTooHigh(uint256 reportedValidatorCount, uint256 depositedValidatorCount); /// @notice Thrown when the coverage is higher than the loss. /// @param coverage The coverage. /// @param loss The loss. error CoverageHigherThanLoss(uint256 coverage, uint256 loss); /// @notice Thrown when the balance increase exceeds the maximum allowed balance increase. /// @param balanceIncrease The balance increase. /// @param maximumAllowedBalanceIncrease The maximum allowed balance increase. error UpperBoundCrossed(uint256 balanceIncrease, uint256 maximumAllowedBalanceIncrease); /// @notice Thrown when the balance increase exceeds the maximum allowed balance increase or maximum allowed coverage. /// @param balanceIncrease The balance increase. /// @param maximumAllowedBalanceIncrease The maximum allowed balance increase. /// @param maximumAllowedCoverage The maximum allowed coverage. error BoostedBoundCrossed(uint256 balanceIncrease, uint256 maximumAllowedBalanceIncrease, uint256 maximumAllowedCoverage); /// @notice Thrown when the balance decrease exceeds the maximum allowed balance decrease. /// @param balanceDecrease The balance decrease. /// @param maximumAllowedBalanceDecrease The maximum allowed balance decrease. error LowerBoundCrossed(uint256 balanceDecrease, uint256 maximumAllowedBalanceDecrease); /// @notice Thrown when the amount of shares to mint is computed to 0 error InvalidNullMint(); /// @notice Traces emitted at the end of the reporting process. /// @param preUnderlyingSupply The pre-reporting underlying supply. /// @param postUnderlyingSupply The post-reporting underlying supply. /// @param preSupply The pre-reporting supply. /// @param postSupply The post-reporting supply. /// @param newExitedEthers The new exited ethers. /// @param newSkimmedEthers The new skimmed ethers. /// @param exitBoostEthers The exit boost ethers. /// @param exitFedEthers The exit fed ethers. /// @param exitBurnedShares The exit burned shares. /// @param exitingProjection The exiting projection. /// @param baseFulfillableDemand The base fulfillable demand. /// @param extraFulfillableDemand The extra fulfillable demand. /// @param rewards The rewards. Can be negative when there is a loss, but cannot include coverage funds. /// @param delta The delta. Can be negative when there is a loss and include all pulled funds. /// @param increaseLimit The increase limit. /// @param coverageIncreaseLimit The coverage increase limit. /// @param decreaseLimit The decrease limit. /// @param consensusLayerDelta The consensus layer delta. /// @param pulledCoverageFunds The pulled coverage funds. /// @param pulledExecutionLayerRewards The pulled execution layer rewards. /// @param pulledExitQueueUnclaimedFunds The pulled exit queue unclaimed funds. struct ReportTraces { // supplied uint128 preUnderlyingSupply; uint128 postUnderlyingSupply; uint128 preSupply; uint128 postSupply; // new consensus layer funds uint128 newExitedEthers; uint128 newSkimmedEthers; // exit related funds uint128 exitBoostEthers; uint128 exitFedEthers; uint128 exitBurnedShares; uint128 exitingProjection; uint128 baseFulfillableDemand; uint128 extraFulfillableDemand; // rewards int128 rewards; // delta and details about sources of funds int128 delta; uint128 increaseLimit; uint128 coverageIncreaseLimit; uint128 decreaseLimit; int128 consensusLayerDelta; uint128 pulledCoverageFunds; uint128 pulledExecutionLayerRewards; uint128 pulledExitQueueUnclaimedFunds; } /// @notice Initializes the contract with the given parameters. /// @param addrs The addresses of the dependencies (factory, withdrawal recipient, exec layer recipient, /// coverage recipient, oracle aggregator, exit queue). /// @param epochsPerFrame_ The number of epochs per frame. /// @param consensusLayerSpec_ The consensus layer spec. /// @param bounds_ The bounds for reporting. /// @param operatorFeeBps_ The operator fee in basis points. /// @param extraData_ The initial extra data that will be provided on each deposit function initialize( address[6] calldata addrs, uint256 epochsPerFrame_, ctypes.ConsensusLayerSpec calldata consensusLayerSpec_, uint64[3] calldata bounds_, uint256 operatorFeeBps_, string calldata extraData_ ) external; /// @notice Returns the address of the factory contract. /// @return The address of the factory contract. function factory() external view returns (address); /// @notice Returns the address of the execution layer recipient contract. /// @return The address of the execution layer recipient contract. function execLayerRecipient() external view returns (address); /// @notice Returns the address of the coverage recipient contract. /// @return The address of the coverage recipient contract. function coverageRecipient() external view returns (address); /// @notice Returns the address of the withdrawal recipient contract. /// @return The address of the withdrawal recipient contract. function withdrawalRecipient() external view returns (address); /// @notice Returns the address of the oracle aggregator contract. /// @return The address of the oracle aggregator contract. function oracleAggregator() external view returns (address); /// @notice Returns the address of the exit queue contract /// @return The address of the exit queue contract function exitQueue() external view returns (address); /// @notice Returns the current validator global extra data /// @return The validator global extra data value function validatorGlobalExtraData() external view returns (string memory); /// @notice Returns whether the given address is a depositor. /// @param depositorAddress The address to check. /// @return Whether the given address is a depositor. function depositors(address depositorAddress) external view returns (bool); /// @notice Returns the total supply of tokens. /// @return The total supply of tokens. function totalSupply() external view returns (uint256); /// @notice Returns the name of the vPool /// @return The name of the vPool function name() external view returns (string memory); /// @notice Returns the symbol of the vPool /// @return The symbol of the vPool function symbol() external view returns (string memory); /// @notice Returns the decimals of the vPool shares /// @return The decimal count function decimals() external pure returns (uint8); /// @notice Returns the total underlying supply of tokens. /// @return The total underlying supply of tokens. function totalUnderlyingSupply() external view returns (uint256); /// @notice Returns the current ETH/SHARES rate based on the total underlying supply and total supply. /// @return The current rate function rate() external view returns (uint256); /// @notice Returns the current requested exit count /// @return The current requested exit count function requestedExits() external view returns (uint32); /// @notice Returns the balance of the given account. /// @param account The address of the account to check. /// @return The balance of the given account. function balanceOf(address account) external view returns (uint256); /// @notice Returns the allowance of the given spender for the given owner. /// @param owner The owner of the allowance. /// @param spender The spender of the allowance. /// @return The allowance of the given spender for the given owner. function allowance(address owner, address spender) external view returns (uint256); /// @notice Returns the details about the held ethers /// @return The structure of ethers inside the contract function ethers() external view returns (ctypes.Ethers memory); /// @notice Returns an array of the IDs of purchased validators. /// @return An array of the IDs of purchased validators. function purchasedValidators() external view returns (uint256[] memory); /// @notice Returns the ID of the purchased validator at the given index. /// @param idx The index of the validator. /// @return The ID of the purchased validator at the given index. function purchasedValidatorAtIndex(uint256 idx) external view returns (uint256); /// @notice Returns the total number of purchased validators. /// @return The total number of purchased validators. function purchasedValidatorCount() external view returns (uint256); /// @notice Returns the last epoch. /// @return The last epoch. function lastEpoch() external view returns (uint256); /// @notice Returns the last validator report that was processed /// @return The last report structure. function lastReport() external view returns (ctypes.ValidatorsReport memory); /// @notice Returns the total amount in ETH covered by the contract. /// @return The total amount in ETH covered by the contract. function totalCovered() external view returns (uint256); /// @notice Returns the number of epochs per frame. /// @return The number of epochs per frame. function epochsPerFrame() external view returns (uint256); /// @notice Returns the consensus layer spec. /// @return The consensus layer spec. function consensusLayerSpec() external pure returns (ctypes.ConsensusLayerSpec memory); /// @notice Returns the report bounds. /// @return maxAPRUpperBound The maximum APR for the upper bound. /// @return maxAPRUpperCoverageBoost The maximum APR for the upper bound with coverage boost. /// @return maxRelativeLowerBound The maximum relative lower bound. function reportBounds() external view returns (uint64 maxAPRUpperBound, uint64 maxAPRUpperCoverageBoost, uint64 maxRelativeLowerBound); /// @notice Returns the operator fee. /// @return The operator fee. function operatorFee() external view returns (uint256); /// @notice Returns whether the given epoch is valid. /// @param epoch The epoch to check. /// @return Whether the given epoch is valid. function isValidEpoch(uint256 epoch) external view returns (bool); /// @notice Reverts if given epoch is invalid, with an explicit custom error based on the issue /// @param epoch The epoch to check. function onlyValidEpoch(uint256 epoch) external view; /// @notice Allows or disallows the given depositor to deposit. /// @param depositorAddress The address of the depositor. /// @param allowed Whether the depositor is allowed to deposit. function allowDepositor(address depositorAddress, bool allowed) external; /// @notice Transfers the given amount of shares to the given address. /// @param to The address to transfer the shares to. /// @param amount The amount of shares to transfer. /// @param data Additional data for the transfer. /// @return Whether the transfer was successful. function transferShares(address to, uint256 amount, bytes calldata data) external returns (bool); /// @notice Increases the allowance for the given spender by the given amount. /// @param spender The spender to increase the allowance for. /// @param amount The amount to increase the allowance by. /// @return Whether the increase was successful. function increaseAllowance(address spender, uint256 amount) external returns (bool); /// @notice Decreases the allowance of a spender by the given amount. /// @param spender The address of the spender. /// @param amount The amount to decrease the allowance by. /// @return Whether the allowance was successfully decreased. function decreaseAllowance(address spender, uint256 amount) external returns (bool); /// @notice Voids the allowance of a spender. /// @param spender The address of the spender. /// @return Whether the allowance was successfully voided. function voidAllowance(address spender) external returns (bool); /// @notice Transfers shares from one account to another. /// @param from The address of the account to transfer shares from. /// @param to The address of the account to transfer shares to. /// @param amount The amount of shares to transfer. /// @param data Optional data to include with the transaction. /// @return Whether the transfer was successful. function transferSharesFrom(address from, address to, uint256 amount, bytes calldata data) external returns (bool); /// @notice Deposits ether into the contract. /// @return The number of shares minted on deposit function deposit() external payable returns (uint256); /// @notice Purchases the maximum number of validators allowed. /// @param max The maximum number of validators to purchase. function purchaseValidators(uint256 max) external; /// @notice Sets the operator fee. /// @param operatorFeeBps The new operator fee, in basis points. function setOperatorFee(uint256 operatorFeeBps) external; /// @notice Sets the number of epochs per frame. /// @param newEpochsPerFrame The new number of epochs per frame. function setEpochsPerFrame(uint256 newEpochsPerFrame) external; /// @notice Sets the consensus layer spec. /// @param consensusLayerSpec_ The new consensus layer spec. function setConsensusLayerSpec(ctypes.ConsensusLayerSpec calldata consensusLayerSpec_) external; /// @notice Sets the global validator extra data /// @param extraData The new extra data to use function setValidatorGlobalExtraData(string calldata extraData) external; /// @notice Sets the bounds for reporting. /// @param maxAPRUpperBound The maximum APR for the upper bound. /// @param maxAPRUpperCoverageBoost The maximum APR for the upper coverage boost. /// @param maxRelativeLowerBound The maximum relative value for the lower bound. function setReportBounds(uint64 maxAPRUpperBound, uint64 maxAPRUpperCoverageBoost, uint64 maxRelativeLowerBound) external; /// @notice Injects ether into the contract. function injectEther() external payable; /// @notice Voids the given amount of shares. /// @param amount The amount of shares to void. function voidShares(uint256 amount) external; /// @notice Reports the validator data for the given epoch. /// @param rprt The consensus layer report to process function report(ctypes.ValidatorsReport calldata rprt) external; }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "./IFeeDispatcher.sol"; import "vsuite/interfaces/IvPoolSharesReceiver.sol"; /// @notice PoolStakeDetails contains the details of a stake /// @param poolId Id of the pool /// @param ethToPool ETH amount sent to the pool /// @param ethToIntegrator ETH amount going to the integrator /// @param pSharesFromPool Amount of pool shares received from the pool /// @param pSharesFromIntegrator Amount of pool shares received from the integrator struct PoolStakeDetails { uint128 poolId; uint128 ethToPool; uint128 ethToIntegrator; uint128 pSharesFromPool; uint128 pSharesFromIntegrator; } /// @notice PoolExitDetails contains the details of an exit /// @param poolId Id of the pool /// @param exitedPoolShares Amount of pool shares exited struct PoolExitDetails { uint128 poolId; uint128 exitedPoolShares; } /// @title MultiPool (V1) Interface /// @author 0xvv @ Kiln /// @notice This contract contains the common functions to all integration contracts. /// Contains the functions to add pools, activate/deactivate a pool, change the fee of a pool and change the commission distribution. interface IMultiPool is IFeeDispatcher, IvPoolSharesReceiver { /// @notice Emitted when vPool shares are received /// @param vPool Address of the vPool sending the shares /// @param poolId Id of the pool in the integrations contract /// @param amount The amount of vPool shares received event VPoolSharesReceived(address vPool, uint256 poolId, uint256 amount); /// @notice Emitted when a vPool in enabled or disabled /// @param poolAddress The new pool address /// @param id Id of the pool /// @param isActive whether the pool can be staked to or not event PoolActivation(address poolAddress, uint256 id, bool isActive); /// @notice Emitted when a vPool address is added to vPools /// @param poolAddress The new pool address /// @param id Id of the pool event PoolAdded(address poolAddress, uint256 id); /// @notice Emitted when the integrator fee is changed /// @param poolId Id of the pool /// @param operatorFeeBps The new fee in basis points event SetFee(uint256 poolId, uint256 operatorFeeBps); /// @notice Emitted when the display name is changed /// @param name The new name event SetName(string name); /// @notice Emitted when the display symbol is changed /// @param symbol The new display symbol event SetSymbol(string symbol); /// @notice Emitted when the max commission is set /// @param maxCommission The new max commission event SetMaxCommission(uint256 maxCommission); /// @notice Emitted when the deposits are paused or unpaused /// @param isPaused Whether the deposits are paused or not event SetDepositsPaused(bool isPaused); /// @notice Emitted when staking occurs, contains the details for all the pools /// @param staker The address staking /// @param depositedEth The amount of ETH staked /// @param mintedTokens The amount of integrator shares minted /// @param stakeDetails Array of details for each pool, contains the pool id, the amount of ETH sent to the pool, /// the amount of ETH sent to the integrator, the amount of pool shares received from the pool and /// the amount of pools shares bought from the integrator event Stake(address indexed staker, uint128 depositedEth, uint128 mintedTokens, PoolStakeDetails[] stakeDetails); /// @notice Emitted when an exit occurs, contains the details for all the pools /// @param staker The address exiting /// @param exitedTokens The amount of integrator shares exited /// @param exitDetails Array of details for each pool, contains the pool id and the amount of pool shares exited event Exit(address indexed staker, uint128 exitedTokens, PoolExitDetails[] exitDetails); /// @notice Emitted when the commission is distributed via a manual call /// @param poolId Id of the pool /// @param shares Amount of pool shares exited /// @param weights Array of weights for each recipient /// @param recipients Array of recipients event ExitedCommissionShares(uint256 indexed poolId, uint256 shares, uint256[] weights, address[] recipients); /// @notice Thrown on stake if deposits are paused error DepositsPaused(); /// @notice Thrown when trying to stake but the sum of amounts is not equal to the msg.value /// @param sum Sum of amounts in the list /// @param msgValue Amount of ETH sent error InvalidAmounts(uint256 sum, uint256 msgValue); /// @notice Thrown when trying to init the contract without providing a pool address error EmptyPoolList(); /// @notice Thrown when trying to change the fee but there are integrator shares left to sell /// @param ethLeft The ETH value of shares left to sell /// @param id Id of the pool error OutstandingCommission(uint256 ethLeft, uint256 id); /// @notice Thrown when trying to add a Pool that is already registered in the contract /// @param newPool The pool address error PoolAlreadyRegistered(address newPool); /// @notice Thrown when trying to deposit to a disabled pool /// @param poolId Id of the pool error PoolDisabled(uint256 poolId); /// @notice Thrown when trying the pool shares callback is called by an address that is not registered /// @param poolAddress The pool address error NotARegisteredPool(address poolAddress); /// @notice Emitted when a pool transfer does not return true. /// @param id The id of the pool. error PoolTransferFailed(uint256 id); /// @notice Thrown when passing an invalid poolId /// @param poolId Invalid pool id error InvalidPoolId(uint256 poolId); /// @notice Thrown when the commission underflow when lowering the fee /// @notice To avoid this, the integrator can call exitCommissionShares before lowering the fee or wait for the integrator shares to be sold error CommissionPaidUnderflow(); /// @notice Thrown when minting a null amount of shares error ZeroSharesMint(); /// @notice Thrown when trying to see a fee over the max fee set at initialization error FeeOverMax(uint256 maxFeeBps); /// @notice Thrown when trying to call the callback outside of the minting process error CallbackNotFromMinting(); /// @notice Thrown when trying to exit the commission shares but there are no shares to exit error NoSharesToExit(uint256 poolId); /// @notice Returns the list of vPools. /// @return vPools The addresses of the pool contract. function pools() external view returns (address[] memory vPools); /// @notice Returns the current fee in basis points for the given pool. /// @return feeBps The current fee in basis points. /// @param id Id of the pool function getFee(uint256 id) external view returns (uint256 feeBps); /// @notice Allows the integrator to change the fee. /// @dev Reverts if there are unsold integrator shares. /// @param poolId vPool id /// @param newFeeBps The new fee in basis points. function changeFee(uint256 poolId, uint256 newFeeBps) external; /// @notice Allows the admin to change the fee sharing upon withdrawal. /// @param recipients The list of fee recipients. /// @param splits List of each recipient share in basis points. function changeSplit(address[] calldata recipients, uint256[] calldata splits) external; /// @notice Allows the integrator to add a vPool. /// @dev Reverts if the pool is already in the pools list. /// @param newPool The address of the new vPool. /// @param fee The fee to be applied to rewards from this vPool, in basis points. function addPool(address newPool, uint256 fee) external; /// @notice Returns true if the pool is active, false otherwise /// @param poolId The id of the vPool. function getPoolActivation(uint256 poolId) external view returns (bool); /// @notice Returns the ETH value of integrator shares left to sell. /// @param poolId The id of the vPool. /// @return The ETH value of unsold integrator shares. function integratorCommissionOwed(uint256 poolId) external view returns (uint256); /// @notice Allows the integrator to exit the integrator shares of a vPool. /// @param poolId The id of the vPool. function exitCommissionShares(uint256 poolId) external; /// @notice Allows the integrator to pause and unpause deposits only. /// @param isPaused Whether the deposits are paused or not. function pauseDeposits(bool isPaused) external; /// @notice Returns true if deposits are paused, false otherwise function depositsPaused() external view returns (bool); }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/libs/LibErrors.sol"; import "utils.sol/libs/LibUint256.sol"; import "utils.sol/libs/LibConstant.sol"; import "utils.sol/types/array.sol"; import "utils.sol/types/uint256.sol"; import "./interfaces/IFeeDispatcher.sol"; /// @title FeeDispatcher (V1) Contract /// @author 0xvv @ Kiln /// @notice This contract contains functions to dispatch the ETH in a contract upon withdrawal. // slither-disable-next-line naming-convention abstract contract FeeDispatcher is IFeeDispatcher { using LArray for types.Array; using LUint256 for types.Uint256; /// @dev The recipients of the fees upon withdrawal. /// @dev Slot: keccak256(bytes("feeDispatcher.1.feeRecipients")) - 1 types.Array internal constant $feeRecipients = types.Array.wrap(0xd681f9d3e640a2dd835404271506ef93f020e2fc065878793505e5ea088fde3d); /// @dev The splits of each recipient of the fees upon withdrawal. /// @dev Slot: keccak256(bytes("feeDispatcher.1.feeSplits")) - 1 types.Array internal constant $feeSplits = types.Array.wrap(0x31a3fa329157566a07927d0c2ba92ff801e4db8af2ec73f92eaf3e7f78d587a8); /// @dev The lock to prevent reentrancy /// @dev Slot: keccak256(bytes("feeDispatcher.1.locked")) - 1 types.Uint256 internal constant $locked = types.Uint256.wrap(0x8472de2bbf04bc62a7ee894bd625126d381bf5e8b726e5cd498c3a9dad76d85b); /// @dev The states of the lock, 1 = unlocked, 2 = locked uint256 internal constant UNLOCKED = 1; uint256 internal constant LOCKED = 2; constructor() { $locked.set(LOCKED); } /// @dev An internal function to set the fee split & unlock the reentrancy lock. /// Should be called in the initializer of the inheriting contract. // slither-disable-next-line dead-code function _initFeeDispatcher(address[] calldata recipients, uint256[] calldata splits) internal { _setFeeSplit(recipients, splits); $locked.set(UNLOCKED); } /// @notice Modifier to prevent reentrancy modifier nonReentrant() virtual { if ($locked.get() == LOCKED) { revert Reentrancy(); } $locked.set(LOCKED); _; $locked.set(UNLOCKED); } /// @inheritdoc IFeeDispatcher // slither-disable-next-line low-level-calls,calls-loop,reentrancy-events,assembly function withdrawCommission() external nonReentrant { uint256 balance = address(this).balance; address[] memory recipients = $feeRecipients.toAddressA(); uint256[] memory splits = $feeSplits.toUintA(); for (uint256 i = 0; i < recipients.length;) { uint256 share = LibUint256.mulDiv(balance, splits[i], LibConstant.BASIS_POINTS_MAX); address recipient = recipients[i]; emit CommissionWithdrawn(recipient, share); (bool success, bytes memory rdata) = recipient.call{value: share}(""); if (!success) { assembly { revert(add(32, rdata), mload(rdata)) } } unchecked { i++; } } } /// @notice Returns the current fee split and recipients /// @return feeRecipients The current fee recipients /// @return feeSplits The current fee splits /// @dev This function is not pure as it fetches the current fee split and recipients from storage function getCurrentSplit() external pure returns (address[] memory, uint256[] memory) { return ($feeRecipients.toAddressA(), $feeSplits.toUintA()); } /// @dev Internal utility to set the fee distribution upon withdrawal /// @param recipients The new fee recipients list /// @param splits The new split between fee recipients // slither-disable-next-line dead-code function _setFeeSplit(address[] calldata recipients, uint256[] calldata splits) internal { if (recipients.length != splits.length) { revert UnequalLengths(recipients.length, splits.length); } $feeSplits.del(); $feeRecipients.del(); uint256 sum; for (uint256 i = 0; i < recipients.length; i++) { uint256 split = splits[i]; sum += split; $feeSplits.toUintA().push(split); $feeRecipients.toAddressA().push(recipients[i]); } if (sum != LibConstant.BASIS_POINTS_MAX) { revert LibErrors.InvalidBPSValue(); } emit NewCommissionSplit(recipients, splits); } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/libs/LibErrors.sol"; import "utils.sol/libs/LibUint256.sol"; import "utils.sol/libs/LibConstant.sol"; import "./interfaces/IExitQueueClaimHelper.sol"; import "./interfaces/IFeeDispatcher.sol"; /// @title ExitQueueClaimeHelper (V1) Contract /// @author gauthiermyr @ Kiln /// @notice This contract contains functions to resolve and claim casks on several exit queues. contract ExitQueueClaimHelper is IExitQueueClaimHelper { /// @inheritdoc IExitQueueClaimHelper function multiResolve(address[] calldata exitQueues, uint256[][] calldata ticketIds) external view override returns (int64[][] memory caskIdsOrErrors) { if (exitQueues.length != ticketIds.length) { revert IFeeDispatcher.UnequalLengths(exitQueues.length, ticketIds.length); } caskIdsOrErrors = new int64[][](exitQueues.length); for (uint256 i = 0; i < exitQueues.length;) { IvExitQueue exitQueue = IvExitQueue(exitQueues[i]); // slither-disable-next-line calls-loop caskIdsOrErrors[i] = exitQueue.resolve(ticketIds[i]); unchecked { ++i; } } } /// @inheritdoc IExitQueueClaimHelper function multiClaim(address[] calldata exitQueues, uint256[][] calldata ticketIds, uint32[][] calldata casksIds) external override returns (IvExitQueue.ClaimStatus[][] memory statuses) { if (exitQueues.length != ticketIds.length) { revert IFeeDispatcher.UnequalLengths(exitQueues.length, ticketIds.length); } if (exitQueues.length != casksIds.length) { revert IFeeDispatcher.UnequalLengths(exitQueues.length, casksIds.length); } statuses = new IvExitQueue.ClaimStatus[][](exitQueues.length); for (uint256 i = 0; i < exitQueues.length;) { IvExitQueue exitQueue = IvExitQueue(exitQueues[i]); // slither-disable-next-line calls-loop statuses[i] = exitQueue.claim(ticketIds[i], casksIds[i], type(uint16).max); unchecked { ++i; } } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./LibErrors.sol"; import "./LibConstant.sol"; /// @title Lib Sanitize /// @dev This library helps sanitizing inputs. library LibSanitize { /// @dev Internal utility to sanitize an address and ensure its value is not 0. /// @param addressValue The address to verify // slither-disable-next-line dead-code function notZeroAddress(address addressValue) internal pure { if (addressValue == address(0)) { revert LibErrors.InvalidZeroAddress(); } } /// @dev Internal utility to sanitize an uint256 value and ensure its value is not 0. /// @param value The value to verify // slither-disable-next-line dead-code function notNullValue(uint256 value) internal pure { if (value == 0) { revert LibErrors.InvalidNullValue(); } } /// @dev Internal utility to sanitize a bps value and ensure it's <= 100%. /// @param value The bps value to verify // slither-disable-next-line dead-code function notInvalidBps(uint256 value) internal pure { if (value > LibConstant.BASIS_POINTS_MAX) { revert LibErrors.InvalidBPSValue(); } } /// @dev Internal utility to sanitize a string value and ensure it's not empty. /// @param stringValue The string value to verify // slither-disable-next-line dead-code function notEmptyString(string memory stringValue) internal pure { if (bytes(stringValue).length == 0) { revert LibErrors.InvalidEmptyString(); } } }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; /// @title Administrable Interface /// @author mortimr @ Kiln /// @dev Unstructured Storage Friendly /// @notice This contract provides all the utilities to handle the administration and its transfer. interface IAdministrable { /// @notice The admin address has been changed. /// @param admin The new admin address event SetAdmin(address admin); /// @notice The pending admin address has been changed. /// @param pendingAdmin The pending admin has been changed event SetPendingAdmin(address pendingAdmin); /// @notice Retrieve the admin address. /// @return adminAddress The admin address function admin() external view returns (address adminAddress); /// @notice Retrieve the pending admin address. /// @return pendingAdminAddress The pending admin address function pendingAdmin() external view returns (address pendingAdminAddress); /// @notice Propose a new admin. /// @dev Only callable by the admin /// @param _newAdmin The new admin to propose function transferAdmin(address _newAdmin) external; /// @notice Accept an admin transfer. /// @dev Only callable by the pending admin function acceptAdmin() external; }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; /// @title Fixable Interface /// @author mortimr @ Kiln /// @dev Unstructured Storage Friendly /// @notice The Fixable contract can be used on cubs to expose a safe noop to force a fix. interface IFixable { /// @notice Noop method to force a global fix to be applied. function fix() external; }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/interfaces/IFixable.sol"; /// @title FeeDispatcher (V1) Interface /// @author 0xvv @ Kiln /// @notice This contract contains functions to dispatch the ETH in a contract upon withdrawal. interface IFeeDispatcher { /// @notice Emitted when the commission split is changed. /// @param recipients The addresses of recipients /// @param splits The percentage of each recipient in basis points event NewCommissionSplit(address[] recipients, uint256[] splits); /// @notice Emitted when the integrator withdraws ETH /// @param withdrawer address withdrawing the ETH /// @param amountWithdrawn amount of ETH withdrawn event CommissionWithdrawn(address indexed withdrawer, uint256 amountWithdrawn); /// @notice Thrown when functions are given lists of different length in batch arguments /// @param lengthA First argument length /// @param lengthB Second argument length error UnequalLengths(uint256 lengthA, uint256 lengthB); /// @notice Thrown when a function is called while the contract is locked error Reentrancy(); /// @notice Allows the integrator to withdraw the ETH in the contract. function withdrawCommission() external; }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; /// @title Pool Shares Receiver Interface /// @author mortimr @ Kiln /// @notice Interface that needs to be implemented for a contract to be able to receive shares interface IvPoolSharesReceiver { /// @notice Callback used by the vPool to notify contracts of shares being transfered /// @param operator The address of the operator of the transfer /// @param from The address sending the funds /// @param amount The amount of shares received /// @param data The attached data /// @return selector Should return its own selector if everything went well function onvPoolSharesReceived(address operator, address from, uint256 amount, bytes memory data) external returns (bytes4 selector); }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; library LibErrors { error Unauthorized(address account, address expected); error InvalidZeroAddress(); error InvalidNullValue(); error InvalidBPSValue(); error InvalidEmptyString(); }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "prb-math/PRBMath.sol"; library LibUint256 { // slither-disable-next-line dead-code function min(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly // slither-disable-next-line assembly assembly { z := xor(x, mul(xor(x, y), lt(y, x))) } } /// @custom:author Vectorized/solady#58681e79de23082fd3881a76022e0842f5c08db8 // slither-disable-next-line dead-code function max(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly // slither-disable-next-line assembly assembly { z := xor(x, mul(xor(x, y), gt(y, x))) } } // slither-disable-next-line dead-code function mulDiv(uint256 a, uint256 b, uint256 c) internal pure returns (uint256) { return PRBMath.mulDiv(a, b, c); } // slither-disable-next-line dead-code function ceil(uint256 num, uint256 den) internal pure returns (uint256) { return (num / den) + (num % den > 0 ? 1 : 0); } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; library LibConstant { /// @dev The basis points value representing 100%. uint256 internal constant BASIS_POINTS_MAX = 10_000; /// @dev The size of a deposit to activate a validator. uint256 internal constant DEPOSIT_SIZE = 32 ether; /// @dev The minimum freeze timeout before freeze is active. uint256 internal constant MINIMUM_FREEZE_TIMEOUT = 100 days; /// @dev Address used to represent ETH when an address is required to identify an asset. address internal constant ETHER = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types.sol"; library LArray { // slither-disable-next-line dead-code function toUintA(types.Array position) internal pure returns (uint256[] storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } // slither-disable-next-line dead-code function toAddressA(types.Array position) internal pure returns (address[] storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } // slither-disable-next-line dead-code function toBoolA(types.Array position) internal pure returns (bool[] storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } // slither-disable-next-line dead-code function toBytes32A(types.Array position) internal pure returns (bytes32[] storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } // slither-disable-next-line dead-code function del(types.Array position) internal { // slither-disable-next-line assembly assembly { let len := sload(position) if len { // clear the length slot sstore(position, 0) // calculate the starting slot of the array elements in storage mstore(0, position) let startPtr := keccak256(0, 0x20) for {} len {} { len := sub(len, 1) sstore(add(startPtr, len), 0) } } } } /// @dev This delete can be used if and only if we only want to clear the length of the array. /// Doing so will create an array that behaves like an empty array in solidity. /// It can have advantages if we often rewrite to the same slots of the array. /// Prefer using `del` if you don't know what you're doing. // slither-disable-next-line dead-code function dangerousDirtyDel(types.Array position) internal { // slither-disable-next-line assembly assembly { sstore(position, 0) } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "vsuite/interfaces/IvExitQueue.sol"; /// @title ExitQueueClaimeHelper (V1) Interface /// @author gauthiermyr @ Kiln interface IExitQueueClaimHelper { /// @notice Resolve a list of casksIds for given exitQueues and tickets /// @param exitQueues List of exit queues /// @param ticketIds List of tickets in each exit queue function multiResolve(address[] calldata exitQueues, uint256[][] calldata ticketIds) external view returns (int64[][] memory caskIdsOrErrors); /// @notice Claim caskIds for given tickets on each exit queue /// @param exitQueues List of exit queues /// @param ticketIds List of tickets in each exit queue /// @param casksIds List of caskIds to claim with each ticket function multiClaim(address[] calldata exitQueues, uint256[][] calldata ticketIds, uint32[][] calldata casksIds) external returns (IvExitQueue.ClaimStatus[][] memory statuse); }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.4; /// @notice Emitted when the result overflows uint256. error PRBMath__MulDivFixedPointOverflow(uint256 prod1); /// @notice Emitted when the result overflows uint256. error PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator); /// @notice Emitted when one of the inputs is type(int256).min. error PRBMath__MulDivSignedInputTooSmall(); /// @notice Emitted when the intermediary absolute result overflows int256. error PRBMath__MulDivSignedOverflow(uint256 rAbs); /// @notice Emitted when the input is MIN_SD59x18. error PRBMathSD59x18__AbsInputTooSmall(); /// @notice Emitted when ceiling a number overflows SD59x18. error PRBMathSD59x18__CeilOverflow(int256 x); /// @notice Emitted when one of the inputs is MIN_SD59x18. error PRBMathSD59x18__DivInputTooSmall(); /// @notice Emitted when one of the intermediary unsigned results overflows SD59x18. error PRBMathSD59x18__DivOverflow(uint256 rAbs); /// @notice Emitted when the input is greater than 133.084258667509499441. error PRBMathSD59x18__ExpInputTooBig(int256 x); /// @notice Emitted when the input is greater than 192. error PRBMathSD59x18__Exp2InputTooBig(int256 x); /// @notice Emitted when flooring a number underflows SD59x18. error PRBMathSD59x18__FloorUnderflow(int256 x); /// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18. error PRBMathSD59x18__FromIntOverflow(int256 x); /// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18. error PRBMathSD59x18__FromIntUnderflow(int256 x); /// @notice Emitted when the product of the inputs is negative. error PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y); /// @notice Emitted when multiplying the inputs overflows SD59x18. error PRBMathSD59x18__GmOverflow(int256 x, int256 y); /// @notice Emitted when the input is less than or equal to zero. error PRBMathSD59x18__LogInputTooSmall(int256 x); /// @notice Emitted when one of the inputs is MIN_SD59x18. error PRBMathSD59x18__MulInputTooSmall(); /// @notice Emitted when the intermediary absolute result overflows SD59x18. error PRBMathSD59x18__MulOverflow(uint256 rAbs); /// @notice Emitted when the intermediary absolute result overflows SD59x18. error PRBMathSD59x18__PowuOverflow(uint256 rAbs); /// @notice Emitted when the input is negative. error PRBMathSD59x18__SqrtNegativeInput(int256 x); /// @notice Emitted when the calculating the square root overflows SD59x18. error PRBMathSD59x18__SqrtOverflow(int256 x); /// @notice Emitted when addition overflows UD60x18. error PRBMathUD60x18__AddOverflow(uint256 x, uint256 y); /// @notice Emitted when ceiling a number overflows UD60x18. error PRBMathUD60x18__CeilOverflow(uint256 x); /// @notice Emitted when the input is greater than 133.084258667509499441. error PRBMathUD60x18__ExpInputTooBig(uint256 x); /// @notice Emitted when the input is greater than 192. error PRBMathUD60x18__Exp2InputTooBig(uint256 x); /// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18. error PRBMathUD60x18__FromUintOverflow(uint256 x); /// @notice Emitted when multiplying the inputs overflows UD60x18. error PRBMathUD60x18__GmOverflow(uint256 x, uint256 y); /// @notice Emitted when the input is less than 1. error PRBMathUD60x18__LogInputTooSmall(uint256 x); /// @notice Emitted when the calculating the square root overflows UD60x18. error PRBMathUD60x18__SqrtOverflow(uint256 x); /// @notice Emitted when subtraction underflows UD60x18. error PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y); /// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library /// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point /// representation. When it does not, it is explicitly mentioned in the NatSpec documentation. library PRBMath { /// STRUCTS /// struct SD59x18 { int256 value; } struct UD60x18 { uint256 value; } /// STORAGE /// /// @dev How many trailing decimals can be represented. uint256 internal constant SCALE = 1e18; /// @dev Largest power of two divisor of SCALE. uint256 internal constant SCALE_LPOTD = 262144; /// @dev SCALE inverted mod 2^256. uint256 internal constant SCALE_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281; /// FUNCTIONS /// /// @notice Calculates the binary exponent of x using the binary fraction method. /// @dev Has to use 192.64-bit fixed-point numbers. /// See https://ethereum.stackexchange.com/a/96594/24693. /// @param x The exponent as an unsigned 192.64-bit fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function exp2(uint256 x) internal pure returns (uint256 result) { unchecked { // Start from 0.5 in the 192.64-bit fixed-point format. result = 0x800000000000000000000000000000000000000000000000; // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows // because the initial result is 2^191 and all magic factors are less than 2^65. if (x & 0x8000000000000000 > 0) { result = (result * 0x16A09E667F3BCC909) >> 64; } if (x & 0x4000000000000000 > 0) { result = (result * 0x1306FE0A31B7152DF) >> 64; } if (x & 0x2000000000000000 > 0) { result = (result * 0x1172B83C7D517ADCE) >> 64; } if (x & 0x1000000000000000 > 0) { result = (result * 0x10B5586CF9890F62A) >> 64; } if (x & 0x800000000000000 > 0) { result = (result * 0x1059B0D31585743AE) >> 64; } if (x & 0x400000000000000 > 0) { result = (result * 0x102C9A3E778060EE7) >> 64; } if (x & 0x200000000000000 > 0) { result = (result * 0x10163DA9FB33356D8) >> 64; } if (x & 0x100000000000000 > 0) { result = (result * 0x100B1AFA5ABCBED61) >> 64; } if (x & 0x80000000000000 > 0) { result = (result * 0x10058C86DA1C09EA2) >> 64; } if (x & 0x40000000000000 > 0) { result = (result * 0x1002C605E2E8CEC50) >> 64; } if (x & 0x20000000000000 > 0) { result = (result * 0x100162F3904051FA1) >> 64; } if (x & 0x10000000000000 > 0) { result = (result * 0x1000B175EFFDC76BA) >> 64; } if (x & 0x8000000000000 > 0) { result = (result * 0x100058BA01FB9F96D) >> 64; } if (x & 0x4000000000000 > 0) { result = (result * 0x10002C5CC37DA9492) >> 64; } if (x & 0x2000000000000 > 0) { result = (result * 0x1000162E525EE0547) >> 64; } if (x & 0x1000000000000 > 0) { result = (result * 0x10000B17255775C04) >> 64; } if (x & 0x800000000000 > 0) { result = (result * 0x1000058B91B5BC9AE) >> 64; } if (x & 0x400000000000 > 0) { result = (result * 0x100002C5C89D5EC6D) >> 64; } if (x & 0x200000000000 > 0) { result = (result * 0x10000162E43F4F831) >> 64; } if (x & 0x100000000000 > 0) { result = (result * 0x100000B1721BCFC9A) >> 64; } if (x & 0x80000000000 > 0) { result = (result * 0x10000058B90CF1E6E) >> 64; } if (x & 0x40000000000 > 0) { result = (result * 0x1000002C5C863B73F) >> 64; } if (x & 0x20000000000 > 0) { result = (result * 0x100000162E430E5A2) >> 64; } if (x & 0x10000000000 > 0) { result = (result * 0x1000000B172183551) >> 64; } if (x & 0x8000000000 > 0) { result = (result * 0x100000058B90C0B49) >> 64; } if (x & 0x4000000000 > 0) { result = (result * 0x10000002C5C8601CC) >> 64; } if (x & 0x2000000000 > 0) { result = (result * 0x1000000162E42FFF0) >> 64; } if (x & 0x1000000000 > 0) { result = (result * 0x10000000B17217FBB) >> 64; } if (x & 0x800000000 > 0) { result = (result * 0x1000000058B90BFCE) >> 64; } if (x & 0x400000000 > 0) { result = (result * 0x100000002C5C85FE3) >> 64; } if (x & 0x200000000 > 0) { result = (result * 0x10000000162E42FF1) >> 64; } if (x & 0x100000000 > 0) { result = (result * 0x100000000B17217F8) >> 64; } if (x & 0x80000000 > 0) { result = (result * 0x10000000058B90BFC) >> 64; } if (x & 0x40000000 > 0) { result = (result * 0x1000000002C5C85FE) >> 64; } if (x & 0x20000000 > 0) { result = (result * 0x100000000162E42FF) >> 64; } if (x & 0x10000000 > 0) { result = (result * 0x1000000000B17217F) >> 64; } if (x & 0x8000000 > 0) { result = (result * 0x100000000058B90C0) >> 64; } if (x & 0x4000000 > 0) { result = (result * 0x10000000002C5C860) >> 64; } if (x & 0x2000000 > 0) { result = (result * 0x1000000000162E430) >> 64; } if (x & 0x1000000 > 0) { result = (result * 0x10000000000B17218) >> 64; } if (x & 0x800000 > 0) { result = (result * 0x1000000000058B90C) >> 64; } if (x & 0x400000 > 0) { result = (result * 0x100000000002C5C86) >> 64; } if (x & 0x200000 > 0) { result = (result * 0x10000000000162E43) >> 64; } if (x & 0x100000 > 0) { result = (result * 0x100000000000B1721) >> 64; } if (x & 0x80000 > 0) { result = (result * 0x10000000000058B91) >> 64; } if (x & 0x40000 > 0) { result = (result * 0x1000000000002C5C8) >> 64; } if (x & 0x20000 > 0) { result = (result * 0x100000000000162E4) >> 64; } if (x & 0x10000 > 0) { result = (result * 0x1000000000000B172) >> 64; } if (x & 0x8000 > 0) { result = (result * 0x100000000000058B9) >> 64; } if (x & 0x4000 > 0) { result = (result * 0x10000000000002C5D) >> 64; } if (x & 0x2000 > 0) { result = (result * 0x1000000000000162E) >> 64; } if (x & 0x1000 > 0) { result = (result * 0x10000000000000B17) >> 64; } if (x & 0x800 > 0) { result = (result * 0x1000000000000058C) >> 64; } if (x & 0x400 > 0) { result = (result * 0x100000000000002C6) >> 64; } if (x & 0x200 > 0) { result = (result * 0x10000000000000163) >> 64; } if (x & 0x100 > 0) { result = (result * 0x100000000000000B1) >> 64; } if (x & 0x80 > 0) { result = (result * 0x10000000000000059) >> 64; } if (x & 0x40 > 0) { result = (result * 0x1000000000000002C) >> 64; } if (x & 0x20 > 0) { result = (result * 0x10000000000000016) >> 64; } if (x & 0x10 > 0) { result = (result * 0x1000000000000000B) >> 64; } if (x & 0x8 > 0) { result = (result * 0x10000000000000006) >> 64; } if (x & 0x4 > 0) { result = (result * 0x10000000000000003) >> 64; } if (x & 0x2 > 0) { result = (result * 0x10000000000000001) >> 64; } if (x & 0x1 > 0) { result = (result * 0x10000000000000001) >> 64; } // We're doing two things at the same time: // // 1. Multiply the result by 2^n + 1, where "2^n" is the integer part and the one is added to account for // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191 // rather than 192. // 2. Convert the result to the unsigned 60.18-decimal fixed-point format. // // This works because 2^(191-ip) = 2^ip / 2^191, where "ip" is the integer part "2^n". result *= SCALE; result >>= (191 - (x >> 64)); } } /// @notice Finds the zero-based index of the first one in the binary representation of x. /// @dev See the note on msb in the "Find First Set" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set /// @param x The uint256 number for which to find the index of the most significant bit. /// @return msb The index of the most significant bit as an uint256. function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) { if (x >= 2**128) { x >>= 128; msb += 128; } if (x >= 2**64) { x >>= 64; msb += 64; } if (x >= 2**32) { x >>= 32; msb += 32; } if (x >= 2**16) { x >>= 16; msb += 16; } if (x >= 2**8) { x >>= 8; msb += 8; } if (x >= 2**4) { x >>= 4; msb += 4; } if (x >= 2**2) { x >>= 2; msb += 2; } if (x >= 2**1) { // No need to shift x any more. msb += 1; } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv. /// /// Requirements: /// - The denominator cannot be zero. /// - The result must fit within uint256. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The multiplicand as an uint256. /// @param y The multiplier as an uint256. /// @param denominator The divisor as an uint256. /// @return result The result as an uint256. function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { // 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) { unchecked { result = prod0 / denominator; } return result; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (prod1 >= denominator) { revert PRBMath__MulDivOverflow(prod1, denominator); } /////////////////////////////////////////////// // 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. unchecked { // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 lpotdod = denominator & (~denominator + 1); assembly { // Divide denominator by lpotdod. denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. prod0 := div(prod0, lpotdod) // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one. lpotdod := add(div(sub(0, lpotdod), lpotdod), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * lpotdod; // 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; } } /// @notice Calculates floor(x*y÷1e18) with full precision. /// /// @dev Variant of "mulDiv" with constant folding, i.e. in which the denominator is always 1e18. Before returning the /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of /// being rounded to 1e-18. See "Listing 6" and text above it at https://accu.org/index.php/journals/1717. /// /// Requirements: /// - The result must fit within uint256. /// /// Caveats: /// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works. /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations: /// 1. x * y = type(uint256).max * SCALE /// 2. (x * y) % SCALE >= SCALE / 2 /// /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number. /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) { uint256 prod0; uint256 prod1; assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } if (prod1 >= SCALE) { revert PRBMath__MulDivFixedPointOverflow(prod1); } uint256 remainder; uint256 roundUpUnit; assembly { remainder := mulmod(x, y, SCALE) roundUpUnit := gt(remainder, 499999999999999999) } if (prod1 == 0) { unchecked { result = (prod0 / SCALE) + roundUpUnit; return result; } } assembly { result := add( mul( or( div(sub(prod0, remainder), SCALE_LPOTD), mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1)) ), SCALE_INVERSE ), roundUpUnit ) } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev An extension of "mulDiv" for signed numbers. Works by computing the signs and the absolute values separately. /// /// Requirements: /// - None of the inputs can be type(int256).min. /// - The result must fit within int256. /// /// @param x The multiplicand as an int256. /// @param y The multiplier as an int256. /// @param denominator The divisor as an int256. /// @return result The result as an int256. function mulDivSigned( int256 x, int256 y, int256 denominator ) internal pure returns (int256 result) { if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) { revert PRBMath__MulDivSignedInputTooSmall(); } // Get hold of the absolute values of x, y and the denominator. uint256 ax; uint256 ay; uint256 ad; unchecked { ax = x < 0 ? uint256(-x) : uint256(x); ay = y < 0 ? uint256(-y) : uint256(y); ad = denominator < 0 ? uint256(-denominator) : uint256(denominator); } // Compute the absolute value of (x*y)÷denominator. The result must fit within int256. uint256 rAbs = mulDiv(ax, ay, ad); if (rAbs > uint256(type(int256).max)) { revert PRBMath__MulDivSignedOverflow(rAbs); } // Get the signs of x, y and the denominator. uint256 sx; uint256 sy; uint256 sd; assembly { sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) sd := sgt(denominator, sub(0, 1)) } // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs. // If yes, the result should be negative. result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs); } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The uint256 number for which to calculate the square root. /// @return result The result as an uint256. function sqrt(uint256 x) internal pure returns (uint256 result) { if (x == 0) { return 0; } // Set the initial guess to the least power of two that is greater than or equal to sqrt(x). uint256 xAux = uint256(x); result = 1; if (xAux >= 0x100000000000000000000000000000000) { xAux >>= 128; result <<= 64; } if (xAux >= 0x10000000000000000) { xAux >>= 64; result <<= 32; } if (xAux >= 0x100000000) { xAux >>= 32; result <<= 16; } if (xAux >= 0x10000) { xAux >>= 16; result <<= 8; } if (xAux >= 0x100) { xAux >>= 8; result <<= 4; } if (xAux >= 0x10) { xAux >>= 4; result <<= 2; } if (xAux >= 0x8) { result <<= 1; } // The operations can never overflow because the result is max 2^127 when it enters this block. unchecked { result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; // Seven iterations should be enough uint256 roundedDownResult = x / result; return result >= roundedDownResult ? roundedDownResult : result; } } }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/interfaces/IFixable.sol"; import "./IvPoolSharesReceiver.sol"; import "../ctypes/ctypes.sol"; /// @title Exit Queue Interface /// @author mortimr @ Kiln /// @notice The exit queue stores exit requests until they are filled and claimable interface IvExitQueue is IFixable, IvPoolSharesReceiver { /// @notice Emitted when the stored Pool address is changed /// @param pool The new pool address event SetPool(address pool); /// @notice Emitted when the stored token uri image url is changed /// @param tokenUriImageUrl The new token uri image url event SetTokenUriImageUrl(string tokenUriImageUrl); /// @notice Emitted when the transfer enabled status is changed /// @param enabled The new transfer enabled status event SetTransferEnabled(bool enabled); /// @notice Emitted when the unclaimed funds buffer is changed /// @param unclaimedFunds The new unclaimed funds buffer event SetUnclaimedFunds(uint256 unclaimedFunds); /// @notice Emitted when ether was supplied to the vPool /// @param amount The amount of ETH supplied event SuppliedEther(uint256 amount); /// @notice Emitted when a ticket is created /// @param owner The address of the ticket owner /// @param idx The index of the ticket /// @param id The ID of the ticket /// @param ticket The ticket details event PrintedTicket(address indexed owner, uint32 idx, uint256 id, ctypes.Ticket ticket); /// @notice Emitted when a cask is created /// @param id The ID of the cask /// @param cask The cask details event ReceivedCask(uint32 id, ctypes.Cask cask); /// @notice Emitted when a ticket is claimed against a cask, can happen several times for the same ticket but different casks /// @param ticketId The ID of the ticket /// @param caskId The ID of the cask /// @param amountFilled The amount of shares filled /// @param amountEthFilled The amount of ETH filled /// @param unclaimedEth The amount of ETH that is added to the unclaimed buffer event FilledTicket( uint256 indexed ticketId, uint32 indexed caskId, uint128 amountFilled, uint256 amountEthFilled, uint256 unclaimedEth ); /// @notice Emitted when a ticket is "reminted" and its external id is modified /// @param oldTicketId The old ID of the ticket /// @param newTicketId The new ID of the ticket /// @param ticketIndex The index of the ticket event TicketIdUpdated(uint256 indexed oldTicketId, uint256 indexed newTicketId, uint32 indexed ticketIndex); /// @notice Emitted when a payment is made after a user performed a claim /// @param recipient The address of the recipient /// @param amount The amount of ETH paid event Payment(address indexed recipient, uint256 amount); /// @notice Transfer of tickets is disabled error TransferDisabled(); /// @notice The provided ticket ID is invalid /// @param id The ID of the ticket error InvalidTicketId(uint256 id); /// @notice The provided cask ID is invalid /// @param id The ID of the cask error InvalidCaskId(uint32 id); /// @notice The provided ticket IDs and cask IDs are not the same length error InvalidLengths(); /// @notice The ticket and cask are not associated /// @param ticketId The ID of the ticket /// @param caskId The ID of the cask error TicketNotMatchingCask(uint256 ticketId, uint32 caskId); /// @notice The claim transfer failed /// @param recipient The address of the recipient /// @param rdata The revert data error ClaimTransferFailed(address recipient, bytes rdata); enum ClaimStatus { CLAIMED, PARTIALLY_CLAIMED, SKIPPED } /// @notice Initializes the ExitQueue (proxy pattern) /// @param vpool The address of the associated vPool /// @param newTokenUriImageUrl The token uri image url function initialize(address vpool, string calldata newTokenUriImageUrl) external; /// @notice Returns the token uri image url /// @return The token uri image url function tokenUriImageUrl() external view returns (string memory); /// @notice Returns the transfer enabled status /// @return True if transfers are enabled function transferEnabled() external view returns (bool); /// @notice Returns the unclaimed funds buffer /// @return The unclaimed funds buffer function unclaimedFunds() external view returns (uint256); /// @notice Returns the id of the ticket based on the index /// @param idx The index of the ticket function ticketIdAtIndex(uint32 idx) external view returns (uint256); /// @notice Returns the details about the ticket with the provided ID /// @param id The ID of the ticket /// @return The ticket details function ticket(uint256 id) external view returns (ctypes.Ticket memory); /// @notice Returns the number of tickets /// @return The number of tickets function ticketCount() external view returns (uint256); /// @notice Returns the details about the cask with the provided ID /// @param id The ID of the cask /// @return The cask details function cask(uint32 id) external view returns (ctypes.Cask memory); /// @notice Returns the number of casks /// @return The number of casks function caskCount() external view returns (uint256); /// @notice Resolves the provided tickets to their associated casks or provide resolution error codes /// @dev TICKET_ID_OUT_OF_BOUNDS = -1; /// TICKET_ALREADY_CLAIMED = -2; /// TICKET_PENDING = -3; /// @param ticketIds The IDs of the tickets to resolve /// @return caskIdsOrErrors The IDs of the casks or error codes function resolve(uint256[] memory ticketIds) external view returns (int64[] memory caskIdsOrErrors); /// @notice Adds eth and creates a new cask /// @dev only callbacle by the vPool /// @param shares The amount of shares to cover with the provided eth function feed(uint256 shares) external payable; /// @notice Pulls eth from the unclaimed eth buffer /// @dev Only callable by the vPool /// @param max The maximum amount of eth to pull function pull(uint256 max) external; /// @notice Claims the provided tickets against their associated casks /// @dev To retrieve the list of casks, an off-chain resolve call should be performed /// @param ticketIds The IDs of the tickets to claim /// @param caskIds The IDs of the casks to claim against /// @param maxClaimDepth The maxiumum recursion depth for the claim, 0 for unlimited function claim(uint256[] calldata ticketIds, uint32[] calldata caskIds, uint16 maxClaimDepth) external returns (ClaimStatus[] memory statuses); /// @notice Sets the token uri image inside the returned token uri /// @param newTokenUriImageUrl The new token uri image url function setTokenUriImageUrl(string calldata newTokenUriImageUrl) external; /// @notice Enables or disables transfers of the tickets /// @param value True to allow transfers function setTransferEnabled(bool value) external; }
{ "remappings": [ "deploy.sol/=lib/deploy.sol/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-gas-snapshot/=lib/forge-gas-snapshot/src/", "forge-std/=lib/forge-std/src/", "murky/=lib/murky/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/", "solmate/=lib/deploy.sol/lib/solmate/src/", "vsuite/=lib/vsuite/src/", "vsuite.test/=lib/vsuite/test/", "prb-math/=lib/vsuite/lib/utils.sol/lib/prb-math/contracts/", "utils.sol.test/=lib/vsuite/lib/utils.sol/test/", "utils.sol/=lib/vsuite/lib/utils.sol/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256","name":"currentVersion","type":"uint256"}],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"CallbackNotFromMinting","type":"error"},{"inputs":[],"name":"CommissionPaidUnderflow","type":"error"},{"inputs":[],"name":"DepositsPaused","type":"error"},{"inputs":[],"name":"EmptyPoolList","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxFeeBps","type":"uint256"}],"name":"FeeOverMax","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"allowance","type":"uint256"}],"name":"InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"balance","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"sum","type":"uint256"},{"internalType":"uint256","name":"msgValue","type":"uint256"}],"name":"InvalidAmounts","type":"error"},{"inputs":[],"name":"InvalidBPSValue","type":"error"},{"inputs":[],"name":"InvalidNullValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"poolId","type":"uint256"}],"name":"InvalidPoolId","type":"error"},{"inputs":[],"name":"InvalidZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"poolId","type":"uint256"}],"name":"NoSharesToExit","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"NonZeroPercentageOnDeactivatedPool","type":"error"},{"inputs":[{"internalType":"address","name":"poolAddress","type":"address"}],"name":"NotARegisteredPool","type":"error"},{"inputs":[{"internalType":"uint256","name":"ethLeft","type":"uint256"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"OutstandingCommission","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"PRBMath__MulDivOverflow","type":"error"},{"inputs":[{"internalType":"address","name":"newPool","type":"address"}],"name":"PoolAlreadyRegistered","type":"error"},{"inputs":[{"internalType":"uint256","name":"poolId","type":"uint256"}],"name":"PoolDisabled","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"PoolTransferFailed","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"Unauthorized","type":"error"},{"inputs":[{"internalType":"uint256","name":"lengthA","type":"uint256"},{"internalType":"uint256","name":"lengthB","type":"uint256"}],"name":"UnequalLengths","type":"error"},{"inputs":[],"name":"ZeroSharesMint","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pSharesSold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountSold","type":"uint256"}],"name":"CommissionSharesSold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"withdrawer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountWithdrawn","type":"uint256"}],"name":"CommissionWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint128","name":"exitedTokens","type":"uint128"},{"components":[{"internalType":"uint128","name":"poolId","type":"uint128"},{"internalType":"uint128","name":"exitedPoolShares","type":"uint128"}],"indexed":false,"internalType":"struct PoolExitDetails[]","name":"exitDetails","type":"tuple[]"}],"name":"Exit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"weights","type":"uint256[]"},{"indexed":false,"internalType":"address[]","name":"recipients","type":"address[]"}],"name":"ExitedCommissionShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"cdata","type":"bytes"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"recipients","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"splits","type":"uint256[]"}],"name":"NewCommissionSplit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"poolAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isActive","type":"bool"}],"name":"PoolActivation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"poolAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"PoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"SetAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"SetDepositsPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"operatorFeeBps","type":"uint256"}],"name":"SetFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxCommission","type":"uint256"}],"name":"SetMaxCommission","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"SetName","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pendingAdmin","type":"address"}],"name":"SetPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"split","type":"uint256[]"}],"name":"SetPoolPercentages","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"symbol","type":"string"}],"name":"SetSymbol","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint128","name":"depositedEth","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"mintedTokens","type":"uint128"},{"components":[{"internalType":"uint128","name":"poolId","type":"uint128"},{"internalType":"uint128","name":"ethToPool","type":"uint128"},{"internalType":"uint128","name":"ethToIntegrator","type":"uint128"},{"internalType":"uint128","name":"pSharesFromPool","type":"uint128"},{"internalType":"uint128","name":"pSharesFromIntegrator","type":"uint128"}],"indexed":false,"internalType":"struct PoolStakeDetails[]","name":"stakeDetails","type":"tuple[]"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"vPool","type":"address"},{"indexed":false,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"VPoolSharesReceived","type":"event"},{"inputs":[{"internalType":"uint256","name":"poolId","type":"uint256"}],"name":"_getPool","outputs":[{"internalType":"contract IvPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"feeBps","type":"uint256"}],"name":"addPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolId","type":"uint256"},{"internalType":"uint256","name":"newFeeBps","type":"uint256"}],"name":"changeFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"splits","type":"uint256[]"}],"name":"changeSplit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolId","type":"uint256"}],"name":"exitCommissionShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCurrentSplit","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolId","type":"uint256"}],"name":"getFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolId","type":"uint256"}],"name":"getPoolActivation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"address[]","name":"pools","type":"address[]"},{"internalType":"uint256[]","name":"poolFees","type":"uint256[]"},{"internalType":"address[]","name":"commissionRecipients","type":"address[]"},{"internalType":"uint256[]","name":"commissionDistribution","type":"uint256[]"},{"internalType":"uint256[]","name":"poolPercentages","type":"uint256[]"},{"internalType":"uint256","name":"maxCommissionBps","type":"uint256"},{"internalType":"uint256","name":"monoTicketThreshold","type":"uint256"}],"internalType":"struct Native20Configuration","name":"args","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolId","type":"uint256"}],"name":"integratorCommissionOwed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"exitQueues","type":"address[]"},{"internalType":"uint256[][]","name":"ticketIds","type":"uint256[][]"},{"internalType":"uint32[][]","name":"casksIds","type":"uint32[][]"}],"name":"multiClaim","outputs":[{"internalType":"enum IvExitQueue.ClaimStatus[][]","name":"statuses","type":"uint8[][]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"exitQueues","type":"address[]"},{"internalType":"uint256[][]","name":"ticketIds","type":"uint256[][]"}],"name":"multiResolve","outputs":[{"internalType":"int64[][]","name":"caskIdsOrErrors","type":"int64[][]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onvPoolSharesReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isPaused","type":"bool"}],"name":"pauseDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pools","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"requestExit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minTicketEthValue","type":"uint256"}],"name":"setMonoTicketThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"poolId","type":"uint256"},{"internalType":"bool","name":"status","type":"bool"},{"internalType":"uint256[]","name":"newPoolPercentages","type":"uint256[]"}],"name":"setPoolActivation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"split","type":"uint256[]"}],"name":"setPoolPercentages","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUnderlyingSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"transferAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawCommission","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200005060027f8472de2bbf04bc62a7ee894bd625126d381bf5e8b726e5cd498c3a9dad76d85b60001b6200009560201b620017c71790919060201c565b6200008f6000197fc4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a7660001b6200009560201b620017c71790919060201c565b62000099565b9055565b61475180620000a96000396000f3fe6080604052600436106101f95760003560e01c806360da3e831161010d578063a81d04e7116100a0578063e3ca2d651161006f578063e3ca2d65146105a2578063ef5ca789146105c2578063f851a440146105e5578063fcee45f4146105fa578063fdc3a3d51461063457600080fd5b8063a81d04e714610506578063b584686914610533578063b7ba18c714610553578063c5c51dca1461058057600080fd5b806375829def116100dc57806375829def14610478578063854e0c6f1461049857806395d89b41146104b85780639b21cf6c146104cd57600080fd5b806360da3e83146103f357806370a0823114610418578063721c651314610438578063738b62e51461045857600080fd5b80632c4e722e116101905780633af9e6691161015f5780633af9e6691461035e5780633e25e8371461037e5780634538e0091461039357806349d6ed56146103b35780634da05606146103d357600080fd5b80632c4e722e14610305578063313ce5671461031a57806332a9caba146103365780633a4b66f11461035657600080fd5b80631468f9ef116101cc5780631468f9ef1461028357806318160ddd146102a3578063235b64c2146102b857806326782247146102d857600080fd5b806306fdde03146101fe5780630e18b681146102295780630eb6f8d914610240578063143a08d414610260575b600080fd5b34801561020a57600080fd5b50610213610654565b604051610220919061389a565b60405180910390f35b34801561023557600080fd5b5061023e6106a3565b005b34801561024c57600080fd5b5061023e61025b366004613906565b610712565b34801561026c57600080fd5b50610275610772565b604051908152602001610220565b34801561028f57600080fd5b5061023e61029e366004613961565b610781565b3480156102af57600080fd5b506102756107b6565b3480156102c457600080fd5b5061023e6102d33660046139c0565b6107c0565b3480156102e457600080fd5b506102ed6107f5565b6040516001600160a01b039091168152602001610220565b34801561031157600080fd5b506102756107ff565b34801561032657600080fd5b5060405160128152602001610220565b34801561034257600080fd5b5061023e6103513660046139ee565b610842565b61023e610879565b34801561036a57600080fd5b50610275610379366004613a1a565b61088b565b34801561038a57600080fd5b5061023e61089c565b34801561039f57600080fd5b5061023e6103ae366004613a37565b610ae4565b3480156103bf57600080fd5b506102756103ce3660046139c0565b610ea5565b3480156103df57600080fd5b5061023e6103ee3660046139c0565b610eb0565b3480156103ff57600080fd5b50610408610ee2565b6040519015158152602001610220565b34801561042457600080fd5b50610275610433366004613a1a565b610f0c565b34801561044457600080fd5b5061023e6104533660046139c0565b610f37565b34801561046457600080fd5b5061023e610473366004613a72565b610f40565b34801561048457600080fd5b5061023e610493366004613a1a565b610fc7565b3480156104a457600080fd5b5061023e6104b3366004613a8f565b610ff9565b3480156104c457600080fd5b5061021361102c565b3480156104d957600080fd5b506104ed6104e8366004613b16565b611057565b6040516001600160e01b03199091168152602001610220565b34801561051257600080fd5b50610526610521366004613961565b611197565b6040516102209190613bd9565b34801561053f57600080fd5b5061040861054e3660046139c0565b61130b565b34801561055f57600080fd5b5061057361056e366004613c66565b611339565b6040516102209190613cff565b34801561058c57600080fd5b50610595611505565b6040516102209190613dea565b3480156105ae57600080fd5b5061023e6105bd366004613dfd565b6115d1565b3480156105ce57600080fd5b506105d7611699565b604051610220929190613e4f565b3480156105f157600080fd5b506102ed61176c565b34801561060657600080fd5b506102756106153660046139c0565b600090815260008051602061463c833981519152602052604090205490565b34801561064057600080fd5b506102ed61064f3660046139c0565b611776565b606061067f7feee152275d096301850a53ae85c6991c818bc6bac8a2174c268aa94ed7cf06f16117cb565b60405160200161068f9190613e7d565b604051602081830303815290604052905090565b6106ab611863565b6001600160a01b0316336001600160a01b0316146106fd57336106cc611863565b60405163295a81c160e01b81526001600160a01b039283166004820152911660248201526044015b60405180910390fd5b6107063361188d565b61071060006118fb565b565b61071a611960565b6001600160a01b0316336001600160a01b03161461073b57336106cc611960565b61074683151561198a565b600085815260008051602061461c833981519152602052604090205561076c8282611994565b50505050565b600061077c611b46565b905090565b610789611960565b6001600160a01b0316336001600160a01b0316146107aa57336106cc611960565b61076c84848484611b7d565b600061077c611d30565b6107c8611960565b6001600160a01b0316336001600160a01b0316146107e957336106cc611960565b6107f281611d48565b50565b600061077c611863565b60008061080a611d30565b90506000811161082257670de0b6b3a764000061083c565b61083c61082d611b46565b670de0b6b3a764000083611d71565b91505090565b61084a611960565b6001600160a01b0316336001600160a01b03161461086b57336106cc611960565b6108758282611d88565b5050565b61088234611f2a565b6107f234611f4b565b6000610896826125dc565b92915050565b60026108b46000805160206146fc8339815191525490565b036108d25760405163558a1e0360e11b815260040160405180910390fd5b60026000805160206146fc8339815191525547600060008051602061459c83398151915280548060200260200160405190810160405280929190818152602001828054801561094a57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161092c575b50505050509050600061096b60008051602061465c83398151915260001b90565b8054806020026020016040519081016040528092919081815260200182805480156109b557602002820191906000526020600020905b8154815260200190600101908083116109a1575b5050505050905060005b8251811015610ac85760006109f0858484815181106109e0576109e0613e99565b6020026020010151612710611d71565b90506000848381518110610a0657610a06613e99565b60200260200101519050806001600160a01b03167fd244b5a3b2e3977ecffe1a5e5ab7661aadfecbae24be711b7a72bb42bd1b2db083604051610a4b91815260200190565b60405180910390a2600080826001600160a01b03168460405160006040518083038185875af1925050503d8060008114610aa1576040519150601f19603f3d011682016040523d82523d6000602084013e610aa6565b606091505b509150915081610ab857805181602001fd5b5050600190920191506109bf9050565b505060016000805160206146fc83398151915255506107109050565b6000610b0e7fc4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a765490565b8103610e5a57610b46610b22826001613ec5565b7fc4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a7655565b7f91efa3d50feccde0d0d202f8ae5c41ca0b2be614cebcb2bd2f4b019396e6568a81600036604051610b7a93929190613f01565b60405180910390a1610bec610b8f8380613f1b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152507feee152275d096301850a53ae85c6991c818bc6bac8a2174c268aa94ed7cf06f1939250506126489050565b7f4df9dcd34ae35f40f2c756fd8ac83210ed0b76d065543ee73d868aec7c7fcf02610c178380613f1b565b604051610c25929190613f61565b60405180910390a1610c9a610c3d6020840184613f1b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152507f4a8b3e24ebc795477af927068865c6fcc26e359a994edca2492e515a46aad711939250506126489050565b7fadf3ae8bd543b3007d464f15cb8ea1db3f44e84d41d203164f40b95e27558ac6610cc86020840184613f1b565b604051610cd6929190613f61565b60405180910390a1610cf6610cf16060840160408501613a1a565b61188d565b610d036060830183613f75565b9050600003610d255760405163e613e6d960e01b815260040160405180910390fd5b610d326080830183613f75565b9050610d416060840184613f75565b905014610d8757610d556060830183613f75565b9050610d646080840184613f75565b604051635020e50560e01b815260048101939093526024830152506044016106f4565b60005b610d976060840184613f75565b9050811015610e0657610dfe610db06060850185613f75565b83818110610dc057610dc0613e99565b9050602002016020810190610dd59190613a1a565b610de26080860186613f75565b84818110610df257610df2613e99565b90506020020135611d88565b600101610d8a565b50610e1c610e1760e0840184613f75565b611994565b610e3e610e2c60a0840184613f75565b610e3960c0860186613f75565b612654565b610e4c826101000135612677565b610875826101200135611d48565b80610e837fc4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a765490565b60405163031b997760e51b8152600481019290925260248201526044016106f4565b6000610896826126de565b610eb8611960565b6001600160a01b0316336001600160a01b031614610ed957336106cc611960565b6107f281612725565b600061077c7fa030c45ae387079bc9a34aa1365121b47b8ef2d06c04682ce63b90b7c06843e75490565b6001600160a01b038116600090815260008051602061467c8339815191526020526040812054610896565b6107f281612a3f565b610f48611960565b6001600160a01b0316336001600160a01b031614610f6957336106cc611960565b60405181151581527f0797bb255611d0d3d24d654500ba8d9fbb79fd62d6d636a3aafa8bf3d5d6c6709060200160405180910390a16107f27fa030c45ae387079bc9a34aa1365121b47b8ef2d06c04682ce63b90b7c06843e7829055565b610fcf611960565b6001600160a01b0316336001600160a01b031614610ff057336106cc611960565b6107f2816118fb565b611001611960565b6001600160a01b0316336001600160a01b03161461102257336106cc611960565b6108758282611994565b606061067f7f4a8b3e24ebc795477af927068865c6fcc26e359a994edca2492e515a46aad7116117cb565b60008061106333612e15565b600081815260008051602061461c83398151915260205260409020549091506001908116146110a85760405163ca5d071f60e01b8152600481018290526024016106f4565b6001600160a01b0386166110d86000805160206145bc8339815191525b6000848152602091909152604090205490565b6001600160a01b03161415806110f657506001600160a01b03851615155b156111145760405163aea5cf9160e01b815260040160405180910390fd5b60008181526000805160206146dc83398151915260205260408120805486929061113f908490613ec5565b909155505060408051338152602081018390529081018590527ff5833c90fcf127b08719749581fc368b15b6e3e8fd79b1dbc2fb14b7ca6e0ccc9060600160405180910390a1506326c873db60e21b95945050505050565b60608382146111c357604051635020e50560e01b815260048101859052602481018390526044016106f4565b836001600160401b038111156111db576111db613ad0565b60405190808252806020026020018201604052801561120e57816020015b60608152602001906001900390816111f95790505b50905060005b8481101561130257600086868381811061123057611230613e99565b90506020020160208101906112459190613a1a565b9050806001600160a01b031663f8c2153586868581811061126857611268613e99565b905060200281019061127a9190613f75565b6040518363ffffffff1660e01b8152600401611297929190613ff0565b600060405180830381865afa1580156112b4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112dc9190810190614027565b8383815181106112ee576112ee613e99565b602090810291909101015250600101611214565b50949350505050565b600061089660008051602061461c8339815191525b6000848152602091909152604090205460019081161490565b606085841461136557604051635020e50560e01b815260048101879052602481018590526044016106f4565b85821461138f57604051635020e50560e01b815260048101879052602481018390526044016106f4565b856001600160401b038111156113a7576113a7613ad0565b6040519080825280602002602001820160405280156113da57816020015b60608152602001906001900390816113c55790505b50905060005b868110156114fa5760008888838181106113fc576113fc613e99565b90506020020160208101906114119190613a1a565b9050806001600160a01b031663adcf116388888581811061143457611434613e99565b90506020028101906114469190613f75565b88888781811061145857611458613e99565b905060200281019061146a9190613f75565b61ffff6040518663ffffffff1660e01b815260040161148d9594939291906140cc565b6000604051808303816000875af11580156114ac573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114d49190810190614142565b8383815181106114e6576114e6613e99565b6020908102919091010152506001016113e0565b509695505050505050565b6060600061151f6000805160206146bc8339815191525490565b90506000816001600160401b0381111561153b5761153b613ad0565b604051908082528060200260200182016040528015611564578160200160208202803683370190505b50905060005b828110156115ca576115986000805160206145bc8339815191525b6000838152602091909152604090205490565b8282815181106115aa576115aa613e99565b6001600160a01b039092166020928302919091019091015260010161156a565b5092915050565b6115d9611960565b6001600160a01b0316336001600160a01b0316146115fa57336106cc611960565b600061160583612e92565b90506116118284612f64565b600061161c84612e92565b60008581526000805160206145dc83398151915260205260408120549192506116458383613ec5565b9050838110156116685760405163cdd14d1b60e01b815260040160405180910390fd5b61167284826141d5565b6000805160206145dc83398151915260009788526020526040909620959095555050505050565b60608060008051602061459c83398151915260008051602061465c83398151915281546040805160208084028201810190925282815291849183018282801561170b57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116116ed575b505050505091508080548060200260200160405190810160405280929190818152602001828054801561175d57602002820191906000526020600020905b815481526020019060010190808311611749575b50505050509050915091509091565b600061077c611960565b600061178e6000805160206146bc8339815191525490565b82106117b05760405163d531737d60e01b8152600481018390526024016106f4565b6108966000805160206145bc8339815191526110c5565b9055565b8054606090829081906117dd906141e8565b80601f0160208091040260200160405190810160405280929190818152602001828054611809906141e8565b80156118565780601f1061182b57610100808354040283529160200191611856565b820191906000526020600020905b81548152906001019060200180831161183957829003601f168201915b5050505050915050919050565b600061077c7f3c1eebcc225c6cc7f5f8765767af6eff617b4139dc3624923a2db67dbca7b68e5490565b61189681613028565b6040516001600160a01b03821681527f5a272403b402d892977df56625f4164ccaf70ca3863991c43ecfe76a6905b0a19060200160405180910390a16107f27f927a17e5ea75d9461748062a2652f4d3698a628896c9832f8488fa0d2846af09829055565b6040516001600160a01b03821681527f2a0f8515de3fa34ef68b99300347b8793c01683350743e96fe440594528298f49060200160405180910390a16107f27f3c1eebcc225c6cc7f5f8765767af6eff617b4139dc3624923a2db67dbca7b68e829055565b600061077c7f927a17e5ea75d9461748062a2652f4d3698a628896c9832f8488fa0d2846af095490565b6000811515610896565b6000805160206146bc8339815191525481146119e357806119c16000805160206146bc8339815191525490565b604051635020e50560e01b8152600481019290925260248201526044016106f4565b60006119fc6000805160206145fc83398151915261304f565b6000805160206145fc83398151915260005b83811015611ae4576000611a2f60008051602061461c833981519152611320565b90506000868684818110611a4557611a45613e99565b90506020020135905081158015611a5b57508015155b15611a7c576040516303b1bb5d60e31b8152600481018490526024016106f4565b868684818110611a8e57611a8e613e99565b9050602002013585611aa09190613ec5565b945083878785818110611ab557611ab5613e99565b835460018101855560009485526020948590209490910292909201359290910191909155505050600101611a0e565b506127108214611b0757604051630a68b9d760e41b815260040160405180910390fd5b7fb73c61a2aeb51508c0c5d9bab21439a39e825916565b3210eddb7310a64e874e8484604051611b38929190613ff0565b60405180910390a150505050565b600080805b6000805160206146bc83398151915254811015611b7757611b6b81613081565b90910190600101611b4b565b50919050565b828114611ba757604051635020e50560e01b815260048101849052602481018290526044016106f4565b611bbe60008051602061465c83398151915261304f565b611bd560008051602061459c83398151915261304f565b6000805b84811015611cc9576000848483818110611bf557611bf5613e99565b9050602002013590508083611c0a9190613ec5565b60008051602061465c83398151915280546001810182556000919091527f7f4138ba837fd9f0217ae6ee377e4094fe6493a1ee263ca7f57cde5da5a7977b01829055925060008051602061459c833981519152878784818110611c6f57611c6f613e99565b9050602002016020810190611c849190613a1a565b81546001810183556000928352602090922090910180546001600160a01b0319166001600160a01b039092169190911790555080611cc18161421c565b915050611bd9565b506127108114611cec57604051630a68b9d760e41b815260040160405180910390fd5b7fbf29864d443bca1c8bf52ec7006503a5e58e06535e2eea7bc37651f7127e376185858585604051611d219493929190614235565b60405180910390a15050505050565b600061077c60008051602061469c8339815191525490565b6107f27f900053b761278bb5de4eeaea5ed9000b89943edad45dcf64a9dab96d0ce29c2e829055565b6000611d7e84848461309f565b90505b9392505050565b611d918161316c565b611d9a82613028565b6000611db26000805160206146bc8339815191525490565b905060005b81811015611e1a57611dd66000805160206145bc833981519152611585565b6001600160a01b0316846001600160a01b031603611e12576040516301b6ee3960e71b81526001600160a01b03851660048201526024016106f4565b600101611db7565b50611e2d836001600160a01b031661318f565b60008281526000805160206145bc833981519152602090815260408083209390935560008051602061463c833981519152905220829055611e6e600161198a565b600082815260008051602061461c8339815191526020526040902055611eaa611e98826001613ec5565b6000805160206146bc83398151915255565b604080516001600160a01b0385168152602081018390527f0c98febfffcec480c66a977e13f14bafdb5199ea9603591a0715b0cabe0c3ae2910160405180910390a160408051828152602081018490527f032dc6a2d839eb179729a55633fdf1c41a1fc4739394154117005db2b354b9b5910160405180910390a1505050565b806000036107f25760405163095e705160e11b815260040160405180910390fd5b6000611f757fa030c45ae387079bc9a34aa1365121b47b8ef2d06c04682ce63b90b7c06843e75490565b15611f935760405163deeb694360e01b815260040160405180910390fd5b60006000805160206145fc833981519152805480602002602001604051908101604052809291908181526020018280548015611fee57602002820191906000526020600020905b815481526020019060010190808311611fda575b50505050509050600081516001600160401b0381111561201057612010613ad0565b60405190808252806020026020018201604052801561206957816020015b6040805160a08101825260008082526020808301829052928201819052606082018190526080820152825260001990920191018161202e5790505b5090506000805b6000805160206146bc8339815191525481101561258b57600084828151811061209b5761209b613e99565b6020026020010151111561258357808382815181106120bc576120bc613e99565b6020026020010151600001906001600160801b031690816001600160801b03168152505060006120f8878684815181106109e0576109e0613e99565b9050612103826131a0565b600061210e83611776565b9050600061211a611d30565b90506000612126611b46565b9050655af3107a400082101561226d5760008581527f03abd4c14227eca60c6fecceef3797455c352f43ab35128096ea0ac0d9b2170a602052604081208054869290612173908490613ec5565b925050819055506000836001600160a01b031663d0e30db0866040518263ffffffff1660e01b815260040160206040518083038185885af11580156121bc573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906121e19190614298565b90506121ed8188613ec5565b96506121f9338261320e565b8488878151811061220c5761220c613e99565b6020026020010151602001906001600160801b031690816001600160801b0316815250508088878151811061224357612243613e99565b6020026020010151606001906001600160801b031690816001600160801b0316815250505061257e565b6000612278866126de565b90506000633b9aca008211156124025781861886831102821861229b81886141d5565b965060006122e0826122ac8b6132a5565b60008c81526000805160206146dc83398151915260205260409020546122d291906141d5565b6122db8c613081565b611d71565b9050816000805160206145dc83398151915260008b815260200190815260200160002060008282546123129190613ec5565b92505081905550818b8a8151811061232c5761232c613e99565b6020026020010151604001906001600160801b031690816001600160801b031681525050808b8a8151811061236357612363613e99565b6020908102919091018101516001600160801b03909216608090920191909152604080518381529182018b905281018390527ffdb2feef2c30ce94651104212914c3249c15af2822e625dac7712175f6fce88e9060600160405180910390a160006123cf838888611d71565b9050806000036123f25760405163d7eb52ab60e01b815260040160405180910390fd5b6123fc8185613ec5565b93505050505b85156125655760008781527f03abd4c14227eca60c6fecceef3797455c352f43ab35128096ea0ac0d9b2170a602052604081208054889290612445908490613ec5565b925050819055506000856001600160a01b031663d0e30db0886040518263ffffffff1660e01b815260040160206040518083038185885af115801561248e573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906124b39190614298565b905060006124c2888787611d71565b9050806000036124e55760405163d7eb52ab60e01b815260040160405180910390fd5b878b8a815181106124f8576124f8613e99565b602002602001015160200181815161251091906142b1565b6001600160801b03169052508a5182908c908b90811061253257612532613e99565b602002602001015160600181815161254a91906142b1565b6001600160801b03169052506125608184613ec5565b925050505b61256f338261320e565b6125798189613ec5565b975050505b505050505b600101612070565b50336001600160a01b03167f22064e3ba88064d71ff211d550f2b1f3e63b19eb3fd647544e21c8f6e5ccc42e8683856040516125c9939291906142d1565b60405180910390a2506001949350505050565b6000806125e7611b46565b905060006125f3611d30565b9050811580612600575080155b1561260f575060009392505050565b6001600160a01b038416600090815260008051602061467c8339815191526020526040902054612640908383611d71565b949350505050565b818061076c83826143b3565b61266084848484611b7d565b60016000805160206146fc8339815191525561076c565b6126808161316c565b6126a97f70be78e680b682a5a3c38e305d79e28594fd0c62048cca29ef1bd1d746ca8785829055565b6040518181527ed422a7205dd59ab69db2ebeb5699ccb6e9e5eed515043c5e4677221986ad3b9060200160405180910390a150565b6000806126ea83612e92565b60008481526000805160206145dc83398151915260205260409020549091508082111561271b5761264081836141d5565b5060009392505050565b6000805160206146bc8339815191525481106127575760405163d531737d60e01b8152600481018290526024016106f4565b6000612762826132a5565b9050806000036127885760405163280d7c2760e11b8152600481018390526024016106f4565b600060008051602061459c8339815191528054806020026020016040519081016040528092919081815260200182805480156127ed57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127cf575b50505050509050600061280e60008051602061465c83398151915260001b90565b80548060200260200160405190810160405280929190818152602001828054801561285857602002820191906000526020600020905b815481526020019060010190808311612844575b50505050509050600061286a85611776565b905060005b83518110156128c6576000612890868584815181106109e0576109e0613e99565b905080156128bd576128bd8782858886815181106128b0576128b0613e99565b60200260200101516133a6565b5060010161286f565b5061298f84826001600160a01b031663143a08d46040518163ffffffff1660e01b8152600401602060405180830381865afa158015612909573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061292d9190614298565b836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561296b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122db9190614298565b60008681527f76a0ecda094c6ccf2a55f6f1ef41b98d3c1f2dfcb9c1970701fe842ce778ff9b6020526040812080549091906129cc908490613ec5565b909155506129db905085612e92565b60008681526000805160206145dc833981519152602052604090819020919091555185907faf5592e0f02600cde237bef50ea4c3508bd3d392bcfc5683b03c1af1c341794b90612a3090879086908890614472565b60405180910390a25050505050565b6000612a5760008051602061469c8339815191525490565b90506000612a63611b46565b9050612a6f3384613506565b6000612a7c848385611d71565b90506000612a966000805160206146bc8339815191525490565b905080600103612b5b57604080516001808252818301909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081612ab7579050509050612b0660008483600081518110612af957612af9613e99565b60200260200101516135e1565b612b106000613720565b336001600160a01b03167f75aa83b91343398bcfa338c4017c29780f24e0178bb796993453746801d80b038783604051612b4b92919061449d565b60405180910390a2505050505050565b60006000805160206145fc833981519152805480602002602001604051908101604052809291908181526020018280548015612bb657602002820191906000526020600020905b815481526020019060010190808311612ba2575b50507f900053b761278bb5de4eeaea5ed9000b89943edad45dcf64a9dab96d0ce29c2e54939450612be692505050565b831015612d125760008060005b84811015612c56576000612c13888684815181106109e0576109e0613e99565b90506000612c2083613081565b90506000612c2e8383614504565b9050888210158015612c3f57508581135b15612c4b578095508394505b505050600101612bf3565b506000821315612d0f57604080516001808252818301909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081612c77579050509050612cb8828783600081518110612af957612af9613e99565b612cc182613720565b336001600160a01b03167f75aa83b91343398bcfa338c4017c29780f24e0178bb796993453746801d80b038a83604051612cfc92919061449d565b60405180910390a2505050505050505050565b50505b6000826001600160401b03811115612d2c57612d2c613ad0565b604051908082528060200260200182016040528015612d7157816020015b6040805180820190915260008082526020820152815260200190600190039081612d4a5790505b50905060005b83811015612dc8576000612d97868584815181106109e0576109e0613e99565b90508015612db657612db68282858581518110612af957612af9613e99565b612dbf82613720565b50600101612d77565b50336001600160a01b03167f75aa83b91343398bcfa338c4017c29780f24e0178bb796993453746801d80b038883604051612e0492919061449d565b60405180910390a250505050505050565b6000805b6000805160206146bc83398151915254811015612e6d57612e476000805160206145bc833981519152611585565b6001600160a01b0316836001600160a01b031603612e655792915050565b600101612e19565b50604051639823215960e01b81526001600160a01b03831660048201526024016106f4565b600080612e9e83613762565b60008481527f03abd4c14227eca60c6fecceef3797455c352f43ab35128096ea0ac0d9b2170a60209081526040808320547f76a0ecda094c6ccf2a55f6f1ef41b98d3c1f2dfcb9c1970701fe842ce778ff9b9092529091205491925090612f058184613ec5565b8210612f1657506000949350505050565b600082612f238386613ec5565b612f2d91906141d5565b9050612f5a8160008051602061463c83398151915260008981526020919091526040902054612710611d71565b9695505050505050565b7f70be78e680b682a5a3c38e305d79e28594fd0c62048cca29ef1bd1d746ca878554821115612fca577f70be78e680b682a5a3c38e305d79e28594fd0c62048cca29ef1bd1d746ca878554604051627431e360e31b81526004016106f491815260200190565b8160008051602061463c833981519152600083815260209182526040908190209290925581518381529081018490527f032dc6a2d839eb179729a55633fdf1c41a1fc4739394154117005db2b354b9b5910160405180910390a15050565b6001600160a01b0381166107f25760405163f6b2911f60e01b815260040160405180910390fd5b8054801561087557600082558160005260206000205b811561307c57600182039150600082820155613065565b505050565b600061308c826126de565b61309583613762565b61089691906141d5565b60008080600019858709858702925082811083820303915050806000036130d9578382816130cf576130cf614524565b0492505050611d81565b83811061310357604051631dcf306360e21b815260048101829052602481018590526044016106f4565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6127108111156107f257604051630a68b9d760e41b815260040160405180910390fd5b60006001600160a01b038216610896565b6000805160206146bc8339815191525481106131d25760405163d531737d60e01b8152600481018290526024016106f4565b60006131eb60008051602061461c833981519152611320565b9050806108755760405163ca5d071f60e01b8152600481018390526024016106f4565b6132448161322860008051602061469c8339815191525490565b6132329190613ec5565b60008051602061469c83398151915255565b6001600160a01b038216600081815260008051602061467c83398151915260209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b60008181526000805160206145bc83398151915260205260408120546000816001600160a01b031663143a08d46040518163ffffffff1660e01b8152600401602060405180830381865afa158015613301573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133259190614298565b9050801561271b576133a1613339856126de565b836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613377573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061339b9190614298565b83611d71565b612640565b60008481526000805160206146dc8339815191526020526040812080548592906133d19084906141d5565b925050819055506000826001600160a01b0316637f9654f5846001600160a01b031663ffed4bf56040518163ffffffff1660e01b8152600401602060405180830381865afa158015613427573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061344b919061453a565b6040516bffffffffffffffffffffffff19606087901b16602082015287906034016040516020818303038152906040526040518463ffffffff1660e01b815260040161349993929190614557565b6020604051808303816000875af11580156134b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134dc919061457e565b9050806134ff5760405163a10785df60e01b8152600481018690526024016106f4565b5050505050565b6001600160a01b038216600090815260008051602061467c8339815191526020526040902054808211156135575760405163cf47918160e01b815260048101839052602481018290526044016106f4565b61357b8261357160008051602061469c8339815191525490565b61323291906141d5565b81810360008051602061467c8339815191526001600160a01b03851660008181526020928352604080822094909455925185815290917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60006135ec84611776565b9050600061369484836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613632573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136569190614298565b846001600160a01b031663143a08d46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561296b573d6000803e3d6000fd5b905060006136a186613762565b6001600160801b0380841660208701528716855290506136c3868385336133a6565b6136cc86613762565b6136d690826141d5565b60008781527f76a0ecda094c6ccf2a55f6f1ef41b98d3c1f2dfcb9c1970701fe842ce778ff9b602052604081208054909190613713908490613ec5565b9091555050505050505050565b60008181526000805160206146dc833981519152602052604090205461374a90600a612710611d71565b613753826132a5565b11156107f2576107f281612725565b60008061376e83611776565b90506000816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d49190614298565b9050806000036137e8575060009392505050565b6126406000805160206146dc833981519152600086815260200190815260200160002054836001600160a01b031663143a08d46040518163ffffffff1660e01b8152600401602060405180830381865afa158015613377573d6000803e3d6000fd5b60005b8381101561386557818101518382015260200161384d565b50506000910152565b6000815180845261388681602086016020860161384a565b601f01601f19169290920160200192915050565b602081526000611d81602083018461386e565b80151581146107f257600080fd5b60008083601f8401126138cd57600080fd5b5081356001600160401b038111156138e457600080fd5b6020830191508360208260051b85010111156138ff57600080fd5b9250929050565b6000806000806060858703121561391c57600080fd5b84359350602085013561392e816138ad565b925060408501356001600160401b0381111561394957600080fd5b613955878288016138bb565b95989497509550505050565b6000806000806040858703121561397757600080fd5b84356001600160401b038082111561398e57600080fd5b61399a888389016138bb565b909650945060208701359150808211156139b357600080fd5b50613955878288016138bb565b6000602082840312156139d257600080fd5b5035919050565b6001600160a01b03811681146107f257600080fd5b60008060408385031215613a0157600080fd5b8235613a0c816139d9565b946020939093013593505050565b600060208284031215613a2c57600080fd5b8135611d81816139d9565b600060208284031215613a4957600080fd5b81356001600160401b03811115613a5f57600080fd5b82016101408185031215611d8157600080fd5b600060208284031215613a8457600080fd5b8135611d81816138ad565b60008060208385031215613aa257600080fd5b82356001600160401b03811115613ab857600080fd5b613ac4858286016138bb565b90969095509350505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613b0e57613b0e613ad0565b604052919050565b60008060008060808587031215613b2c57600080fd5b8435613b37816139d9565b9350602085810135613b48816139d9565b93506040860135925060608601356001600160401b0380821115613b6b57600080fd5b818801915088601f830112613b7f57600080fd5b813581811115613b9157613b91613ad0565b613ba3601f8201601f19168501613ae6565b91508082528984828501011115613bb957600080fd5b808484018584013760008482840101525080935050505092959194509250565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b83811015613c5857888603603f19018552825180518088529088019088880190845b81811015613c4257835160070b8352928a0192918a0191600101613c23565b5090975050509386019391860191600101613c01565b509398975050505050505050565b60008060008060008060608789031215613c7f57600080fd5b86356001600160401b0380821115613c9657600080fd5b613ca28a838b016138bb565b90985096506020890135915080821115613cbb57600080fd5b613cc78a838b016138bb565b90965094506040890135915080821115613ce057600080fd5b50613ced89828a016138bb565b979a9699509497509295939492505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613d9957878503603f1901845281518051808752908701908787019060005b81811015613d8357835160038110613d7157634e487b7160e01b600052602160045260246000fd5b83529289019291890191600101613d49565b5090965050509285019290850190600101613d26565b5092979650505050505050565b600081518084526020808501945080840160005b83811015613ddf5781516001600160a01b031687529582019590820190600101613dba565b509495945050505050565b602081526000611d816020830184613da6565b60008060408385031215613e1057600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015613ddf57815187529582019590820190600101613e33565b604081526000613e626040830185613da6565b8281036020840152613e748185613e1f565b95945050505050565b60008251613e8f81846020870161384a565b9190910192915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561089657610896613eaf565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b838152604060208201526000613e74604083018486613ed8565b6000808335601e19843603018112613f3257600080fd5b8301803591506001600160401b03821115613f4c57600080fd5b6020019150368190038213156138ff57600080fd5b602081526000611d7e602083018486613ed8565b6000808335601e19843603018112613f8c57600080fd5b8301803591506001600160401b03821115613fa657600080fd5b6020019150600581901b36038213156138ff57600080fd5b81835260006001600160fb1b03831115613fd757600080fd5b8260051b80836020870137939093016020019392505050565b602081526000611d7e602083018486613fbe565b60006001600160401b0382111561401d5761401d613ad0565b5060051b60200190565b6000602080838503121561403a57600080fd5b82516001600160401b0381111561405057600080fd5b8301601f8101851361406157600080fd5b805161407461406f82614004565b613ae6565b81815260059190911b8201830190838101908783111561409357600080fd5b928401925b828410156140c15783518060070b81146140b25760008081fd5b82529284019290840190614098565b979650505050505050565b6060815260006140e0606083018789613fbe565b828103602084810191909152858252869181016000805b8881101561412657843563ffffffff8116808214614113578384fd5b84525093830193918301916001016140f7565b505080935050505061ffff831660408301529695505050505050565b6000602080838503121561415557600080fd5b82516001600160401b0381111561416b57600080fd5b8301601f8101851361417c57600080fd5b805161418a61406f82614004565b81815260059190911b820183019083810190878311156141a957600080fd5b928401925b828410156140c1578351600381106141c65760008081fd5b825292840192908401906141ae565b8181038181111561089657610896613eaf565b600181811c908216806141fc57607f821691505b602082108103611b7757634e487b7160e01b600052602260045260246000fd5b60006001820161422e5761422e613eaf565b5060010190565b6040808252810184905260008560608301825b8781101561427857823561425b816139d9565b6001600160a01b0316825260209283019290910190600101614248565b50838103602085015261428c818688613fbe565b98975050505050505050565b6000602082840312156142aa57600080fd5b5051919050565b6001600160801b038181168382160190808211156115ca576115ca613eaf565b600060608083016001600160801b03808816855260208188168187015260408481880152838851808652608095508589019150838a0160005b8281101561435357815180518816855286810151881687860152858101518816868601528981015188168a86015288015187168885015260a0909301929085019060010161430a565b50919c9b505050505050505050505050565b601f82111561307c57600081815260208120601f850160051c8101602086101561438c5750805b601f850160051c820191505b818110156143ab57828155600101614398565b505050505050565b81516001600160401b038111156143cc576143cc613ad0565b6143e0816143da84546141e8565b84614365565b602080601f83116001811461441557600084156143fd5750858301515b600019600386901b1c1916600185901b1785556143ab565b600085815260208120601f198616915b8281101561444457888601518255948401946001909101908401614425565b50858210156144625787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b83815260606020820152600061448b6060830185613e1f565b8281036040840152612f5a8185613da6565b600060408083016001600160801b03808716855260208381870152828751808552606088019150828901945060005b818110156144f557855180518616845284015185168484015294830194918601916001016144cc565b50909998505050505050505050565b81810360008312801583831316838312821617156115ca576115ca613eaf565b634e487b7160e01b600052601260045260246000fd5b60006020828403121561454c57600080fd5b8151611d81816139d9565b60018060a01b0384168152826020820152606060408201526000613e74606083018461386e565b60006020828403121561459057600080fd5b8151611d81816138ad56fed681f9d3e640a2dd835404271506ef93f020e2fc065878793505e5ea088fde3dbbbff6eb43d00812703825948233d51219dc930ada33999d17cf576c509bebe56c8f9259db4f6802ea7a1e0a01ddb54668b622f1e8d6b610ad7ba4d95f59da293803482dd7707d12238e38a3b1b5e55fa6e13d81c36ce29ec5c267cc02c53fe317b1774c0811229612ec3762023ccd209d6a131e52cdd22f3427eaa8005bcb2f725bc5812d869f51ca713008babaeead3e54db7feab7d4cb185136396950f0e331a3fa329157566a07927d0c2ba92ff801e4db8af2ec73f92eaf3e7f78d587a84f74125ce1aafb5d1699fc2e5e8f96929ff1a99170dc9bda82c8944acc5c7286b24a0f21470b6927dcbaaf5b1f54865bd687f4a2ce4c43edf1e20339a4c05baece6dbdcc28927f6ed428550e539c70c9145bd20fc6e3d7611bd20e170e9b1840357e26a850dc4edaa8b82b6511eec141075372c9c551d3ddb37c35a301f000188472de2bbf04bc62a7ee894bd625126d381bf5e8b726e5cd498c3a9dad76d85ba26469706673582212209059cc9e8f7e3d93db0d54557f2ea823be7fefe01fcbc046156e35b108fa831c64736f6c63430008110033
Deployed Bytecode
0x6080604052600436106101f95760003560e01c806360da3e831161010d578063a81d04e7116100a0578063e3ca2d651161006f578063e3ca2d65146105a2578063ef5ca789146105c2578063f851a440146105e5578063fcee45f4146105fa578063fdc3a3d51461063457600080fd5b8063a81d04e714610506578063b584686914610533578063b7ba18c714610553578063c5c51dca1461058057600080fd5b806375829def116100dc57806375829def14610478578063854e0c6f1461049857806395d89b41146104b85780639b21cf6c146104cd57600080fd5b806360da3e83146103f357806370a0823114610418578063721c651314610438578063738b62e51461045857600080fd5b80632c4e722e116101905780633af9e6691161015f5780633af9e6691461035e5780633e25e8371461037e5780634538e0091461039357806349d6ed56146103b35780634da05606146103d357600080fd5b80632c4e722e14610305578063313ce5671461031a57806332a9caba146103365780633a4b66f11461035657600080fd5b80631468f9ef116101cc5780631468f9ef1461028357806318160ddd146102a3578063235b64c2146102b857806326782247146102d857600080fd5b806306fdde03146101fe5780630e18b681146102295780630eb6f8d914610240578063143a08d414610260575b600080fd5b34801561020a57600080fd5b50610213610654565b604051610220919061389a565b60405180910390f35b34801561023557600080fd5b5061023e6106a3565b005b34801561024c57600080fd5b5061023e61025b366004613906565b610712565b34801561026c57600080fd5b50610275610772565b604051908152602001610220565b34801561028f57600080fd5b5061023e61029e366004613961565b610781565b3480156102af57600080fd5b506102756107b6565b3480156102c457600080fd5b5061023e6102d33660046139c0565b6107c0565b3480156102e457600080fd5b506102ed6107f5565b6040516001600160a01b039091168152602001610220565b34801561031157600080fd5b506102756107ff565b34801561032657600080fd5b5060405160128152602001610220565b34801561034257600080fd5b5061023e6103513660046139ee565b610842565b61023e610879565b34801561036a57600080fd5b50610275610379366004613a1a565b61088b565b34801561038a57600080fd5b5061023e61089c565b34801561039f57600080fd5b5061023e6103ae366004613a37565b610ae4565b3480156103bf57600080fd5b506102756103ce3660046139c0565b610ea5565b3480156103df57600080fd5b5061023e6103ee3660046139c0565b610eb0565b3480156103ff57600080fd5b50610408610ee2565b6040519015158152602001610220565b34801561042457600080fd5b50610275610433366004613a1a565b610f0c565b34801561044457600080fd5b5061023e6104533660046139c0565b610f37565b34801561046457600080fd5b5061023e610473366004613a72565b610f40565b34801561048457600080fd5b5061023e610493366004613a1a565b610fc7565b3480156104a457600080fd5b5061023e6104b3366004613a8f565b610ff9565b3480156104c457600080fd5b5061021361102c565b3480156104d957600080fd5b506104ed6104e8366004613b16565b611057565b6040516001600160e01b03199091168152602001610220565b34801561051257600080fd5b50610526610521366004613961565b611197565b6040516102209190613bd9565b34801561053f57600080fd5b5061040861054e3660046139c0565b61130b565b34801561055f57600080fd5b5061057361056e366004613c66565b611339565b6040516102209190613cff565b34801561058c57600080fd5b50610595611505565b6040516102209190613dea565b3480156105ae57600080fd5b5061023e6105bd366004613dfd565b6115d1565b3480156105ce57600080fd5b506105d7611699565b604051610220929190613e4f565b3480156105f157600080fd5b506102ed61176c565b34801561060657600080fd5b506102756106153660046139c0565b600090815260008051602061463c833981519152602052604090205490565b34801561064057600080fd5b506102ed61064f3660046139c0565b611776565b606061067f7feee152275d096301850a53ae85c6991c818bc6bac8a2174c268aa94ed7cf06f16117cb565b60405160200161068f9190613e7d565b604051602081830303815290604052905090565b6106ab611863565b6001600160a01b0316336001600160a01b0316146106fd57336106cc611863565b60405163295a81c160e01b81526001600160a01b039283166004820152911660248201526044015b60405180910390fd5b6107063361188d565b61071060006118fb565b565b61071a611960565b6001600160a01b0316336001600160a01b03161461073b57336106cc611960565b61074683151561198a565b600085815260008051602061461c833981519152602052604090205561076c8282611994565b50505050565b600061077c611b46565b905090565b610789611960565b6001600160a01b0316336001600160a01b0316146107aa57336106cc611960565b61076c84848484611b7d565b600061077c611d30565b6107c8611960565b6001600160a01b0316336001600160a01b0316146107e957336106cc611960565b6107f281611d48565b50565b600061077c611863565b60008061080a611d30565b90506000811161082257670de0b6b3a764000061083c565b61083c61082d611b46565b670de0b6b3a764000083611d71565b91505090565b61084a611960565b6001600160a01b0316336001600160a01b03161461086b57336106cc611960565b6108758282611d88565b5050565b61088234611f2a565b6107f234611f4b565b6000610896826125dc565b92915050565b60026108b46000805160206146fc8339815191525490565b036108d25760405163558a1e0360e11b815260040160405180910390fd5b60026000805160206146fc8339815191525547600060008051602061459c83398151915280548060200260200160405190810160405280929190818152602001828054801561094a57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161092c575b50505050509050600061096b60008051602061465c83398151915260001b90565b8054806020026020016040519081016040528092919081815260200182805480156109b557602002820191906000526020600020905b8154815260200190600101908083116109a1575b5050505050905060005b8251811015610ac85760006109f0858484815181106109e0576109e0613e99565b6020026020010151612710611d71565b90506000848381518110610a0657610a06613e99565b60200260200101519050806001600160a01b03167fd244b5a3b2e3977ecffe1a5e5ab7661aadfecbae24be711b7a72bb42bd1b2db083604051610a4b91815260200190565b60405180910390a2600080826001600160a01b03168460405160006040518083038185875af1925050503d8060008114610aa1576040519150601f19603f3d011682016040523d82523d6000602084013e610aa6565b606091505b509150915081610ab857805181602001fd5b5050600190920191506109bf9050565b505060016000805160206146fc83398151915255506107109050565b6000610b0e7fc4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a765490565b8103610e5a57610b46610b22826001613ec5565b7fc4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a7655565b7f91efa3d50feccde0d0d202f8ae5c41ca0b2be614cebcb2bd2f4b019396e6568a81600036604051610b7a93929190613f01565b60405180910390a1610bec610b8f8380613f1b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152507feee152275d096301850a53ae85c6991c818bc6bac8a2174c268aa94ed7cf06f1939250506126489050565b7f4df9dcd34ae35f40f2c756fd8ac83210ed0b76d065543ee73d868aec7c7fcf02610c178380613f1b565b604051610c25929190613f61565b60405180910390a1610c9a610c3d6020840184613f1b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152507f4a8b3e24ebc795477af927068865c6fcc26e359a994edca2492e515a46aad711939250506126489050565b7fadf3ae8bd543b3007d464f15cb8ea1db3f44e84d41d203164f40b95e27558ac6610cc86020840184613f1b565b604051610cd6929190613f61565b60405180910390a1610cf6610cf16060840160408501613a1a565b61188d565b610d036060830183613f75565b9050600003610d255760405163e613e6d960e01b815260040160405180910390fd5b610d326080830183613f75565b9050610d416060840184613f75565b905014610d8757610d556060830183613f75565b9050610d646080840184613f75565b604051635020e50560e01b815260048101939093526024830152506044016106f4565b60005b610d976060840184613f75565b9050811015610e0657610dfe610db06060850185613f75565b83818110610dc057610dc0613e99565b9050602002016020810190610dd59190613a1a565b610de26080860186613f75565b84818110610df257610df2613e99565b90506020020135611d88565b600101610d8a565b50610e1c610e1760e0840184613f75565b611994565b610e3e610e2c60a0840184613f75565b610e3960c0860186613f75565b612654565b610e4c826101000135612677565b610875826101200135611d48565b80610e837fc4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a765490565b60405163031b997760e51b8152600481019290925260248201526044016106f4565b6000610896826126de565b610eb8611960565b6001600160a01b0316336001600160a01b031614610ed957336106cc611960565b6107f281612725565b600061077c7fa030c45ae387079bc9a34aa1365121b47b8ef2d06c04682ce63b90b7c06843e75490565b6001600160a01b038116600090815260008051602061467c8339815191526020526040812054610896565b6107f281612a3f565b610f48611960565b6001600160a01b0316336001600160a01b031614610f6957336106cc611960565b60405181151581527f0797bb255611d0d3d24d654500ba8d9fbb79fd62d6d636a3aafa8bf3d5d6c6709060200160405180910390a16107f27fa030c45ae387079bc9a34aa1365121b47b8ef2d06c04682ce63b90b7c06843e7829055565b610fcf611960565b6001600160a01b0316336001600160a01b031614610ff057336106cc611960565b6107f2816118fb565b611001611960565b6001600160a01b0316336001600160a01b03161461102257336106cc611960565b6108758282611994565b606061067f7f4a8b3e24ebc795477af927068865c6fcc26e359a994edca2492e515a46aad7116117cb565b60008061106333612e15565b600081815260008051602061461c83398151915260205260409020549091506001908116146110a85760405163ca5d071f60e01b8152600481018290526024016106f4565b6001600160a01b0386166110d86000805160206145bc8339815191525b6000848152602091909152604090205490565b6001600160a01b03161415806110f657506001600160a01b03851615155b156111145760405163aea5cf9160e01b815260040160405180910390fd5b60008181526000805160206146dc83398151915260205260408120805486929061113f908490613ec5565b909155505060408051338152602081018390529081018590527ff5833c90fcf127b08719749581fc368b15b6e3e8fd79b1dbc2fb14b7ca6e0ccc9060600160405180910390a1506326c873db60e21b95945050505050565b60608382146111c357604051635020e50560e01b815260048101859052602481018390526044016106f4565b836001600160401b038111156111db576111db613ad0565b60405190808252806020026020018201604052801561120e57816020015b60608152602001906001900390816111f95790505b50905060005b8481101561130257600086868381811061123057611230613e99565b90506020020160208101906112459190613a1a565b9050806001600160a01b031663f8c2153586868581811061126857611268613e99565b905060200281019061127a9190613f75565b6040518363ffffffff1660e01b8152600401611297929190613ff0565b600060405180830381865afa1580156112b4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112dc9190810190614027565b8383815181106112ee576112ee613e99565b602090810291909101015250600101611214565b50949350505050565b600061089660008051602061461c8339815191525b6000848152602091909152604090205460019081161490565b606085841461136557604051635020e50560e01b815260048101879052602481018590526044016106f4565b85821461138f57604051635020e50560e01b815260048101879052602481018390526044016106f4565b856001600160401b038111156113a7576113a7613ad0565b6040519080825280602002602001820160405280156113da57816020015b60608152602001906001900390816113c55790505b50905060005b868110156114fa5760008888838181106113fc576113fc613e99565b90506020020160208101906114119190613a1a565b9050806001600160a01b031663adcf116388888581811061143457611434613e99565b90506020028101906114469190613f75565b88888781811061145857611458613e99565b905060200281019061146a9190613f75565b61ffff6040518663ffffffff1660e01b815260040161148d9594939291906140cc565b6000604051808303816000875af11580156114ac573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114d49190810190614142565b8383815181106114e6576114e6613e99565b6020908102919091010152506001016113e0565b509695505050505050565b6060600061151f6000805160206146bc8339815191525490565b90506000816001600160401b0381111561153b5761153b613ad0565b604051908082528060200260200182016040528015611564578160200160208202803683370190505b50905060005b828110156115ca576115986000805160206145bc8339815191525b6000838152602091909152604090205490565b8282815181106115aa576115aa613e99565b6001600160a01b039092166020928302919091019091015260010161156a565b5092915050565b6115d9611960565b6001600160a01b0316336001600160a01b0316146115fa57336106cc611960565b600061160583612e92565b90506116118284612f64565b600061161c84612e92565b60008581526000805160206145dc83398151915260205260408120549192506116458383613ec5565b9050838110156116685760405163cdd14d1b60e01b815260040160405180910390fd5b61167284826141d5565b6000805160206145dc83398151915260009788526020526040909620959095555050505050565b60608060008051602061459c83398151915260008051602061465c83398151915281546040805160208084028201810190925282815291849183018282801561170b57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116116ed575b505050505091508080548060200260200160405190810160405280929190818152602001828054801561175d57602002820191906000526020600020905b815481526020019060010190808311611749575b50505050509050915091509091565b600061077c611960565b600061178e6000805160206146bc8339815191525490565b82106117b05760405163d531737d60e01b8152600481018390526024016106f4565b6108966000805160206145bc8339815191526110c5565b9055565b8054606090829081906117dd906141e8565b80601f0160208091040260200160405190810160405280929190818152602001828054611809906141e8565b80156118565780601f1061182b57610100808354040283529160200191611856565b820191906000526020600020905b81548152906001019060200180831161183957829003601f168201915b5050505050915050919050565b600061077c7f3c1eebcc225c6cc7f5f8765767af6eff617b4139dc3624923a2db67dbca7b68e5490565b61189681613028565b6040516001600160a01b03821681527f5a272403b402d892977df56625f4164ccaf70ca3863991c43ecfe76a6905b0a19060200160405180910390a16107f27f927a17e5ea75d9461748062a2652f4d3698a628896c9832f8488fa0d2846af09829055565b6040516001600160a01b03821681527f2a0f8515de3fa34ef68b99300347b8793c01683350743e96fe440594528298f49060200160405180910390a16107f27f3c1eebcc225c6cc7f5f8765767af6eff617b4139dc3624923a2db67dbca7b68e829055565b600061077c7f927a17e5ea75d9461748062a2652f4d3698a628896c9832f8488fa0d2846af095490565b6000811515610896565b6000805160206146bc8339815191525481146119e357806119c16000805160206146bc8339815191525490565b604051635020e50560e01b8152600481019290925260248201526044016106f4565b60006119fc6000805160206145fc83398151915261304f565b6000805160206145fc83398151915260005b83811015611ae4576000611a2f60008051602061461c833981519152611320565b90506000868684818110611a4557611a45613e99565b90506020020135905081158015611a5b57508015155b15611a7c576040516303b1bb5d60e31b8152600481018490526024016106f4565b868684818110611a8e57611a8e613e99565b9050602002013585611aa09190613ec5565b945083878785818110611ab557611ab5613e99565b835460018101855560009485526020948590209490910292909201359290910191909155505050600101611a0e565b506127108214611b0757604051630a68b9d760e41b815260040160405180910390fd5b7fb73c61a2aeb51508c0c5d9bab21439a39e825916565b3210eddb7310a64e874e8484604051611b38929190613ff0565b60405180910390a150505050565b600080805b6000805160206146bc83398151915254811015611b7757611b6b81613081565b90910190600101611b4b565b50919050565b828114611ba757604051635020e50560e01b815260048101849052602481018290526044016106f4565b611bbe60008051602061465c83398151915261304f565b611bd560008051602061459c83398151915261304f565b6000805b84811015611cc9576000848483818110611bf557611bf5613e99565b9050602002013590508083611c0a9190613ec5565b60008051602061465c83398151915280546001810182556000919091527f7f4138ba837fd9f0217ae6ee377e4094fe6493a1ee263ca7f57cde5da5a7977b01829055925060008051602061459c833981519152878784818110611c6f57611c6f613e99565b9050602002016020810190611c849190613a1a565b81546001810183556000928352602090922090910180546001600160a01b0319166001600160a01b039092169190911790555080611cc18161421c565b915050611bd9565b506127108114611cec57604051630a68b9d760e41b815260040160405180910390fd5b7fbf29864d443bca1c8bf52ec7006503a5e58e06535e2eea7bc37651f7127e376185858585604051611d219493929190614235565b60405180910390a15050505050565b600061077c60008051602061469c8339815191525490565b6107f27f900053b761278bb5de4eeaea5ed9000b89943edad45dcf64a9dab96d0ce29c2e829055565b6000611d7e84848461309f565b90505b9392505050565b611d918161316c565b611d9a82613028565b6000611db26000805160206146bc8339815191525490565b905060005b81811015611e1a57611dd66000805160206145bc833981519152611585565b6001600160a01b0316846001600160a01b031603611e12576040516301b6ee3960e71b81526001600160a01b03851660048201526024016106f4565b600101611db7565b50611e2d836001600160a01b031661318f565b60008281526000805160206145bc833981519152602090815260408083209390935560008051602061463c833981519152905220829055611e6e600161198a565b600082815260008051602061461c8339815191526020526040902055611eaa611e98826001613ec5565b6000805160206146bc83398151915255565b604080516001600160a01b0385168152602081018390527f0c98febfffcec480c66a977e13f14bafdb5199ea9603591a0715b0cabe0c3ae2910160405180910390a160408051828152602081018490527f032dc6a2d839eb179729a55633fdf1c41a1fc4739394154117005db2b354b9b5910160405180910390a1505050565b806000036107f25760405163095e705160e11b815260040160405180910390fd5b6000611f757fa030c45ae387079bc9a34aa1365121b47b8ef2d06c04682ce63b90b7c06843e75490565b15611f935760405163deeb694360e01b815260040160405180910390fd5b60006000805160206145fc833981519152805480602002602001604051908101604052809291908181526020018280548015611fee57602002820191906000526020600020905b815481526020019060010190808311611fda575b50505050509050600081516001600160401b0381111561201057612010613ad0565b60405190808252806020026020018201604052801561206957816020015b6040805160a08101825260008082526020808301829052928201819052606082018190526080820152825260001990920191018161202e5790505b5090506000805b6000805160206146bc8339815191525481101561258b57600084828151811061209b5761209b613e99565b6020026020010151111561258357808382815181106120bc576120bc613e99565b6020026020010151600001906001600160801b031690816001600160801b03168152505060006120f8878684815181106109e0576109e0613e99565b9050612103826131a0565b600061210e83611776565b9050600061211a611d30565b90506000612126611b46565b9050655af3107a400082101561226d5760008581527f03abd4c14227eca60c6fecceef3797455c352f43ab35128096ea0ac0d9b2170a602052604081208054869290612173908490613ec5565b925050819055506000836001600160a01b031663d0e30db0866040518263ffffffff1660e01b815260040160206040518083038185885af11580156121bc573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906121e19190614298565b90506121ed8188613ec5565b96506121f9338261320e565b8488878151811061220c5761220c613e99565b6020026020010151602001906001600160801b031690816001600160801b0316815250508088878151811061224357612243613e99565b6020026020010151606001906001600160801b031690816001600160801b0316815250505061257e565b6000612278866126de565b90506000633b9aca008211156124025781861886831102821861229b81886141d5565b965060006122e0826122ac8b6132a5565b60008c81526000805160206146dc83398151915260205260409020546122d291906141d5565b6122db8c613081565b611d71565b9050816000805160206145dc83398151915260008b815260200190815260200160002060008282546123129190613ec5565b92505081905550818b8a8151811061232c5761232c613e99565b6020026020010151604001906001600160801b031690816001600160801b031681525050808b8a8151811061236357612363613e99565b6020908102919091018101516001600160801b03909216608090920191909152604080518381529182018b905281018390527ffdb2feef2c30ce94651104212914c3249c15af2822e625dac7712175f6fce88e9060600160405180910390a160006123cf838888611d71565b9050806000036123f25760405163d7eb52ab60e01b815260040160405180910390fd5b6123fc8185613ec5565b93505050505b85156125655760008781527f03abd4c14227eca60c6fecceef3797455c352f43ab35128096ea0ac0d9b2170a602052604081208054889290612445908490613ec5565b925050819055506000856001600160a01b031663d0e30db0886040518263ffffffff1660e01b815260040160206040518083038185885af115801561248e573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906124b39190614298565b905060006124c2888787611d71565b9050806000036124e55760405163d7eb52ab60e01b815260040160405180910390fd5b878b8a815181106124f8576124f8613e99565b602002602001015160200181815161251091906142b1565b6001600160801b03169052508a5182908c908b90811061253257612532613e99565b602002602001015160600181815161254a91906142b1565b6001600160801b03169052506125608184613ec5565b925050505b61256f338261320e565b6125798189613ec5565b975050505b505050505b600101612070565b50336001600160a01b03167f22064e3ba88064d71ff211d550f2b1f3e63b19eb3fd647544e21c8f6e5ccc42e8683856040516125c9939291906142d1565b60405180910390a2506001949350505050565b6000806125e7611b46565b905060006125f3611d30565b9050811580612600575080155b1561260f575060009392505050565b6001600160a01b038416600090815260008051602061467c8339815191526020526040902054612640908383611d71565b949350505050565b818061076c83826143b3565b61266084848484611b7d565b60016000805160206146fc8339815191525561076c565b6126808161316c565b6126a97f70be78e680b682a5a3c38e305d79e28594fd0c62048cca29ef1bd1d746ca8785829055565b6040518181527ed422a7205dd59ab69db2ebeb5699ccb6e9e5eed515043c5e4677221986ad3b9060200160405180910390a150565b6000806126ea83612e92565b60008481526000805160206145dc83398151915260205260409020549091508082111561271b5761264081836141d5565b5060009392505050565b6000805160206146bc8339815191525481106127575760405163d531737d60e01b8152600481018290526024016106f4565b6000612762826132a5565b9050806000036127885760405163280d7c2760e11b8152600481018390526024016106f4565b600060008051602061459c8339815191528054806020026020016040519081016040528092919081815260200182805480156127ed57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127cf575b50505050509050600061280e60008051602061465c83398151915260001b90565b80548060200260200160405190810160405280929190818152602001828054801561285857602002820191906000526020600020905b815481526020019060010190808311612844575b50505050509050600061286a85611776565b905060005b83518110156128c6576000612890868584815181106109e0576109e0613e99565b905080156128bd576128bd8782858886815181106128b0576128b0613e99565b60200260200101516133a6565b5060010161286f565b5061298f84826001600160a01b031663143a08d46040518163ffffffff1660e01b8152600401602060405180830381865afa158015612909573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061292d9190614298565b836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561296b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122db9190614298565b60008681527f76a0ecda094c6ccf2a55f6f1ef41b98d3c1f2dfcb9c1970701fe842ce778ff9b6020526040812080549091906129cc908490613ec5565b909155506129db905085612e92565b60008681526000805160206145dc833981519152602052604090819020919091555185907faf5592e0f02600cde237bef50ea4c3508bd3d392bcfc5683b03c1af1c341794b90612a3090879086908890614472565b60405180910390a25050505050565b6000612a5760008051602061469c8339815191525490565b90506000612a63611b46565b9050612a6f3384613506565b6000612a7c848385611d71565b90506000612a966000805160206146bc8339815191525490565b905080600103612b5b57604080516001808252818301909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081612ab7579050509050612b0660008483600081518110612af957612af9613e99565b60200260200101516135e1565b612b106000613720565b336001600160a01b03167f75aa83b91343398bcfa338c4017c29780f24e0178bb796993453746801d80b038783604051612b4b92919061449d565b60405180910390a2505050505050565b60006000805160206145fc833981519152805480602002602001604051908101604052809291908181526020018280548015612bb657602002820191906000526020600020905b815481526020019060010190808311612ba2575b50507f900053b761278bb5de4eeaea5ed9000b89943edad45dcf64a9dab96d0ce29c2e54939450612be692505050565b831015612d125760008060005b84811015612c56576000612c13888684815181106109e0576109e0613e99565b90506000612c2083613081565b90506000612c2e8383614504565b9050888210158015612c3f57508581135b15612c4b578095508394505b505050600101612bf3565b506000821315612d0f57604080516001808252818301909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081612c77579050509050612cb8828783600081518110612af957612af9613e99565b612cc182613720565b336001600160a01b03167f75aa83b91343398bcfa338c4017c29780f24e0178bb796993453746801d80b038a83604051612cfc92919061449d565b60405180910390a2505050505050505050565b50505b6000826001600160401b03811115612d2c57612d2c613ad0565b604051908082528060200260200182016040528015612d7157816020015b6040805180820190915260008082526020820152815260200190600190039081612d4a5790505b50905060005b83811015612dc8576000612d97868584815181106109e0576109e0613e99565b90508015612db657612db68282858581518110612af957612af9613e99565b612dbf82613720565b50600101612d77565b50336001600160a01b03167f75aa83b91343398bcfa338c4017c29780f24e0178bb796993453746801d80b038883604051612e0492919061449d565b60405180910390a250505050505050565b6000805b6000805160206146bc83398151915254811015612e6d57612e476000805160206145bc833981519152611585565b6001600160a01b0316836001600160a01b031603612e655792915050565b600101612e19565b50604051639823215960e01b81526001600160a01b03831660048201526024016106f4565b600080612e9e83613762565b60008481527f03abd4c14227eca60c6fecceef3797455c352f43ab35128096ea0ac0d9b2170a60209081526040808320547f76a0ecda094c6ccf2a55f6f1ef41b98d3c1f2dfcb9c1970701fe842ce778ff9b9092529091205491925090612f058184613ec5565b8210612f1657506000949350505050565b600082612f238386613ec5565b612f2d91906141d5565b9050612f5a8160008051602061463c83398151915260008981526020919091526040902054612710611d71565b9695505050505050565b7f70be78e680b682a5a3c38e305d79e28594fd0c62048cca29ef1bd1d746ca878554821115612fca577f70be78e680b682a5a3c38e305d79e28594fd0c62048cca29ef1bd1d746ca878554604051627431e360e31b81526004016106f491815260200190565b8160008051602061463c833981519152600083815260209182526040908190209290925581518381529081018490527f032dc6a2d839eb179729a55633fdf1c41a1fc4739394154117005db2b354b9b5910160405180910390a15050565b6001600160a01b0381166107f25760405163f6b2911f60e01b815260040160405180910390fd5b8054801561087557600082558160005260206000205b811561307c57600182039150600082820155613065565b505050565b600061308c826126de565b61309583613762565b61089691906141d5565b60008080600019858709858702925082811083820303915050806000036130d9578382816130cf576130cf614524565b0492505050611d81565b83811061310357604051631dcf306360e21b815260048101829052602481018590526044016106f4565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6127108111156107f257604051630a68b9d760e41b815260040160405180910390fd5b60006001600160a01b038216610896565b6000805160206146bc8339815191525481106131d25760405163d531737d60e01b8152600481018290526024016106f4565b60006131eb60008051602061461c833981519152611320565b9050806108755760405163ca5d071f60e01b8152600481018390526024016106f4565b6132448161322860008051602061469c8339815191525490565b6132329190613ec5565b60008051602061469c83398151915255565b6001600160a01b038216600081815260008051602061467c83398151915260209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b60008181526000805160206145bc83398151915260205260408120546000816001600160a01b031663143a08d46040518163ffffffff1660e01b8152600401602060405180830381865afa158015613301573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133259190614298565b9050801561271b576133a1613339856126de565b836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613377573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061339b9190614298565b83611d71565b612640565b60008481526000805160206146dc8339815191526020526040812080548592906133d19084906141d5565b925050819055506000826001600160a01b0316637f9654f5846001600160a01b031663ffed4bf56040518163ffffffff1660e01b8152600401602060405180830381865afa158015613427573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061344b919061453a565b6040516bffffffffffffffffffffffff19606087901b16602082015287906034016040516020818303038152906040526040518463ffffffff1660e01b815260040161349993929190614557565b6020604051808303816000875af11580156134b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134dc919061457e565b9050806134ff5760405163a10785df60e01b8152600481018690526024016106f4565b5050505050565b6001600160a01b038216600090815260008051602061467c8339815191526020526040902054808211156135575760405163cf47918160e01b815260048101839052602481018290526044016106f4565b61357b8261357160008051602061469c8339815191525490565b61323291906141d5565b81810360008051602061467c8339815191526001600160a01b03851660008181526020928352604080822094909455925185815290917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60006135ec84611776565b9050600061369484836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613632573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136569190614298565b846001600160a01b031663143a08d46040518163ffffffff1660e01b8152600401602060405180830381865afa15801561296b573d6000803e3d6000fd5b905060006136a186613762565b6001600160801b0380841660208701528716855290506136c3868385336133a6565b6136cc86613762565b6136d690826141d5565b60008781527f76a0ecda094c6ccf2a55f6f1ef41b98d3c1f2dfcb9c1970701fe842ce778ff9b602052604081208054909190613713908490613ec5565b9091555050505050505050565b60008181526000805160206146dc833981519152602052604090205461374a90600a612710611d71565b613753826132a5565b11156107f2576107f281612725565b60008061376e83611776565b90506000816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137d49190614298565b9050806000036137e8575060009392505050565b6126406000805160206146dc833981519152600086815260200190815260200160002054836001600160a01b031663143a08d46040518163ffffffff1660e01b8152600401602060405180830381865afa158015613377573d6000803e3d6000fd5b60005b8381101561386557818101518382015260200161384d565b50506000910152565b6000815180845261388681602086016020860161384a565b601f01601f19169290920160200192915050565b602081526000611d81602083018461386e565b80151581146107f257600080fd5b60008083601f8401126138cd57600080fd5b5081356001600160401b038111156138e457600080fd5b6020830191508360208260051b85010111156138ff57600080fd5b9250929050565b6000806000806060858703121561391c57600080fd5b84359350602085013561392e816138ad565b925060408501356001600160401b0381111561394957600080fd5b613955878288016138bb565b95989497509550505050565b6000806000806040858703121561397757600080fd5b84356001600160401b038082111561398e57600080fd5b61399a888389016138bb565b909650945060208701359150808211156139b357600080fd5b50613955878288016138bb565b6000602082840312156139d257600080fd5b5035919050565b6001600160a01b03811681146107f257600080fd5b60008060408385031215613a0157600080fd5b8235613a0c816139d9565b946020939093013593505050565b600060208284031215613a2c57600080fd5b8135611d81816139d9565b600060208284031215613a4957600080fd5b81356001600160401b03811115613a5f57600080fd5b82016101408185031215611d8157600080fd5b600060208284031215613a8457600080fd5b8135611d81816138ad565b60008060208385031215613aa257600080fd5b82356001600160401b03811115613ab857600080fd5b613ac4858286016138bb565b90969095509350505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613b0e57613b0e613ad0565b604052919050565b60008060008060808587031215613b2c57600080fd5b8435613b37816139d9565b9350602085810135613b48816139d9565b93506040860135925060608601356001600160401b0380821115613b6b57600080fd5b818801915088601f830112613b7f57600080fd5b813581811115613b9157613b91613ad0565b613ba3601f8201601f19168501613ae6565b91508082528984828501011115613bb957600080fd5b808484018584013760008482840101525080935050505092959194509250565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b83811015613c5857888603603f19018552825180518088529088019088880190845b81811015613c4257835160070b8352928a0192918a0191600101613c23565b5090975050509386019391860191600101613c01565b509398975050505050505050565b60008060008060008060608789031215613c7f57600080fd5b86356001600160401b0380821115613c9657600080fd5b613ca28a838b016138bb565b90985096506020890135915080821115613cbb57600080fd5b613cc78a838b016138bb565b90965094506040890135915080821115613ce057600080fd5b50613ced89828a016138bb565b979a9699509497509295939492505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613d9957878503603f1901845281518051808752908701908787019060005b81811015613d8357835160038110613d7157634e487b7160e01b600052602160045260246000fd5b83529289019291890191600101613d49565b5090965050509285019290850190600101613d26565b5092979650505050505050565b600081518084526020808501945080840160005b83811015613ddf5781516001600160a01b031687529582019590820190600101613dba565b509495945050505050565b602081526000611d816020830184613da6565b60008060408385031215613e1057600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015613ddf57815187529582019590820190600101613e33565b604081526000613e626040830185613da6565b8281036020840152613e748185613e1f565b95945050505050565b60008251613e8f81846020870161384a565b9190910192915050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561089657610896613eaf565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b838152604060208201526000613e74604083018486613ed8565b6000808335601e19843603018112613f3257600080fd5b8301803591506001600160401b03821115613f4c57600080fd5b6020019150368190038213156138ff57600080fd5b602081526000611d7e602083018486613ed8565b6000808335601e19843603018112613f8c57600080fd5b8301803591506001600160401b03821115613fa657600080fd5b6020019150600581901b36038213156138ff57600080fd5b81835260006001600160fb1b03831115613fd757600080fd5b8260051b80836020870137939093016020019392505050565b602081526000611d7e602083018486613fbe565b60006001600160401b0382111561401d5761401d613ad0565b5060051b60200190565b6000602080838503121561403a57600080fd5b82516001600160401b0381111561405057600080fd5b8301601f8101851361406157600080fd5b805161407461406f82614004565b613ae6565b81815260059190911b8201830190838101908783111561409357600080fd5b928401925b828410156140c15783518060070b81146140b25760008081fd5b82529284019290840190614098565b979650505050505050565b6060815260006140e0606083018789613fbe565b828103602084810191909152858252869181016000805b8881101561412657843563ffffffff8116808214614113578384fd5b84525093830193918301916001016140f7565b505080935050505061ffff831660408301529695505050505050565b6000602080838503121561415557600080fd5b82516001600160401b0381111561416b57600080fd5b8301601f8101851361417c57600080fd5b805161418a61406f82614004565b81815260059190911b820183019083810190878311156141a957600080fd5b928401925b828410156140c1578351600381106141c65760008081fd5b825292840192908401906141ae565b8181038181111561089657610896613eaf565b600181811c908216806141fc57607f821691505b602082108103611b7757634e487b7160e01b600052602260045260246000fd5b60006001820161422e5761422e613eaf565b5060010190565b6040808252810184905260008560608301825b8781101561427857823561425b816139d9565b6001600160a01b0316825260209283019290910190600101614248565b50838103602085015261428c818688613fbe565b98975050505050505050565b6000602082840312156142aa57600080fd5b5051919050565b6001600160801b038181168382160190808211156115ca576115ca613eaf565b600060608083016001600160801b03808816855260208188168187015260408481880152838851808652608095508589019150838a0160005b8281101561435357815180518816855286810151881687860152858101518816868601528981015188168a86015288015187168885015260a0909301929085019060010161430a565b50919c9b505050505050505050505050565b601f82111561307c57600081815260208120601f850160051c8101602086101561438c5750805b601f850160051c820191505b818110156143ab57828155600101614398565b505050505050565b81516001600160401b038111156143cc576143cc613ad0565b6143e0816143da84546141e8565b84614365565b602080601f83116001811461441557600084156143fd5750858301515b600019600386901b1c1916600185901b1785556143ab565b600085815260208120601f198616915b8281101561444457888601518255948401946001909101908401614425565b50858210156144625787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b83815260606020820152600061448b6060830185613e1f565b8281036040840152612f5a8185613da6565b600060408083016001600160801b03808716855260208381870152828751808552606088019150828901945060005b818110156144f557855180518616845284015185168484015294830194918601916001016144cc565b50909998505050505050505050565b81810360008312801583831316838312821617156115ca576115ca613eaf565b634e487b7160e01b600052601260045260246000fd5b60006020828403121561454c57600080fd5b8151611d81816139d9565b60018060a01b0384168152826020820152606060408201526000613e74606083018461386e565b60006020828403121561459057600080fd5b8151611d81816138ad56fed681f9d3e640a2dd835404271506ef93f020e2fc065878793505e5ea088fde3dbbbff6eb43d00812703825948233d51219dc930ada33999d17cf576c509bebe56c8f9259db4f6802ea7a1e0a01ddb54668b622f1e8d6b610ad7ba4d95f59da293803482dd7707d12238e38a3b1b5e55fa6e13d81c36ce29ec5c267cc02c53fe317b1774c0811229612ec3762023ccd209d6a131e52cdd22f3427eaa8005bcb2f725bc5812d869f51ca713008babaeead3e54db7feab7d4cb185136396950f0e331a3fa329157566a07927d0c2ba92ff801e4db8af2ec73f92eaf3e7f78d587a84f74125ce1aafb5d1699fc2e5e8f96929ff1a99170dc9bda82c8944acc5c7286b24a0f21470b6927dcbaaf5b1f54865bd687f4a2ce4c43edf1e20339a4c05baece6dbdcc28927f6ed428550e539c70c9145bd20fc6e3d7611bd20e170e9b1840357e26a850dc4edaa8b82b6511eec141075372c9c551d3ddb37c35a301f000188472de2bbf04bc62a7ee894bd625126d381bf5e8b726e5cd498c3a9dad76d85ba26469706673582212209059cc9e8f7e3d93db0d54557f2ea823be7fefe01fcbc046156e35b108fa831c64736f6c63430008110033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.