Source Code
Latest 1 from a total of 1 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Add Budget | 41310843 | 173 days ago | IN | 0 S | 0.0048115 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
GenericHarvester
Compiler Version
v0.8.28+commit.7893614a
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { IERC3156FlashBorrower } from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import { IERC3156FlashLender } from "@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol";
import { RouterSwapper } from "@helpers/RouterSwapper.sol";
import { IParallelizer } from "contracts/interfaces/IParallelizer.sol";
import { ITokenP } from "contracts/interfaces/ITokenP.sol";
import { IERC4626 } from "contracts/interfaces/external/IERC4626.sol";
import "../utils/Errors.sol";
import { BaseHarvester, YieldBearingParams } from "./BaseHarvester.sol";
enum SwapType {
VAULT,
SWAP
}
/// @title GenericHarvester
/// @author Cooper Labs
/// @custom:contact [email protected]
/// @dev Generic contract for anyone to permissionlessly adjust the reserves of Angle Parallelizer
/// @dev This contract is an authorized fork of Angle's GenericHarvester contract:
/// https://github.com/AngleProtocol/angle-transmuter/blob/main/contracts/helpers/GenericHarvester.sol
contract GenericHarvester is BaseHarvester, IERC3156FlashBorrower, RouterSwapper {
using SafeCast for uint256;
using SafeERC20 for IERC20;
bytes32 public constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
/// @notice Parallel stablecoin flashloan contract
IERC3156FlashLender public immutable flashloan;
/// @notice Budget of tokenP available for each users
mapping(address => uint256) public budget;
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INITIALIZATION
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
constructor(
address initialTokenTransferAddress,
address initialSwapRouter,
ITokenP definitivetokenP,
IParallelizer definitiveParallelizer,
address initialAuthority,
IERC3156FlashLender definitiveFlashloan
)
RouterSwapper(initialSwapRouter, initialTokenTransferAddress)
BaseHarvester(initialAuthority, definitivetokenP, definitiveParallelizer)
{
if (address(definitiveFlashloan) == address(0)) revert ZeroAddress();
flashloan = definitiveFlashloan;
IERC20(tokenP).approve(address(definitiveFlashloan), type(uint256).max);
}
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BUDGET HANDLING
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/**
* @notice Add budget to be spent by the receiver during the flashloan
* @param amount amount of tokenP to add to the budget
* @param receiver address of the receiver
*/
function addBudget(uint256 amount, address receiver) public virtual {
budget[receiver] += amount;
IERC20(tokenP).safeTransferFrom(msg.sender, address(this), amount);
}
/**
* @notice Remove budget from the owner and send it to the receiver
* @param amount amount of tokenP to remove from the budget
* @param receiver address of the receiver
*/
function removeBudget(uint256 amount, address receiver) public virtual {
budget[msg.sender] -= amount; // Will revert if not enough funds
IERC20(tokenP).safeTransfer(receiver, amount);
}
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HARVEST
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/// @notice Invests or divests from the yield asset associated to `yieldBearingAsset` based on the current exposure
/// to this yieldBearingAsset
/// @dev This transaction either reduces the exposure to `yieldBearingAsset` in the Parallelizer or frees up
/// some yieldBearingAsset that can then be used for people looking to burn deposit tokens
/// @dev Due to potential transaction fees within the Parallelizer, this function doesn't exactly bring
/// `yieldBearingAsset` to the target exposure
/// @dev scale is a number between 0 and 1e9 that represents the proportion of the tokenP to harvest,
/// it is used to lower the amount of the asset to harvest for example to have a lower slippage
function harvest(address yieldBearingAsset, uint256 scale, bytes calldata extraData) public virtual {
if (scale > 1e9) revert InvalidParam();
updateLimitExposuresYieldAsset(yieldBearingAsset);
YieldBearingParams memory yieldBearingInfo = yieldBearingData[yieldBearingAsset];
(uint8 increase, uint256 amount) = _computeRebalanceAmount(yieldBearingAsset, yieldBearingInfo);
amount = (amount * scale) / 1e9;
if (amount == 0) revert ZeroAmount();
(SwapType swapType, bytes memory data) = abi.decode(extraData, (SwapType, bytes));
try parallelizer.updateOracle(yieldBearingAsset) { } catch { }
_adjustYieldExposure(
amount,
increase,
yieldBearingAsset,
yieldBearingInfo.asset,
(amount * (1e9 - yieldBearingInfo.maxSlippage)) / 1e9,
swapType,
data
);
}
/// @inheritdoc IERC3156FlashBorrower
function onFlashLoan(
address initiator,
address,
uint256 amount,
uint256 fee,
bytes calldata data
)
public
virtual
returns (bytes32)
{
if (msg.sender != address(flashloan) || initiator != address(this) || fee != 0) revert NotTrusted();
address sender;
uint256 typeAction;
uint256 minAmountOut;
SwapType swapType;
bytes memory callData;
address tokenOut;
address tokenIn;
{
address yieldBearingAsset;
address asset;
(sender, typeAction, yieldBearingAsset, asset, minAmountOut, swapType, callData) =
abi.decode(data, (address, uint256, address, address, uint256, SwapType, bytes));
if (typeAction == 1) {
// Increase yield exposure action: we bring in the yield bearing asset
tokenOut = yieldBearingAsset;
tokenIn = asset;
} else {
// Decrease yield exposure action: we bring in the deposit asset
tokenIn = yieldBearingAsset;
tokenOut = asset;
}
}
uint256 amountOut =
parallelizer.swapExactInput(amount, 0, address(tokenP), tokenIn, address(this), block.timestamp);
// Swap to tokenIn
amountOut = _swapToTokenOut(typeAction, tokenIn, tokenOut, amountOut, swapType, callData);
_adjustAllowance(tokenOut, address(parallelizer), amountOut);
uint256 amountStableOut =
parallelizer.swapExactInput(amountOut, minAmountOut, tokenOut, address(tokenP), address(this), block.timestamp);
if (amount > amountStableOut) {
budget[sender] -= amount - amountStableOut; // Will revert if not enough funds
}
return CALLBACK_SUCCESS;
}
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SETTERS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/**
* @notice Set the token transfer address
* @param newTokenTransferAddress address of the token transfer contract
*/
function setTokenTransferAddress(address newTokenTransferAddress) public override restricted {
super.setTokenTransferAddress(newTokenTransferAddress);
}
/**
* @notice Set the swap router
* @param newSwapRouter address of the swap router
*/
function setSwapRouter(address newSwapRouter) public override restricted {
super.setSwapRouter(newSwapRouter);
}
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INTERNALS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/// @notice Burns `amountStablecoins` for one yieldBearing asset, swap for asset then mints deposit tokens
/// from the proceeds of the swap.
/// @dev If `increase` is 1, then the system tries to increase its exposure to the yield bearing asset which means
/// burning tokenP for the deposit asset, swapping for the yield bearing asset, then minting the tokenP
/// @dev This function reverts if the second tokenP mint gives less than `minAmountOut` of ag tokens
/// @dev This function reverts if the swap slippage is higher than `maxSlippage`
function _adjustYieldExposure(
uint256 amountStablecoins,
uint8 increase,
address yieldBearingAsset,
address asset,
uint256 minAmountOut,
SwapType swapType,
bytes memory extraData
)
internal
{
flashloan.flashLoan(
IERC3156FlashBorrower(address(this)),
address(tokenP),
amountStablecoins,
abi.encode(msg.sender, increase, yieldBearingAsset, asset, minAmountOut, swapType, extraData)
);
}
function _swapToTokenOut(
uint256 typeAction,
address tokenIn,
address tokenOut,
uint256 amount,
SwapType swapType,
bytes memory callData
)
internal
returns (uint256 amountOut)
{
if (swapType == SwapType.SWAP) {
amountOut = _swapToTokenOutSwap(tokenIn, tokenOut, amount, callData);
} else if (swapType == SwapType.VAULT) {
amountOut = _swapToTokenOutVault(typeAction, tokenIn, tokenOut, amount);
}
}
/**
* @notice Swap token using the router/aggregator
* @param tokenIn address of the token to swap
* @param tokenOut address of the token to receive
* @param amount amount of token to swap
* @param callData bytes to call the router/aggregator
*/
function _swapToTokenOutSwap(
address tokenIn,
address tokenOut,
uint256 amount,
bytes memory callData
)
internal
returns (uint256)
{
uint256 balance = IERC20(tokenOut).balanceOf(address(this));
address[] memory tokens = new address[](1);
tokens[0] = tokenIn;
bytes[] memory callDatas = new bytes[](1);
callDatas[0] = callData;
uint256[] memory amounts = new uint256[](1);
amounts[0] = amount;
_swap(tokens, callDatas, amounts);
return IERC20(tokenOut).balanceOf(address(this)) - balance;
}
/**
* @dev Deposit or redeem the vault asset
* @param typeAction 1 for deposit, 2 for redeem
* @param tokenIn address of the token to swap
* @param tokenOut address of the token to receive
* @param amount amount of token to swap
*/
function _swapToTokenOutVault(
uint256 typeAction,
address tokenIn,
address tokenOut,
uint256 amount
)
internal
returns (uint256 amountOut)
{
if (typeAction == 1) {
// Granting allowance with the yieldBearingAsset for the vault asset
_adjustAllowance(tokenIn, tokenOut, amount);
amountOut = IERC4626(tokenOut).deposit(amount, address(this));
} else {
amountOut = IERC4626(tokenIn).redeem(amount, address(this), address(this));
}
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
/// @title Swapper
/// @author Angle Labs, Inc.
/// @dev Abstract contract for swapping tokens using a router/aggregator
/// @dev This contract is an authorized fork of Angle's `RouterSwapper` contract
/// https://github.com/AngleProtocol/utils/blob/main/src/RouterSwapper.sol
abstract contract RouterSwapper {
using SafeERC20 for IERC20;
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error SwapError();
error ZeroAddress();
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Event emitted when the swap router is updated
*/
event SwapRouterUpdated(address newSwapRouter);
/**
* @notice Event emitted when the token proxy is updated
*/
event TokenTransferAddressUpdated(address newTokenTransferAddress);
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
modifier noZeroAddress(address targetAddress) {
if (targetAddress == address(0)) {
revert ZeroAddress();
}
_;
}
/*//////////////////////////////////////////////////////////////
MUTABLE VARIABLES
//////////////////////////////////////////////////////////////*/
/**
* @notice address of the router/aggregator
*/
address public swapRouter;
/**
* @notice address to approve to transfer tokens to
*/
address public tokenTransferAddress;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(address initialSwapRouter, address initialTokenTransferAddress) {
swapRouter = initialSwapRouter;
tokenTransferAddress = initialTokenTransferAddress;
}
/*//////////////////////////////////////////////////////////////
ADMIN FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Set the router/aggregator address
* @param newSwapRouter address of the new router/aggregator
*/
function setSwapRouter(address newSwapRouter) public virtual noZeroAddress(newSwapRouter) {
swapRouter = newSwapRouter;
emit SwapRouterUpdated(newSwapRouter);
}
/**
* @notice Set the token transfer address
* @param newTokenTransferAddress address of the new token transfer address
*/
function setTokenTransferAddress(address newTokenTransferAddress)
public
virtual
noZeroAddress(newTokenTransferAddress)
{
tokenTransferAddress = newTokenTransferAddress;
emit TokenTransferAddressUpdated(newTokenTransferAddress);
}
/*//////////////////////////////////////////////////////////////
SWAP FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Approve the router/aggregator to spend the token if needed
* @param token address of the token to approve
* @param spender address of the router/aggregator
* @param amount amount to approve
*/
function _approveTokenIfNeeded(address token, address spender, uint256 amount) internal {
uint256 allowance = IERC20(token).allowance(address(this), spender);
if (allowance < amount) {
IERC20(token).safeIncreaseAllowance(spender, amount - allowance);
}
}
/**
* @notice Perform the swap using the router/aggregator
* @param callData bytes to call the router/aggregator
*/
function _performRouterSwap(bytes memory callData) internal {
(bool success, bytes memory retData) = swapRouter.call(callData);
if (!success) {
if (retData.length != 0) {
assembly ("memory-safe") {
revert(add(32, retData), mload(retData))
}
}
revert SwapError();
}
}
/**
* @notice Swap tokens using the router/aggregator
* @param tokens array of tokens to swap
* @param callDatas array of bytes to call the router/aggregator
* @param amounts array of amounts to swap
*/
function _swapCalldata(address[] calldata tokens, bytes[] calldata callDatas, uint256[] calldata amounts) internal {
uint256 length = tokens.length;
for (uint256 i; i < length; ++i) {
_approveTokenIfNeeded(tokens[i], tokenTransferAddress, amounts[i]);
_performRouterSwap(callDatas[i]);
}
}
/**
* @notice Swap tokens using the router/aggregator
* @param tokens array of tokens to swap
* @param callDatas array of bytes to call the router/aggregator
* @param amounts array of amounts to swap
*/
function _swap(address[] memory tokens, bytes[] memory callDatas, uint256[] memory amounts) internal {
uint256 length = tokens.length;
for (uint256 i; i < length; ++i) {
_approveTokenIfNeeded(tokens[i], tokenTransferAddress, amounts[i]);
_performRouterSwap(callDatas[i]);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/AuthorityUtils.sol)
pragma solidity ^0.8.20;
import {IAuthority} from "./IAuthority.sol";
library AuthorityUtils {
/**
* @dev Since `AccessManager` implements an extended IAuthority interface, invoking `canCall` with backwards compatibility
* for the preexisting `IAuthority` interface requires special care to avoid reverting on insufficient return data.
* This helper function takes care of invoking `canCall` in a backwards compatible way without reverting.
*/
function canCallWithDelay(
address authority,
address caller,
address target,
bytes4 selector
) internal view returns (bool immediate, uint32 delay) {
(bool success, bytes memory data) = authority.staticcall(
abi.encodeCall(IAuthority.canCall, (caller, target, selector))
);
if (success) {
if (data.length >= 0x40) {
(immediate, delay) = abi.decode(data, (bool, uint32));
} else if (data.length >= 0x20) {
immediate = abi.decode(data, (bool));
}
}
return (immediate, delay);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAccessManaged.sol)
pragma solidity ^0.8.20;
interface IAccessManaged {
/**
* @dev Authority that manages this contract was updated.
*/
event AuthorityUpdated(address authority);
error AccessManagedUnauthorized(address caller);
error AccessManagedRequiredDelay(address caller, uint32 delay);
error AccessManagedInvalidAuthority(address authority);
/**
* @dev Returns the current authority.
*/
function authority() external view returns (address);
/**
* @dev Transfers control to a new authority. The caller must be the current authority.
*/
function setAuthority(address) external;
/**
* @dev Returns true only in the context of a delayed restricted call, at the moment that the scheduled operation is
* being consumed. Prevents denial of service for delayed restricted calls in the case that the contract performs
* attacker controlled calls.
*/
function isConsumingScheduledOp() external view returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/manager/IAccessManager.sol)
pragma solidity ^0.8.20;
import {Time} from "../../utils/types/Time.sol";
interface IAccessManager {
/**
* @dev A delayed operation was scheduled.
*/
event OperationScheduled(
bytes32 indexed operationId,
uint32 indexed nonce,
uint48 schedule,
address caller,
address target,
bytes data
);
/**
* @dev A scheduled operation was executed.
*/
event OperationExecuted(bytes32 indexed operationId, uint32 indexed nonce);
/**
* @dev A scheduled operation was canceled.
*/
event OperationCanceled(bytes32 indexed operationId, uint32 indexed nonce);
/**
* @dev Informational labelling for a roleId.
*/
event RoleLabel(uint64 indexed roleId, string label);
/**
* @dev Emitted when `account` is granted `roleId`.
*
* NOTE: The meaning of the `since` argument depends on the `newMember` argument.
* If the role is granted to a new member, the `since` argument indicates when the account becomes a member of the role,
* otherwise it indicates the execution delay for this account and roleId is updated.
*/
event RoleGranted(uint64 indexed roleId, address indexed account, uint32 delay, uint48 since, bool newMember);
/**
* @dev Emitted when `account` membership or `roleId` is revoked. Unlike granting, revoking is instantaneous.
*/
event RoleRevoked(uint64 indexed roleId, address indexed account);
/**
* @dev Role acting as admin over a given `roleId` is updated.
*/
event RoleAdminChanged(uint64 indexed roleId, uint64 indexed admin);
/**
* @dev Role acting as guardian over a given `roleId` is updated.
*/
event RoleGuardianChanged(uint64 indexed roleId, uint64 indexed guardian);
/**
* @dev Grant delay for a given `roleId` will be updated to `delay` when `since` is reached.
*/
event RoleGrantDelayChanged(uint64 indexed roleId, uint32 delay, uint48 since);
/**
* @dev Target mode is updated (true = closed, false = open).
*/
event TargetClosed(address indexed target, bool closed);
/**
* @dev Role required to invoke `selector` on `target` is updated to `roleId`.
*/
event TargetFunctionRoleUpdated(address indexed target, bytes4 selector, uint64 indexed roleId);
/**
* @dev Admin delay for a given `target` will be updated to `delay` when `since` is reached.
*/
event TargetAdminDelayUpdated(address indexed target, uint32 delay, uint48 since);
error AccessManagerAlreadyScheduled(bytes32 operationId);
error AccessManagerNotScheduled(bytes32 operationId);
error AccessManagerNotReady(bytes32 operationId);
error AccessManagerExpired(bytes32 operationId);
error AccessManagerLockedRole(uint64 roleId);
error AccessManagerBadConfirmation();
error AccessManagerUnauthorizedAccount(address msgsender, uint64 roleId);
error AccessManagerUnauthorizedCall(address caller, address target, bytes4 selector);
error AccessManagerUnauthorizedConsume(address target);
error AccessManagerUnauthorizedCancel(address msgsender, address caller, address target, bytes4 selector);
error AccessManagerInvalidInitialAdmin(address initialAdmin);
/**
* @dev Check if an address (`caller`) is authorised to call a given function on a given contract directly (with
* no restriction). Additionally, it returns the delay needed to perform the call indirectly through the {schedule}
* & {execute} workflow.
*
* This function is usually called by the targeted contract to control immediate execution of restricted functions.
* Therefore we only return true if the call can be performed without any delay. If the call is subject to a
* previously set delay (not zero), then the function should return false and the caller should schedule the operation
* for future execution.
*
* If `immediate` is true, the delay can be disregarded and the operation can be immediately executed, otherwise
* the operation can be executed if and only if delay is greater than 0.
*
* NOTE: The IAuthority interface does not include the `uint32` delay. This is an extension of that interface that
* is backward compatible. Some contracts may thus ignore the second return argument. In that case they will fail
* to identify the indirect workflow, and will consider calls that require a delay to be forbidden.
*
* NOTE: This function does not report the permissions of the admin functions in the manager itself. These are defined by the
* {AccessManager} documentation.
*/
function canCall(
address caller,
address target,
bytes4 selector
) external view returns (bool allowed, uint32 delay);
/**
* @dev Expiration delay for scheduled proposals. Defaults to 1 week.
*
* IMPORTANT: Avoid overriding the expiration with 0. Otherwise every contract proposal will be expired immediately,
* disabling any scheduling usage.
*/
function expiration() external view returns (uint32);
/**
* @dev Minimum setback for all delay updates, with the exception of execution delays. It
* can be increased without setback (and reset via {revokeRole} in the case event of an
* accidental increase). Defaults to 5 days.
*/
function minSetback() external view returns (uint32);
/**
* @dev Get whether the contract is closed disabling any access. Otherwise role permissions are applied.
*
* NOTE: When the manager itself is closed, admin functions are still accessible to avoid locking the contract.
*/
function isTargetClosed(address target) external view returns (bool);
/**
* @dev Get the role required to call a function.
*/
function getTargetFunctionRole(address target, bytes4 selector) external view returns (uint64);
/**
* @dev Get the admin delay for a target contract. Changes to contract configuration are subject to this delay.
*/
function getTargetAdminDelay(address target) external view returns (uint32);
/**
* @dev Get the id of the role that acts as an admin for the given role.
*
* The admin permission is required to grant the role, revoke the role and update the execution delay to execute
* an operation that is restricted to this role.
*/
function getRoleAdmin(uint64 roleId) external view returns (uint64);
/**
* @dev Get the role that acts as a guardian for a given role.
*
* The guardian permission allows canceling operations that have been scheduled under the role.
*/
function getRoleGuardian(uint64 roleId) external view returns (uint64);
/**
* @dev Get the role current grant delay.
*
* Its value may change at any point without an event emitted following a call to {setGrantDelay}.
* Changes to this value, including effect timepoint are notified in advance by the {RoleGrantDelayChanged} event.
*/
function getRoleGrantDelay(uint64 roleId) external view returns (uint32);
/**
* @dev Get the access details for a given account for a given role. These details include the timepoint at which
* membership becomes active, and the delay applied to all operation by this user that requires this permission
* level.
*
* Returns:
* [0] Timestamp at which the account membership becomes valid. 0 means role is not granted.
* [1] Current execution delay for the account.
* [2] Pending execution delay for the account.
* [3] Timestamp at which the pending execution delay will become active. 0 means no delay update is scheduled.
*/
function getAccess(
uint64 roleId,
address account
) external view returns (uint48 since, uint32 currentDelay, uint32 pendingDelay, uint48 effect);
/**
* @dev Check if a given account currently has the permission level corresponding to a given role. Note that this
* permission might be associated with an execution delay. {getAccess} can provide more details.
*/
function hasRole(uint64 roleId, address account) external view returns (bool isMember, uint32 executionDelay);
/**
* @dev Give a label to a role, for improved role discoverability by UIs.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {RoleLabel} event.
*/
function labelRole(uint64 roleId, string calldata label) external;
/**
* @dev Add `account` to `roleId`, or change its execution delay.
*
* This gives the account the authorization to call any function that is restricted to this role. An optional
* execution delay (in seconds) can be set. If that delay is non 0, the user is required to schedule any operation
* that is restricted to members of this role. The user will only be able to execute the operation after the delay has
* passed, before it has expired. During this period, admin and guardians can cancel the operation (see {cancel}).
*
* If the account has already been granted this role, the execution delay will be updated. This update is not
* immediate and follows the delay rules. For example, if a user currently has a delay of 3 hours, and this is
* called to reduce that delay to 1 hour, the new delay will take some time to take effect, enforcing that any
* operation executed in the 3 hours that follows this update was indeed scheduled before this update.
*
* Requirements:
*
* - the caller must be an admin for the role (see {getRoleAdmin})
* - granted role must not be the `PUBLIC_ROLE`
*
* Emits a {RoleGranted} event.
*/
function grantRole(uint64 roleId, address account, uint32 executionDelay) external;
/**
* @dev Remove an account from a role, with immediate effect. If the account does not have the role, this call has
* no effect.
*
* Requirements:
*
* - the caller must be an admin for the role (see {getRoleAdmin})
* - revoked role must not be the `PUBLIC_ROLE`
*
* Emits a {RoleRevoked} event if the account had the role.
*/
function revokeRole(uint64 roleId, address account) external;
/**
* @dev Renounce role permissions for the calling account with immediate effect. If the sender is not in
* the role this call has no effect.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* Emits a {RoleRevoked} event if the account had the role.
*/
function renounceRole(uint64 roleId, address callerConfirmation) external;
/**
* @dev Change admin role for a given role.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {RoleAdminChanged} event
*/
function setRoleAdmin(uint64 roleId, uint64 admin) external;
/**
* @dev Change guardian role for a given role.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {RoleGuardianChanged} event
*/
function setRoleGuardian(uint64 roleId, uint64 guardian) external;
/**
* @dev Update the delay for granting a `roleId`.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {RoleGrantDelayChanged} event.
*/
function setGrantDelay(uint64 roleId, uint32 newDelay) external;
/**
* @dev Set the role required to call functions identified by the `selectors` in the `target` contract.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {TargetFunctionRoleUpdated} event per selector.
*/
function setTargetFunctionRole(address target, bytes4[] calldata selectors, uint64 roleId) external;
/**
* @dev Set the delay for changing the configuration of a given target contract.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {TargetAdminDelayUpdated} event.
*/
function setTargetAdminDelay(address target, uint32 newDelay) external;
/**
* @dev Set the closed flag for a contract.
*
* Closing the manager itself won't disable access to admin methods to avoid locking the contract.
*
* Requirements:
*
* - the caller must be a global admin
*
* Emits a {TargetClosed} event.
*/
function setTargetClosed(address target, bool closed) external;
/**
* @dev Return the timepoint at which a scheduled operation will be ready for execution. This returns 0 if the
* operation is not yet scheduled, has expired, was executed, or was canceled.
*/
function getSchedule(bytes32 id) external view returns (uint48);
/**
* @dev Return the nonce for the latest scheduled operation with a given id. Returns 0 if the operation has never
* been scheduled.
*/
function getNonce(bytes32 id) external view returns (uint32);
/**
* @dev Schedule a delayed operation for future execution, and return the operation identifier. It is possible to
* choose the timestamp at which the operation becomes executable as long as it satisfies the execution delays
* required for the caller. The special value zero will automatically set the earliest possible time.
*
* Returns the `operationId` that was scheduled. Since this value is a hash of the parameters, it can reoccur when
* the same parameters are used; if this is relevant, the returned `nonce` can be used to uniquely identify this
* scheduled operation from other occurrences of the same `operationId` in invocations of {execute} and {cancel}.
*
* Emits a {OperationScheduled} event.
*
* NOTE: It is not possible to concurrently schedule more than one operation with the same `target` and `data`. If
* this is necessary, a random byte can be appended to `data` to act as a salt that will be ignored by the target
* contract if it is using standard Solidity ABI encoding.
*/
function schedule(
address target,
bytes calldata data,
uint48 when
) external returns (bytes32 operationId, uint32 nonce);
/**
* @dev Execute a function that is delay restricted, provided it was properly scheduled beforehand, or the
* execution delay is 0.
*
* Returns the nonce that identifies the previously scheduled operation that is executed, or 0 if the
* operation wasn't previously scheduled (if the caller doesn't have an execution delay).
*
* Emits an {OperationExecuted} event only if the call was scheduled and delayed.
*/
function execute(address target, bytes calldata data) external payable returns (uint32);
/**
* @dev Cancel a scheduled (delayed) operation. Returns the nonce that identifies the previously scheduled
* operation that is cancelled.
*
* Requirements:
*
* - the caller must be the proposer, a guardian of the targeted function, or a global admin
*
* Emits a {OperationCanceled} event.
*/
function cancel(address caller, address target, bytes calldata data) external returns (uint32);
/**
* @dev Consume a scheduled operation targeting the caller. If such an operation exists, mark it as consumed
* (emit an {OperationExecuted} event and clean the state). Otherwise, throw an error.
*
* This is useful for contract that want to enforce that calls targeting them were scheduled on the manager,
* with all the verifications that it implies.
*
* Emit a {OperationExecuted} event.
*/
function consumeScheduledOp(address caller, bytes calldata data) external;
/**
* @dev Hashing function for delayed operations.
*/
function hashOperation(address caller, address target, bytes calldata data) external view returns (bytes32);
/**
* @dev Changes the authority of a target managed by this manager instance.
*
* Requirements:
*
* - the caller must be a global admin
*/
function updateAuthority(address target, address newAuthority) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAuthority.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard interface for permissioning originally defined in Dappsys.
*/
interface IAuthority {
/**
* @dev Returns true if the caller can invoke on a target the function identified by a function selector.
*/
function canCall(address caller, address target, bytes4 selector) external view returns (bool allowed);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC3156FlashBorrower.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-3156 FlashBorrower, as defined in
* https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
*/
interface IERC3156FlashBorrower {
/**
* @dev Receive a flash loan.
* @param initiator The initiator of the loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param fee The additional amount of tokens to repay.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
* @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan"
*/
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC3156FlashLender.sol)
pragma solidity ^0.8.20;
import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol";
/**
* @dev Interface of the ERC-3156 FlashLender, as defined in
* https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
*/
interface IERC3156FlashLender {
/**
* @dev The amount of currency available to be lended.
* @param token The loan currency.
* @return The amount of `token` that can be borrowed.
*/
function maxFlashLoan(address token) external view returns (uint256);
/**
* @dev The fee to be charged for a given loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @return The amount of `token` to be charged for the loan, on top of the returned principal.
*/
function flashFee(address token, uint256 amount) external view returns (uint256);
/**
* @dev Initiate a flash loan.
* @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
*/
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 amount,
bytes calldata data
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*
* _Available since v5.1._
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2²⁵⁶ + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= prod1) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
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⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// 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²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, 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;
}
}
/**
* @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
assembly ("memory-safe") {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
uint256 exp;
unchecked {
exp = 128 * SafeCast.toUint(value > (1 << 128) - 1);
value >>= exp;
result += exp;
exp = 64 * SafeCast.toUint(value > (1 << 64) - 1);
value >>= exp;
result += exp;
exp = 32 * SafeCast.toUint(value > (1 << 32) - 1);
value >>= exp;
result += exp;
exp = 16 * SafeCast.toUint(value > (1 << 16) - 1);
value >>= exp;
result += exp;
exp = 8 * SafeCast.toUint(value > (1 << 8) - 1);
value >>= exp;
result += exp;
exp = 4 * SafeCast.toUint(value > (1 << 4) - 1);
value >>= exp;
result += exp;
exp = 2 * SafeCast.toUint(value > (1 << 2) - 1);
value >>= exp;
result += exp;
result += SafeCast.toUint(value > 1);
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
uint256 isGt;
unchecked {
isGt = SafeCast.toUint(value > (1 << 128) - 1);
value >>= isGt * 128;
result += isGt * 16;
isGt = SafeCast.toUint(value > (1 << 64) - 1);
value >>= isGt * 64;
result += isGt * 8;
isGt = SafeCast.toUint(value > (1 << 32) - 1);
value >>= isGt * 32;
result += isGt * 4;
isGt = SafeCast.toUint(value > (1 << 16) - 1);
value >>= isGt * 16;
result += isGt * 2;
result += SafeCast.toUint(value > (1 << 8) - 1);
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/types/Time.sol)
pragma solidity ^0.8.20;
import {Math} from "../math/Math.sol";
import {SafeCast} from "../math/SafeCast.sol";
/**
* @dev This library provides helpers for manipulating time-related objects.
*
* It uses the following types:
* - `uint48` for timepoints
* - `uint32` for durations
*
* While the library doesn't provide specific types for timepoints and duration, it does provide:
* - a `Delay` type to represent duration that can be programmed to change value automatically at a given point
* - additional helper functions
*/
library Time {
using Time for *;
/**
* @dev Get the block timestamp as a Timepoint.
*/
function timestamp() internal view returns (uint48) {
return SafeCast.toUint48(block.timestamp);
}
/**
* @dev Get the block number as a Timepoint.
*/
function blockNumber() internal view returns (uint48) {
return SafeCast.toUint48(block.number);
}
// ==================================================== Delay =====================================================
/**
* @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the
* future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value.
* This allows updating the delay applied to some operation while keeping some guarantees.
*
* In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for
* some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set
* the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should
* still apply for some time.
*
*
* The `Delay` type is 112 bits long, and packs the following:
*
* ```
* | [uint48]: effect date (timepoint)
* | | [uint32]: value before (duration)
* ↓ ↓ ↓ [uint32]: value after (duration)
* 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC
* ```
*
* NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently
* supported.
*/
type Delay is uint112;
/**
* @dev Wrap a duration into a Delay to add the one-step "update in the future" feature
*/
function toDelay(uint32 duration) internal pure returns (Delay) {
return Delay.wrap(duration);
}
/**
* @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled
* change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered.
*/
function _getFullAt(
Delay self,
uint48 timepoint
) private pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
(valueBefore, valueAfter, effect) = self.unpack();
return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect);
}
/**
* @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the
* effect timepoint is 0, then the pending value should not be considered.
*/
function getFull(Delay self) internal view returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
return _getFullAt(self, timestamp());
}
/**
* @dev Get the current value.
*/
function get(Delay self) internal view returns (uint32) {
(uint32 delay, , ) = self.getFull();
return delay;
}
/**
* @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to
* enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the
* new delay becomes effective.
*/
function withUpdate(
Delay self,
uint32 newValue,
uint32 minSetback
) internal view returns (Delay updatedDelay, uint48 effect) {
uint32 value = self.get();
uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0));
effect = timestamp() + setback;
return (pack(value, newValue, effect), effect);
}
/**
* @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint).
*/
function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) {
uint112 raw = Delay.unwrap(self);
valueAfter = uint32(raw);
valueBefore = uint32(raw >> 32);
effect = uint48(raw >> 64);
return (valueBefore, valueAfter, effect);
}
/**
* @dev pack the components into a Delay object.
*/
function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) {
return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter));
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { AccessManaged } from "../utils/AccessManaged.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IParallelizer } from "contracts/interfaces/IParallelizer.sol";
import { ITokenP } from "contracts/interfaces/ITokenP.sol";
import "contracts/interfaces/IHarvester.sol";
import "../utils/Errors.sol";
struct YieldBearingParams {
// Address of the asset used to mint the yield bearing asset
address asset;
// Target exposure to the collateral yield bearing asset used
uint64 targetExposure;
// Maximum exposure within the Parallelizer to the deposit asset
uint64 maxExposure;
// Minimum exposure within the Parallelizer to the deposit asset
uint64 minExposure;
// Whether limit exposures should be overriden or read onchain through the Parallelizer
// This value should be 1 to override exposures or 2 if these shouldn't be overriden
uint64 overrideExposures;
// Maximum slippage when dealing with the Parallelizer
uint96 maxSlippage;
}
/// @title BaseHarvester
/// @author Cooper Labs
/// @custom:contact [email protected]
/// @dev Abstract contract for a harvester that aims at rebalancing a Parallelizer
/// @dev This contract is an authorized fork of Angle's BaseHarvester contract:
/// https://github.com/AngleProtocol/angle-transmuter/blob/main/contracts/helpers/BaseHarvester.sol
abstract contract BaseHarvester is IHarvester, AccessManaged {
using SafeERC20 for IERC20;
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/**
* @notice Checks whether the `msg.sender` is trusted to update
* target exposure and do others non critical operations
*/
modifier onlyTrusted() {
if (!isTrusted[msg.sender]) revert NotTrusted();
_;
}
/**
* @notice Checks whether the `msg.sender` is trusted or guardian to update
* target exposure and do others non critical operations
*/
modifier onlyTrustedOrRestricted() {
if (!isTrusted[msg.sender] && !_checkCanCall(_msgSender(), _msgData())) {
revert NotTrustedOrGuardian();
}
_;
}
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VARIABLES
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/// @notice Reference to the `parallelizer` implementation this contract aims at rebalancing
IParallelizer public immutable parallelizer;
/// @notice TokenP handled by the `parallelizer` of interest
ITokenP public immutable tokenP;
/// @notice Max slippage when dealing with the Parallelizer
mapping(address => uint96) public maxTokenSlippage;
/// @notice Data associated to a yield bearing asset
mapping(address => YieldBearingParams) public yieldBearingData;
/// @notice trusted addresses that can update target exposure and do others non critical operations
mapping(address => bool) public isTrusted;
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
event Recovered(address token, uint256 amount, address to);
event TrustedToggled(address trusted, bool status);
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
constructor(
address initialAuthority,
ITokenP definitiveTokenP,
IParallelizer definitiveParallelizer
)
AccessManaged(initialAuthority)
{
tokenP = definitiveTokenP;
parallelizer = definitiveParallelizer;
}
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
GUARDIAN FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/**
* @notice Set the yieldBearingAsset data
* @param yieldBearingAsset address of the yieldBearingAsset
* @param asset address of the asset
* @param targetExposure target exposure to the yieldBearingAsset asset used
* @param minExposure minimum exposure within the Parallelizer to the asset
* @param maxExposure maximum exposure within the Parallelizer to the asset
* @param overrideExposures whether limit exposures should be overriden or read onchain through the Parallelizer
*/
function setYieldBearingAssetData(
address yieldBearingAsset,
address asset,
uint64 targetExposure,
uint64 minExposure,
uint64 maxExposure,
uint64 overrideExposures,
uint96 maxSlippage
)
external
restricted
{
_setYieldBearingAssetData(
yieldBearingAsset, asset, targetExposure, minExposure, maxExposure, overrideExposures, maxSlippage
);
}
/**
* @notice Set the limit exposures to the asset linked to the yield bearing asset
* @param yieldBearingAsset address of the yield bearing asset
*/
function updateLimitExposuresYieldAsset(address yieldBearingAsset) public virtual {
YieldBearingParams storage yieldBearingInfo = yieldBearingData[yieldBearingAsset];
if (yieldBearingInfo.overrideExposures == 2) {
_updateLimitExposuresYieldAsset(yieldBearingInfo.asset, yieldBearingInfo);
}
}
/**
* @notice Set the max allowed slippage
* @param newMaxSlippage new max allowed slippage
*/
function setMaxSlippage(address yieldBearingAsset, uint96 newMaxSlippage) external restricted {
_setMaxSlippage(yieldBearingAsset, newMaxSlippage);
}
/**
* @notice Toggle the trusted status of an address
* @param trusted address to toggle the trusted status
*/
function toggleTrusted(address trusted) external restricted {
emit TrustedToggled(trusted, isTrusted[trusted]);
isTrusted[trusted] = !isTrusted[trusted];
}
/**
* @notice Recover ERC20 tokens
* @param tokenAddress address of the token to recover
* @param amountToRecover amount to recover
* @param to address to send the recovered tokens
*/
function recoverERC20(address tokenAddress, uint256 amountToRecover, address to) external restricted {
emit Recovered(tokenAddress, amountToRecover, to);
IERC20(tokenAddress).safeTransfer(to, amountToRecover);
}
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TRUSTED FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/**
* @notice Set the target exposure of a yield bearing asset
* @param yieldBearingAsset address of the yield bearing asset
* @param targetExposure target exposure to the yield bearing asset used
*/
function setTargetExposure(address yieldBearingAsset, uint64 targetExposure) external onlyTrustedOrRestricted {
yieldBearingData[yieldBearingAsset].targetExposure = targetExposure;
}
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/**
* @notice Compute the amount needed to rebalance the Parallelizer
* @param yieldBearingAsset address of the yield bearing asset
* @return increase whether the exposure should be increased
* @return amount amount to be rebalanced
*/
function computeRebalanceAmount(address yieldBearingAsset) external view returns (uint8 increase, uint256 amount) {
return _computeRebalanceAmount(yieldBearingAsset, yieldBearingData[yieldBearingAsset]);
}
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
function _computeRebalanceAmount(
address yieldBearingAsset,
YieldBearingParams memory yieldBearingInfo
)
internal
view
returns (uint8 increase, uint256 amount)
{
(uint256 stablecoinsFromYieldBearingAsset, uint256 stablecoinsIssued) =
parallelizer.getIssuedByCollateral(yieldBearingAsset);
(uint256 stablecoinsFromAsset,) = parallelizer.getIssuedByCollateral(yieldBearingInfo.asset);
uint256 targetExposureScaled = yieldBearingInfo.targetExposure * stablecoinsIssued;
if (stablecoinsFromYieldBearingAsset * 1e9 > targetExposureScaled) {
// Need to decrease exposure to yield bearing asset
amount = stablecoinsFromYieldBearingAsset - targetExposureScaled / 1e9;
uint256 maxValueScaled = yieldBearingInfo.maxExposure * stablecoinsIssued;
// These checks assume that there are no transaction fees on the stablecoin->collateral conversion and so
// it's still possible that exposure goes above the max exposure in some rare cases
if (stablecoinsFromAsset * 1e9 > maxValueScaled) {
amount = 0;
} else if ((stablecoinsFromAsset + amount) * 1e9 > maxValueScaled) {
amount = maxValueScaled / 1e9 - stablecoinsFromAsset;
}
} else {
// In this case, exposure after the operation might remain slightly below the targetExposure as less
// collateral may be obtained by burning stablecoins for the yield asset and unwrapping it
increase = 1;
amount = targetExposureScaled / 1e9 - stablecoinsFromYieldBearingAsset;
uint256 minValueScaled = yieldBearingInfo.minExposure * stablecoinsIssued;
if (stablecoinsFromAsset * 1e9 < minValueScaled) {
amount = 0;
} else if (stablecoinsFromAsset * 1e9 < minValueScaled + amount * 1e9) {
amount = stablecoinsFromAsset - minValueScaled / 1e9;
}
}
}
function _setYieldBearingAssetData(
address yieldBearingAsset,
address asset,
uint64 targetExposure,
uint64 minExposure,
uint64 maxExposure,
uint64 overrideExposures,
uint96 maxSlippage
)
internal
virtual
{
YieldBearingParams storage yieldBearingInfo = yieldBearingData[yieldBearingAsset];
yieldBearingInfo.asset = asset;
if (targetExposure >= 1e9) revert InvalidParam();
if (maxSlippage >= 1e9) revert InvalidParam();
yieldBearingInfo.targetExposure = targetExposure;
yieldBearingInfo.overrideExposures = overrideExposures;
yieldBearingInfo.maxSlippage = maxSlippage;
if (overrideExposures == 1) {
if (maxExposure >= 1e9 || minExposure >= maxExposure) revert InvalidParam();
yieldBearingInfo.maxExposure = maxExposure;
yieldBearingInfo.minExposure = minExposure;
} else {
yieldBearingInfo.overrideExposures = 2;
_updateLimitExposuresYieldAsset(asset, yieldBearingInfo);
}
}
function _updateLimitExposuresYieldAsset(
address asset,
YieldBearingParams storage yieldBearingInfo
)
internal
virtual
{
uint64[] memory xFeeMint;
(xFeeMint,) = parallelizer.getCollateralMintFees(asset);
uint256 length = xFeeMint.length;
if (length <= 1) yieldBearingInfo.maxExposure = 1e9;
else yieldBearingInfo.maxExposure = xFeeMint[length - 2];
uint64[] memory xFeeBurn;
(xFeeBurn,) = parallelizer.getCollateralBurnFees(asset);
length = xFeeBurn.length;
if (length <= 1) yieldBearingInfo.minExposure = 0;
else yieldBearingInfo.minExposure = xFeeBurn[length - 2];
}
function _setMaxSlippage(address yieldBearingAsset, uint96 newMaxSlippage) internal virtual {
if (newMaxSlippage > 1e9) revert InvalidParam();
maxTokenSlippage[yieldBearingAsset] = newMaxSlippage;
}
function _scaleAmountBasedOnDecimals(
uint256 decimalsTokenIn,
uint256 decimalsTokenOut,
uint256 amountIn,
bool assetIn
)
internal
pure
returns (uint256)
{
if (decimalsTokenIn > decimalsTokenOut) {
if (assetIn) {
amountIn /= 10 ** (decimalsTokenIn - decimalsTokenOut);
} else {
amountIn *= 10 ** (decimalsTokenIn - decimalsTokenOut);
}
} else if (decimalsTokenIn < decimalsTokenOut) {
if (assetIn) {
amountIn *= 10 ** (decimalsTokenOut - decimalsTokenIn);
} else {
amountIn /= 10 ** (decimalsTokenOut - decimalsTokenIn);
}
}
return amountIn;
}
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HELPER
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
function _adjustAllowance(address token, address sender, uint256 amountIn) internal {
uint256 allowance = IERC20(token).allowance(address(this), sender);
if (allowance < amountIn) IERC20(token).safeIncreaseAllowance(sender, type(uint256).max - allowance);
}
}// SPDX-License-Identifier: MIT pragma solidity 0.8.28; import "../parallelizer/Storage.sol"; /// @title IDiamondCut /// @author Cooper Labs /// @custom:contact [email protected] /// @dev Reference: EIP-2535 Diamonds /// @dev Forked from https://github.com/mudgen/diamond-3/blob/master/contracts/interfaces/IDiamondCut.sol by mudgen /// @dev This interface is an authorized fork of Angle's `IDiamondCut` interface /// https://github.com/AngleProtocol/angle-transmuter/blob/main/contracts/interfaces/IDiamondCut.sol interface IDiamondCut { /// @notice Add/replace/remove any number of functions and optionally execute a function with delegatecall /// @param _diamondCut Contains the facet addresses and function selectors /// @param _init The address of the contract or facet to execute _calldata /// @param _calldata A function call, including function selector and arguments, executed with delegatecall on /// _init function diamondCut(FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.28; /// @title IDiamondEtherscan /// @author Cooper Labs /// @custom:contact [email protected] interface IDiamondEtherscan { /// @notice Sets a dummy implementation with the same layout at the diamond proxy contract with all its facets function setDummyImplementation(address _implementation) external; /// @notice Address of the dummy implementation used to make the DiamondProxy contract interpretable by Etherscan function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.28; import "../parallelizer/Storage.sol"; /// @notice IDiamondLoupe /// @author Cooper Labs /// @custom:contact [email protected] /// @dev Reference: EIP-2535 Diamonds /// @dev Forked from https://github.com/mudgen/diamond-3/blob/master/contracts/interfaces/IDiamondLoupe.sol by mudgen interface IDiamondLoupe { /// @notice Gets all facet addresses and their four byte function selectors. /// @return facets_ Facet function facets() external view returns (Facet[] memory facets_); /// @notice Gets all the function selectors supported by a specific facet. /// @param _facet The facet address. /// @return facetFunctionSelectors_ function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_); /// @notice Get all the facet addresses used by a diamond. /// @return facetAddresses_ function facetAddresses() external view returns (address[] memory facetAddresses_); /// @notice Gets the facet that supports the given selector. /// @dev If facet is not found return address(0). /// @param _functionSelector The function selector. /// @return facetAddress_ The facet address. function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_); }
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { ITokenP } from "contracts/interfaces/ITokenP.sol";
import "../parallelizer/Storage.sol";
/// @title IGetters
/// @author Cooper Labs
/// @custom:contact [email protected]
/// @dev This interface is an authorized fork of Angle's `IGetters` interface
/// https://github.com/AngleProtocol/angle-transmuter/blob/main/contracts/interfaces/IGetters.sol
interface IGetters {
/// @notice Checks whether a given `selector` is actually a valid selector corresponding to a function in one of
/// the
/// facets of the proxy
function isValidSelector(bytes4 selector) external view returns (bool);
/// @notice Stablecoin minted by parallelizer
function tokenP() external view returns (ITokenP);
/// @notice Returns the list of collateral assets supported by the system
function getCollateralList() external view returns (address[] memory);
/// @notice Returns all the info in storage associated to a `collateral`
function getCollateralInfo(address collateral) external view returns (Collateral memory);
/// @notice Returns the decimals of a given `collateral`
function getCollateralDecimals(address collateral) external view returns (uint8);
/// @notice Returns the `xFee` and `yFee` arrays from which fees are computed when coming to mint
/// with `collateral`
function getCollateralMintFees(address collateral) external view returns (uint64[] memory, int64[] memory);
/// @notice Returns the `xFee` and `yFee` arrays from which fees are computed when coming to burn
/// for `collateral`
function getCollateralBurnFees(address collateral) external view returns (uint64[] memory, int64[] memory);
/// @notice Returns the `xFee` and `yFee` arrays used to compute the penalty factor depending on the collateral
/// ratio when users come to redeem
function getRedemptionFees() external view returns (uint64[] memory, int64[] memory);
/// @notice Returns the collateral ratio of Parallelizer in base `10**9` and a rounded version of the total amount
/// of stablecoins issued
function getCollateralRatio() external view returns (uint64 collatRatio, uint256 stablecoinsIssued);
/// @notice Returns the total amount of stablecoins issued through Parallelizer
function getTotalIssued() external view returns (uint256 stablecoinsIssued);
/// @notice Returns the amount of stablecoins issued from `collateral` and the total amount of stablecoins issued
/// through Parallelizer
function getIssuedByCollateral(address collateral)
external
view
returns (uint256 stablecoinsFromCollateral, uint256 stablecoinsIssued);
/// @notice Returns if a collateral is "managed" and the associated manager configuration
function getManagerData(address collateral)
external
view
returns (bool isManaged, IERC20[] memory subCollaterals, bytes memory config);
/// @notice Returns the oracle values associated to `collateral`
/// @return mint Oracle value to be used for a mint transaction with `collateral`
/// @return burn Oracle value that will be used for `collateral` for a burn transaction. This value
/// is then used along with oracle values for all other collateral assets to get a global burn value for the oracle
/// @return ratio Ratio, in base `10**18` between the oracle value of the `collateral` and its target price.
/// This value is 10**18 if the oracle is greater than the collateral price
/// @return minRatio Minimum ratio across all collateral assets between a collateral burn price and its target
/// price. This value is independent of `collateral` and is used to normalize the burn oracle value for burn
/// transactions.
/// @return redemption Oracle value that would be used to price `collateral` when computing the collateral ratio
/// during a redemption
function getOracleValues(address collateral)
external
view
returns (uint256 mint, uint256 burn, uint256 ratio, uint256 minRatio, uint256 redemption);
/// @notice Returns the data used to compute oracle values for `collateral`
/// @return oracleType Type of oracle (Chainlink, external smart contract, ...)
/// @return targetType Type passed to read the value of the target price
/// @return oracleData Extra data needed to read the oracle. For Chainlink oracles, this data is supposed to give
/// the addresses of the Chainlink feeds to read, the stale periods for each feed, ...
/// @return targetData Extra data needed to read the target price of the asset
function getOracle(address collateral)
external
view
returns (
OracleReadType oracleType,
OracleReadType targetType,
bytes memory oracleData,
bytes memory targetData,
bytes memory hyperparameters
);
/// @notice Returns if the associated functionality is paused or not
function isPaused(address collateral, ActionType action) external view returns (bool);
/// @notice Returns if `sender` is trusted to update normalizers
function isTrusted(address sender) external view returns (bool);
/// @notice Returns if `sender` is trusted to update sell rewards
function isTrustedSeller(address sender) external view returns (bool);
/// @notice Checks whether `sender` has a non null entry in the `isWhitelistedForType` storage mapping
/// @dev Note that ultimately whitelisting may depend as well on external providers
function isWhitelistedForType(WhitelistType whitelistType, address sender) external view returns (bool);
/// @notice Checks whether `sender` can deal with `collateral` during burns and redemptions
function isWhitelistedForCollateral(address collateral, address sender) external returns (bool);
/// @notice Checks whether only whitelisted address can deal with `collateral` during burns and redemptions
function isWhitelistedCollateral(address collateral) external view returns (bool);
/// @notice Gets the data needed to deal with whitelists for `collateral`
function getCollateralWhitelistData(address collateral) external view returns (bytes memory);
/// @notice Returns the stablecoin cap for `collateral`
function getStablecoinCap(address collateral) external view returns (uint256);
/// @notice Returns the address of the `accessManager` contract
function accessManager() external view returns (address);
/// @dev Returns true only in the context of a delayed restricted call, at the moment that the scheduled operation is
/// being consumed. Prevents denial of service for delayed restricted calls in the case that the contract performs
/// attacker controlled calls.
function isConsumingScheduledOp() external view returns (bytes4);
}// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.28; /// @title IHarvester /// @author Cooper Labs /// @custom:contact [email protected] /// @dev This interface is an authorized fork of Angle's `IHarvester` interface /// https://github.com/AngleProtocol/angle-transmuter/blob/main/contracts/interfaces/IHarvester.sol interface IHarvester { function setYieldBearingAssetData( address yieldBearingAsset, address stablecoin, uint64 targetExposure, uint64 minExposureYieldAsset, uint64 maxExposureYieldAsset, uint64 overrideExposures, uint96 maxSlippage ) external; function updateLimitExposuresYieldAsset(address yieldBearingAsset) external; function setMaxSlippage(address yieldBearingAsset, uint96 newMaxSlippage) external; function harvest(address yieldBearingAsset, uint256 scale, bytes calldata extraData) external; }
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { IDiamondCut } from "./IDiamondCut.sol";
import { IDiamondEtherscan } from "./IDiamondEtherscan.sol";
import { IDiamondLoupe } from "./IDiamondLoupe.sol";
import { IGetters } from "./IGetters.sol";
import { IRedeemer } from "./IRedeemer.sol";
import { IRewardHandler } from "./IRewardHandler.sol";
import { ISettersGovernor, ISettersGuardian } from "./ISetters.sol";
import { ISwapper } from "./ISwapper.sol";
/// @title IParallelizer
/// @author Cooper Labs
/// @custom:contact [email protected]
/// @dev This interface is an authorized fork of Angle's `IParallelizer` interface
/// https://github.com/AngleProtocol/angle-transmuter/blob/main/contracts/interfaces/IParallelizer.sol
interface IParallelizer is
IDiamondCut,
IDiamondEtherscan,
IDiamondLoupe,
IGetters,
IRedeemer,
IRewardHandler,
ISettersGovernor,
ISettersGuardian,
ISwapper
{ }// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.28; /// @title IRedeemer /// @author Cooper Labs /// @custom:contact [email protected] /// @dev This interface is an authorized fork of Angle's `IRedeemer` interface /// https://github.com/AngleProtocol/angle-transmuter/blob/main/contracts/interfaces/IRedeemer.sol interface IRedeemer { /// @notice Redeems `amount` of stablecoins from the system /// @param receiver Address which should be receiving the output tokens /// @param deadline Timestamp before which the redemption should have occured /// @param minAmountOuts Minimum amount of each token given back in the redemption to obtain /// @return tokens List of tokens returned /// @return amounts Amount given for each token in the `tokens` array function redeem( uint256 amount, address receiver, uint256 deadline, uint256[] memory minAmountOuts ) external returns (address[] memory tokens, uint256[] memory amounts); /// @notice Same as the redeem function above with the additional feature to specify a list of `forfeitTokens` for /// which the Parallelizer system will not try to do a transfer to `receiver`. function redeemWithForfeit( uint256 amount, address receiver, uint256 deadline, uint256[] memory minAmountOuts, address[] memory forfeitTokens ) external returns (address[] memory tokens, uint256[] memory amounts); /// @notice Simulate the exact output that a redemption of `amount` of stablecoins would give at a given block /// @return tokens List of tokens that would be given /// @return amounts Amount that would be obtained for each token in the `tokens` array function quoteRedemptionCurve(uint256 amount) external view returns (address[] memory tokens, uint256[] memory amounts); /// @notice Updates the normalizer variable by `amount` function updateNormalizer(uint256 amount, bool increase) external returns (uint256); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.28; /// @title IRewardHandler /// @author Cooper Labs /// @custom:contact [email protected] /// @dev This interface is an authorized fork of Angle's `IRewardHandler` interface /// https://github.com/AngleProtocol/angle-transmuter/blob/main/contracts/interfaces/IRewardHandler.sol interface IRewardHandler { /// @notice Sells some external tokens through a odos call /// @param minAmountOut Minimum amount of the outToken to get /// @param payload Payload to pass to odos /// @return amountOut Amount obtained of the outToken function sellRewards(uint256 minAmountOut, bytes memory payload) external returns (uint256 amountOut); }
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol";
import "../parallelizer/Storage.sol";
/// @title ISettersGovernor
/// @author Cooper Labs
/// @custom:contact [email protected]
/// @dev This interface is an authorized fork of Angle's `ISettersGovernor` interface
/// https://github.com/AngleProtocol/angle-transmuter/blob/main/contracts/interfaces/ISetters.sol
interface ISettersGovernor {
/// @notice Recovers `amount` of `token` from the Parallelizer contract
function recoverERC20(address collateral, IERC20 token, address to, uint256 amount) external;
/// @notice Sets a new access manager address
function setAccessManager(address _newAccessManager) external;
/// @notice Sets (or unsets) a collateral manager `collateral`
/// @dev If `checkExternalManagerBalance` is true, the function will check that the current manager no longer has
/// assets before setting the new manager
function setCollateralManager(
address collateral,
bool checkExternalManagerBalance,
ManagerStorage memory managerData
)
external;
/// @notice Sets the allowance of the contract on `token` for `spender` to `amount`
function changeAllowance(IERC20 token, address spender, uint256 amount) external;
/// @notice Changes the trusted status for `sender` when for selling rewards or updating the normalizer
function toggleTrusted(address sender, TrustedType t) external;
/// @notice Changes whether a `collateral` can only be handled during burns and redemptions by whitelisted
/// addresses
/// and sets the data used to read into the whitelist
function setWhitelistStatus(address collateral, uint8 whitelistStatus, bytes memory whitelistData) external;
/// @notice Add `collateral` as a supported collateral in the system
function addCollateral(address collateral) external;
/// @notice Adjusts the amount of stablecoins issued from `collateral` by `amount`
function adjustStablecoins(address collateral, uint128 amount, bool increase) external;
/// @notice Revokes `collateral` from the system
/// @dev If `checkExternalManagerBalance` is true, the function will check that the current manager no longer has
/// assets before revoking the collateral
function revokeCollateral(address collateral, bool checkExternalManagerBalance) external;
/// @notice Sets the `oracleConfig` used to read the value of `collateral` for the mint, burn and redemption
/// operations
function setOracle(address collateral, bytes memory oracleConfig) external;
/// @notice Update oracle data for a given `collateral`
function updateOracle(address collateral) external;
}
/// @title ISettersGovernor
/// @author Cooper Labs
/// @custom:contact [email protected]
interface ISettersGuardian {
/// @notice Changes the pause status for mint or burn transactions for `collateral`
function togglePause(address collateral, ActionType action) external;
/// @notice Sets the mint or burn fees for `collateral`
function setFees(address collateral, uint64[] memory xFee, int64[] memory yFee, bool mint) external;
/// @notice Sets the parameters for the redemption curve
function setRedemptionCurveParams(uint64[] memory xFee, int64[] memory yFee) external;
/// @notice Changes the whitelist status for a collateral with `whitelistType` for an address `who`
function toggleWhitelist(WhitelistType whitelistType, address who) external;
/// @notice Sets the stablecoin cap that can be issued from a `collateral`
function setStablecoinCap(address collateral, uint256 stablecoinCap) external;
}// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.28; /// @title ISwapper /// @author Cooper Labs /// @custom:contact [email protected] /// @dev This interface is an authorized fork of Angle's `ISwapper` interface /// https://github.com/AngleProtocol/angle-transmuter/blob/main/contracts/interfaces/ISwapper.sol interface ISwapper { /// @notice Swaps (that is to say mints or burns) an exact amount of `tokenIn` for an amount of `tokenOut` /// @param amountIn Amount of `tokenIn` to bring /// @param amountOutMin Minimum amount of `tokenOut` to get: if `amountOut` is inferior to this amount, the /// function will revert /// @param tokenIn Token to bring for the swap /// @param tokenOut Token to get out of the swap /// @param to Address to which `tokenOut` must be sent /// @param deadline Timestamp before which the transaction must be executed /// @return amountOut Amount of `tokenOut` obtained through the swap function swapExactInput( uint256 amountIn, uint256 amountOutMin, address tokenIn, address tokenOut, address to, uint256 deadline ) external returns (uint256 amountOut); /// @notice Same as `swapExactInput`, but using Permit2 signatures for `tokenIn` /// @dev Can only be used to mint, hence `tokenOut` is not needed function swapExactInputWithPermit( uint256 amountIn, uint256 amountOutMin, address tokenIn, address to, uint256 deadline, bytes calldata permitData ) external returns (uint256 amountOut); /// @notice Swaps (that is to say mints or burns) an amount of `tokenIn` for an exact amount of `tokenOut` /// @param amountOut Amount of `tokenOut` to obtain from the swap /// @param amountInMax Maximum amount of `tokenIn` to bring in order to get `amountOut` of `tokenOut` /// @param tokenIn Token to bring for the swap /// @param tokenOut Token to get out of the swap /// @param to Address to which `tokenOut` must be sent /// @param deadline Timestamp before which the transaction must be executed /// @return amountIn Amount of `tokenIn` used to perform the swap function swapExactOutput( uint256 amountOut, uint256 amountInMax, address tokenIn, address tokenOut, address to, uint256 deadline ) external returns (uint256 amountIn); /// @notice Same as `swapExactOutput`, but using Permit2 signatures for `tokenIn` /// @dev Can only be used to mint, hence `tokenOut` is not needed function swapExactOutputWithPermit( uint256 amountOut, uint256 amountInMax, address tokenIn, address to, uint256 deadline, bytes calldata permitData ) external returns (uint256 amountIn); /// @notice Simulates what a call to `swapExactInput` with `amountIn` of `tokenIn` for `tokenOut` would give. /// If called right before and at the same block, the `amountOut` outputted by this function is exactly the /// amount that will be obtained with `swapExactInput` function quoteIn(uint256 amountIn, address tokenIn, address tokenOut) external view returns (uint256 amountOut); /// @notice Simulates what a call to `swapExactOutput` for `amountOut` of `tokenOut` with `tokenIn` would give. /// If called right before and at the same block, the `amountIn` outputted by this function is exactly the /// amount that will be obtained with `swapExactOutput` function quoteOut(uint256 amountOut, address tokenIn, address tokenOut) external view returns (uint256 amountIn); }
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/// @title ITokenP
/// @author Cooper Labs
/// @custom:contact [email protected]
/// @notice Interface for the stablecoins `tokenP` contracts
/// @dev This interface is an authorized fork of Angle's `IAgToken` interface
/// https://github.com/AngleProtocol/angle-transmuter/blob/main/contracts/interfaces/IAgToken.sol
interface ITokenP is IERC20 {
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
MINTER ROLE ONLY FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/// @notice Lets a whitelisted contract mint tokenPs
/// @param account Address to mint to
/// @param amount Amount to mint
function mint(address account, uint256 amount) external;
/// @notice Burns `amount` tokens from a `burner` address after being asked to by `sender`
/// @param amount Amount of tokens to burn
/// @param burner Address to burn from
/// @param sender Address which requested the burn from `burner`
/// @dev This method is to be called by a contract with the minter right after being requested
/// to do so by a `sender` address willing to burn tokens from another `burner` address
/// @dev The method checks the allowance between the `sender` and the `burner`
function burnFrom(uint256 amount, address burner, address sender) external;
/// @notice Burns `amount` tokens from a `burner` address
/// @param amount Amount of tokens to burn
/// @param burner Address to burn from
/// @dev This method is to be called by a contract with a minter right on the tokenP after being
/// requested to do so by an address willing to burn tokens from its address
function burnSelf(uint256 amount, address burner) external;
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
EXTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
/// @notice Amount of decimals of the stablecoin
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: GPL-3.0
// OpenZeppelin Contracts (last updated v4.7.0) (interfaces/IERC4626.sol)
pragma solidity >=0.5.0;
/// @notice ERC4626 interface
/// @author OpenZeppelin
/// @dev In this implementation, the interface only contains the functions that the IERC4626 interface adds on top of
/// the IERC20 interface
interface IERC4626 {
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IAccessManager } from "@openzeppelin/contracts/access/manager/IAccessManager.sol";
import { ITokenP } from "contracts/interfaces/ITokenP.sol";
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ENUMS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
enum FacetCutAction {
Add,
Replace,
Remove
}
enum ManagerType {
EXTERNAL
}
enum ActionType {
Mint,
Burn,
Redeem
}
enum TrustedType {
Updater,
Seller
}
enum QuoteType {
MintExactInput,
MintExactOutput,
BurnExactInput,
BurnExactOutput
}
enum OracleReadType {
CHAINLINK_FEEDS,
EXTERNAL,
NO_ORACLE,
STABLE,
WSTETH,
CBETH,
RETH,
SFRXETH,
MAX,
MORPHO_ORACLE
}
enum OracleQuoteType {
UNIT,
TARGET
}
enum WhitelistType {
BACKED
}
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
STRUCTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
struct Permit2Details {
address to; // Address that will receive the funds
uint256 nonce; // Nonce of the transaction
bytes signature; // Permit signature of the user
}
struct FacetCut {
address facetAddress; // Facet contract address
FacetCutAction action; // Can be add, remove or replace
bytes4[] functionSelectors; // Ex. bytes4(keccak256("transfer(address,uint256)"))
}
struct Facet {
address facetAddress; // Facet contract address
bytes4[] functionSelectors; // Ex. bytes4(keccak256("transfer(address,uint256)"))
}
struct FacetInfo {
address facetAddress; // Facet contract address
uint16 selectorPosition; // Position in the list of all selectors
}
struct DiamondStorage {
bytes4[] selectors; // List of all available selectors
mapping(bytes4 => FacetInfo) selectorInfo; // Selector to (address, position in list)
IAccessManager accessManager; // Contract handling access management
}
struct ImplementationStorage {
address implementation; // Dummy implementation address for Etherscan usability
}
struct ManagerStorage {
IERC20[] subCollaterals; // Subtokens handled by the manager or strategies
bytes config; // Additional configuration data
}
struct Collateral {
uint8 isManaged; // If the collateral is managed through external strategies
uint8 isMintLive; // If minting from this asset is unpaused
uint8 isBurnLive; // If burning to this asset is unpaused
uint8 decimals; // IERC20Metadata(collateral).decimals()
uint8 onlyWhitelisted; // If only whitelisted addresses can burn or redeem for this token
uint216 normalizedStables; // Normalized amount of stablecoins issued from this collateral
uint64[] xFeeMint; // Increasing exposures in [0,BASE_9[
int64[] yFeeMint; // Mint fees at the exposures specified in `xFeeMint`
uint64[] xFeeBurn; // Decreasing exposures in ]0,BASE_9]
int64[] yFeeBurn; // Burn fees at the exposures specified in `xFeeBurn`
bytes oracleConfig; // Data about the oracle used for the collateral
bytes whitelistData; // For whitelisted collateral, data used to verify whitelists
ManagerStorage managerData; // For managed collateral, data used to handle the strategies
uint256 stablecoinCap; // Cap on the amount of stablecoins that can be issued from this collateral
}
struct ParallelizerStorage {
ITokenP tokenP; // tokenP handled by the system
uint8 isRedemptionLive; // If redemption is unpaused
uint8 statusReentrant; // If call is reentrant or not
bool consumingSchedule; // If the contract is consuming a scheduled operation
uint128 normalizedStables; // Normalized amount of stablecoins issued by the system
uint128 normalizer; // To reconcile `normalizedStables` values with the actual amount
address[] collateralList; // List of collateral assets supported by the system
uint64[] xRedemptionCurve; // Increasing collateral ratios > 0
int64[] yRedemptionCurve; // Value of the redemption fees at `xRedemptionCurve`
mapping(address => Collateral) collaterals; // Maps a collateral asset to its parameters
mapping(address => uint256) isTrusted; // If an address is trusted to update the normalizer value
mapping(address => uint256) isSellerTrusted; // If an address is trusted to sell accruing reward tokens or to run
// keeper jobs on oracles
mapping(WhitelistType => mapping(address => uint256)) isWhitelistedForType;
}
// Whether an address is whitelisted for a specific whitelist type// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import { AuthorityUtils } from "@openzeppelin/contracts/access/manager/AuthorityUtils.sol";
import { IAccessManager } from "@openzeppelin/contracts/access/manager/IAccessManager.sol";
import { IAccessManaged } from "@openzeppelin/contracts/access/manager/IAccessManaged.sol";
import { Context } from "@openzeppelin/contracts/utils/Context.sol";
import "../utils/Errors.sol";
/// @title AccessControl
/// @author Cooper Labs
/// @custom:contact [email protected]
/// @dev Fork of OpenZeppelin's `AccessManaged` contract
/// updated to make _checkCanCall to return bool
/// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/manager/AccessManaged.sol
contract AccessManaged is Context, IAccessManaged {
address private _authority;
bool private _consumingSchedule;
/**
* @dev Initializes the contract connected to an initial authority.
*/
constructor(address initialAuthority) {
_setAuthority(initialAuthority);
}
/**
* @dev Restricts access to a function as defined by the connected Authority for this contract and the
* caller and selector of the function that entered the contract.
*
* [IMPORTANT]
* ====
* In general, this modifier should only be used on `external` functions. It is okay to use it on `public`
* functions that are used as external entry points and are not called internally. Unless you know what you're
* doing, it should never be used on `internal` functions. Failure to follow these rules can have critical security
* implications! This is because the permissions are determined by the function that entered the contract, i.e. the
* function at the bottom of the call stack, and not the function where the modifier is visible in the source code.
* ====
*
* [WARNING]
* ====
* Avoid adding this modifier to the
* https://docs.soliditylang.org/en/v0.8.20/contracts.html#receive-ether-function[`receive()`]
* function or the https://docs.soliditylang.org/en/v0.8.20/contracts.html#fallback-function[`fallback()`]. These
* functions are the only execution paths where a function selector cannot be unambiguously determined from the
* calldata
* since the selector defaults to `0x00000000` in the `receive()` function and similarly in the `fallback()`
* function
* if no calldata is provided. (See {_checkCanCall}).
*
* The `receive()` function will always panic whereas the `fallback()` may panic depending on the calldata length.
* ====
*/
modifier restricted() {
address caller = _msgSender();
require(_checkCanCall(caller, _msgData()), AccessManagedUnauthorized(caller));
_;
}
/// @inheritdoc IAccessManaged
function authority() public view virtual returns (address) {
return _authority;
}
/// @inheritdoc IAccessManaged
function setAuthority(address newAuthority) public virtual {
address caller = _msgSender();
if (caller != authority()) {
revert AccessManagedUnauthorized(caller);
}
if (newAuthority.code.length == 0) {
revert AccessManagedInvalidAuthority(newAuthority);
}
_setAuthority(newAuthority);
}
/// @inheritdoc IAccessManaged
function isConsumingScheduledOp() public view returns (bytes4) {
return _consumingSchedule ? this.isConsumingScheduledOp.selector : bytes4(0);
}
/**
* @dev Transfers control to a new authority. Internal function with no access restriction. Allows bypassing the
* permissions set by the current authority.
*/
function _setAuthority(address newAuthority) internal virtual {
_authority = newAuthority;
emit AuthorityUpdated(newAuthority);
}
function _checkCanCall(address caller, bytes calldata data) internal virtual returns (bool) {
(bool immediate, uint32 delay) =
AuthorityUtils.canCallWithDelay(authority(), caller, address(this), bytes4(data[0:4]));
if (!immediate) {
if (delay > 0) {
_consumingSchedule = true;
IAccessManager(authority()).consumeScheduledOp(caller, data);
_consumingSchedule = false;
} else {
return false;
}
}
return true;
}
}// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.28; error AccessManagedUnauthorized(address caller); error AlreadyAdded(); error CannotAddFunctionToDiamondThatAlreadyExists(bytes4 _selector); error CannotAddSelectorsToZeroAddress(bytes4[] _selectors); error CannotRemoveFunctionThatDoesNotExist(bytes4 _selector); error CannotRemoveImmutableFunction(bytes4 _selector); error CannotReplaceFunctionsFromFacetWithZeroAddress(bytes4[] _selectors); error CannotReplaceFunctionThatDoesNotExists(bytes4 _selector); error CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet(bytes4 _selector); error CannotReplaceImmutableFunction(bytes4 _selector); error ContractHasNoCode(); error CollateralBacked(); error FunctionNotFound(bytes4 _functionSelector); error IncorrectFacetCutAction(uint8 _action); error InitializationFunctionReverted(address _initializationContractAddress, bytes _calldata); error InvalidChainlinkRate(); error InvalidLengths(); error InvalidNegativeFees(); error InvalidOracleType(); error InvalidParam(); error InvalidParams(); error InvalidRate(); error InvalidSwap(); error InvalidTokens(); error InvalidAccessManager(); error ManagerHasAssets(); error NoSelectorsProvidedForFacetForCut(address _facetAddress); error NotAllowed(); error NotCollateral(); error NotGovernor(); error NotGuardian(); error NotTrusted(); error NotTrustedOrGuardian(); error NotWhitelisted(); error OdosSwapFailed(); error OracleUpdateFailed(); error Paused(); error ReentrantCall(); error RemoveFacetAddressMustBeZeroAddress(address _facetAddress); error TooBigAmountIn(); error TooLate(); error TooSmallAmountOut(); error ZeroAddress(); error ZeroAmount(); error SwapError(); error SlippageTooHigh(); error InsufficientFunds();
{
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": [],
"viaIR": true,
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"initialTokenTransferAddress","type":"address"},{"internalType":"address","name":"initialSwapRouter","type":"address"},{"internalType":"contract ITokenP","name":"definitivetokenP","type":"address"},{"internalType":"contract IParallelizer","name":"definitiveParallelizer","type":"address"},{"internalType":"address","name":"initialAuthority","type":"address"},{"internalType":"contract IERC3156FlashLender","name":"definitiveFlashloan","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"authority","type":"address"}],"name":"AccessManagedInvalidAuthority","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"uint32","name":"delay","type":"uint32"}],"name":"AccessManagedRequiredDelay","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"AccessManagedUnauthorized","type":"error"},{"inputs":[],"name":"InvalidParam","type":"error"},{"inputs":[],"name":"NotTrusted","type":"error"},{"inputs":[],"name":"NotTrustedOrGuardian","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SwapError","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"authority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newSwapRouter","type":"address"}],"name":"SwapRouterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newTokenTransferAddress","type":"address"}],"name":"TokenTransferAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"trusted","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"TrustedToggled","type":"event"},{"inputs":[],"name":"CALLBACK_SUCCESS","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"addBudget","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"budget","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"yieldBearingAsset","type":"address"}],"name":"computeRebalanceAmount","outputs":[{"internalType":"uint8","name":"increase","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flashloan","outputs":[{"internalType":"contract IERC3156FlashLender","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"yieldBearingAsset","type":"address"},{"internalType":"uint256","name":"scale","type":"uint256"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isConsumingScheduledOp","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isTrusted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxTokenSlippage","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onFlashLoan","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"parallelizer","outputs":[{"internalType":"contract IParallelizer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amountToRecover","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"removeBudget","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"yieldBearingAsset","type":"address"},{"internalType":"uint96","name":"newMaxSlippage","type":"uint96"}],"name":"setMaxSlippage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSwapRouter","type":"address"}],"name":"setSwapRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"yieldBearingAsset","type":"address"},{"internalType":"uint64","name":"targetExposure","type":"uint64"}],"name":"setTargetExposure","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTokenTransferAddress","type":"address"}],"name":"setTokenTransferAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"yieldBearingAsset","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint64","name":"targetExposure","type":"uint64"},{"internalType":"uint64","name":"minExposure","type":"uint64"},{"internalType":"uint64","name":"maxExposure","type":"uint64"},{"internalType":"uint64","name":"overrideExposures","type":"uint64"},{"internalType":"uint96","name":"maxSlippage","type":"uint96"}],"name":"setYieldBearingAssetData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trusted","type":"address"}],"name":"toggleTrusted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenP","outputs":[{"internalType":"contract ITokenP","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenTransferAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"yieldBearingAsset","type":"address"}],"name":"updateLimitExposuresYieldAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"yieldBearingData","outputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint64","name":"targetExposure","type":"uint64"},{"internalType":"uint64","name":"maxExposure","type":"uint64"},{"internalType":"uint64","name":"minExposure","type":"uint64"},{"internalType":"uint64","name":"overrideExposures","type":"uint64"},{"internalType":"uint96","name":"maxSlippage","type":"uint96"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60e080604052346101e95760c08161278a803803809161001f828561020f565b8339810103126101e95761003281610246565b9061003f60208201610246565b6040820151926001600160a01b038416918285036101e95760608401516001600160a01b03811681036101e95760a061007a60808701610246565b950151956001600160a01b038716958688036101e9575f80546001600160a01b0319166001600160a01b0390921691821790556040519081527f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad90602090a160a052608052600480546001600160a01b039283166001600160a01b0319918216179091556005805493909216921691909117905581156102005760446020925f9460c052604051948593849263095ea7b360e01b84526004840152811960248401525af180156101f5576101b9575b60405161252f908161025b823960805181818161027601528181610ce401528181610e1b01528181611d1901526120ab015260a0518181816103bf0152818161066a01528181610e480152818161155201526115d9015260c05181818161040701528181610d5901526115960152f35b6020813d6020116101ed575b816101d26020938361020f565b810103126101e95751801515036101e9575f610149565b5f80fd5b3d91506101c5565b6040513d5f823e3d90fd5b63d92e233d60e01b5f5260045ffd5b601f909101601f19168101906001600160401b0382119082101761023257604052565b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036101e95756fe60806040526004361015610011575f80fd5b5f5f3560e01c80630dd3932d1461164357806313047520146115fd5780631978a5ed146115ba5780631b89b61a14611577578063212c8fb1146114be57806323e30c8b14610d0857806335b37d1a14610cc55780634127365714610c435780635a7cb38f14610c1d578063641bd50314610b6b5780637a9e5e4b14610a9d5780637ee8434914610a0c5780638195001d146109eb5780638237e538146109b15780638fb360371461093e57806396d64879146109015780639ae784861461082c578063b51609b4146107a5578063bf7e214f14610780578063c31c9c071461075a578063c5e6d5ea146106c9578063c9c6667414610691578063d2d0ec1014610628578063da94e205146105af578063e234b903146105005763edf0ef0314610138575f80fd5b346104ac5760603660031901126104ac57610151611899565b60243560443567ffffffffffffffff81116104ac576101749036906004016118c5565b9290633b9aca0083116104d8578161018d600293611a0c565b6001600160a01b03811690815f5283602052633b9aca0061022c61022460405f206bffffffffffffffffffffffff6040519889926101ca8461194b565b67ffffffffffffffff81546001600160a01b038116865260a01c16602085015267ffffffffffffffff60018201548181166040870152818160401c16606087015260801c1660808501520154169460a08201958652611d0c565b979097611a52565b049586156104b0578301926040818503126104ac5780359360028510156104ac57602082013567ffffffffffffffff81116104ac5761026b92016119b9565b936001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b156104ac575f80916024604051809481937f1cb44dfc0000000000000000000000000000000000000000000000000000000083528960048401525af1610490575b506001600160a01b036bffffffffffffffffffffffff915116915116633b9aca00036bffffffffffffffffffffffff811161047c5760ff946103fa97946103849460209894633b9aca0061033e6bffffffffffffffffffffffff61037697168a611a52565b0491604051998a97338d8a01521660408801526060870152608086015260a085015260c084015260e0808401526101008301906122e5565b03601f19810184528361197b565b60405193849283927f5cffe9de0000000000000000000000000000000000000000000000000000000084523060048501526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016602485015260448401526080606484015260848301906122e5565b0381856001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1801561047157610437575080f35b6020813d602011610469575b816104506020938361197b565b810103126104655761046190612309565b5080f35b5080fd5b3d9150610443565b6040513d84823e3d90fd5b602488634e487b7160e01b81526011600452fd5b61049d9198505f9061197b565b5f966001600160a01b036102d9565b5f80fd5b7f1f2a2005000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd2529034000000000000000000000000000000000000000000000000000000005f5260045ffd5b346104ac5760203660031901126104ac576001600160a01b03610521611899565b6105343361052f3633611a65565b6118f3565b168015610587576020817ffd238617dbf7bc2e2e9c11b00a61a76432989bf0d6ca3a5aa34381a8752db4039273ffffffffffffffffffffffffffffffffffffffff196005541617600555604051908152a1005b7fd92e233d000000000000000000000000000000000000000000000000000000005f5260045ffd5b346104ac5760403660031901126104ac576105c8611899565b602435906bffffffffffffffffffffffff82168092036104ac576105f03361052f3633611a65565b633b9aca0082116104d8576001600160a01b03165f52600160205260405f20906bffffffffffffffffffffffff198254161790555f80f35b346104ac5760403660031901126104ac5761068f6004356106476118af565b335f52600660205260405f2061065e8382546119ff565b90556001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001661228e565b005b346104ac5760203660031901126104ac576001600160a01b036106b2611899565b165f526006602052602060405f2054604051908152f35b346104ac5760203660031901126104ac576001600160a01b036106ea611899565b165f52600260205260c060405f2080549067ffffffffffffffff6bffffffffffffffffffffffff60026001840154930154169181604051946001600160a01b038116865260a01c1660208501528181166040850152818160401c16606085015260801c16608083015260a0820152f35b346104ac575f3660031901126104ac5760206001600160a01b0360045416604051908152f35b346104ac575f3660031901126104ac5760206001600160a01b035f5416604051908152f35b346104ac5760603660031901126104ac576107be611899565b6024356044356001600160a01b0381168082036104ac577fb197f0a554c4d7840105e6ae65f0e275e9e8605a969dffa8caa7f1f118a2e1f5606061068f9561080a3361052f3633611a65565b6001600160a01b036040519116938482528660208301526040820152a161228e565b346104ac5760403660031901126104ac57610845611899565b60243567ffffffffffffffff811681036104ac57335f52600360205260ff60405f20541615806108f0575b6108c8576001600160a01b0361068f92165f52600260205260405f20907fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff67ffffffffffffffff60a01b83549260a01b169116179055565b7f0dcc030f000000000000000000000000000000000000000000000000000000005f5260045ffd5b506108fb3633611a65565b15610870565b346104ac5760203660031901126104ac576001600160a01b03610922611899565b165f526003602052602060ff60405f2054166040519015158152f35b346104ac575f3660031901126104ac575f5460a01c60ff16156109a95760207f8fb36037000000000000000000000000000000000000000000000000000000005b7fffffffff0000000000000000000000000000000000000000000000000000000060405191168152f35b60205f61097f565b346104ac575f3660031901126104ac5760206040517f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd98152f35b346104ac5760203660031901126104ac5761068f610a07611899565b611a0c565b346104ac5760203660031901126104ac576001600160a01b03610a2d611899565b610a3b3361052f3633611a65565b16805f5260036020527f7628ea5f6112a16b36a8239aa208395a8e8f221688cfb3a5461faffb9700abcd604060ff815f20541681519084825215156020820152a15f908152600360205260409020805460ff818116151660ff19909116179055005b346104ac5760203660031901126104ac57610ab6611899565b5f54906001600160a01b0382163303610b5957803b15610b245773ffffffffffffffffffffffffffffffffffffffff197f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad926001600160a01b036020931691829116175f55604051908152a1005b6001600160a01b03907fc2f31e5e000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b62d1953b60e31b5f523360045260245ffd5b346104ac5760203660031901126104ac576040610c0e610b89611899565b6001600160a01b0381165f526002602052825f20906bffffffffffffffffffffffff6002855193610bb98561194b565b67ffffffffffffffff81546001600160a01b038116875260a01c16602086015267ffffffffffffffff60018201548181168988015281818a1c16606088015260801c16608086015201541660a0830152611d0c565b60ff8351921682526020820152f35b346104ac575f3660031901126104ac5760206001600160a01b0360055416604051908152f35b346104ac5760203660031901126104ac576001600160a01b03610c64611899565b610c723361052f3633611a65565b168015610587576020817f36db479a3b4d3672bd6f5fca4484283f60b5ac70647b1ceec13ecbb1d030a2df9273ffffffffffffffffffffffffffffffffffffffff196004541617600455604051908152a1005b346104ac575f3660031901126104ac5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346104ac5760a03660031901126104ac57610d21611899565b610d296118af565b5060443560843567ffffffffffffffff81116104ac57610d4d9036906004016118c5565b90926001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163314908115916114aa575b50801561149f575b6114775782019060e0838303126104ac57610da683611937565b92610db360408201611937565b610dbf60608301611937565b60a08301359460028610156104ac5760c08401359067ffffffffffffffff82116104ac57610df96001600160a01b039291839287016119b9565b9216921694600160208501351495865f146114715792915b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169687926001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001694604051926301db50ff60e51b84528960048501525f602485015286604485015260208460c4815f6001600160a01b0387169a8b60648401523060848401524260a48401525af19384156110c6575f9461143d575b505f926001810361129957505050506001600160a01b03851690604051936370a0823160e01b8552306004860152602085602481865afa9485156110c6575f95611265575b50604093845192610f13868561197b565b60018452601f1986019283366020870137610f2d8561206b565b52855191610f3b878461197b565b600183525f5b8481106112545750610f528361206b565b52610f5c8261206b565b50855192610f6a878561197b565b60018452366020850137610f7d8361206b565b528251925f5b84811061111957505050505060206024918351928380926370a0823160e01b82523060048301525afa91821561111057505f916110d1575b5060809660c4936001600160a01b03610fd960209897955f956119ff565b945b610fe6868583611c6b565b6040519a8b9889976301db50ff60e51b895260048901520135602487015216604485015260648401523060848401524260a48401525af19182156110c6575f92611092575b5081811161105e575b60206040517f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd98152f35b6001600160a01b0391611070916119ff565b91165f52600660205261108860405f209182546119ff565b9055808080611034565b9091506020813d6020116110be575b816110ae6020938361197b565b810103126104ac5751908361102b565b3d91506110a1565b6040513d5f823e3d90fd5b905060209493919294813d602011611108575b816110f16020938361197b565b810103126104ac5751929390929091906080610fbb565b3d91506110e4565b513d5f823e3d90fd5b6001600160a01b0361112b828461208c565b51166001600160a01b036005541690611144838761208c565b518951636eb1769f60e11b81523060048201526001600160a01b03841660248201529290602084604481865afa93841561124a575f94611217575b508084106111fb575b505050505f80611198838661208c565b516001600160a01b036004541682602083519301915af16111b7612316565b90156111c65750600101610f83565b805190816111f6577f7c3eb9ca000000000000000000000000000000000000000000000000000000005f5260045ffd5b602001fd5b61120e93611208916119ff565b916123b2565b8e808080611188565b9093506020813d8211611242575b816112326020938361197b565b810103126104ac5751925f61117f565b3d9150611225565b8b513d5f823e3d90fd5b806060602080938701015201610f41565b9094506020813d602011611291575b816112816020938361197b565b810103126104ac5751938b610f02565b3d9150611274565b90919394505f9a979592989a50156112c9575b50505050925f6080969360c4936001600160a01b03602097610fdb565b93965091928692901561139357506112e2918391611c6b565b604051907f6e553f6500000000000000000000000000000000000000000000000000000000825260048201523060248201526020816044815f6001600160a01b0389165af19081156110c6575f91611359575b50925f6080969360c4936001600160a01b036020975b9750829699508195506112ac565b95929390506020863d60201161138b575b816113776020938361197b565b810103126104ac579451919492915f611335565b3d915061136a565b90506020915060645f9360405194859384927fba08765200000000000000000000000000000000000000000000000000000000845260048401523060248401523060448401525af19081156110c6575f91611403575b50925f6080969360c4936001600160a01b0360209761134b565b95929390506020863d602011611435575b816114216020938361197b565b810103126104ac579451919492915f6113e9565b3d9150611414565b9093506020813d602011611469575b816114596020938361197b565b810103126104ac5751928c610ebd565b3d915061144c565b91610e11565b7fc22a648e000000000000000000000000000000000000000000000000000000005f5260045ffd5b506064351515610d8c565b6001600160a01b0316301415905084610d84565b346104ac5760403660031901126104ac5761068f6004356001600160a01b036114e56118af565b165f52600660205260405f206114fc828254611916565b9055604051907f23b872dd00000000000000000000000000000000000000000000000000000000602083015233602483015230604483015260648201526064815261154860848261197b565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016612345565b346104ac575f3660031901126104ac5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346104ac575f3660031901126104ac5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346104ac5760203660031901126104ac576001600160a01b0361161e611899565b165f52600160205260206bffffffffffffffffffffffff60405f205416604051908152f35b346104ac5760e03660031901126104ac5761165c611899565b6116646118af565b6044359167ffffffffffffffff8316918284036104ac576064359267ffffffffffffffff8416918285036104ac576084359567ffffffffffffffff87168097036104ac5760a4359467ffffffffffffffff8616908187036104ac5760c435906bffffffffffffffffffffffff82168092036104ac576001600160a01b03906116f03361052f3633611a65565b165f526002602052633b9aca0060405f20956001600160a01b03861673ffffffffffffffffffffffffffffffffffffffff1988541617875510156104d857633b9aca008110156104d85761177d60019386907fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff67ffffffffffffffff60a01b83549260a01b169116179055565b828501967fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff77ffffffffffffffff0000000000000000000000000000000089549260801b16911617875560028501906bffffffffffffffffffffffff19825416179055145f1461185157505083633b9aca00811091821592611846575b50506104d85761068f9267ffffffffffffffff19825416178155906fffffffffffffffff0000000000000000196fffffffffffffffff000000000000000083549260401b169116179055565b1015905083856117fa565b929150925061068f93507002000000000000000000000000000000007fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8254161790556120a0565b600435906001600160a01b03821682036104ac57565b602435906001600160a01b03821682036104ac57565b9181601f840112156104ac5782359167ffffffffffffffff83116104ac57602083818601950101116104ac57565b156118fb5750565b6001600160a01b039062d1953b60e31b5f521660045260245ffd5b9190820180921161192357565b634e487b7160e01b5f52601160045260245ffd5b35906001600160a01b03821682036104ac57565b60c0810190811067ffffffffffffffff82111761196757604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761196757604052565b67ffffffffffffffff811161196757601f01601f191660200190565b81601f820112156104ac578035906119d08261199d565b926119de604051948561197b565b828452602083830101116104ac57815f926020809301838601378301015290565b9190820391821161192357565b6001600160a01b03165f52600260205260405f20600267ffffffffffffffff600183015460801c1614611a3c5750565b806001600160a01b03611a509254166120a0565b565b8181029291811591840414171561192357565b905f915f54916001600160a01b03831692816004116104ac575f5f905f80604051966001600160a01b0360208901917fb700961300000000000000000000000000000000000000000000000000000000835216978860248201523060448201527fffffffff00000000000000000000000000000000000000000000000000000000833516606482015260648152611afd60848261197b565b5190895afa611b0a612316565b90611bf2575b5015611b22575b505050505050600190565b63ffffffff1615611be95760ff60a01b191674010000000000000000000000000000000000000000175f55823b156104ac576064925f92836040519586809581947f94c7d7ee0000000000000000000000000000000000000000000000000000000083526004830152604060248301528060448301528084848401378181018301849052601f01601f191681010301925af180156110c657611bd6575b5060ff60a01b1981541690555f8080808080611b17565b611be291505f9061197b565b5f5f611bbf565b50505050505f90565b80519092909160408310611c3457505081604091810103126104ac576040611c1c60208301612309565b91015163ffffffff811681036104ac57905b5f611b10565b916020819492941015611c49575b5050611c2e565b81925090602091810103126104ac576020611c649101612309565b5f80611c42565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152909391169190602084604481865afa9384156110c6575f94611cc2575b508310611cb757505050565b611a509219916123b2565b9093506020813d602011611cee575b81611cde6020938361197b565b810103126104ac5751925f611cab565b3d9150611cd1565b91908260409103126104ac576020825192015190565b915f926001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906001600160a01b0360405191634a71aecf60e11b8352166004820152604081602481855afa9081156110c6575f905f92611f28575b5060406001600160a01b038651166024825180968193634a71aecf60e11b835260048301525afa9283156110c6575f93611ef6575b50611dbd8267ffffffffffffffff602088015116611a52565b633b9aca008202828104633b9aca00148315171561192357811015611e6d576040611dfc611e059493633b9aca0067ffffffffffffffff9404906119ff565b96015116611a52565b633b9aca008202828104633b9aca00148315171561192357811015611e2b57505f925050565b611e358483611916565b633b9aca00810290808204633b9aca001490151715611923578110611e58575050565b611e6a929350633b9aca0090046119ff565b90565b95509067ffffffffffffffff6060611dfc611e9094633b9aca0060019a046119ff565b633b9aca008202828104633b9aca0014831517156119235781811015611eb857505f93505050565b633b9aca008502858104633b9aca00148615171561192357611eda9083611916565b11611ee3575050565b611e6a929350633b9aca009004906119ff565b611f1991935060403d604011611f21575b611f11818361197b565b810190611cf6565b50915f611da4565b503d611f07565b9050611f43915060403d604011611f2157611f11818361197b565b905f611d6f565b67ffffffffffffffff81116119675760051b60200190565b91906040838203126104ac57825167ffffffffffffffff81116104ac57830181601f820112156104ac578051611f9781611f4a565b91611fa5604051938461197b565b81835260208084019260051b820101908482116104ac57602001915b81831061204a575050509260208101519067ffffffffffffffff82116104ac57019080601f830112156104ac57815190611ffa82611f4a565b92612008604051948561197b565b82845260208085019360051b8201019182116104ac57602001915b8183106120305750505090565b82518060070b81036104ac57815260209283019201612023565b825167ffffffffffffffff811681036104ac57815260209283019201611fc1565b8051156120785760200190565b634e487b7160e01b5f52603260045260245ffd5b80518210156120785760209160051b010190565b906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916001600160a01b03604051917fb85780bc000000000000000000000000000000000000000000000000000000008352168060048301525f82602481875afa9182156110c6575f92612271575b5081516001811161222b575060018301805467ffffffffffffffff1916633b9aca001790555f91505b6024604051809581937f847da7be00000000000000000000000000000000000000000000000000000000835260048301525afa9182156110c6575f92612206575b50815191600183116121ac575060010180546fffffffffffffffff00000000000000001916905550565b60011983019283116119235767ffffffffffffffff6121d0611a509460019361208c565b51169101906fffffffffffffffff0000000000000000196fffffffffffffffff000000000000000083549260401b169116179055565b6122239192503d805f833e61221b818361197b565b810190611f62565b50905f612182565b60011981019081116119235761224b67ffffffffffffffff915f9461208c565b511667ffffffffffffffff60018501911667ffffffffffffffff19825416179055612141565b6122869192503d805f833e61221b818361197b565b50905f612118565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0390921660248301526044820192909252611a50916122e08260648101610376565b612345565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b519081151582036104ac57565b3d15612340573d906123278261199d565b91612335604051938461197b565b82523d5f602084013e565b606090565b905f602091828151910182855af1156110c6575f513d6123a957506001600160a01b0381163b155b6123745750565b6001600160a01b03907f5274afe7000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b6001141561236d565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152929392821692602082604481875afa80156110c6575f906124c5575b6123fb9250611916565b9160205f60405194612446866124388582019363095ea7b360e01b85528a60248401602090939291936001600160a01b0360408201951681520152565b03601f19810188528761197b565b85519082865af1903d5f5190836124a6575b5050501561246557505050565b6122e0611a50936001600160a01b036040519163095ea7b360e01b60208401521660248201525f6044820152604481526124a060648261197b565b82612345565b919250906124bb57503b15155b5f8080612458565b60019150146124b3565b506020823d6020116124f1575b816124df6020938361197b565b810103126104ac576123fb91516123f1565b3d91506124d256fea2646970667358221220ec283012c4b4807e318035ba023be8591bf414e2388206dea6cd585b6cb7364064736f6c634300081c0033000000000000000000000000ac041df48df9791b0654f1dbbf2cc8450c5f2e9d000000000000000000000000ac041df48df9791b0654f1dbbf2cc8450c5f2e9d00000000000000000000000008417cdb7f52a5021bb4eb6e0deaf3f295c3f182000000000000000000000000befbae2330186f031b469e26283acc66bb5f88260000000000000000000000008efb3ded78fbaef2a4efe01e01bbd911e4094b780000000000000000000000002cb56df31b909854b01d4b1ead5676cf90e885e7
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f5f3560e01c80630dd3932d1461164357806313047520146115fd5780631978a5ed146115ba5780631b89b61a14611577578063212c8fb1146114be57806323e30c8b14610d0857806335b37d1a14610cc55780634127365714610c435780635a7cb38f14610c1d578063641bd50314610b6b5780637a9e5e4b14610a9d5780637ee8434914610a0c5780638195001d146109eb5780638237e538146109b15780638fb360371461093e57806396d64879146109015780639ae784861461082c578063b51609b4146107a5578063bf7e214f14610780578063c31c9c071461075a578063c5e6d5ea146106c9578063c9c6667414610691578063d2d0ec1014610628578063da94e205146105af578063e234b903146105005763edf0ef0314610138575f80fd5b346104ac5760603660031901126104ac57610151611899565b60243560443567ffffffffffffffff81116104ac576101749036906004016118c5565b9290633b9aca0083116104d8578161018d600293611a0c565b6001600160a01b03811690815f5283602052633b9aca0061022c61022460405f206bffffffffffffffffffffffff6040519889926101ca8461194b565b67ffffffffffffffff81546001600160a01b038116865260a01c16602085015267ffffffffffffffff60018201548181166040870152818160401c16606087015260801c1660808501520154169460a08201958652611d0c565b979097611a52565b049586156104b0578301926040818503126104ac5780359360028510156104ac57602082013567ffffffffffffffff81116104ac5761026b92016119b9565b936001600160a01b037f000000000000000000000000befbae2330186f031b469e26283acc66bb5f882616803b156104ac575f80916024604051809481937f1cb44dfc0000000000000000000000000000000000000000000000000000000083528960048401525af1610490575b506001600160a01b036bffffffffffffffffffffffff915116915116633b9aca00036bffffffffffffffffffffffff811161047c5760ff946103fa97946103849460209894633b9aca0061033e6bffffffffffffffffffffffff61037697168a611a52565b0491604051998a97338d8a01521660408801526060870152608086015260a085015260c084015260e0808401526101008301906122e5565b03601f19810184528361197b565b60405193849283927f5cffe9de0000000000000000000000000000000000000000000000000000000084523060048501526001600160a01b037f00000000000000000000000008417cdb7f52a5021bb4eb6e0deaf3f295c3f18216602485015260448401526080606484015260848301906122e5565b0381856001600160a01b037f0000000000000000000000002cb56df31b909854b01d4b1ead5676cf90e885e7165af1801561047157610437575080f35b6020813d602011610469575b816104506020938361197b565b810103126104655761046190612309565b5080f35b5080fd5b3d9150610443565b6040513d84823e3d90fd5b602488634e487b7160e01b81526011600452fd5b61049d9198505f9061197b565b5f966001600160a01b036102d9565b5f80fd5b7f1f2a2005000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd2529034000000000000000000000000000000000000000000000000000000005f5260045ffd5b346104ac5760203660031901126104ac576001600160a01b03610521611899565b6105343361052f3633611a65565b6118f3565b168015610587576020817ffd238617dbf7bc2e2e9c11b00a61a76432989bf0d6ca3a5aa34381a8752db4039273ffffffffffffffffffffffffffffffffffffffff196005541617600555604051908152a1005b7fd92e233d000000000000000000000000000000000000000000000000000000005f5260045ffd5b346104ac5760403660031901126104ac576105c8611899565b602435906bffffffffffffffffffffffff82168092036104ac576105f03361052f3633611a65565b633b9aca0082116104d8576001600160a01b03165f52600160205260405f20906bffffffffffffffffffffffff198254161790555f80f35b346104ac5760403660031901126104ac5761068f6004356106476118af565b335f52600660205260405f2061065e8382546119ff565b90556001600160a01b037f00000000000000000000000008417cdb7f52a5021bb4eb6e0deaf3f295c3f1821661228e565b005b346104ac5760203660031901126104ac576001600160a01b036106b2611899565b165f526006602052602060405f2054604051908152f35b346104ac5760203660031901126104ac576001600160a01b036106ea611899565b165f52600260205260c060405f2080549067ffffffffffffffff6bffffffffffffffffffffffff60026001840154930154169181604051946001600160a01b038116865260a01c1660208501528181166040850152818160401c16606085015260801c16608083015260a0820152f35b346104ac575f3660031901126104ac5760206001600160a01b0360045416604051908152f35b346104ac575f3660031901126104ac5760206001600160a01b035f5416604051908152f35b346104ac5760603660031901126104ac576107be611899565b6024356044356001600160a01b0381168082036104ac577fb197f0a554c4d7840105e6ae65f0e275e9e8605a969dffa8caa7f1f118a2e1f5606061068f9561080a3361052f3633611a65565b6001600160a01b036040519116938482528660208301526040820152a161228e565b346104ac5760403660031901126104ac57610845611899565b60243567ffffffffffffffff811681036104ac57335f52600360205260ff60405f20541615806108f0575b6108c8576001600160a01b0361068f92165f52600260205260405f20907fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff67ffffffffffffffff60a01b83549260a01b169116179055565b7f0dcc030f000000000000000000000000000000000000000000000000000000005f5260045ffd5b506108fb3633611a65565b15610870565b346104ac5760203660031901126104ac576001600160a01b03610922611899565b165f526003602052602060ff60405f2054166040519015158152f35b346104ac575f3660031901126104ac575f5460a01c60ff16156109a95760207f8fb36037000000000000000000000000000000000000000000000000000000005b7fffffffff0000000000000000000000000000000000000000000000000000000060405191168152f35b60205f61097f565b346104ac575f3660031901126104ac5760206040517f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd98152f35b346104ac5760203660031901126104ac5761068f610a07611899565b611a0c565b346104ac5760203660031901126104ac576001600160a01b03610a2d611899565b610a3b3361052f3633611a65565b16805f5260036020527f7628ea5f6112a16b36a8239aa208395a8e8f221688cfb3a5461faffb9700abcd604060ff815f20541681519084825215156020820152a15f908152600360205260409020805460ff818116151660ff19909116179055005b346104ac5760203660031901126104ac57610ab6611899565b5f54906001600160a01b0382163303610b5957803b15610b245773ffffffffffffffffffffffffffffffffffffffff197f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad926001600160a01b036020931691829116175f55604051908152a1005b6001600160a01b03907fc2f31e5e000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b62d1953b60e31b5f523360045260245ffd5b346104ac5760203660031901126104ac576040610c0e610b89611899565b6001600160a01b0381165f526002602052825f20906bffffffffffffffffffffffff6002855193610bb98561194b565b67ffffffffffffffff81546001600160a01b038116875260a01c16602086015267ffffffffffffffff60018201548181168988015281818a1c16606088015260801c16608086015201541660a0830152611d0c565b60ff8351921682526020820152f35b346104ac575f3660031901126104ac5760206001600160a01b0360055416604051908152f35b346104ac5760203660031901126104ac576001600160a01b03610c64611899565b610c723361052f3633611a65565b168015610587576020817f36db479a3b4d3672bd6f5fca4484283f60b5ac70647b1ceec13ecbb1d030a2df9273ffffffffffffffffffffffffffffffffffffffff196004541617600455604051908152a1005b346104ac575f3660031901126104ac5760206040516001600160a01b037f000000000000000000000000befbae2330186f031b469e26283acc66bb5f8826168152f35b346104ac5760a03660031901126104ac57610d21611899565b610d296118af565b5060443560843567ffffffffffffffff81116104ac57610d4d9036906004016118c5565b90926001600160a01b037f0000000000000000000000002cb56df31b909854b01d4b1ead5676cf90e885e7163314908115916114aa575b50801561149f575b6114775782019060e0838303126104ac57610da683611937565b92610db360408201611937565b610dbf60608301611937565b60a08301359460028610156104ac5760c08401359067ffffffffffffffff82116104ac57610df96001600160a01b039291839287016119b9565b9216921694600160208501351495865f146114715792915b6001600160a01b037f000000000000000000000000befbae2330186f031b469e26283acc66bb5f8826169687926001600160a01b037f00000000000000000000000008417cdb7f52a5021bb4eb6e0deaf3f295c3f1821694604051926301db50ff60e51b84528960048501525f602485015286604485015260208460c4815f6001600160a01b0387169a8b60648401523060848401524260a48401525af19384156110c6575f9461143d575b505f926001810361129957505050506001600160a01b03851690604051936370a0823160e01b8552306004860152602085602481865afa9485156110c6575f95611265575b50604093845192610f13868561197b565b60018452601f1986019283366020870137610f2d8561206b565b52855191610f3b878461197b565b600183525f5b8481106112545750610f528361206b565b52610f5c8261206b565b50855192610f6a878561197b565b60018452366020850137610f7d8361206b565b528251925f5b84811061111957505050505060206024918351928380926370a0823160e01b82523060048301525afa91821561111057505f916110d1575b5060809660c4936001600160a01b03610fd960209897955f956119ff565b945b610fe6868583611c6b565b6040519a8b9889976301db50ff60e51b895260048901520135602487015216604485015260648401523060848401524260a48401525af19182156110c6575f92611092575b5081811161105e575b60206040517f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd98152f35b6001600160a01b0391611070916119ff565b91165f52600660205261108860405f209182546119ff565b9055808080611034565b9091506020813d6020116110be575b816110ae6020938361197b565b810103126104ac5751908361102b565b3d91506110a1565b6040513d5f823e3d90fd5b905060209493919294813d602011611108575b816110f16020938361197b565b810103126104ac5751929390929091906080610fbb565b3d91506110e4565b513d5f823e3d90fd5b6001600160a01b0361112b828461208c565b51166001600160a01b036005541690611144838761208c565b518951636eb1769f60e11b81523060048201526001600160a01b03841660248201529290602084604481865afa93841561124a575f94611217575b508084106111fb575b505050505f80611198838661208c565b516001600160a01b036004541682602083519301915af16111b7612316565b90156111c65750600101610f83565b805190816111f6577f7c3eb9ca000000000000000000000000000000000000000000000000000000005f5260045ffd5b602001fd5b61120e93611208916119ff565b916123b2565b8e808080611188565b9093506020813d8211611242575b816112326020938361197b565b810103126104ac5751925f61117f565b3d9150611225565b8b513d5f823e3d90fd5b806060602080938701015201610f41565b9094506020813d602011611291575b816112816020938361197b565b810103126104ac5751938b610f02565b3d9150611274565b90919394505f9a979592989a50156112c9575b50505050925f6080969360c4936001600160a01b03602097610fdb565b93965091928692901561139357506112e2918391611c6b565b604051907f6e553f6500000000000000000000000000000000000000000000000000000000825260048201523060248201526020816044815f6001600160a01b0389165af19081156110c6575f91611359575b50925f6080969360c4936001600160a01b036020975b9750829699508195506112ac565b95929390506020863d60201161138b575b816113776020938361197b565b810103126104ac579451919492915f611335565b3d915061136a565b90506020915060645f9360405194859384927fba08765200000000000000000000000000000000000000000000000000000000845260048401523060248401523060448401525af19081156110c6575f91611403575b50925f6080969360c4936001600160a01b0360209761134b565b95929390506020863d602011611435575b816114216020938361197b565b810103126104ac579451919492915f6113e9565b3d9150611414565b9093506020813d602011611469575b816114596020938361197b565b810103126104ac5751928c610ebd565b3d915061144c565b91610e11565b7fc22a648e000000000000000000000000000000000000000000000000000000005f5260045ffd5b506064351515610d8c565b6001600160a01b0316301415905084610d84565b346104ac5760403660031901126104ac5761068f6004356001600160a01b036114e56118af565b165f52600660205260405f206114fc828254611916565b9055604051907f23b872dd00000000000000000000000000000000000000000000000000000000602083015233602483015230604483015260648201526064815261154860848261197b565b6001600160a01b037f00000000000000000000000008417cdb7f52a5021bb4eb6e0deaf3f295c3f18216612345565b346104ac575f3660031901126104ac5760206040516001600160a01b037f0000000000000000000000002cb56df31b909854b01d4b1ead5676cf90e885e7168152f35b346104ac575f3660031901126104ac5760206040516001600160a01b037f00000000000000000000000008417cdb7f52a5021bb4eb6e0deaf3f295c3f182168152f35b346104ac5760203660031901126104ac576001600160a01b0361161e611899565b165f52600160205260206bffffffffffffffffffffffff60405f205416604051908152f35b346104ac5760e03660031901126104ac5761165c611899565b6116646118af565b6044359167ffffffffffffffff8316918284036104ac576064359267ffffffffffffffff8416918285036104ac576084359567ffffffffffffffff87168097036104ac5760a4359467ffffffffffffffff8616908187036104ac5760c435906bffffffffffffffffffffffff82168092036104ac576001600160a01b03906116f03361052f3633611a65565b165f526002602052633b9aca0060405f20956001600160a01b03861673ffffffffffffffffffffffffffffffffffffffff1988541617875510156104d857633b9aca008110156104d85761177d60019386907fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff67ffffffffffffffff60a01b83549260a01b169116179055565b828501967fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff77ffffffffffffffff0000000000000000000000000000000089549260801b16911617875560028501906bffffffffffffffffffffffff19825416179055145f1461185157505083633b9aca00811091821592611846575b50506104d85761068f9267ffffffffffffffff19825416178155906fffffffffffffffff0000000000000000196fffffffffffffffff000000000000000083549260401b169116179055565b1015905083856117fa565b929150925061068f93507002000000000000000000000000000000007fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8254161790556120a0565b600435906001600160a01b03821682036104ac57565b602435906001600160a01b03821682036104ac57565b9181601f840112156104ac5782359167ffffffffffffffff83116104ac57602083818601950101116104ac57565b156118fb5750565b6001600160a01b039062d1953b60e31b5f521660045260245ffd5b9190820180921161192357565b634e487b7160e01b5f52601160045260245ffd5b35906001600160a01b03821682036104ac57565b60c0810190811067ffffffffffffffff82111761196757604052565b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761196757604052565b67ffffffffffffffff811161196757601f01601f191660200190565b81601f820112156104ac578035906119d08261199d565b926119de604051948561197b565b828452602083830101116104ac57815f926020809301838601378301015290565b9190820391821161192357565b6001600160a01b03165f52600260205260405f20600267ffffffffffffffff600183015460801c1614611a3c5750565b806001600160a01b03611a509254166120a0565b565b8181029291811591840414171561192357565b905f915f54916001600160a01b03831692816004116104ac575f5f905f80604051966001600160a01b0360208901917fb700961300000000000000000000000000000000000000000000000000000000835216978860248201523060448201527fffffffff00000000000000000000000000000000000000000000000000000000833516606482015260648152611afd60848261197b565b5190895afa611b0a612316565b90611bf2575b5015611b22575b505050505050600190565b63ffffffff1615611be95760ff60a01b191674010000000000000000000000000000000000000000175f55823b156104ac576064925f92836040519586809581947f94c7d7ee0000000000000000000000000000000000000000000000000000000083526004830152604060248301528060448301528084848401378181018301849052601f01601f191681010301925af180156110c657611bd6575b5060ff60a01b1981541690555f8080808080611b17565b611be291505f9061197b565b5f5f611bbf565b50505050505f90565b80519092909160408310611c3457505081604091810103126104ac576040611c1c60208301612309565b91015163ffffffff811681036104ac57905b5f611b10565b916020819492941015611c49575b5050611c2e565b81925090602091810103126104ac576020611c649101612309565b5f80611c42565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152909391169190602084604481865afa9384156110c6575f94611cc2575b508310611cb757505050565b611a509219916123b2565b9093506020813d602011611cee575b81611cde6020938361197b565b810103126104ac5751925f611cab565b3d9150611cd1565b91908260409103126104ac576020825192015190565b915f926001600160a01b037f000000000000000000000000befbae2330186f031b469e26283acc66bb5f882616906001600160a01b0360405191634a71aecf60e11b8352166004820152604081602481855afa9081156110c6575f905f92611f28575b5060406001600160a01b038651166024825180968193634a71aecf60e11b835260048301525afa9283156110c6575f93611ef6575b50611dbd8267ffffffffffffffff602088015116611a52565b633b9aca008202828104633b9aca00148315171561192357811015611e6d576040611dfc611e059493633b9aca0067ffffffffffffffff9404906119ff565b96015116611a52565b633b9aca008202828104633b9aca00148315171561192357811015611e2b57505f925050565b611e358483611916565b633b9aca00810290808204633b9aca001490151715611923578110611e58575050565b611e6a929350633b9aca0090046119ff565b90565b95509067ffffffffffffffff6060611dfc611e9094633b9aca0060019a046119ff565b633b9aca008202828104633b9aca0014831517156119235781811015611eb857505f93505050565b633b9aca008502858104633b9aca00148615171561192357611eda9083611916565b11611ee3575050565b611e6a929350633b9aca009004906119ff565b611f1991935060403d604011611f21575b611f11818361197b565b810190611cf6565b50915f611da4565b503d611f07565b9050611f43915060403d604011611f2157611f11818361197b565b905f611d6f565b67ffffffffffffffff81116119675760051b60200190565b91906040838203126104ac57825167ffffffffffffffff81116104ac57830181601f820112156104ac578051611f9781611f4a565b91611fa5604051938461197b565b81835260208084019260051b820101908482116104ac57602001915b81831061204a575050509260208101519067ffffffffffffffff82116104ac57019080601f830112156104ac57815190611ffa82611f4a565b92612008604051948561197b565b82845260208085019360051b8201019182116104ac57602001915b8183106120305750505090565b82518060070b81036104ac57815260209283019201612023565b825167ffffffffffffffff811681036104ac57815260209283019201611fc1565b8051156120785760200190565b634e487b7160e01b5f52603260045260245ffd5b80518210156120785760209160051b010190565b906001600160a01b037f000000000000000000000000befbae2330186f031b469e26283acc66bb5f882616916001600160a01b03604051917fb85780bc000000000000000000000000000000000000000000000000000000008352168060048301525f82602481875afa9182156110c6575f92612271575b5081516001811161222b575060018301805467ffffffffffffffff1916633b9aca001790555f91505b6024604051809581937f847da7be00000000000000000000000000000000000000000000000000000000835260048301525afa9182156110c6575f92612206575b50815191600183116121ac575060010180546fffffffffffffffff00000000000000001916905550565b60011983019283116119235767ffffffffffffffff6121d0611a509460019361208c565b51169101906fffffffffffffffff0000000000000000196fffffffffffffffff000000000000000083549260401b169116179055565b6122239192503d805f833e61221b818361197b565b810190611f62565b50905f612182565b60011981019081116119235761224b67ffffffffffffffff915f9461208c565b511667ffffffffffffffff60018501911667ffffffffffffffff19825416179055612141565b6122869192503d805f833e61221b818361197b565b50905f612118565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b0390921660248301526044820192909252611a50916122e08260648101610376565b612345565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b519081151582036104ac57565b3d15612340573d906123278261199d565b91612335604051938461197b565b82523d5f602084013e565b606090565b905f602091828151910182855af1156110c6575f513d6123a957506001600160a01b0381163b155b6123745750565b6001600160a01b03907f5274afe7000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b6001141561236d565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152929392821692602082604481875afa80156110c6575f906124c5575b6123fb9250611916565b9160205f60405194612446866124388582019363095ea7b360e01b85528a60248401602090939291936001600160a01b0360408201951681520152565b03601f19810188528761197b565b85519082865af1903d5f5190836124a6575b5050501561246557505050565b6122e0611a50936001600160a01b036040519163095ea7b360e01b60208401521660248201525f6044820152604481526124a060648261197b565b82612345565b919250906124bb57503b15155b5f8080612458565b60019150146124b3565b506020823d6020116124f1575b816124df6020938361197b565b810103126104ac576123fb91516123f1565b3d91506124d256fea2646970667358221220ec283012c4b4807e318035ba023be8591bf414e2388206dea6cd585b6cb7364064736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ac041df48df9791b0654f1dbbf2cc8450c5f2e9d000000000000000000000000ac041df48df9791b0654f1dbbf2cc8450c5f2e9d00000000000000000000000008417cdb7f52a5021bb4eb6e0deaf3f295c3f182000000000000000000000000befbae2330186f031b469e26283acc66bb5f88260000000000000000000000008efb3ded78fbaef2a4efe01e01bbd911e4094b780000000000000000000000002cb56df31b909854b01d4b1ead5676cf90e885e7
-----Decoded View---------------
Arg [0] : initialTokenTransferAddress (address): 0xaC041Df48dF9791B0654f1Dbbf2CC8450C5f2e9D
Arg [1] : initialSwapRouter (address): 0xaC041Df48dF9791B0654f1Dbbf2CC8450C5f2e9D
Arg [2] : definitivetokenP (address): 0x08417cdb7F52a5021bB4eb6E0deAf3f295c3f182
Arg [3] : definitiveParallelizer (address): 0xBEFBAe2330186F031b469e26283aCc66bb5F8826
Arg [4] : initialAuthority (address): 0x8eFb3DED78FbaEF2a4eFe01E01BBD911E4094b78
Arg [5] : definitiveFlashloan (address): 0x2cb56dF31b909854B01D4B1EAd5676cf90e885E7
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000ac041df48df9791b0654f1dbbf2cc8450c5f2e9d
Arg [1] : 000000000000000000000000ac041df48df9791b0654f1dbbf2cc8450c5f2e9d
Arg [2] : 00000000000000000000000008417cdb7f52a5021bb4eb6e0deaf3f295c3f182
Arg [3] : 000000000000000000000000befbae2330186f031b469e26283acc66bb5f8826
Arg [4] : 0000000000000000000000008efb3ded78fbaef2a4efe01e01bbd911e4094b78
Arg [5] : 0000000000000000000000002cb56df31b909854b01d4b1ead5676cf90e885e7
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$123.85
Net Worth in S
Token Allocations
USDP
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| SONIC | 100.00% | $0.999711 | 123.8885 | $123.85 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.