Source Code
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
There are no matching entriesUpdate your filters to view other transactions | |||||||||
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
CoWSwapFarm
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 1000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {GPv2Settlement} from "@cowprotocol/contracts/GPv2Settlement.sol";
import {FixedPointMathLib} from "@solmate/src/utils/FixedPointMathLib.sol";
import {GPv2Order, IERC20 as ICoWERC20} from "@cowprotocol/contracts/libraries/GPv2Order.sol";
import {Farm} from "@integrations/Farm.sol";
import {IOracle} from "@interfaces/IOracle.sol";
import {CoreRoles} from "@libraries/CoreRoles.sol";
import {Accounting} from "@finance/Accounting.sol";
import {IMaturityFarm, IFarm} from "@interfaces/IMaturityFarm.sol";
/// @title CoWSwap Farm
/// @notice This contract is used to deploy assets using CoW Swap limit orders. Funds are deposited in the farm
/// in assetTokens, and are then swapped into and out of wrapTokens using CoW Swap.
/// @dev This farm is considered illiquid as swapping in & out will incur slippage.
contract CoWSwapFarm is Farm, IMaturityFarm {
using SafeERC20 for IERC20;
using FixedPointMathLib for uint256;
event OrderSigned(
uint256 indexed timestamp, bytes orderUid, GPv2Order.Data order, uint32 validTo, uint256 buyAmount
);
error SwapCooldown();
error InvalidAmountIn(uint256 amountIn);
error InvalidAmountOut(uint256 minOut, uint256 provided);
/// @notice Reference to the wrap token (to which assetTokens are swapped).
address public immutable wrapToken;
/// @notice Reference to accounting contract.
address public immutable accounting;
/// @notice Duration of the farm (maturity() returns block.timestamp + duration)
/// @dev This can be set to 0, treating the farm as a liquid farm, however there will be
/// slippage to swap in & out of the farm, which acts as some kind of entrance & exit fees.
/// Consider setting a duration that is at least long enough to earn yield that covers the swap fees.
uint256 private immutable duration;
/// @notice timestamp of last order
uint256 public lastOrderSignTimestamp = 1;
/// @notice cooldown period between order signings
uint256 public constant _SIGN_COOLDOWN = 20 minutes;
/// @notice address of the GPv2Settlement contract
address public immutable settlementContract;
/// @notice address of the GPv2VaultRelayer contract
address public immutable vaultRelayer;
constructor(
address _core,
address _assetToken,
address _wrapToken,
address _accounting,
uint256 _duration,
address _settlementContract,
address _vaultRelayer
) Farm(_core, _assetToken) {
wrapToken = _wrapToken;
accounting = _accounting;
duration = _duration;
settlementContract = _settlementContract;
vaultRelayer = _vaultRelayer;
// set default slippage tolerance to 99.5%
maxSlippage = 0.995e18;
}
/// @notice Maturity is virtually set as "always in the future" to reflect
/// that there are swap fees to exit the farm.
/// In reality we can always swap out, so maturity should be block.timestamp, but these farms
/// should be treated as illiquid & having a maturity in the future is a good compromise,
/// because we don't want to allocate funds there unless they stay for at least enough time
/// to earn yield that covers the swap fees (that act as some kind of entrance & exit fees).
function maturity() public view override returns (uint256) {
return block.timestamp + duration;
}
/// @notice Returns the total assets in the farm
/// @dev Note that the assets() function includes the current balance of assetTokens,
/// this is because deposit()s and withdraw()als in this farm are handled asynchronously,
/// as they have to go through swaps which calldata has to be generated offchain.
/// This farm therefore holds its reserve in 2 tokens, assetToken and wrapToken.
function assets() public view override(Farm, IFarm) returns (uint256) {
uint256 assetTokenBalance = IERC20(assetToken).balanceOf(address(this));
uint256 wrapTokenAssetsValue = convertToAssets(IERC20(wrapToken).balanceOf(address(this)));
return assetTokenBalance + wrapTokenAssetsValue;
}
/// @notice Current liquidity of the farm is the held assetTokens.
function liquidity() public view override returns (uint256) {
return IERC20(assetToken).balanceOf(address(this));
}
/// @dev Deposit does nothing, assetTokens are just held on this farm.
/// @dev See call to wrapAssets() for the actual swap into wrapTokens.
function _deposit(uint256) internal view override {}
function deposit() external view override(Farm, IFarm) onlyCoreRole(CoreRoles.FARM_MANAGER) whenNotPaused {
_deposit(0);
}
/// @dev Withdrawal can only handle the held assetTokens (i.e. the liquidity()).
/// @dev See call to unwrapAssets() for the actual swap out of wrapTokens.
function _withdraw(uint256 _amount, address _to) internal override {
IERC20(assetToken).safeTransfer(_to, _amount);
}
/// @notice Converts a number of wrapTokens to assetTokens based on oracle rates.
function convertToAssets(uint256 _wrapTokenAmount) public view returns (uint256) {
uint256 assetTokenPrice = Accounting(accounting).price(assetToken);
uint256 wrapTokenPrice = Accounting(accounting).price(wrapToken);
return _wrapTokenAmount.mulDivDown(wrapTokenPrice, assetTokenPrice);
}
/// @notice Converts a number of assetTokens to wrapTokens based on oracle rates.
function convertToWrapTokens(uint256 _assetsAmount) public view returns (uint256) {
uint256 assetTokenPrice = Accounting(accounting).price(assetToken);
uint256 wrapTokenPrice = Accounting(accounting).price(wrapToken);
return _assetsAmount.mulDivDown(assetTokenPrice, wrapTokenPrice);
}
/// @notice Wraps assetTokens as wrapTokens.
function signWrapOrder(uint256 _assetsIn, uint256 _minWrapTokensOut)
external
whenNotPaused
onlyCoreRole(CoreRoles.FARM_SWAP_CALLER)
returns (bytes memory)
{
require(_assetsIn > 0 && _assetsIn <= liquidity(), InvalidAmountIn(_assetsIn));
require(block.timestamp > lastOrderSignTimestamp + _SIGN_COOLDOWN, SwapCooldown());
lastOrderSignTimestamp = block.timestamp;
uint256 minOutSlippage = convertToWrapTokens(_assetsIn).mulWadDown(maxSlippage);
require(_minWrapTokensOut >= minOutSlippage, InvalidAmountOut(minOutSlippage, _minWrapTokensOut));
IERC20(assetToken).forceApprove(vaultRelayer, _assetsIn);
return _signOrder(_order(assetToken, wrapToken, _assetsIn, _minWrapTokensOut));
}
/// @notice Unwraps wrapTokens to assetTokens.
function signUnwrapOrder(uint256 _wrapTokensIn, uint256 _minAssetsOut)
external
whenNotPaused
onlyCoreRole(CoreRoles.FARM_SWAP_CALLER)
returns (bytes memory)
{
require(
_wrapTokensIn > 0 && _wrapTokensIn <= IERC20(wrapToken).balanceOf(address(this)),
InvalidAmountIn(_wrapTokensIn)
);
require(block.timestamp > lastOrderSignTimestamp + _SIGN_COOLDOWN, SwapCooldown());
lastOrderSignTimestamp = block.timestamp;
uint256 minOutSlippage = convertToAssets(_wrapTokensIn.mulWadDown(maxSlippage));
require(_minAssetsOut >= minOutSlippage, InvalidAmountOut(minOutSlippage, _minAssetsOut));
IERC20(wrapToken).forceApprove(vaultRelayer, _wrapTokensIn);
return _signOrder(_order(wrapToken, assetToken, _wrapTokensIn, _minAssetsOut));
}
function _order(address _tokenIn, address _tokenOut, uint256 _amountIn, uint256 _minAmountOut)
internal
view
returns (GPv2Order.Data memory)
{
return GPv2Order.Data({
sellToken: ICoWERC20(_tokenIn),
buyToken: ICoWERC20(_tokenOut),
receiver: address(this),
sellAmount: _amountIn,
buyAmount: _minAmountOut,
validTo: uint32(block.timestamp + _SIGN_COOLDOWN),
// keccak256 {"appCode":"infiniFi","version":"1.0.0","metadata":{}}
appData: 0x3cac71ef99d0dfbf5b937334b5b7ab672b679ba2bbd4d6fe8e0c54a2dab31109,
feeAmount: 0,
kind: GPv2Order.KIND_SELL,
partiallyFillable: false,
sellTokenBalance: GPv2Order.BALANCE_ERC20,
buyTokenBalance: GPv2Order.BALANCE_ERC20
});
}
function _signOrder(GPv2Order.Data memory order) internal returns (bytes memory) {
GPv2Settlement settlement = GPv2Settlement(payable(settlementContract));
bytes32 orderDigest = GPv2Order.hash(order, settlement.domainSeparator());
bytes memory orderUid = new bytes(GPv2Order.UID_LENGTH);
GPv2Order.packOrderUidParams(orderUid, orderDigest, address(this), order.validTo);
settlement.setPreSignature(orderUid, true);
emit OrderSigned(block.timestamp, orderUid, order, order.validTo, order.buyAmount);
return orderUid;
}
}// 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.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 Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(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: LGPL-3.0-or-later
pragma solidity >=0.7.6 <0.9.0;
pragma abicoder v2;
import "./GPv2VaultRelayer.sol";
import "./interfaces/GPv2Authentication.sol";
import "./interfaces/IERC20.sol";
import "./interfaces/IVault.sol";
import "./libraries/GPv2Interaction.sol";
import "./libraries/GPv2Order.sol";
import "./libraries/GPv2Trade.sol";
import "./libraries/GPv2Transfer.sol";
import "./libraries/SafeCast.sol";
import "./libraries/SafeMath.sol";
import "./mixins/GPv2Signing.sol";
import "./mixins/ReentrancyGuard.sol";
import "./mixins/StorageAccessible.sol";
/// @title Gnosis Protocol v2 Settlement Contract
/// @author Gnosis Developers
contract GPv2Settlement is GPv2Signing, ReentrancyGuard, StorageAccessible {
using GPv2Order for bytes;
using GPv2Transfer for IVault;
using SafeCast for int256;
using SafeCast for uint256;
using SafeMath for uint256;
/// @dev The authenticator is used to determine who can call the settle function.
/// That is, only authorized solvers have the ability to invoke settlements.
/// Any valid authenticator implements an isSolver method called by the onlySolver
/// modifier below.
GPv2Authentication public immutable authenticator;
/// @dev The Balancer Vault the protocol used for managing user funds.
IVault public immutable vault;
/// @dev The Balancer Vault relayer which can interact on behalf of users.
/// This contract is created during deployment
GPv2VaultRelayer public immutable vaultRelayer;
/// @dev Map each user order by UID to the amount that has been filled so
/// far. If this amount is larger than or equal to the amount traded in the
/// order (amount sold for sell orders, amount bought for buy orders) then
/// the order cannot be traded anymore. If the order is fill or kill, then
/// this value is only used to determine whether the order has already been
/// executed.
mapping(bytes => uint256) public filledAmount;
/// @dev Event emitted for each executed trade.
event Trade(
address indexed owner,
IERC20 sellToken,
IERC20 buyToken,
uint256 sellAmount,
uint256 buyAmount,
uint256 feeAmount,
bytes orderUid
);
/// @dev Event emitted for each executed interaction.
///
/// For gas efficiency, only the interaction calldata selector (first 4
/// bytes) is included in the event. For interactions without calldata or
/// whose calldata is shorter than 4 bytes, the selector will be `0`.
event Interaction(address indexed target, uint256 value, bytes4 selector);
/// @dev Event emitted when a settlement completes
event Settlement(address indexed solver);
/// @dev Event emitted when an order is invalidated.
event OrderInvalidated(address indexed owner, bytes orderUid);
constructor(GPv2Authentication authenticator_, IVault vault_) {
authenticator = authenticator_;
vault = vault_;
vaultRelayer = new GPv2VaultRelayer(vault_);
}
// solhint-disable-next-line no-empty-blocks
receive() external payable {
// NOTE: Include an empty receive function so that the settlement
// contract can receive Ether from contract interactions.
}
/// @dev This modifier is called by settle function to block any non-listed
/// senders from settling batches.
modifier onlySolver() {
require(authenticator.isSolver(msg.sender), "GPv2: not a solver");
_;
}
/// @dev Modifier to ensure that an external function is only callable as a
/// settlement interaction.
modifier onlyInteraction() {
require(address(this) == msg.sender, "GPv2: not an interaction");
_;
}
/// @dev Settle the specified orders at a clearing price. Note that it is
/// the responsibility of the caller to ensure that all GPv2 invariants are
/// upheld for the input settlement, otherwise this call will revert.
/// Namely:
/// - All orders are valid and signed
/// - Accounts have sufficient balance and approval.
/// - Settlement contract has sufficient balance to execute trades. Note
/// this implies that the accumulated fees held in the contract can also
/// be used for settlement. This is OK since:
/// - Solvers need to be authorized
/// - Misbehaving solvers will be slashed for abusing accumulated fees for
/// settlement
/// - Critically, user orders are entirely protected
///
/// @param tokens An array of ERC20 tokens to be traded in the settlement.
/// Trades encode tokens as indices into this array.
/// @param clearingPrices An array of clearing prices where the `i`-th price
/// is for the `i`-th token in the [`tokens`] array.
/// @param trades Trades for signed orders.
/// @param interactions Smart contract interactions split into three
/// separate lists to be run before the settlement, during the settlement
/// and after the settlement respectively.
function settle(
IERC20[] calldata tokens,
uint256[] calldata clearingPrices,
GPv2Trade.Data[] calldata trades,
GPv2Interaction.Data[][3] calldata interactions
) external nonReentrant onlySolver {
executeInteractions(interactions[0]);
(
GPv2Transfer.Data[] memory inTransfers,
GPv2Transfer.Data[] memory outTransfers
) = computeTradeExecutions(tokens, clearingPrices, trades);
vaultRelayer.transferFromAccounts(inTransfers);
executeInteractions(interactions[1]);
vault.transferToAccounts(outTransfers);
executeInteractions(interactions[2]);
emit Settlement(msg.sender);
}
/// @dev Settle an order directly against Balancer V2 pools.
///
/// @param swaps The Balancer V2 swap steps to use for trading.
/// @param tokens An array of ERC20 tokens to be traded in the settlement.
/// Swaps and the trade encode tokens as indices into this array.
/// @param trade The trade to match directly against Balancer liquidity. The
/// order will always be fully executed, so the trade's `executedAmount`
/// field is used to represent a swap limit amount.
function swap(
IVault.BatchSwapStep[] calldata swaps,
IERC20[] calldata tokens,
GPv2Trade.Data calldata trade
) external nonReentrant onlySolver {
RecoveredOrder memory recoveredOrder = allocateRecoveredOrder();
GPv2Order.Data memory order = recoveredOrder.data;
recoverOrderFromTrade(recoveredOrder, tokens, trade);
IVault.SwapKind kind = order.kind == GPv2Order.KIND_SELL
? IVault.SwapKind.GIVEN_IN
: IVault.SwapKind.GIVEN_OUT;
IVault.FundManagement memory funds;
funds.sender = recoveredOrder.owner;
funds.fromInternalBalance =
order.sellTokenBalance == GPv2Order.BALANCE_INTERNAL;
funds.recipient = payable(recoveredOrder.receiver);
funds.toInternalBalance =
order.buyTokenBalance == GPv2Order.BALANCE_INTERNAL;
int256[] memory limits = new int256[](tokens.length);
uint256 limitAmount = trade.executedAmount;
// NOTE: Array allocation initializes elements to 0, so we only need to
// set the limits we care about. This ensures that the swap will respect
// the order's limit price.
if (order.kind == GPv2Order.KIND_SELL) {
require(limitAmount >= order.buyAmount, "GPv2: limit too low");
limits[trade.sellTokenIndex] = order.sellAmount.toInt256();
limits[trade.buyTokenIndex] = -limitAmount.toInt256();
} else {
require(limitAmount <= order.sellAmount, "GPv2: limit too high");
limits[trade.sellTokenIndex] = limitAmount.toInt256();
limits[trade.buyTokenIndex] = -order.buyAmount.toInt256();
}
GPv2Transfer.Data memory feeTransfer;
feeTransfer.account = recoveredOrder.owner;
feeTransfer.token = order.sellToken;
feeTransfer.amount = order.feeAmount;
feeTransfer.balance = order.sellTokenBalance;
int256[] memory tokenDeltas = vaultRelayer.batchSwapWithFee(
kind,
swaps,
tokens,
funds,
limits,
// NOTE: Specify a deadline to ensure that an expire order
// cannot be used to trade.
order.validTo,
feeTransfer
);
bytes memory orderUid = recoveredOrder.uid;
uint256 executedSellAmount = tokenDeltas[trade.sellTokenIndex]
.toUint256();
uint256 executedBuyAmount = (-tokenDeltas[trade.buyTokenIndex])
.toUint256();
// NOTE: Check that the orders were completely filled and update their
// filled amounts to avoid replaying them. The limit price and order
// validity has already been verified when executing the swap through
// the `limit` and `deadline` parameters.
require(filledAmount[orderUid] == 0, "GPv2: order filled");
if (order.kind == GPv2Order.KIND_SELL) {
require(
executedSellAmount == order.sellAmount,
"GPv2: sell amount not respected"
);
filledAmount[orderUid] = order.sellAmount;
} else {
require(
executedBuyAmount == order.buyAmount,
"GPv2: buy amount not respected"
);
filledAmount[orderUid] = order.buyAmount;
}
emit Trade(
recoveredOrder.owner,
order.sellToken,
order.buyToken,
executedSellAmount,
executedBuyAmount,
order.feeAmount,
orderUid
);
emit Settlement(msg.sender);
}
/// @dev Invalidate onchain an order that has been signed offline.
///
/// @param orderUid The unique identifier of the order that is to be made
/// invalid after calling this function. The user that created the order
/// must be the sender of this message. See [`extractOrderUidParams`]
/// for details on orderUid.
function invalidateOrder(bytes calldata orderUid) external {
(, address owner, ) = orderUid.extractOrderUidParams();
require(owner == msg.sender, "GPv2: caller does not own order");
filledAmount[orderUid] = type(uint256).max;
emit OrderInvalidated(owner, orderUid);
}
/// @dev Free storage from the filled amounts of **expired** orders to claim
/// a gas refund. This method can only be called as an interaction.
///
/// @param orderUids The unique identifiers of the expired order to free
/// storage for.
function freeFilledAmountStorage(
bytes[] calldata orderUids
) external onlyInteraction {
freeOrderStorage(filledAmount, orderUids);
}
/// @dev Free storage from the pre signatures of **expired** orders to claim
/// a gas refund. This method can only be called as an interaction.
///
/// @param orderUids The unique identifiers of the expired order to free
/// storage for.
function freePreSignatureStorage(
bytes[] calldata orderUids
) external onlyInteraction {
freeOrderStorage(preSignature, orderUids);
}
/// @dev Process all trades one at a time returning the computed net in and
/// out transfers for the trades.
///
/// This method reverts if processing of any single trade fails. See
/// [`computeTradeExecution`] for more details.
///
/// @param tokens An array of ERC20 tokens to be traded in the settlement.
/// @param clearingPrices An array of token clearing prices.
/// @param trades Trades for signed orders.
/// @return inTransfers Array of in transfers of executed sell amounts.
/// @return outTransfers Array of out transfers of executed buy amounts.
function computeTradeExecutions(
IERC20[] calldata tokens,
uint256[] calldata clearingPrices,
GPv2Trade.Data[] calldata trades
)
internal
returns (
GPv2Transfer.Data[] memory inTransfers,
GPv2Transfer.Data[] memory outTransfers
)
{
RecoveredOrder memory recoveredOrder = allocateRecoveredOrder();
inTransfers = new GPv2Transfer.Data[](trades.length);
outTransfers = new GPv2Transfer.Data[](trades.length);
for (uint256 i; i < trades.length; ++i) {
GPv2Trade.Data calldata trade = trades[i];
recoverOrderFromTrade(recoveredOrder, tokens, trade);
computeTradeExecution(
recoveredOrder,
clearingPrices[trade.sellTokenIndex],
clearingPrices[trade.buyTokenIndex],
trade.executedAmount,
inTransfers[i],
outTransfers[i]
);
}
}
/// @dev Compute the in and out transfer amounts for a single trade.
/// This function reverts if:
/// - The order has expired
/// - The order's limit price is not respected
/// - The order gets over-filled
/// - The fee discount is larger than the executed fee
///
/// @param recoveredOrder The recovered order to process.
/// @param sellPrice The price of the order's sell token.
/// @param buyPrice The price of the order's buy token.
/// @param executedAmount The portion of the order to execute. This will be
/// ignored for fill-or-kill orders.
/// @param inTransfer Memory location for computed executed sell amount
/// transfer.
/// @param outTransfer Memory location for computed executed buy amount
/// transfer.
function computeTradeExecution(
RecoveredOrder memory recoveredOrder,
uint256 sellPrice,
uint256 buyPrice,
uint256 executedAmount,
GPv2Transfer.Data memory inTransfer,
GPv2Transfer.Data memory outTransfer
) internal {
GPv2Order.Data memory order = recoveredOrder.data;
bytes memory orderUid = recoveredOrder.uid;
// solhint-disable-next-line not-rely-on-time
require(order.validTo >= block.timestamp, "GPv2: order expired");
// NOTE: The following computation is derived from the equation:
// ```
// amount_x * price_x = amount_y * price_y
// ```
// Intuitively, if a chocolate bar is 0,50€ and a beer is 4€, 1 beer
// is roughly worth 8 chocolate bars (`1 * 4 = 8 * 0.5`). From this
// equation, we can derive:
// - The limit price for selling `x` and buying `y` is respected iff
// ```
// limit_x * price_x >= limit_y * price_y
// ```
// - The executed amount of token `y` given some amount of `x` and
// clearing prices is:
// ```
// amount_y = amount_x * price_x / price_y
// ```
require(
order.sellAmount.mul(sellPrice) >= order.buyAmount.mul(buyPrice),
"GPv2: limit price not respected"
);
uint256 executedSellAmount;
uint256 executedBuyAmount;
uint256 executedFeeAmount;
uint256 currentFilledAmount;
if (order.kind == GPv2Order.KIND_SELL) {
if (order.partiallyFillable) {
executedSellAmount = executedAmount;
executedFeeAmount = order.feeAmount.mul(executedSellAmount).div(
order.sellAmount
);
} else {
executedSellAmount = order.sellAmount;
executedFeeAmount = order.feeAmount;
}
executedBuyAmount = executedSellAmount.mul(sellPrice).ceilDiv(
buyPrice
);
currentFilledAmount = filledAmount[orderUid].add(
executedSellAmount
);
require(
currentFilledAmount <= order.sellAmount,
"GPv2: order filled"
);
} else {
if (order.partiallyFillable) {
executedBuyAmount = executedAmount;
executedFeeAmount = order.feeAmount.mul(executedBuyAmount).div(
order.buyAmount
);
} else {
executedBuyAmount = order.buyAmount;
executedFeeAmount = order.feeAmount;
}
executedSellAmount = executedBuyAmount.mul(buyPrice).div(sellPrice);
currentFilledAmount = filledAmount[orderUid].add(executedBuyAmount);
require(
currentFilledAmount <= order.buyAmount,
"GPv2: order filled"
);
}
executedSellAmount = executedSellAmount.add(executedFeeAmount);
filledAmount[orderUid] = currentFilledAmount;
emit Trade(
recoveredOrder.owner,
order.sellToken,
order.buyToken,
executedSellAmount,
executedBuyAmount,
executedFeeAmount,
orderUid
);
inTransfer.account = recoveredOrder.owner;
inTransfer.token = order.sellToken;
inTransfer.amount = executedSellAmount;
inTransfer.balance = order.sellTokenBalance;
outTransfer.account = recoveredOrder.receiver;
outTransfer.token = order.buyToken;
outTransfer.amount = executedBuyAmount;
outTransfer.balance = order.buyTokenBalance;
}
/// @dev Execute a list of arbitrary contract calls from this contract.
/// @param interactions The list of interactions to execute.
function executeInteractions(
GPv2Interaction.Data[] calldata interactions
) internal {
for (uint256 i; i < interactions.length; ++i) {
GPv2Interaction.Data calldata interaction = interactions[i];
// To prevent possible attack on user funds, we explicitly disable
// any interactions with the vault relayer contract.
require(
interaction.target != address(vaultRelayer),
"GPv2: forbidden interaction"
);
GPv2Interaction.execute(interaction);
emit Interaction(
interaction.target,
interaction.value,
GPv2Interaction.selector(interaction)
);
}
}
/// @dev Claims refund for the specified storage and order UIDs.
///
/// This method reverts if any of the orders are still valid.
///
/// @param orderUids Order refund data for freeing storage.
/// @param orderStorage Order storage mapped on a UID.
function freeOrderStorage(
mapping(bytes => uint256) storage orderStorage,
bytes[] calldata orderUids
) internal {
for (uint256 i; i < orderUids.length; ++i) {
bytes calldata orderUid = orderUids[i];
(, , uint32 validTo) = orderUid.extractOrderUidParams();
// solhint-disable-next-line not-rely-on-time
require(validTo < block.timestamp, "GPv2: order still valid");
orderStorage[orderUid] = 0;
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
/*//////////////////////////////////////////////////////////////
SIMPLIFIED FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
uint256 internal constant MAX_UINT256 = 2**256 - 1;
uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
}
/*//////////////////////////////////////////////////////////////
LOW LEVEL FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// Divide x * y by the denominator.
z := div(mul(x, y), denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// If x * y modulo the denominator is strictly greater than 0,
// 1 is added to round up the division of x * y by the denominator.
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
switch x
case 0 {
switch n
case 0 {
// 0 ** 0 = 1
z := scalar
}
default {
// 0 ** n = 0
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
// If n is even, store scalar in z for now.
z := scalar
}
default {
// If n is odd, store x in z for now.
z := x
}
// Shifting right by 1 is like dividing by 2.
let half := shr(1, scalar)
for {
// Shift n right by 1 before looping to halve it.
n := shr(1, n)
} n {
// Shift n right by 1 each iteration to halve it.
n := shr(1, n)
} {
// Revert immediately if x ** 2 would overflow.
// Equivalent to iszero(eq(div(xx, x), x)) here.
if shr(128, x) {
revert(0, 0)
}
// Store x squared.
let xx := mul(x, x)
// Round to the nearest number.
let xxRound := add(xx, half)
// Revert if xx + half overflowed.
if lt(xxRound, xx) {
revert(0, 0)
}
// Set x to scaled xxRound.
x := div(xxRound, scalar)
// If n is even:
if mod(n, 2) {
// Compute z * x.
let zx := mul(z, x)
// If z * x overflowed:
if iszero(eq(div(zx, x), z)) {
// Revert if x is non-zero.
if iszero(iszero(x)) {
revert(0, 0)
}
}
// Round to the nearest number.
let zxRound := add(zx, half)
// Revert if zx + half overflowed.
if lt(zxRound, zx) {
revert(0, 0)
}
// Return properly scaled zxRound.
z := div(zxRound, scalar)
}
}
}
}
}
/*//////////////////////////////////////////////////////////////
GENERAL NUMBER UTILITIES
//////////////////////////////////////////////////////////////*/
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let y := x // We start y at x, which will help us make our initial estimate.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// We check y >= 2^(k + 8) but shift right by k bits
// each branch to ensure that if x >= 256, then y >= 256.
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
// Goal was to get z*z*y within a small factor of x. More iterations could
// get y in a tighter range. Currently, we will have y in [256, 256*2^16).
// We ensured y >= 256 so that the relative difference between y and y+1 is small.
// That's not possible if x < 256 but we can just verify those cases exhaustively.
// Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
// Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
// Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.
// For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
// (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.
// Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
// sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.
// There is no overflow risk here since y < 2^136 after the first branch above.
z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If x+1 is a perfect square, the Babylonian method cycles between
// floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
// Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
// If you don't care whether the floor or ceil square root is returned, you can remove this statement.
z := sub(z, lt(div(x, z), z))
}
}
function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Mod x by y. Note this will return
// 0 instead of reverting if y is zero.
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Divide x by y. Note this will return
// 0 instead of reverting if y is zero.
r := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Add 1 to x * y if x % y > 0. Note this will
// return 0 instead of reverting if y is zero.
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity >=0.7.6 <0.9.0;
import "../interfaces/IERC20.sol";
/// @title Gnosis Protocol v2 Order Library
/// @author Gnosis Developers
library GPv2Order {
/// @dev The complete data for a Gnosis Protocol order. This struct contains
/// all order parameters that are signed for submitting to GP.
struct Data {
IERC20 sellToken;
IERC20 buyToken;
address receiver;
uint256 sellAmount;
uint256 buyAmount;
uint32 validTo;
bytes32 appData;
uint256 feeAmount;
bytes32 kind;
bool partiallyFillable;
bytes32 sellTokenBalance;
bytes32 buyTokenBalance;
}
/// @dev The order EIP-712 type hash for the [`GPv2Order.Data`] struct.
///
/// This value is pre-computed from the following expression:
/// ```
/// keccak256(
/// "Order(" +
/// "address sellToken," +
/// "address buyToken," +
/// "address receiver," +
/// "uint256 sellAmount," +
/// "uint256 buyAmount," +
/// "uint32 validTo," +
/// "bytes32 appData," +
/// "uint256 feeAmount," +
/// "string kind," +
/// "bool partiallyFillable," +
/// "string sellTokenBalance," +
/// "string buyTokenBalance" +
/// ")"
/// )
/// ```
bytes32 internal constant TYPE_HASH =
hex"d5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e489";
/// @dev The marker value for a sell order for computing the order struct
/// hash. This allows the EIP-712 compatible wallets to display a
/// descriptive string for the order kind (instead of 0 or 1).
///
/// This value is pre-computed from the following expression:
/// ```
/// keccak256("sell")
/// ```
bytes32 internal constant KIND_SELL =
hex"f3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775";
/// @dev The OrderKind marker value for a buy order for computing the order
/// struct hash.
///
/// This value is pre-computed from the following expression:
/// ```
/// keccak256("buy")
/// ```
bytes32 internal constant KIND_BUY =
hex"6ed88e868af0a1983e3886d5f3e95a2fafbd6c3450bc229e27342283dc429ccc";
/// @dev The TokenBalance marker value for using direct ERC20 balances for
/// computing the order struct hash.
///
/// This value is pre-computed from the following expression:
/// ```
/// keccak256("erc20")
/// ```
bytes32 internal constant BALANCE_ERC20 =
hex"5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9";
/// @dev The TokenBalance marker value for using Balancer Vault external
/// balances (in order to re-use Vault ERC20 approvals) for computing the
/// order struct hash.
///
/// This value is pre-computed from the following expression:
/// ```
/// keccak256("external")
/// ```
bytes32 internal constant BALANCE_EXTERNAL =
hex"abee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea0632";
/// @dev The TokenBalance marker value for using Balancer Vault internal
/// balances for computing the order struct hash.
///
/// This value is pre-computed from the following expression:
/// ```
/// keccak256("internal")
/// ```
bytes32 internal constant BALANCE_INTERNAL =
hex"4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce";
/// @dev Marker address used to indicate that the receiver of the trade
/// proceeds should the owner of the order.
///
/// This is chosen to be `address(0)` for gas efficiency as it is expected
/// to be the most common case.
address internal constant RECEIVER_SAME_AS_OWNER = address(0);
/// @dev The byte length of an order unique identifier.
uint256 internal constant UID_LENGTH = 56;
/// @dev Returns the actual receiver for an order. This function checks
/// whether or not the [`receiver`] field uses the marker value to indicate
/// it is the same as the order owner.
///
/// @return receiver The actual receiver of trade proceeds.
function actualReceiver(
Data memory order,
address owner
) internal pure returns (address receiver) {
if (order.receiver == RECEIVER_SAME_AS_OWNER) {
receiver = owner;
} else {
receiver = order.receiver;
}
}
/// @dev Return the EIP-712 signing hash for the specified order.
///
/// @param order The order to compute the EIP-712 signing hash for.
/// @param domainSeparator The EIP-712 domain separator to use.
/// @return orderDigest The 32 byte EIP-712 struct hash.
function hash(
Data memory order,
bytes32 domainSeparator
) internal pure returns (bytes32 orderDigest) {
bytes32 structHash;
// NOTE: Compute the EIP-712 order struct hash in place. As suggested
// in the EIP proposal, noting that the order struct has 12 fields, and
// prefixing the type hash `(1 + 12) * 32 = 416` bytes to hash.
// <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-encodedata>
// solhint-disable-next-line no-inline-assembly
assembly {
let dataStart := sub(order, 32)
let temp := mload(dataStart)
mstore(dataStart, TYPE_HASH)
structHash := keccak256(dataStart, 416)
mstore(dataStart, temp)
}
// NOTE: Now that we have the struct hash, compute the EIP-712 signing
// hash using scratch memory past the free memory pointer. The signing
// hash is computed from `"\x19\x01" || domainSeparator || structHash`.
// <https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html#layout-in-memory>
// <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#specification>
// solhint-disable-next-line no-inline-assembly
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, "\x19\x01")
mstore(add(freeMemoryPointer, 2), domainSeparator)
mstore(add(freeMemoryPointer, 34), structHash)
orderDigest := keccak256(freeMemoryPointer, 66)
}
}
/// @dev Packs order UID parameters into the specified memory location. The
/// result is equivalent to `abi.encodePacked(...)` with the difference that
/// it allows re-using the memory for packing the order UID.
///
/// This function reverts if the order UID buffer is not the correct size.
///
/// @param orderUid The buffer pack the order UID parameters into.
/// @param orderDigest The EIP-712 struct digest derived from the order
/// parameters.
/// @param owner The address of the user who owns this order.
/// @param validTo The epoch time at which the order will stop being valid.
function packOrderUidParams(
bytes memory orderUid,
bytes32 orderDigest,
address owner,
uint32 validTo
) internal pure {
require(orderUid.length == UID_LENGTH, "GPv2: uid buffer overflow");
// NOTE: Write the order UID to the allocated memory buffer. The order
// parameters are written to memory in **reverse order** as memory
// operations write 32-bytes at a time and we want to use a packed
// encoding. This means, for example, that after writing the value of
// `owner` to bytes `20:52`, writing the `orderDigest` to bytes `0:32`
// will **overwrite** bytes `20:32`. This is desirable as addresses are
// only 20 bytes and `20:32` should be `0`s:
//
// | 1111111111222222222233333333334444444444555555
// byte | 01234567890123456789012345678901234567890123456789012345
// -------+---------------------------------------------------------
// field | [.........orderDigest..........][......owner.......][vT]
// -------+---------------------------------------------------------
// mstore | [000000000000000000000000000.vT]
// | [00000000000.......owner.......]
// | [.........orderDigest..........]
//
// Additionally, since Solidity `bytes memory` are length prefixed,
// 32 needs to be added to all the offsets.
//
// solhint-disable-next-line no-inline-assembly
assembly {
mstore(add(orderUid, 56), validTo)
mstore(add(orderUid, 52), owner)
mstore(add(orderUid, 32), orderDigest)
}
}
/// @dev Extracts specific order information from the standardized unique
/// order id of the protocol.
///
/// @param orderUid The unique identifier used to represent an order in
/// the protocol. This uid is the packed concatenation of the order digest,
/// the validTo order parameter and the address of the user who created the
/// order. It is used by the user to interface with the contract directly,
/// and not by calls that are triggered by the solvers.
/// @return orderDigest The EIP-712 signing digest derived from the order
/// parameters.
/// @return owner The address of the user who owns this order.
/// @return validTo The epoch time at which the order will stop being valid.
function extractOrderUidParams(
bytes calldata orderUid
)
internal
pure
returns (bytes32 orderDigest, address owner, uint32 validTo)
{
require(orderUid.length == UID_LENGTH, "GPv2: invalid uid");
// Use assembly to efficiently decode packed calldata.
// solhint-disable-next-line no-inline-assembly
assembly {
orderDigest := calldataload(orderUid.offset)
owner := shr(96, calldataload(add(orderUid.offset, 32)))
validTo := shr(224, calldataload(add(orderUid.offset, 52)))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {FixedPointMathLib} from "@solmate/src/utils/FixedPointMathLib.sol";
import {IFarm} from "@interfaces/IFarm.sol";
import {CoreRoles} from "@libraries/CoreRoles.sol";
import {CoreControlled} from "@core/CoreControlled.sol";
/// @notice InfiniFi Farm base contract
abstract contract Farm is CoreControlled, IFarm {
using FixedPointMathLib for uint256;
address public immutable assetToken;
/// @notice cap on the amount of assets that can be deposited into the farm
uint256 public cap;
/// @notice Max slippage for depositing and witdhrawing assets from the farm.
/// @dev Stored as a percentage with 18 decimals of precision, of the minimum
/// position size compared to the previous position size (so actually 1 - slippage).
/// @dev Set to 0 to disable slippage checks.
uint256 public maxSlippage;
error CapExceeded(uint256 newAmount, uint256 cap);
error SlippageTooHigh(uint256 minAssetsOut, uint256 assetsReceived);
event CapUpdated(uint256 newCap);
event MaxSlippageUpdated(uint256 newMaxSlippage);
constructor(address _core, address _assetToken) CoreControlled(_core) {
assetToken = _assetToken;
cap = type(uint256).max;
// default to 99.9999%
// most farms should not have deposits/withdrawals fees, unless explicitly
// implemented, and should at worst round against depositors which should
// only cause some wei of losses when our farms do a deposit/withdraw.
maxSlippage = 0.999999e18;
}
/// @notice set the deposit cap of the farm
function setCap(uint256 _newCap) external onlyCoreRole(CoreRoles.PROTOCOL_PARAMETERS) {
cap = _newCap;
emit CapUpdated(_newCap);
}
/// @notice set the max tolerated slippage for depositing and witdhrawing assets from the farm
function setMaxSlippage(uint256 _maxSlippage) external onlyCoreRole(CoreRoles.PROTOCOL_PARAMETERS) {
maxSlippage = _maxSlippage;
emit MaxSlippageUpdated(_maxSlippage);
}
// --------------------------------------------------------------------
// Accounting
// --------------------------------------------------------------------
function assets() public view virtual returns (uint256);
// --------------------------------------------------------------------
// Adapter logic
// --------------------------------------------------------------------
function maxDeposit() external view virtual returns (uint256) {
uint256 currentAssets = assets();
if (currentAssets >= cap) {
return 0;
}
return cap - currentAssets;
}
function deposit() external virtual onlyCoreRole(CoreRoles.FARM_MANAGER) whenNotPaused {
uint256 assetsToDeposit = ERC20(assetToken).balanceOf(address(this));
uint256 assetsBefore = assets();
if (assetsBefore + assetsToDeposit > cap) {
revert CapExceeded(assetsBefore + assetsToDeposit, cap);
}
_deposit(assetsToDeposit);
uint256 assetsAfter = assets();
uint256 assetsReceived = assetsAfter - assetsBefore;
// check slippage
uint256 minAssetsOut = assetsToDeposit.mulWadDown(maxSlippage);
require(assetsReceived >= minAssetsOut, SlippageTooHigh(minAssetsOut, assetsReceived));
emit AssetsUpdated(block.timestamp, assetsBefore, assetsAfter);
}
function _deposit(uint256 assetsToDeposit) internal virtual;
function withdraw(uint256 amount, address to) external virtual onlyCoreRole(CoreRoles.FARM_MANAGER) whenNotPaused {
uint256 assetsBefore = assets();
_withdraw(amount, to);
uint256 assetsAfter = assets();
uint256 assetsSpent = assetsBefore - assetsAfter;
uint256 minAssetsOut = assetsSpent.mulWadDown(maxSlippage);
require(amount >= minAssetsOut, SlippageTooHigh(minAssetsOut, amount));
emit AssetsUpdated(block.timestamp, assetsBefore, assetsAfter);
}
function _withdraw(uint256, address) internal virtual;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
interface IOracle {
/// @notice price of a token expressed in a reference token.
/// @dev be mindful of the decimals here, because if quote token
/// doesn't have 18 decimals, value is used to scale the decimals.
/// For example, for USDC quote (6 decimals) expressed in
/// DAI reference (18 decimals), value should be around ~1e30,
/// so that price is:
/// 1e6 * 1e30 / WAD (1e18)
/// ~= WAD (1e18)
/// ~= 1:1
function price() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
/// @notice Holds a complete list of all roles which can be held by contracts inside the InfiniFi protocol.
library CoreRoles {
/// ----------- Core roles for access control --------------
/// @notice the all-powerful role. Controls all other roles and protocol functionality.
bytes32 internal constant GOVERNOR = keccak256("GOVERNOR");
/// @notice Can pause contracts in an emergency.
bytes32 internal constant PAUSE = keccak256("PAUSE");
/// @notice Can unpause contracts after an emergency.
bytes32 internal constant UNPAUSE = keccak256("UNPAUSE");
/// @notice can tweak protocol parameters
bytes32 internal constant PROTOCOL_PARAMETERS = keccak256("PROTOCOL_PARAMETERS");
/// @notice can manage minor roles
bytes32 internal constant MINOR_ROLES_MANAGER = keccak256("MINOR_ROLES_MANAGER");
/// ----------- User Flow Management -----------------------
/// @notice Granted to the user entry point of the system
bytes32 internal constant ENTRY_POINT = keccak256("ENTRY_POINT");
/// ----------- Token Management ---------------------------
/// @notice can mint DebtToken arbitrarily
bytes32 internal constant RECEIPT_TOKEN_MINTER = keccak256("RECEIPT_TOKEN_MINTER");
/// @notice can burn DebtToken tokens
bytes32 internal constant RECEIPT_TOKEN_BURNER = keccak256("RECEIPT_TOKEN_BURNER");
/// @notice can mint arbitrarily & burn held LockedPositionToken
bytes32 internal constant LOCKED_TOKEN_MANAGER = keccak256("LOCKED_TOKEN_MANAGER");
/// @notice can prevent transfers of LockedPositionToken
bytes32 internal constant TRANSFER_RESTRICTOR = keccak256("TRANSFER_RESTRICTOR");
/// ----------- Funds Management & Accounting --------------
/// @notice contract that can allocate funds between farms
bytes32 internal constant FARM_MANAGER = keccak256("FARM_MANAGER");
/// @notice addresses who can use the manual rebalancer
bytes32 internal constant MANUAL_REBALANCER = keccak256("MANUAL_REBALANCER");
/// @notice addresses who can use the periodic rebalancer
bytes32 internal constant PERIODIC_REBALANCER = keccak256("PERIODIC_REBALANCER");
/// @notice addresses who can move funds from farms to a safe address
bytes32 internal constant EMERGENCY_WITHDRAWAL = keccak256("EMERGENCY_WITHDRAWAL");
/// @notice addresses who can trigger swaps in Farms
bytes32 internal constant FARM_SWAP_CALLER = keccak256("FARM_SWAP_CALLER");
/// @notice can set oracles references within the system
bytes32 internal constant ORACLE_MANAGER = keccak256("ORACLE_MANAGER");
/// @notice trusted to report profit and losses in the system.
/// This role can be used to slash depositors in case of losses, and
/// can also deposit profits for distribution to end users.
bytes32 internal constant FINANCE_MANAGER = keccak256("FINANCE_MANAGER");
/// ----------- Timelock management ------------------------
/// The hashes are the same as OpenZeppelins's roles in TimelockController
/// @notice can propose new actions in timelocks
bytes32 internal constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE");
/// @notice can execute actions in timelocks after their delay
bytes32 internal constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
/// @notice can cancel actions in timelocks
bytes32 internal constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE");
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {FixedPointMathLib} from "@solmate/src/utils/FixedPointMathLib.sol";
import {IFarm} from "@interfaces/IFarm.sol";
import {IOracle} from "@interfaces/IOracle.sol";
import {CoreRoles} from "@libraries/CoreRoles.sol";
import {FarmRegistry} from "@integrations/FarmRegistry.sol";
import {CoreControlled} from "@core/CoreControlled.sol";
import {FixedPriceOracle} from "@finance/oracles/FixedPriceOracle.sol";
/// @notice InfiniFi Accounting contract
contract Accounting is CoreControlled {
using FixedPointMathLib for uint256;
event PriceSet(uint256 indexed timestamp, address indexed asset, uint256 price);
event OracleSet(uint256 indexed timestamp, address indexed asset, address oracle);
/// @notice reference to the farm registry
address public immutable farmRegistry;
constructor(address _core, address _farmRegistry) CoreControlled(_core) {
farmRegistry = _farmRegistry;
}
/// @notice mapping from asset to oracle
mapping(address => address) public oracle;
/// @notice returns the price of an asset
function price(address _asset) external view returns (uint256) {
return IOracle(oracle[_asset]).price();
}
/// @notice set the oracle for an asset
function setOracle(address _asset, address _oracle) external onlyCoreRole(CoreRoles.ORACLE_MANAGER) {
oracle[_asset] = _oracle;
emit OracleSet(block.timestamp, _asset, _oracle);
}
/// -------------------------------------------------------------------------------------------
/// Reference token getters (e.g. USD for iUSD, ETH for iETH, ...)
/// @dev note that the "USD" token does not exist, it is just an abstract unit of account
/// used in the protocol to represent stablecoins pegged to USD, that allows to uniformly
/// account for a diverse reserve composed of USDC, DAI, FRAX, etc.
/// -------------------------------------------------------------------------------------------
/// @notice returns the sum of the value of all assets held on protocol contracts listed in the farm registry.
function totalAssetsValue() external view returns (uint256 _totalValue) {
address[] memory assets = FarmRegistry(farmRegistry).getEnabledAssets();
for (uint256 i = 0; i < assets.length; i++) {
uint256 assetPrice = IOracle(oracle[assets[i]]).price();
uint256 _assets = _calculateTotalAssets(FarmRegistry(farmRegistry).getAssetFarms(assets[i]));
_totalValue += _assets.mulWadDown(assetPrice);
}
}
/// @notice returns the sum of the value of all liquid assets held on protocol contracts listed in the farm registry.
/// @dev see totalAssetsValue()
function totalAssetsValueOf(uint256 _type) external view returns (uint256 _totalValue) {
address[] memory assets = FarmRegistry(farmRegistry).getEnabledAssets();
for (uint256 i = 0; i < assets.length; i++) {
uint256 assetPrice = IOracle(oracle[assets[i]]).price();
address[] memory assetFarms = FarmRegistry(farmRegistry).getAssetTypeFarms(assets[i], uint256(_type));
uint256 _assets = _calculateTotalAssets(assetFarms);
_totalValue += _assets.mulWadDown(assetPrice);
}
}
/// -------------------------------------------------------------------------------------------
/// Specific asset getters (e.g. USDC, DAI, ...)
/// -------------------------------------------------------------------------------------------
/// @notice returns the sum of the balance of all farms of a given asset.
function totalAssets(address _asset) external view returns (uint256) {
return _calculateTotalAssets(FarmRegistry(farmRegistry).getAssetFarms(_asset));
}
function totalAssetsOf(address _asset, uint256 _type) external view returns (uint256) {
return _calculateTotalAssets(FarmRegistry(farmRegistry).getAssetTypeFarms(_asset, uint256(_type)));
}
/// -------------------------------------------------------------------------------------------
/// Internal helpers
/// -------------------------------------------------------------------------------------------
function _calculateTotalAssets(address[] memory _farms) internal view returns (uint256 _totalAssets) {
uint256 length = _farms.length;
for (uint256 index = 0; index < length; index++) {
_totalAssets += IFarm(_farms[index]).assets();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IFarm} from "@interfaces/IFarm.sol";
/// @notice Interface for an InfiniFi Farm contract that has a maturity date
/// @dev These farms represent illiquid farm/asset class
interface IMaturityFarm is IFarm {
/// @notice timestamp at which more funds can be made available for withdrawal
function maturity() external view returns (uint256);
}// 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: LGPL-3.0-or-later
pragma solidity >=0.7.6 <0.9.0;
pragma abicoder v2;
import "./interfaces/IERC20.sol";
import "./interfaces/IVault.sol";
import "./libraries/GPv2Transfer.sol";
/// @title Gnosis Protocol v2 Vault Relayer Contract
/// @author Gnosis Developers
contract GPv2VaultRelayer {
using GPv2Transfer for IVault;
/// @dev The creator of the contract which has special permissions. This
/// value is set at creation time and cannot change.
address private immutable creator;
/// @dev The vault this relayer is for.
IVault private immutable vault;
constructor(IVault vault_) {
creator = msg.sender;
vault = vault_;
}
/// @dev Modifier that ensures that a function can only be called by the
/// creator of this contract.
modifier onlyCreator() {
require(msg.sender == creator, "GPv2: not creator");
_;
}
/// @dev Transfers all sell amounts for the executed trades from their
/// owners to the caller.
///
/// This function reverts if:
/// - The caller is not the creator of the vault relayer
/// - Any ERC20 transfer fails
///
/// @param transfers The transfers to execute.
function transferFromAccounts(
GPv2Transfer.Data[] calldata transfers
) external onlyCreator {
vault.transferFromAccounts(transfers, msg.sender);
}
/// @dev Performs a Balancer batched swap on behalf of a user and sends a
/// fee to the caller.
///
/// This function reverts if:
/// - The caller is not the creator of the vault relayer
/// - The swap fails
/// - The fee transfer fails
///
/// @param kind The Balancer swap kind, this can either be `GIVEN_IN` for
/// sell orders or `GIVEN_OUT` for buy orders.
/// @param swaps The swaps to perform.
/// @param tokens The tokens for the swaps. Swaps encode to and from tokens
/// as indices into this array.
/// @param funds The fund management settings, specifying the user the swap
/// is being performed for as well as the recipient of the proceeds.
/// @param limits Swap limits for encoding limit prices.
/// @param deadline The deadline for the swap.
/// @param feeTransfer The transfer data for the caller fee.
/// @return tokenDeltas The executed swap amounts.
function batchSwapWithFee(
IVault.SwapKind kind,
IVault.BatchSwapStep[] calldata swaps,
IERC20[] memory tokens,
IVault.FundManagement memory funds,
int256[] memory limits,
uint256 deadline,
GPv2Transfer.Data calldata feeTransfer
) external onlyCreator returns (int256[] memory tokenDeltas) {
tokenDeltas = vault.batchSwap(
kind,
swaps,
tokens,
funds,
limits,
deadline
);
vault.fastTransferFromAccount(feeTransfer, msg.sender);
}
}// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity >=0.7.6 <0.9.0;
/// @title Gnosis Protocol v2 Authentication Interface
/// @author Gnosis Developers
interface GPv2Authentication {
/// @dev determines whether the provided address is an authenticated solver.
/// @param prospectiveSolver the address of prospective solver.
/// @return true when prospectiveSolver is an authenticated solver, otherwise false.
function isSolver(address prospectiveSolver) external view returns (bool);
}// SPDX-License-Identifier: MIT
// Vendored from OpenZeppelin contracts with minor modifications:
// - Modified Solidity version
// - Formatted code
// - Added `name`, `symbol` and `decimals` function declarations
// <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/token/ERC20/IERC20.sol>
pragma solidity >=0.7.6 <0.9.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface 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 number of decimals the token uses.
*/
function decimals() external view returns (uint8);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(
address recipient,
uint256 amount
) 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 `amount` 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 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @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
);
}// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.6 <0.9.0;
pragma abicoder v2;
import "./IERC20.sol";
/**
* @dev Minimal interface for the Vault core contract only containing methods
* used by Gnosis Protocol V2. Original source:
* <https://github.com/balancer-labs/balancer-core-v2/blob/v1.0.0/contracts/vault/interfaces/IVault.sol>
*/
interface IVault {
// Internal Balance
//
// Users can deposit tokens into the Vault, where they are allocated to their Internal Balance, and later
// transferred or withdrawn. It can also be used as a source of tokens when joining Pools, as a destination
// when exiting them, and as either when performing swaps. This usage of Internal Balance results in greatly reduced
// gas costs when compared to relying on plain ERC20 transfers, leading to large savings for frequent users.
//
// Internal Balance management features batching, which means a single contract call can be used to perform multiple
// operations of different kinds, with different senders and recipients, at once.
/**
* @dev Performs a set of user balance operations, which involve Internal Balance (deposit, withdraw or transfer)
* and plain ERC20 transfers using the Vault's allowance. This last feature is particularly useful for relayers, as
* it lets integrators reuse a user's Vault allowance.
*
* For each operation, if the caller is not `sender`, it must be an authorized relayer for them.
*/
function manageUserBalance(UserBalanceOp[] memory ops) external payable;
/**
* @dev Data for `manageUserBalance` operations, which include the possibility for ETH to be sent and received
without manual WETH wrapping or unwrapping.
*/
struct UserBalanceOp {
UserBalanceOpKind kind;
IERC20 asset;
uint256 amount;
address sender;
address payable recipient;
}
// There are four possible operations in `manageUserBalance`:
//
// - DEPOSIT_INTERNAL
// Increases the Internal Balance of the `recipient` account by transferring tokens from the corresponding
// `sender`. The sender must have allowed the Vault to use their tokens via `IERC20.approve()`.
//
// ETH can be used by passing the ETH sentinel value as the asset and forwarding ETH in the call: it will be wrapped
// and deposited as WETH. Any ETH amount remaining will be sent back to the caller (not the sender, which is
// relevant for relayers).
//
// Emits an `InternalBalanceChanged` event.
//
//
// - WITHDRAW_INTERNAL
// Decreases the Internal Balance of the `sender` account by transferring tokens to the `recipient`.
//
// ETH can be used by passing the ETH sentinel value as the asset. This will deduct WETH instead, unwrap it and send
// it to the recipient as ETH.
//
// Emits an `InternalBalanceChanged` event.
//
//
// - TRANSFER_INTERNAL
// Transfers tokens from the Internal Balance of the `sender` account to the Internal Balance of `recipient`.
//
// Reverts if the ETH sentinel value is passed.
//
// Emits an `InternalBalanceChanged` event.
//
//
// - TRANSFER_EXTERNAL
// Transfers tokens from `sender` to `recipient`, using the Vault's ERC20 allowance. This is typically used by
// relayers, as it lets them reuse a user's Vault allowance.
//
// Reverts if the ETH sentinel value is passed.
//
// Emits an `ExternalBalanceTransfer` event.
enum UserBalanceOpKind {
DEPOSIT_INTERNAL,
WITHDRAW_INTERNAL,
TRANSFER_INTERNAL,
TRANSFER_EXTERNAL
}
// Swaps
//
// Users can swap tokens with Pools by calling the `swap` and `batchSwap` functions. To do this,
// they need not trust Pool contracts in any way: all security checks are made by the Vault. They must however be
// aware of the Pools' pricing algorithms in order to estimate the prices Pools will quote.
//
// The `swap` function executes a single swap, while `batchSwap` can perform multiple swaps in sequence.
// In each individual swap, tokens of one kind are sent from the sender to the Pool (this is the 'token in'),
// and tokens of another kind are sent from the Pool to the recipient in exchange (this is the 'token out').
// More complex swaps, such as one token in to multiple tokens out can be achieved by batching together
// individual swaps.
//
// There are two swap kinds:
// - 'given in' swaps, where the amount of tokens in (sent to the Pool) is known, and the Pool determines (via the
// `onSwap` hook) the amount of tokens out (to send to the recipient).
// - 'given out' swaps, where the amount of tokens out (received from the Pool) is known, and the Pool determines
// (via the `onSwap` hook) the amount of tokens in (to receive from the sender).
//
// Additionally, it is possible to chain swaps using a placeholder input amount, which the Vault replaces with
// the calculated output of the previous swap. If the previous swap was 'given in', this will be the calculated
// tokenOut amount. If the previous swap was 'given out', it will use the calculated tokenIn amount. These extended
// swaps are known as 'multihop' swaps, since they 'hop' through a number of intermediate tokens before arriving at
// the final intended token.
//
// In all cases, tokens are only transferred in and out of the Vault (or withdrawn from and deposited into Internal
// Balance) after all individual swaps have been completed, and the net token balance change computed. This makes
// certain swap patterns, such as multihops, or swaps that interact with the same token pair in multiple Pools, cost
// much less gas than they would otherwise.
//
// It also means that under certain conditions it is possible to perform arbitrage by swapping with multiple
// Pools in a way that results in net token movement out of the Vault (profit), with no tokens being sent in (only
// updating the Pool's internal accounting).
//
// To protect users from front-running or the market changing rapidly, they supply a list of 'limits' for each token
// involved in the swap, where either the maximum number of tokens to send (by passing a positive value) or the
// minimum amount of tokens to receive (by passing a negative value) is specified.
//
// Additionally, a 'deadline' timestamp can also be provided, forcing the swap to fail if it occurs after
// this point in time (e.g. if the transaction failed to be included in a block promptly).
//
// If interacting with Pools that hold WETH, it is possible to both send and receive ETH directly: the Vault will do
// the wrapping and unwrapping. To enable this mechanism, the IAsset sentinel value (the zero address) must be
// passed in the `assets` array instead of the WETH address. Note that it is possible to combine ETH and WETH in the
// same swap. Any excess ETH will be sent back to the caller (not the sender, which is relevant for relayers).
//
// Finally, Internal Balance can be used when either sending or receiving tokens.
enum SwapKind {
GIVEN_IN,
GIVEN_OUT
}
/**
* @dev Performs a swap with a single Pool.
*
* If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens
* taken from the Pool, which must be greater than or equal to `limit`.
*
* If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens
* sent to the Pool, which must be less than or equal to `limit`.
*
* Internal Balance usage and the recipient are determined by the `funds` struct.
*
* Emits a `Swap` event.
*/
function swap(
SingleSwap memory singleSwap,
FundManagement memory funds,
uint256 limit,
uint256 deadline
) external payable returns (uint256);
/**
* @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on
* the `kind` value.
*
* `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address).
* Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault.
*
* The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
* used to extend swap behavior.
*/
struct SingleSwap {
bytes32 poolId;
SwapKind kind;
IERC20 assetIn;
IERC20 assetOut;
uint256 amount;
bytes userData;
}
/**
* @dev Performs a series of swaps with one or multiple Pools. In each individual swap, the caller determines either
* the amount of tokens sent to or received from the Pool, depending on the `kind` value.
*
* Returns an array with the net Vault asset balance deltas. Positive amounts represent tokens (or ETH) sent to the
* Vault, and negative amounts represent tokens (or ETH) sent by the Vault. Each delta corresponds to the asset at
* the same index in the `assets` array.
*
* Swaps are executed sequentially, in the order specified by the `swaps` array. Each array element describes a
* Pool, the token to be sent to this Pool, the token to receive from it, and an amount that is either `amountIn` or
* `amountOut` depending on the swap kind.
*
* Multihop swaps can be executed by passing an `amount` value of zero for a swap. This will cause the amount in/out
* of the previous swap to be used as the amount in for the current one. In a 'given in' swap, 'tokenIn' must equal
* the previous swap's `tokenOut`. For a 'given out' swap, `tokenOut` must equal the previous swap's `tokenIn`.
*
* The `assets` array contains the addresses of all assets involved in the swaps. These are either token addresses,
* or the IAsset sentinel value for ETH (the zero address). Each entry in the `swaps` array specifies tokens in and
* out by referencing an index in `assets`. Note that Pools never interact with ETH directly: it will be wrapped to
* or unwrapped from WETH by the Vault.
*
* Internal Balance usage, sender, and recipient are determined by the `funds` struct. The `limits` array specifies
* the minimum or maximum amount of each token the vault is allowed to transfer.
*
* `batchSwap` can be used to make a single swap, like `swap` does, but doing so requires more gas than the
* equivalent `swap` call.
*
* Emits `Swap` events.
*/
function batchSwap(
SwapKind kind,
BatchSwapStep[] memory swaps,
IERC20[] memory assets,
FundManagement memory funds,
int256[] memory limits,
uint256 deadline
) external payable returns (int256[] memory);
/**
* @dev Data for each individual swap executed by `batchSwap`. The asset in and out fields are indexes into the
* `assets` array passed to that function, and ETH assets are converted to WETH.
*
* If `amount` is zero, the multihop mechanism is used to determine the actual amount based on the amount in/out
* from the previous swap, depending on the swap kind.
*
* The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
* used to extend swap behavior.
*/
struct BatchSwapStep {
bytes32 poolId;
uint256 assetInIndex;
uint256 assetOutIndex;
uint256 amount;
bytes userData;
}
/**
* @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the
* `recipient` account.
*
* If the caller is not `sender`, it must be an authorized relayer for them.
*
* If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20
* transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender`
* must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of
* `joinPool`.
*
* If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of
* transferred. This matches the behavior of `exitPool`.
*
* Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a
* revert.
*/
struct FundManagement {
address sender;
bool fromInternalBalance;
address payable recipient;
bool toInternalBalance;
}
}// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity >=0.7.6 <0.9.0;
/// @title Gnosis Protocol v2 Interaction Library
/// @author Gnosis Developers
library GPv2Interaction {
/// @dev Interaction data for performing arbitrary contract interactions.
/// Submitted to [`GPv2Settlement.settle`] for code execution.
struct Data {
address target;
uint256 value;
bytes callData;
}
/// @dev Execute an arbitrary contract interaction.
///
/// @param interaction Interaction data.
function execute(Data calldata interaction) internal {
address target = interaction.target;
uint256 value = interaction.value;
bytes calldata callData = interaction.callData;
// NOTE: Use assembly to call the interaction instead of a low level
// call for two reasons:
// - We don't want to copy the return data, since we discard it for
// interactions.
// - Solidity will under certain conditions generate code to copy input
// calldata twice to memory (the second being a "memcopy loop").
// <https://github.com/gnosis/gp-v2-contracts/pull/417#issuecomment-775091258>
// solhint-disable-next-line no-inline-assembly
assembly {
let freeMemoryPointer := mload(0x40)
calldatacopy(freeMemoryPointer, callData.offset, callData.length)
if iszero(
call(
gas(),
target,
value,
freeMemoryPointer,
callData.length,
0,
0
)
) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
}
/// @dev Extracts the Solidity ABI selector for the specified interaction.
///
/// @param interaction Interaction data.
/// @return result The 4 byte function selector of the call encoded in
/// this interaction.
function selector(
Data calldata interaction
) internal pure returns (bytes4 result) {
bytes calldata callData = interaction.callData;
if (callData.length >= 4) {
// NOTE: Read the first word of the interaction's calldata. The
// value does not need to be shifted since `bytesN` values are left
// aligned, and the value does not need to be masked since masking
// occurs when the value is accessed and not stored:
// <https://docs.soliditylang.org/en/v0.7.6/abi-spec.html#encoding-of-indexed-event-parameters>
// <https://docs.soliditylang.org/en/v0.7.6/assembly.html#access-to-external-variables-functions-and-libraries>
// solhint-disable-next-line no-inline-assembly
assembly {
result := calldataload(callData.offset)
}
}
}
}// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity >=0.7.6 <0.9.0;
import "../interfaces/IERC20.sol";
import "../mixins/GPv2Signing.sol";
import "./GPv2Order.sol";
/// @title Gnosis Protocol v2 Trade Library.
/// @author Gnosis Developers
library GPv2Trade {
using GPv2Order for GPv2Order.Data;
using GPv2Order for bytes;
/// @dev A struct representing a trade to be executed as part a batch
/// settlement.
struct Data {
uint256 sellTokenIndex;
uint256 buyTokenIndex;
address receiver;
uint256 sellAmount;
uint256 buyAmount;
uint32 validTo;
bytes32 appData;
uint256 feeAmount;
uint256 flags;
uint256 executedAmount;
bytes signature;
}
/// @dev Extracts the order data and signing scheme for the specified trade.
///
/// @param trade The trade.
/// @param tokens The list of tokens included in the settlement. The token
/// indices in the trade parameters map to tokens in this array.
/// @param order The memory location to extract the order data to.
function extractOrder(
Data calldata trade,
IERC20[] calldata tokens,
GPv2Order.Data memory order
) internal pure returns (GPv2Signing.Scheme signingScheme) {
order.sellToken = tokens[trade.sellTokenIndex];
order.buyToken = tokens[trade.buyTokenIndex];
order.receiver = trade.receiver;
order.sellAmount = trade.sellAmount;
order.buyAmount = trade.buyAmount;
order.validTo = trade.validTo;
order.appData = trade.appData;
order.feeAmount = trade.feeAmount;
(
order.kind,
order.partiallyFillable,
order.sellTokenBalance,
order.buyTokenBalance,
signingScheme
) = extractFlags(trade.flags);
}
/// @dev Decodes trade flags.
///
/// Trade flags are used to tightly encode information on how to decode
/// an order. Examples that directly affect the structure of an order are
/// the kind of order (either a sell or a buy order) as well as whether the
/// order is partially fillable or if it is a "fill-or-kill" order. It also
/// encodes the signature scheme used to validate the order. As the most
/// likely values are fill-or-kill sell orders by an externally owned
/// account, the flags are chosen such that `0x00` represents this kind of
/// order. The flags byte uses the following format:
///
/// ```
/// bit | 31 ... | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
/// ----+----------+-------+---+-------+---+---+
/// | reserved | * * | * | * * | * | * |
/// | | | | | | |
/// | | | | | | +---- order kind bit, 0 for a sell order
/// | | | | | | and 1 for a buy order
/// | | | | | |
/// | | | | | +-------- order fill bit, 0 for fill-or-kill
/// | | | | | and 1 for a partially fillable order
/// | | | | |
/// | | | +---+------------ use internal sell token balance bit:
/// | | | 0x: ERC20 token balance
/// | | | 10: external Balancer Vault balance
/// | | | 11: internal Balancer Vault balance
/// | | |
/// | | +-------------------- use buy token balance bit
/// | | 0: ERC20 token balance
/// | | 1: internal Balancer Vault balance
/// | |
/// +---+------------------------ signature scheme bits:
/// 00: EIP-712
/// 01: eth_sign
/// 10: EIP-1271
/// 11: pre_sign
/// ```
function extractFlags(
uint256 flags
)
internal
pure
returns (
bytes32 kind,
bool partiallyFillable,
bytes32 sellTokenBalance,
bytes32 buyTokenBalance,
GPv2Signing.Scheme signingScheme
)
{
if (flags & 0x01 == 0) {
kind = GPv2Order.KIND_SELL;
} else {
kind = GPv2Order.KIND_BUY;
}
partiallyFillable = flags & 0x02 != 0;
if (flags & 0x08 == 0) {
sellTokenBalance = GPv2Order.BALANCE_ERC20;
} else if (flags & 0x04 == 0) {
sellTokenBalance = GPv2Order.BALANCE_EXTERNAL;
} else {
sellTokenBalance = GPv2Order.BALANCE_INTERNAL;
}
if (flags & 0x10 == 0) {
buyTokenBalance = GPv2Order.BALANCE_ERC20;
} else {
buyTokenBalance = GPv2Order.BALANCE_INTERNAL;
}
// NOTE: Take advantage of the fact that Solidity will revert if the
// following expression does not produce a valid enum value. This means
// we check here that the leading reserved bits must be 0.
signingScheme = GPv2Signing.Scheme(flags >> 5);
}
}// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity >=0.7.6 <0.9.0;
pragma abicoder v2;
import "../interfaces/IERC20.sol";
import "../interfaces/IVault.sol";
import "./GPv2Order.sol";
import "./GPv2SafeERC20.sol";
/// @title Gnosis Protocol v2 Transfers
/// @author Gnosis Developers
library GPv2Transfer {
using GPv2SafeERC20 for IERC20;
/// @dev Transfer data.
struct Data {
address account;
IERC20 token;
uint256 amount;
bytes32 balance;
}
/// @dev Ether marker address used to indicate an Ether transfer.
address internal constant BUY_ETH_ADDRESS =
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev Execute the specified transfer from the specified account to a
/// recipient. The recipient will either receive internal Vault balances or
/// ERC20 token balances depending on whether the account is using internal
/// balances or not.
///
/// This method is used for transferring fees to the settlement contract
/// when settling a single order directly with Balancer.
///
/// Note that this method is subtly different from `transferFromAccounts`
/// with a single transfer with respect to how it deals with internal
/// balances. Specifically, this method will perform an **internal balance
/// transfer to the settlement contract instead of a withdrawal to the
/// external balance of the settlement contract** for trades that specify
/// trading with internal balances. This is done as a gas optimization in
/// the single order "fast-path".
///
/// @param vault The Balancer vault to use.
/// @param transfer The transfer to perform specifying the sender account.
/// @param recipient The recipient for the transfer.
function fastTransferFromAccount(
IVault vault,
Data calldata transfer,
address recipient
) internal {
require(
address(transfer.token) != BUY_ETH_ADDRESS,
"GPv2: cannot transfer native ETH"
);
if (transfer.balance == GPv2Order.BALANCE_ERC20) {
transfer.token.safeTransferFrom(
transfer.account,
recipient,
transfer.amount
);
} else {
IVault.UserBalanceOp[]
memory balanceOps = new IVault.UserBalanceOp[](1);
IVault.UserBalanceOp memory balanceOp = balanceOps[0];
balanceOp.kind = transfer.balance == GPv2Order.BALANCE_EXTERNAL
? IVault.UserBalanceOpKind.TRANSFER_EXTERNAL
: IVault.UserBalanceOpKind.TRANSFER_INTERNAL;
balanceOp.asset = transfer.token;
balanceOp.amount = transfer.amount;
balanceOp.sender = transfer.account;
balanceOp.recipient = payable(recipient);
vault.manageUserBalance(balanceOps);
}
}
/// @dev Execute the specified transfers from the specified accounts to a
/// single recipient. The recipient will receive all transfers as ERC20
/// token balances, regardless of whether or not the accounts are using
/// internal Vault balances.
///
/// This method is used for accumulating user balances into the settlement
/// contract.
///
/// @param vault The Balancer vault to use.
/// @param transfers The batched transfers to perform specifying the
/// sender accounts.
/// @param recipient The single recipient for all the transfers.
function transferFromAccounts(
IVault vault,
Data[] calldata transfers,
address recipient
) internal {
// NOTE: Allocate buffer of Vault balance operations large enough to
// hold all GP transfers. This is done to avoid re-allocations (which
// are gas inefficient) while still allowing all transfers to be batched
// into a single Vault call.
IVault.UserBalanceOp[] memory balanceOps = new IVault.UserBalanceOp[](
transfers.length
);
uint256 balanceOpCount = 0;
for (uint256 i = 0; i < transfers.length; i++) {
Data calldata transfer = transfers[i];
require(
address(transfer.token) != BUY_ETH_ADDRESS,
"GPv2: cannot transfer native ETH"
);
if (transfer.balance == GPv2Order.BALANCE_ERC20) {
transfer.token.safeTransferFrom(
transfer.account,
recipient,
transfer.amount
);
} else {
IVault.UserBalanceOp memory balanceOp = balanceOps[
balanceOpCount++
];
balanceOp.kind = transfer.balance == GPv2Order.BALANCE_EXTERNAL
? IVault.UserBalanceOpKind.TRANSFER_EXTERNAL
: IVault.UserBalanceOpKind.WITHDRAW_INTERNAL;
balanceOp.asset = transfer.token;
balanceOp.amount = transfer.amount;
balanceOp.sender = transfer.account;
balanceOp.recipient = payable(recipient);
}
}
if (balanceOpCount > 0) {
truncateBalanceOpsArray(balanceOps, balanceOpCount);
vault.manageUserBalance(balanceOps);
}
}
/// @dev Execute the specified transfers to their respective accounts.
///
/// This method is used for paying out trade proceeds from the settlement
/// contract.
///
/// @param vault The Balancer vault to use.
/// @param transfers The batched transfers to perform.
function transferToAccounts(
IVault vault,
Data[] memory transfers
) internal {
IVault.UserBalanceOp[] memory balanceOps = new IVault.UserBalanceOp[](
transfers.length
);
uint256 balanceOpCount = 0;
for (uint256 i = 0; i < transfers.length; i++) {
Data memory transfer = transfers[i];
if (address(transfer.token) == BUY_ETH_ADDRESS) {
require(
transfer.balance != GPv2Order.BALANCE_INTERNAL,
"GPv2: unsupported internal ETH"
);
payable(transfer.account).transfer(transfer.amount);
} else if (transfer.balance == GPv2Order.BALANCE_ERC20) {
transfer.token.safeTransfer(transfer.account, transfer.amount);
} else {
IVault.UserBalanceOp memory balanceOp = balanceOps[
balanceOpCount++
];
balanceOp.kind = IVault.UserBalanceOpKind.DEPOSIT_INTERNAL;
balanceOp.asset = transfer.token;
balanceOp.amount = transfer.amount;
balanceOp.sender = address(this);
balanceOp.recipient = payable(transfer.account);
}
}
if (balanceOpCount > 0) {
truncateBalanceOpsArray(balanceOps, balanceOpCount);
vault.manageUserBalance(balanceOps);
}
}
/// @dev Truncate a Vault balance operation array to its actual size.
///
/// This method **does not** check whether or not the new length is valid,
/// and specifying a size that is larger than the array's actual length is
/// undefined behaviour.
///
/// @param balanceOps The memory array of balance operations to truncate.
/// @param newLength The new length to set.
function truncateBalanceOpsArray(
IVault.UserBalanceOp[] memory balanceOps,
uint256 newLength
) private pure {
// NOTE: Truncate the vault transfers array to the specified length.
// This is done by setting the array's length which occupies the first
// word in memory pointed to by the `balanceOps` memory variable.
// <https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html>
// solhint-disable-next-line no-inline-assembly
assembly {
mstore(balanceOps, newLength)
}
}
}// SPDX-License-Identifier: MIT
// Vendored from OpenZeppelin contracts with minor modifications:
// - Modified Solidity version
// - Formatted code
// - Shortened revert messages
// - Removed unused methods
// - Convert to `type(*).*` notation
// <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/utils/SafeCast.sol>
pragma solidity >=0.7.6 <0.9.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX 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.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @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) {
require(value >= 0, "SafeCast: not positive");
return uint256(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) {
require(
value <= uint256(type(int256).max),
"SafeCast: int256 overflow"
);
return int256(value);
}
}// SPDX-License-Identifier: MIT
// Vendored from OpenZeppelin contracts with minor modifications:
// - Modified Solidity version
// - Formatted code
// - Shortened some revert messages
// - Removed unused methods
// - Added `ceilDiv` method
// <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/math/SafeMath.sol>
pragma solidity >=0.7.6 <0.9.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when 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 SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: mul overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by 0");
return a / b;
}
/**
* @dev Returns the ceiling integer division of two unsigned integers,
* reverting on division by zero. The result is rounded towards up the
* nearest integer, instead of truncating the fractional part.
*
* Requirements:
*
* - The divisor cannot be zero.
* - The sum of the dividend and divisor cannot overflow.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: ceiling division by 0");
return a / b + (a % b == 0 ? 0 : 1);
}
}// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity >=0.7.6 <0.9.0;
import "../interfaces/GPv2EIP1271.sol";
import "../libraries/GPv2Order.sol";
import "../libraries/GPv2Trade.sol";
/// @title Gnosis Protocol v2 Signing Library.
/// @author Gnosis Developers
abstract contract GPv2Signing {
using GPv2Order for GPv2Order.Data;
using GPv2Order for bytes;
/// @dev Recovered trade data containing the extracted order and the
/// recovered owner address.
struct RecoveredOrder {
GPv2Order.Data data;
bytes uid;
address owner;
address receiver;
}
/// @dev Signing scheme used for recovery.
enum Scheme {
Eip712,
EthSign,
Eip1271,
PreSign
}
/// @dev The EIP-712 domain type hash used for computing the domain
/// separator.
bytes32 private constant DOMAIN_TYPE_HASH =
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
/// @dev The EIP-712 domain name used for computing the domain separator.
bytes32 private constant DOMAIN_NAME = keccak256("Gnosis Protocol");
/// @dev The EIP-712 domain version used for computing the domain separator.
bytes32 private constant DOMAIN_VERSION = keccak256("v2");
/// @dev Marker value indicating an order is pre-signed.
uint256 private constant PRE_SIGNED =
uint256(keccak256("GPv2Signing.Scheme.PreSign"));
/// @dev The domain separator used for signing orders that gets mixed in
/// making signatures for different domains incompatible. This domain
/// separator is computed following the EIP-712 standard and has replay
/// protection mixed in so that signed orders are only valid for specific
/// GPv2 contracts.
bytes32 public immutable domainSeparator;
/// @dev Storage indicating whether or not an order has been signed by a
/// particular address.
mapping(bytes => uint256) public preSignature;
/// @dev Event that is emitted when an account either pre-signs an order or
/// revokes an existing pre-signature.
event PreSignature(address indexed owner, bytes orderUid, bool signed);
constructor() {
// NOTE: Currently, the only way to get the chain ID in solidity is
// using assembly.
uint256 chainId;
// solhint-disable-next-line no-inline-assembly
assembly {
chainId := chainid()
}
domainSeparator = keccak256(
abi.encode(
DOMAIN_TYPE_HASH,
DOMAIN_NAME,
DOMAIN_VERSION,
chainId,
address(this)
)
);
}
/// @dev Sets a presignature for the specified order UID.
///
/// @param orderUid The unique identifier of the order to pre-sign.
/// @param signed True to set the order as tradable with pre-sign, false to
/// false to unset it.
function setPreSignature(bytes calldata orderUid, bool signed) external {
(, address owner, ) = orderUid.extractOrderUidParams();
require(owner == msg.sender, "GPv2: cannot presign order");
if (signed) {
preSignature[orderUid] = PRE_SIGNED;
} else {
preSignature[orderUid] = 0;
}
emit PreSignature(owner, orderUid, signed);
}
/// @dev Returns an empty recovered order with a pre-allocated buffer for
/// packing the unique identifier.
///
/// @return recoveredOrder The empty recovered order data.
function allocateRecoveredOrder()
internal
pure
returns (RecoveredOrder memory recoveredOrder)
{
recoveredOrder.uid = new bytes(GPv2Order.UID_LENGTH);
}
/// @dev Extracts order data and recovers the signer from the specified
/// trade.
///
/// @param recoveredOrder Memory location used for writing the recovered order data.
/// @param tokens The list of tokens included in the settlement. The token
/// indices in the trade parameters map to tokens in this array.
/// @param trade The trade data to recover the order data from.
function recoverOrderFromTrade(
RecoveredOrder memory recoveredOrder,
IERC20[] calldata tokens,
GPv2Trade.Data calldata trade
) internal view {
GPv2Order.Data memory order = recoveredOrder.data;
Scheme signingScheme = GPv2Trade.extractOrder(trade, tokens, order);
(bytes32 orderDigest, address owner) = recoverOrderSigner(
order,
signingScheme,
trade.signature
);
recoveredOrder.uid.packOrderUidParams(
orderDigest,
owner,
order.validTo
);
recoveredOrder.owner = owner;
recoveredOrder.receiver = order.actualReceiver(owner);
}
/// @dev The length of any signature from an externally owned account.
uint256 private constant ECDSA_SIGNATURE_LENGTH = 65;
/// @dev Recovers an order's signer from the specified order and signature.
///
/// @param order The order to recover a signature for.
/// @param signingScheme The signing scheme.
/// @param signature The signature bytes.
/// @return orderDigest The computed order hash.
/// @return owner The recovered address from the specified signature.
function recoverOrderSigner(
GPv2Order.Data memory order,
Scheme signingScheme,
bytes calldata signature
) internal view returns (bytes32 orderDigest, address owner) {
orderDigest = order.hash(domainSeparator);
if (signingScheme == Scheme.Eip712) {
owner = recoverEip712Signer(orderDigest, signature);
} else if (signingScheme == Scheme.EthSign) {
owner = recoverEthsignSigner(orderDigest, signature);
} else if (signingScheme == Scheme.Eip1271) {
owner = recoverEip1271Signer(orderDigest, signature);
} else {
// signingScheme == Scheme.PreSign
owner = recoverPreSigner(orderDigest, signature, order.validTo);
}
}
/// @dev Perform an ECDSA recover for the specified message and calldata
/// signature.
///
/// The signature is encoded by tighyly packing the following struct:
/// ```
/// struct EncodedSignature {
/// bytes32 r;
/// bytes32 s;
/// uint8 v;
/// }
/// ```
///
/// @param message The signed message.
/// @param encodedSignature The encoded signature.
function ecdsaRecover(
bytes32 message,
bytes calldata encodedSignature
) internal pure returns (address signer) {
require(
encodedSignature.length == ECDSA_SIGNATURE_LENGTH,
"GPv2: malformed ecdsa signature"
);
bytes32 r;
bytes32 s;
uint8 v;
// NOTE: Use assembly to efficiently decode signature data.
// solhint-disable-next-line no-inline-assembly
assembly {
// r = uint256(encodedSignature[0:32])
r := calldataload(encodedSignature.offset)
// s = uint256(encodedSignature[32:64])
s := calldataload(add(encodedSignature.offset, 32))
// v = uint8(encodedSignature[64])
v := shr(248, calldataload(add(encodedSignature.offset, 64)))
}
signer = ecrecover(message, v, r, s);
require(signer != address(0), "GPv2: invalid ecdsa signature");
}
/// @dev Decodes signature bytes originating from an EIP-712-encoded
/// signature.
///
/// EIP-712 signs typed data. The specifications are described in the
/// related EIP (<https://eips.ethereum.org/EIPS/eip-712>).
///
/// EIP-712 signatures are encoded as standard ECDSA signatures as described
/// in the corresponding decoding function [`ecdsaRecover`].
///
/// @param orderDigest The EIP-712 signing digest derived from the order
/// parameters.
/// @param encodedSignature Calldata pointing to tightly packed signature
/// bytes.
/// @return owner The address of the signer.
function recoverEip712Signer(
bytes32 orderDigest,
bytes calldata encodedSignature
) internal pure returns (address owner) {
owner = ecdsaRecover(orderDigest, encodedSignature);
}
/// @dev Decodes signature bytes originating from the output of the eth_sign
/// RPC call.
///
/// The specifications are described in the Ethereum documentation
/// (<https://eth.wiki/json-rpc/API#eth_sign>).
///
/// eth_sign signatures are encoded as standard ECDSA signatures as
/// described in the corresponding decoding function
/// [`ecdsaRecover`].
///
/// @param orderDigest The EIP-712 signing digest derived from the order
/// parameters.
/// @param encodedSignature Calldata pointing to tightly packed signature
/// bytes.
/// @return owner The address of the signer.
function recoverEthsignSigner(
bytes32 orderDigest,
bytes calldata encodedSignature
) internal pure returns (address owner) {
// The signed message is encoded as:
// `"\x19Ethereum Signed Message:\n" || length || data`, where
// the length is a constant (32 bytes) and the data is defined as:
// `orderDigest`.
bytes32 ethsignDigest = keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", orderDigest)
);
owner = ecdsaRecover(ethsignDigest, encodedSignature);
}
/// @dev Verifies the input calldata as an EIP-1271 contract signature and
/// returns the address of the signer.
///
/// The encoded signature tightly packs the following struct:
///
/// ```
/// struct EncodedEip1271Signature {
/// address owner;
/// bytes signature;
/// }
/// ```
///
/// This function enforces that the encoded data stores enough bytes to
/// cover the full length of the decoded signature.
///
/// @param encodedSignature The encoded EIP-1271 signature.
/// @param orderDigest The EIP-712 signing digest derived from the order
/// parameters.
/// @return owner The address of the signer.
function recoverEip1271Signer(
bytes32 orderDigest,
bytes calldata encodedSignature
) internal view returns (address owner) {
// NOTE: Use assembly to read the verifier address from the encoded
// signature bytes.
// solhint-disable-next-line no-inline-assembly
assembly {
// owner = address(encodedSignature[0:20])
owner := shr(96, calldataload(encodedSignature.offset))
}
// NOTE: Configure prettier to ignore the following line as it causes
// a panic in the Solidity plugin.
// prettier-ignore
bytes calldata signature = encodedSignature[20:];
require(
EIP1271Verifier(owner).isValidSignature(orderDigest, signature) ==
GPv2EIP1271.MAGICVALUE,
"GPv2: invalid eip1271 signature"
);
}
/// @dev Verifies the order has been pre-signed. The signature is the
/// address of the signer of the order.
///
/// @param orderDigest The EIP-712 signing digest derived from the order
/// parameters.
/// @param encodedSignature The pre-sign signature reprenting the order UID.
/// @param validTo The order expiry timestamp.
/// @return owner The address of the signer.
function recoverPreSigner(
bytes32 orderDigest,
bytes calldata encodedSignature,
uint32 validTo
) internal view returns (address owner) {
require(encodedSignature.length == 20, "GPv2: malformed presignature");
// NOTE: Use assembly to read the owner address from the encoded
// signature bytes.
// solhint-disable-next-line no-inline-assembly
assembly {
// owner = address(encodedSignature[0:20])
owner := shr(96, calldataload(encodedSignature.offset))
}
bytes memory orderUid = new bytes(GPv2Order.UID_LENGTH);
orderUid.packOrderUidParams(orderDigest, owner, validTo);
require(
preSignature[orderUid] == PRE_SIGNED,
"GPv2: order not presigned"
);
}
}// SPDX-License-Identifier: MIT
// Vendored from OpenZeppelin contracts with minor modifications:
// - Modified Solidity version
// - Formatted code
// <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/utils/ReentrancyGuard.sol>
pragma solidity >=0.7.6 <0.9.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: LGPL-3.0-only
// Vendored from Gnosis utility contracts with minor modifications:
// - Modified Solidity version
// - Formatted code
// - Added linter directives to ignore low level call and assembly warnings
// <https://github.com/gnosis/util-contracts/blob/v3.1.0-solc-7/contracts/StorageAccessible.sol>
pragma solidity >=0.7.6 <0.9.0;
/// @title ViewStorageAccessible - Interface on top of StorageAccessible base class to allow simulations from view functions
interface ViewStorageAccessible {
/**
* @dev Same as `simulateDelegatecall` on StorageAccessible. Marked as view so that it can be called from external contracts
* that want to run simulations from within view functions. Will revert if the invoked simulation attempts to change state.
*/
function simulateDelegatecall(
address targetContract,
bytes memory calldataPayload
) external view returns (bytes memory);
/**
* @dev Same as `getStorageAt` on StorageAccessible. This method allows reading aribtrary ranges of storage.
*/
function getStorageAt(
uint256 offset,
uint256 length
) external view returns (bytes memory);
}
/// @title StorageAccessible - generic base contract that allows callers to access all internal storage.
contract StorageAccessible {
/**
* @dev Reads `length` bytes of storage in the currents contract
* @param offset - the offset in the current contract's storage in words to start reading from
* @param length - the number of words (32 bytes) of data to read
* @return the bytes that were read.
*/
function getStorageAt(
uint256 offset,
uint256 length
) external view returns (bytes memory) {
bytes memory result = new bytes(length * 32);
for (uint256 index = 0; index < length; index++) {
// solhint-disable-next-line no-inline-assembly
assembly {
let word := sload(add(offset, index))
mstore(add(add(result, 0x20), mul(index, 0x20)), word)
}
}
return result;
}
/**
* @dev Performs a delegetecall on a targetContract in the context of self.
* Internally reverts execution to avoid side effects (making it static). Catches revert and returns encoded result as bytes.
* @param targetContract Address of the contract containing the code to execute.
* @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
*/
function simulateDelegatecall(
address targetContract,
bytes memory calldataPayload
) public returns (bytes memory response) {
bytes memory innerCall = abi.encodeWithSelector(
this.simulateDelegatecallInternal.selector,
targetContract,
calldataPayload
);
// solhint-disable-next-line avoid-low-level-calls
(, response) = address(this).call(innerCall);
bool innerSuccess = response[response.length - 1] == 0x01;
setLength(response, response.length - 1);
if (innerSuccess) {
return response;
} else {
revertWith(response);
}
}
/**
* @dev Performs a delegetecall on a targetContract in the context of self.
* Internally reverts execution to avoid side effects (making it static). Returns encoded result as revert message
* concatenated with the success flag of the inner call as a last byte.
* @param targetContract Address of the contract containing the code to execute.
* @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
*/
function simulateDelegatecallInternal(
address targetContract,
bytes memory calldataPayload
) external returns (bytes memory response) {
bool success;
// solhint-disable-next-line avoid-low-level-calls
(success, response) = targetContract.delegatecall(calldataPayload);
revertWith(abi.encodePacked(response, success));
}
function revertWith(bytes memory response) internal pure {
// solhint-disable-next-line no-inline-assembly
assembly {
revert(add(response, 0x20), mload(response))
}
}
function setLength(bytes memory buffer, uint256 length) internal pure {
// solhint-disable-next-line no-inline-assembly
assembly {
mstore(buffer, length)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC-20
* applications.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* Both values are immutable: they can only be set once during construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Skips emitting an {Approval} event indicating an allowance update. This is not
* required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
*
* ```solidity
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner`'s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance < type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
/// @notice Interface for an InfiniFi Farm contract
interface IFarm {
/// @notice emitted when there is a deposit of withdrawal from the farm
event AssetsUpdated(uint256 timestamp, uint256 assetsBefore, uint256 assetsAfter);
// --------------------------------------------------------------------
// Accounting
// --------------------------------------------------------------------
/// @notice the cap of the farm
function cap() external view returns (uint256);
/// @notice the asset used by deposits and withdrawals in the farm
function assetToken() external view returns (address);
/// @notice the total assets in the farm, reported as a balance of asset()
function assets() external view returns (uint256);
// --------------------------------------------------------------------
// Adapter logic
// --------------------------------------------------------------------
/// @notice deposit all asset() held by the contract into the farm
function deposit() external;
/// @notice Returns the max deposit amount for the underlying protocol
function maxDeposit() external view returns (uint256);
/// @notice withdraw an amount of the asset() from the farm
/// @param amount Amount of assets to withdraw
/// @param to Address to receive the withdrawn assets
function withdraw(uint256 amount, address to) external;
/// @notice available number of assetToken() withdrawable instantly from the farm
function liquidity() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {CoreRoles} from "@libraries/CoreRoles.sol";
import {InfiniFiCore} from "@core/InfiniFiCore.sol";
/// @notice Defines some modifiers and utilities around interacting with Core
abstract contract CoreControlled is Pausable {
error UnderlyingCallReverted(bytes returnData);
/// @notice emitted when the reference to core is updated
event CoreUpdate(address indexed oldCore, address indexed newCore);
/// @notice reference to Core
InfiniFiCore private _core;
constructor(address coreAddress) {
_core = InfiniFiCore(coreAddress);
}
/// @notice named onlyCoreRole to prevent collision with OZ onlyRole modifier
modifier onlyCoreRole(bytes32 role) {
require(_core.hasRole(role, msg.sender), "UNAUTHORIZED");
_;
}
/// @notice address of the Core contract referenced
function core() public view returns (InfiniFiCore) {
return _core;
}
/// @notice WARNING CALLING THIS FUNCTION CAN POTENTIALLY
/// BRICK A CONTRACT IF CORE IS SET INCORRECTLY
/// @notice set new reference to core
/// only callable by governor
/// @param newCore to reference
function setCore(address newCore) external onlyCoreRole(CoreRoles.GOVERNOR) {
_setCore(newCore);
}
/// @notice WARNING CALLING THIS FUNCTION CAN POTENTIALLY
/// BRICK A CONTRACT IF CORE IS SET INCORRECTLY
/// @notice set new reference to core
/// @param newCore to reference
function _setCore(address newCore) internal {
address oldCore = address(_core);
_core = InfiniFiCore(newCore);
emit CoreUpdate(oldCore, newCore);
}
/// @notice set pausable methods to paused
function pause() public onlyCoreRole(CoreRoles.PAUSE) {
_pause();
}
/// @notice set pausable methods to unpaused
function unpause() public onlyCoreRole(CoreRoles.UNPAUSE) {
_unpause();
}
/// ------------------------------------------
/// ------------ Emergency Action ------------
/// ------------------------------------------
/// inspired by MakerDAO Multicall:
/// https://github.com/makerdao/multicall/blob/master/src/Multicall.sol
/// @notice struct to pack calldata and targets for an emergency action
struct Call {
/// @notice target address to call
address target;
/// @notice amount of eth to send with the call
uint256 value;
/// @notice payload to send to target
bytes callData;
}
/// @notice due to inflexibility of current smart contracts,
/// add this ability to be able to execute arbitrary calldata
/// against arbitrary addresses.
/// callable only by governor
function emergencyAction(Call[] calldata calls)
external
payable
virtual
onlyCoreRole(CoreRoles.GOVERNOR)
returns (bytes[] memory returnData)
{
returnData = new bytes[](calls.length);
for (uint256 i = 0; i < calls.length; i++) {
address payable target = payable(calls[i].target);
uint256 value = calls[i].value;
bytes calldata callData = calls[i].callData;
(bool success, bytes memory returned) = target.call{value: value}(callData);
require(success, UnderlyingCallReverted(returned));
returnData[i] = returned;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IFarm} from "@interfaces/IFarm.sol";
import {CoreRoles} from "@libraries/CoreRoles.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {CoreControlled} from "@core/CoreControlled.sol";
/// @notice InfiniFi Farm registry
contract FarmRegistry is CoreControlled {
error FarmAlreadyAdded(address farm);
error FarmNotFound(address farm);
error AssetNotEnabled(address farm, address asset);
error AssetAlreadyEnabled(address asset);
error AssetNotFound(address asset);
event AssetEnabled(uint256 indexed timestamp, address asset);
event AssetDisabled(uint256 indexed timestamp, address asset);
event FarmsAdded(uint256 indexed timestamp, uint256 farmType, address[] indexed farms);
event FarmsRemoved(uint256 indexed timestamp, uint256 farmType, address[] indexed farms);
using EnumerableSet for EnumerableSet.AddressSet;
EnumerableSet.AddressSet private assets;
EnumerableSet.AddressSet private farms;
mapping(uint256 _type => EnumerableSet.AddressSet _farms) private typeFarms;
mapping(address _asset => EnumerableSet.AddressSet _farms) private assetFarms;
mapping(address _asset => mapping(uint256 _type => EnumerableSet.AddressSet _farms)) private assetTypeFarms;
constructor(address _core) CoreControlled(_core) {}
/// ----------------------------------------------------------------------------
/// READ METHODS
/// ----------------------------------------------------------------------------
function getEnabledAssets() external view returns (address[] memory) {
return assets.values();
}
function isAssetEnabled(address _asset) external view returns (bool) {
return assets.contains(_asset);
}
function getFarms() external view returns (address[] memory) {
return farms.values();
}
function getTypeFarms(uint256 _type) external view returns (address[] memory) {
return typeFarms[_type].values();
}
function getAssetFarms(address _asset) external view returns (address[] memory) {
return assetFarms[_asset].values();
}
function getAssetTypeFarms(address _asset, uint256 _type) external view returns (address[] memory) {
return assetTypeFarms[_asset][_type].values();
}
function isFarm(address _farm) external view returns (bool) {
return farms.contains(_farm);
}
function isFarmOfAsset(address _farm, address _asset) external view returns (bool) {
return assetFarms[_asset].contains(_farm);
}
function isFarmOfType(address _farm, uint256 _type) external view returns (bool) {
return typeFarms[_type].contains(_farm);
}
/// ----------------------------------------------------------------------------
/// WRITE METHODS
/// ----------------------------------------------------------------------------
function enableAsset(address _asset) external onlyCoreRole(CoreRoles.GOVERNOR) {
require(assets.add(_asset), AssetAlreadyEnabled(_asset));
emit AssetEnabled(block.timestamp, _asset);
}
function disableAsset(address _asset) external onlyCoreRole(CoreRoles.GOVERNOR) {
require(assets.remove(_asset), AssetNotFound(_asset));
emit AssetDisabled(block.timestamp, _asset);
}
function addFarms(uint256 _type, address[] calldata _list) external onlyCoreRole(CoreRoles.PROTOCOL_PARAMETERS) {
_addFarms(_type, _list);
emit FarmsAdded(block.timestamp, _type, _list);
}
function removeFarms(uint256 _type, address[] calldata _list)
external
onlyCoreRole(CoreRoles.PROTOCOL_PARAMETERS)
{
_removeFarms(_type, _list);
emit FarmsRemoved(block.timestamp, _type, _list);
}
/// ----------------------------------------------------------------------------
/// INTERNAL METHODS
/// ----------------------------------------------------------------------------
function _addFarms(uint256 _type, address[] calldata _list) internal {
for (uint256 i = 0; i < _list.length; i++) {
address farmAsset = IFarm(_list[i]).assetToken();
require(assets.contains(farmAsset), AssetNotEnabled(_list[i], farmAsset));
require(farms.add(_list[i]), FarmAlreadyAdded(_list[i]));
require(typeFarms[_type].add(_list[i]), FarmAlreadyAdded(_list[i]));
require(assetFarms[farmAsset].add(_list[i]), FarmAlreadyAdded(_list[i]));
require(assetTypeFarms[farmAsset][_type].add(_list[i]), FarmAlreadyAdded(_list[i]));
}
}
function _removeFarms(uint256 _type, address[] calldata _list) internal {
for (uint256 i = 0; i < _list.length; i++) {
address farmAsset = IFarm(_list[i]).assetToken();
require(farms.remove(_list[i]), FarmNotFound(_list[i]));
require(typeFarms[_type].remove(_list[i]), FarmNotFound(_list[i]));
require(assetFarms[farmAsset].remove(_list[i]), FarmNotFound(_list[i]));
require(assetTypeFarms[farmAsset][_type].remove(_list[i]), FarmNotFound(_list[i]));
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IOracle} from "@interfaces/IOracle.sol";
import {CoreControlled, CoreRoles} from "@core/CoreControlled.sol";
contract FixedPriceOracle is IOracle, CoreControlled {
uint256 public price;
event PriceSet(uint256 indexed timestamp, uint256 price);
constructor(address _core, uint256 _price) CoreControlled(_core) {
price = _price;
}
function setPrice(uint256 _price) external onlyCoreRole(CoreRoles.ORACLE_MANAGER) {
price = _price;
emit PriceSet(block.timestamp, _price);
}
}// 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.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity >=0.7.6 <0.9.0;
import "../interfaces/IERC20.sol";
/// @title Gnosis Protocol v2 Safe ERC20 Transfer Library
/// @author Gnosis Developers
/// @dev Gas-efficient version of Openzeppelin's SafeERC20 contract.
library GPv2SafeERC20 {
/// @dev Wrapper around a call to the ERC20 function `transfer` that reverts
/// also when the token returns `false`.
function safeTransfer(IERC20 token, address to, uint256 value) internal {
bytes4 selector_ = token.transfer.selector;
// solhint-disable-next-line no-inline-assembly
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, selector_)
mstore(
add(freeMemoryPointer, 4),
and(to, 0xffffffffffffffffffffffffffffffffffffffff)
)
mstore(add(freeMemoryPointer, 36), value)
if iszero(call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
require(getLastTransferResult(token), "GPv2: failed transfer");
}
/// @dev Wrapper around a call to the ERC20 function `transferFrom` that
/// reverts also when the token returns `false`.
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
bytes4 selector_ = token.transferFrom.selector;
// solhint-disable-next-line no-inline-assembly
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, selector_)
mstore(
add(freeMemoryPointer, 4),
and(from, 0xffffffffffffffffffffffffffffffffffffffff)
)
mstore(
add(freeMemoryPointer, 36),
and(to, 0xffffffffffffffffffffffffffffffffffffffff)
)
mstore(add(freeMemoryPointer, 68), value)
if iszero(call(gas(), token, 0, freeMemoryPointer, 100, 0, 0)) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
require(getLastTransferResult(token), "GPv2: failed transferFrom");
}
/// @dev Verifies that the last return was a successful `transfer*` call.
/// This is done by checking that the return data is either empty, or
/// is a valid ABI encoded boolean.
function getLastTransferResult(
IERC20 token
) private view returns (bool success) {
// NOTE: Inspecting previous return data requires assembly. Note that
// we write the return data to memory 0 in the case where the return
// data size is 32, this is OK since the first 64 bytes of memory are
// reserved by Solidy as a scratch space that can be used within
// assembly blocks.
// <https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html>
// solhint-disable-next-line no-inline-assembly
assembly {
/// @dev Revert with an ABI encoded Solidity error with a message
/// that fits into 32-bytes.
///
/// An ABI encoded Solidity error has the following memory layout:
///
/// ------------+----------------------------------
/// byte range | value
/// ------------+----------------------------------
/// 0x00..0x04 | selector("Error(string)")
/// 0x04..0x24 | string offset (always 0x20)
/// 0x24..0x44 | string length
/// 0x44..0x64 | string value, padded to 32-bytes
function revertWithMessage(length, message) {
mstore(0x00, "\x08\xc3\x79\xa0")
mstore(0x04, 0x20)
mstore(0x24, length)
mstore(0x44, message)
revert(0x00, 0x64)
}
switch returndatasize()
// Non-standard ERC20 transfer without return.
case 0 {
// NOTE: When the return data size is 0, verify that there
// is code at the address. This is done in order to maintain
// compatibility with Solidity calling conventions.
// <https://docs.soliditylang.org/en/v0.7.6/control-structures.html#external-function-calls>
if iszero(extcodesize(token)) {
revertWithMessage(20, "GPv2: not a contract")
}
success := 1
}
// Standard ERC20 transfer returning boolean success value.
case 32 {
returndatacopy(0, 0, returndatasize())
// NOTE: For ABI encoding v1, any non-zero value is accepted
// as `true` for a boolean. In order to stay compatible with
// OpenZeppelin's `SafeERC20` library which is known to work
// with the existing ERC20 implementation we care about,
// make sure we return success for any non-zero return value
// from the `transfer*` call.
success := iszero(iszero(mload(0)))
}
default {
revertWithMessage(31, "GPv2: malformed transfer result")
}
}
}
}// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity >=0.7.6 <0.9.0;
library GPv2EIP1271 {
/// @dev Value returned by a call to `isValidSignature` if the signature
/// was verified successfully. The value is defined in EIP-1271 as:
/// bytes4(keccak256("isValidSignature(bytes32,bytes)"))
bytes4 internal constant MAGICVALUE = 0x1626ba7e;
}
/// @title EIP1271 Interface
/// @dev Standardized interface for an implementation of smart contract
/// signatures as described in EIP-1271. The code that follows is identical to
/// the code in the standard with the exception of formatting and syntax
/// changes to adapt the code to our Solidity version.
interface EIP1271Verifier {
/// @dev Should return whether the signature provided is valid for the
/// provided data
/// @param _hash Hash of the data to be signed
/// @param _signature Signature byte array associated with _data
///
/// MUST return the bytes4 magic value 0x1626ba7e when function passes.
/// MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for
/// solc > 0.5)
/// MUST allow external calls
///
function isValidSignature(
bytes32 _hash,
bytes memory _signature
) external view returns (bytes4 magicValue);
}// 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.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) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC-20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC-721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC-1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
bool private _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {CoreRoles} from "@libraries/CoreRoles.sol";
import {AccessControlEnumerable} from "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol";
/// @notice Maintains roles and access control
contract InfiniFiCore is AccessControlEnumerable {
error RoleAlreadyExists(bytes32 role);
error RoleDoesNotExist(bytes32 role);
error LengthMismatch(uint256 expected, uint256 actual);
/// @notice construct Core
constructor() {
// For initial setup before going live, deployer can then call
// renounceRole(bytes32 role, address account)
_grantRole(CoreRoles.GOVERNOR, msg.sender);
// Initial roles setup: direct hierarchy, everything under governor
_setRoleAdmin(CoreRoles.GOVERNOR, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.PAUSE, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.UNPAUSE, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.PROTOCOL_PARAMETERS, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.MINOR_ROLES_MANAGER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.ENTRY_POINT, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.RECEIPT_TOKEN_MINTER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.RECEIPT_TOKEN_BURNER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.LOCKED_TOKEN_MANAGER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.TRANSFER_RESTRICTOR, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.FARM_MANAGER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.MANUAL_REBALANCER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.PERIODIC_REBALANCER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.EMERGENCY_WITHDRAWAL, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.FARM_SWAP_CALLER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.ORACLE_MANAGER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.FINANCE_MANAGER, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.PROPOSER_ROLE, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.EXECUTOR_ROLE, CoreRoles.GOVERNOR);
_setRoleAdmin(CoreRoles.CANCELLER_ROLE, CoreRoles.GOVERNOR);
}
/// @notice creates a new role to be maintained
/// @param role the new role id
/// @param adminRole the admin role id for `role`
function createRole(bytes32 role, bytes32 adminRole) external onlyRole(CoreRoles.GOVERNOR) {
require(getRoleAdmin(role) == bytes32(0), RoleAlreadyExists(role));
_setRoleAdmin(role, adminRole);
}
/// @notice override admin role of an existing role
/// @param role the role id
/// @param adminRole the admin role id
function setRoleAdmin(bytes32 role, bytes32 adminRole) external onlyRole(CoreRoles.GOVERNOR) {
require(getRoleAdmin(role) != bytes32(0), RoleDoesNotExist(role));
_setRoleAdmin(role, adminRole);
}
/// @notice batch granting of roles to various addresses
/// @dev if msg.sender does not have admin role needed to grant any of the
/// granted roles, the whole transaction reverts.
function grantRoles(bytes32[] calldata roles, address[] calldata accounts) external {
require(roles.length == accounts.length, LengthMismatch(roles.length, accounts.length));
for (uint256 i = 0; i < roles.length; i++) {
_checkRole(getRoleAdmin(roles[i]));
_grantRole(roles[i], accounts[i]);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
import {Arrays} from "../Arrays.sol";
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
* - Set can be cleared (all elements removed) in O(n).
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function _clear(Set storage set) private {
uint256 len = _length(set);
for (uint256 i = 0; i < len; ++i) {
delete set._positions[set._values[i]];
}
Arrays.unsafeSetLength(set._values, 0);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(Bytes32Set storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(AddressSet storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(UintSet storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
}// 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) (access/extensions/AccessControlEnumerable.sol)
pragma solidity ^0.8.20;
import {IAccessControlEnumerable} from "./IAccessControlEnumerable.sol";
import {AccessControl} from "../AccessControl.sol";
import {EnumerableSet} from "../../utils/structs/EnumerableSet.sol";
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
using EnumerableSet for EnumerableSet.AddressSet;
mapping(bytes32 role => EnumerableSet.AddressSet) private _roleMembers;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {
return _roleMembers[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {
return _roleMembers[role].length();
}
/**
* @dev Return all accounts that have `role`
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function getRoleMembers(bytes32 role) public view virtual returns (address[] memory) {
return _roleMembers[role].values();
}
/**
* @dev Overload {AccessControl-_grantRole} to track enumerable memberships
*/
function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {
bool granted = super._grantRole(role, account);
if (granted) {
_roleMembers[role].add(account);
}
return granted;
}
/**
* @dev Overload {AccessControl-_revokeRole} to track enumerable memberships
*/
function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {
bool revoked = super._revokeRole(role, account);
if (revoked) {
_roleMembers[role].remove(account);
}
return revoked;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Arrays.sol)
// This file was procedurally generated from scripts/generate/templates/Arrays.js.
pragma solidity ^0.8.20;
import {Comparators} from "./Comparators.sol";
import {SlotDerivation} from "./SlotDerivation.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {Math} from "./math/Math.sol";
/**
* @dev Collection of functions related to array types.
*/
library Arrays {
using SlotDerivation for bytes32;
using StorageSlot for bytes32;
/**
* @dev Sort an array of uint256 (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
uint256[] memory array,
function(uint256, uint256) pure returns (bool) comp
) internal pure returns (uint256[] memory) {
_quickSort(_begin(array), _end(array), comp);
return array;
}
/**
* @dev Variant of {sort} that sorts an array of uint256 in increasing order.
*/
function sort(uint256[] memory array) internal pure returns (uint256[] memory) {
sort(array, Comparators.lt);
return array;
}
/**
* @dev Sort an array of address (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
address[] memory array,
function(address, address) pure returns (bool) comp
) internal pure returns (address[] memory) {
sort(_castToUint256Array(array), _castToUint256Comp(comp));
return array;
}
/**
* @dev Variant of {sort} that sorts an array of address in increasing order.
*/
function sort(address[] memory array) internal pure returns (address[] memory) {
sort(_castToUint256Array(array), Comparators.lt);
return array;
}
/**
* @dev Sort an array of bytes32 (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
bytes32[] memory array,
function(bytes32, bytes32) pure returns (bool) comp
) internal pure returns (bytes32[] memory) {
sort(_castToUint256Array(array), _castToUint256Comp(comp));
return array;
}
/**
* @dev Variant of {sort} that sorts an array of bytes32 in increasing order.
*/
function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {
sort(_castToUint256Array(array), Comparators.lt);
return array;
}
/**
* @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops
* at end (exclusive). Sorting follows the `comp` comparator.
*
* Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.
*
* IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should
* be used only if the limits are within a memory array.
*/
function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {
unchecked {
if (end - begin < 0x40) return;
// Use first element as pivot
uint256 pivot = _mload(begin);
// Position where the pivot should be at the end of the loop
uint256 pos = begin;
for (uint256 it = begin + 0x20; it < end; it += 0x20) {
if (comp(_mload(it), pivot)) {
// If the value stored at the iterator's position comes before the pivot, we increment the
// position of the pivot and move the value there.
pos += 0x20;
_swap(pos, it);
}
}
_swap(begin, pos); // Swap pivot into place
_quickSort(begin, pos, comp); // Sort the left side of the pivot
_quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot
}
}
/**
* @dev Pointer to the memory location of the first element of `array`.
*/
function _begin(uint256[] memory array) private pure returns (uint256 ptr) {
assembly ("memory-safe") {
ptr := add(array, 0x20)
}
}
/**
* @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word
* that comes just after the last element of the array.
*/
function _end(uint256[] memory array) private pure returns (uint256 ptr) {
unchecked {
return _begin(array) + array.length * 0x20;
}
}
/**
* @dev Load memory word (as a uint256) at location `ptr`.
*/
function _mload(uint256 ptr) private pure returns (uint256 value) {
assembly {
value := mload(ptr)
}
}
/**
* @dev Swaps the elements memory location `ptr1` and `ptr2`.
*/
function _swap(uint256 ptr1, uint256 ptr2) private pure {
assembly {
let value1 := mload(ptr1)
let value2 := mload(ptr2)
mstore(ptr1, value2)
mstore(ptr2, value1)
}
}
/// @dev Helper: low level cast address memory array to uint256 memory array
function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast bytes32 memory array to uint256 memory array
function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast address comp function to uint256 comp function
function _castToUint256Comp(
function(address, address) pure returns (bool) input
) private pure returns (function(uint256, uint256) pure returns (bool) output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast bytes32 comp function to uint256 comp function
function _castToUint256Comp(
function(bytes32, bytes32) pure returns (bool) input
) private pure returns (function(uint256, uint256) pure returns (bool) output) {
assembly {
output := input
}
}
/**
* @dev Searches a sorted `array` and returns the first index that contains
* a value greater or equal to `element`. If no such index exists (i.e. all
* values in the array are strictly less than `element`), the array length is
* returned. Time complexity O(log n).
*
* NOTE: The `array` is expected to be sorted in ascending order, and to
* contain no repeated elements.
*
* IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks
* support for repeated elements in the array. The {lowerBound} function should
* be used instead.
*/
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
low = mid + 1;
}
}
// At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
if (low > 0 && unsafeAccess(array, low - 1).value == element) {
return low - 1;
} else {
return low;
}
}
/**
* @dev Searches an `array` sorted in ascending order and returns the first
* index that contains a value greater or equal than `element`. If no such index
* exists (i.e. all values in the array are strictly less than `element`), the array
* length is returned. Time complexity O(log n).
*
* See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].
*/
function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value < element) {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
} else {
high = mid;
}
}
return low;
}
/**
* @dev Searches an `array` sorted in ascending order and returns the first
* index that contains a value strictly greater than `element`. If no such index
* exists (i.e. all values in the array are strictly less than `element`), the array
* length is returned. Time complexity O(log n).
*
* See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].
*/
function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
}
}
return low;
}
/**
* @dev Same as {lowerBound}, but with an array in memory.
*/
function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeMemoryAccess(array, mid) < element) {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
} else {
high = mid;
}
}
return low;
}
/**
* @dev Same as {upperBound}, but with an array in memory.
*/
function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeMemoryAccess(array, mid) > element) {
high = mid;
} else {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
}
}
return low;
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getAddressSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getBytes32Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getUint256Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getBytesSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getStringSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(string[] memory arr, uint256 pos) internal pure returns (string memory res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(address[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(bytes32[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(uint256[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(bytes[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(string[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/extensions/IAccessControlEnumerable.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "../IAccessControl.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC-165 detection.
*/
interface IAccessControlEnumerable is IAccessControl {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides a set of functions to compare values.
*
* _Available since v5.1._
*/
library Comparators {
function lt(uint256 a, uint256 b) internal pure returns (bool) {
return a < b;
}
function gt(uint256 a, uint256 b) internal pure returns (bool) {
return a > b;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/SlotDerivation.sol)
// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.
pragma solidity ^0.8.20;
/**
* @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots
* corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by
* the solidity language / compiler.
*
* See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].
*
* Example usage:
* ```solidity
* contract Example {
* // Add the library methods
* using StorageSlot for bytes32;
* using SlotDerivation for bytes32;
*
* // Declare a namespace
* string private constant _NAMESPACE = "<namespace>"; // eg. OpenZeppelin.Slot
*
* function setValueInNamespace(uint256 key, address newValue) internal {
* _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;
* }
*
* function getValueInNamespace(uint256 key) internal view returns (address) {
* return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;
* }
* }
* ```
*
* TIP: Consider using this library along with {StorageSlot}.
*
* NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking
* upgrade safety will ignore the slots accessed through this library.
*
* _Available since v5.1._
*/
library SlotDerivation {
/**
* @dev Derive an ERC-7201 slot from a string (namespace).
*/
function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {
assembly ("memory-safe") {
mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))
slot := and(keccak256(0x00, 0x20), not(0xff))
}
}
/**
* @dev Add an offset to a slot to get the n-th element of a structure or an array.
*/
function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {
unchecked {
return bytes32(uint256(slot) + pos);
}
}
/**
* @dev Derive the location of the first element in an array from the slot where the length is stored.
*/
function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, slot)
result := keccak256(0x00, 0x20)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, and(key, shr(96, not(0))))
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, iszero(iszero(key)))
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
let length := mload(key)
let begin := add(key, 0x20)
let end := add(begin, length)
let cache := mload(end)
mstore(end, slot)
result := keccak256(begin, add(length, 0x20))
mstore(end, cache)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
let length := mload(key)
let begin := add(key, 0x20)
let end := add(begin, length)
let cache := mload(end)
mstore(end, slot)
result := keccak256(begin, add(length, 0x20))
mstore(end, cache)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC-1967 implementation slot:
* ```solidity
* contract ERC1967 {
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct Int256Slot {
int256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Int256Slot` with member `value` located at `slot`.
*/
function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
/**
* @dev Returns a `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
}// 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 Return the 512-bit addition of two uint256.
*
* The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
*/
function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
assembly ("memory-safe") {
low := add(a, b)
high := lt(low, a)
}
}
/**
* @dev Return the 512-bit multiplication of two uint256.
*
* The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
*/
function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
// 512-bit multiply [high low] = 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 = high * 2²⁵⁶ + low.
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
low := mul(a, b)
high := sub(sub(mm, low), lt(mm, low))
}
}
/**
* @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
success = c >= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a - b;
success = c <= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a * b;
assembly ("memory-safe") {
// Only true when the multiplication doesn't overflow
// (c / a == b) || (a == 0)
success := or(eq(div(c, a), b), iszero(a))
}
// equivalent to: success ? c : 0
result = c * SafeCast.toUint(success);
}
}
/**
* @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 {
success = b > 0;
assembly ("memory-safe") {
// The `DIV` opcode returns zero when the denominator is 0.
result := div(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 {
success = b > 0;
assembly ("memory-safe") {
// The `MOD` opcode returns zero when the denominator is 0.
result := mod(a, b)
}
}
}
/**
* @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryAdd(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
*/
function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
(, uint256 result) = trySub(a, b);
return result;
}
/**
* @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryMul(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @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 {
(uint256 high, uint256 low) = mul512(x, y);
// Handle non-overflow cases, 256 by 256 division.
if (high == 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 low / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= high) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [high low].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
high := sub(high, gt(remainder, low))
low := sub(low, 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 ("memory-safe") {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [high low] by twos.
low := div(low, 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 high into low.
low |= high * 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 high
// is no longer required.
result = low * 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 Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
*/
function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
if (high >= 1 << n) {
Panic.panic(Panic.UNDER_OVERFLOW);
}
return (high << (256 - n)) | (low >> n);
}
}
/**
* @dev Calculates x * y >> n with full precision, following the selected rounding direction.
*/
function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 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 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// If upper 8 bits of 16-bit half set, add 8 to result
r |= SafeCast.toUint((x >> r) > 0xff) << 3;
// If upper 4 bits of 8-bit half set, add 4 to result
r |= SafeCast.toUint((x >> r) > 0xf) << 2;
// Shifts value right by the current result and use it as an index into this lookup table:
//
// | x (4 bits) | index | table[index] = MSB position |
// |------------|---------|-----------------------------|
// | 0000 | 0 | table[0] = 0 |
// | 0001 | 1 | table[1] = 0 |
// | 0010 | 2 | table[2] = 1 |
// | 0011 | 3 | table[3] = 1 |
// | 0100 | 4 | table[4] = 2 |
// | 0101 | 5 | table[5] = 2 |
// | 0110 | 6 | table[6] = 2 |
// | 0111 | 7 | table[7] = 2 |
// | 1000 | 8 | table[8] = 3 |
// | 1001 | 9 | table[9] = 3 |
// | 1010 | 10 | table[10] = 3 |
// | 1011 | 11 | table[11] = 3 |
// | 1100 | 12 | table[12] = 3 |
// | 1101 | 13 | table[13] = 3 |
// | 1110 | 14 | table[14] = 3 |
// | 1111 | 15 | table[15] = 3 |
//
// The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
assembly ("memory-safe") {
r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
}
}
/**
* @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 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
}
/**
* @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) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted to signal this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
* Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// 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/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))
}
}
}{
"remappings": [
"@openzeppelin/=lib/openzeppelin-contracts/",
"@forge-std/=lib/forge-std/src/",
"@solmate/=lib/solmate/",
"@cowprotocol/=lib/cowprotocol/src/",
"@core/=src/core/",
"@tokens/=src/tokens/",
"@locking/=src/locking/",
"@funding/=src/funding/",
"@gateway/=src/gateway/",
"@finance/=src/finance/",
"@libraries/=src/libraries/",
"@interfaces/=src/interfaces/",
"@governance/=src/governance/",
"@integrations/=src/integrations/",
"@test/=test/",
"@deployment/=deployment/",
"cowprotocol/=lib/cowprotocol/src/",
"ds-test/=lib/solmate/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"solmate/=lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 1000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_core","type":"address"},{"internalType":"address","name":"_assetToken","type":"address"},{"internalType":"address","name":"_wrapToken","type":"address"},{"internalType":"address","name":"_accounting","type":"address"},{"internalType":"uint256","name":"_duration","type":"uint256"},{"internalType":"address","name":"_settlementContract","type":"address"},{"internalType":"address","name":"_vaultRelayer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"newAmount","type":"uint256"},{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"CapExceeded","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"InvalidAmountIn","type":"error"},{"inputs":[{"internalType":"uint256","name":"minOut","type":"uint256"},{"internalType":"uint256","name":"provided","type":"uint256"}],"name":"InvalidAmountOut","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"uint256","name":"minAssetsOut","type":"uint256"},{"internalType":"uint256","name":"assetsReceived","type":"uint256"}],"name":"SlippageTooHigh","type":"error"},{"inputs":[],"name":"SwapCooldown","type":"error"},{"inputs":[{"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"UnderlyingCallReverted","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetsBefore","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetsAfter","type":"uint256"}],"name":"AssetsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newCap","type":"uint256"}],"name":"CapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldCore","type":"address"},{"indexed":true,"internalType":"address","name":"newCore","type":"address"}],"name":"CoreUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMaxSlippage","type":"uint256"}],"name":"MaxSlippageUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"orderUid","type":"bytes"},{"components":[{"internalType":"contract IERC20","name":"sellToken","type":"address"},{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes32","name":"kind","type":"bytes32"},{"internalType":"bool","name":"partiallyFillable","type":"bool"},{"internalType":"bytes32","name":"sellTokenBalance","type":"bytes32"},{"internalType":"bytes32","name":"buyTokenBalance","type":"bytes32"}],"indexed":false,"internalType":"struct GPv2Order.Data","name":"order","type":"tuple"},{"indexed":false,"internalType":"uint32","name":"validTo","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"buyAmount","type":"uint256"}],"name":"OrderSigned","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"_SIGN_COOLDOWN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accounting","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_wrapTokenAmount","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetsAmount","type":"uint256"}],"name":"convertToWrapTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"core","outputs":[{"internalType":"contract InfiniFiCore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct CoreControlled.Call[]","name":"calls","type":"tuple[]"}],"name":"emergencyAction","outputs":[{"internalType":"bytes[]","name":"returnData","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"lastOrderSignTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maturity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSlippage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCap","type":"uint256"}],"name":"setCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newCore","type":"address"}],"name":"setCore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxSlippage","type":"uint256"}],"name":"setMaxSlippage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settlementContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_wrapTokensIn","type":"uint256"},{"internalType":"uint256","name":"_minAssetsOut","type":"uint256"}],"name":"signUnwrapOrder","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetsIn","type":"uint256"},{"internalType":"uint256","name":"_minWrapTokensOut","type":"uint256"}],"name":"signWrapOrder","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultRelayer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrapToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6101406040526001600355348015610015575f5ffd5b5060405161265f38038061265f833981016040819052610034916100a9565b5f8054610100600160a81b0319166101006001600160a01b03998a168102919091179091559587166080525f1960015593861660a05291851660c05260e05283169091521661012052670dcef33a6f838000600255610123565b80516001600160a01b03811681146100a4575f5ffd5b919050565b5f5f5f5f5f5f5f60e0888a0312156100bf575f5ffd5b6100c88861008e565b96506100d66020890161008e565b95506100e46040890161008e565b94506100f26060890161008e565b93506080880151925061010760a0890161008e565b915061011560c0890161008e565b905092959891949750929550565b60805160a05160c05160e051610100516101205161245b6102045f395f818161049001528181610a7301526111ee01525f81816104d70152611bcd01525f610b8801525f818161045d01528181610710015281816107bd01528181610bf00152610c9d01525f81816102c9015281816107900152818161093401528181610a5101528181610aa001528181610c700152818161123c015261131201525f818161020b015281816106e401528181610ac101528181610b0c01528181610bc4015281816111cc0152818161121b0152818161128301526118fd015261245b5ff3fe6080604052600436106101a3575f3560e01c80635c975abb116100e75780638456cb59116100875780639b552cc2116100625780639b552cc21461047f578063d0e30db0146104b2578063ea42418b146104c6578063f2f4eb26146104f9575f5ffd5b80638456cb59146104235780638c04166f146104375780639624e83e1461044c575f5ffd5b806371a97305116100c257806371a97305146103bb578063761a1ea3146103cf5780637df3927e146103e45780638000963014610404575f5ffd5b80635c975abb146103675780636083e59a146103885780636de66ab81461039c575f5ffd5b806329d955a1116101525780633f4ba83a1161012d5780633f4ba83a146103005780633ffb788e1461031457806343f68a491461032957806347786d3714610348575f5ffd5b806329d955a1146102995780633517c604146102b8578063355274ea146102eb575f5ffd5b806316c78ddf1161018257806316c78ddf146102455780631a68650214610271578063204f83f914610285575f5ffd5b8062f714ce146101a757806307a2d13a146101c85780631083f761146101fa575b5f5ffd5b3480156101b2575f5ffd5b506101c66101c1366004612070565b61051a565b005b3480156101d3575f5ffd5b506101e76101e236600461209a565b6106cd565b6040519081526020015b60405180910390f35b348015610205575f5ffd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101f1565b348015610250575f5ffd5b5061026461025f3660046120b1565b61083b565b6040516101f191906120ff565b34801561027c575f5ffd5b506101e7610af5565b348015610290575f5ffd5b506101e7610b82565b3480156102a4575f5ffd5b506101e76102b336600461209a565b610bad565b3480156102c3575f5ffd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102f6575f5ffd5b506101e760015481565b34801561030b575f5ffd5b506101c6610d13565b34801561031f575f5ffd5b506101e76104b081565b348015610334575f5ffd5b506101c661034336600461209a565b610dee565b348015610353575f5ffd5b506101c661036236600461209a565b610efb565b348015610372575f5ffd5b505f5460ff1660405190151581526020016101f1565b348015610393575f5ffd5b506101e7611000565b3480156103a7575f5ffd5b506102646103b63660046120b1565b611030565b3480156103c6575f5ffd5b506101e7611262565b3480156103da575f5ffd5b506101e760035481565b6103f76103f2366004612111565b61138e565b6040516101f19190612182565b34801561040f575f5ffd5b506101c661041e3660046121e5565b611629565b34801561042e575f5ffd5b506101c6611706565b348015610442575f5ffd5b506101e760025481565b348015610457575f5ffd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561048a575f5ffd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104bd575f5ffd5b506101c66117de565b3480156104d1575f5ffd5b5061022d7f000000000000000000000000000000000000000000000000000000000000000081565b348015610504575f5ffd5b505f5461010090046001600160a01b031661022d565b5f54604051632474521560e21b81527f5f33620cda06d02d58df96005b92bc83bd059a566e48e016372f3fbdc974e371600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa15801561058b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105af91906121fe565b6105ef5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064015b60405180910390fd5b6105f76118b2565b5f610600611262565b905061060c84846118f0565b5f610615611262565b90505f6106228284612238565b90505f61063a6002548361192490919063ffffffff16565b9050808781811015610681576040517f76baadda000000000000000000000000000000000000000000000000000000008152600481019290925260248201526044016105e6565b505060408051428152602081018690529081018490527f35a901c4413e585f9121eb5cf07e67760bd4ac498dd031249e5cd2cd225f74e49060600160405180910390a150505050505050565b6040516315d5220f60e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301525f9182917f0000000000000000000000000000000000000000000000000000000000000000169063aea9107890602401602060405180830381865afa158015610755573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610779919061224b565b6040516315d5220f60e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192505f917f0000000000000000000000000000000000000000000000000000000000000000169063aea9107890602401602060405180830381865afa158015610802573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610826919061224b565b9050610833848284611941565b949350505050565b60606108456118b2565b5f54604051632474521560e21b81527f456cfaf8d1ec98ae5bbe595a448911a58cb2e264d4686992e15dec9d0f363e03600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa1580156108b6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108da91906121fe565b6109155760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b5f841180156109a957506040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610981573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109a5919061224b565b8411155b84906109cb57604051636450874f60e11b81526004016105e691815260200190565b506104b06003546109dc9190612262565b42116109fb57604051635ab1f4a960e01b815260040160405180910390fd5b426003556002545f90610a13906101e2908790611924565b9050808481811015610a41576040516378e9a2e760e01b8152600481019290925260248201526044016105e6565b50610a9890506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000008761195c565b610aec610ae77f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008888611a62565b611bc8565b95945050505050565b6040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610b59573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b7d919061224b565b905090565b5f610b7d7f000000000000000000000000000000000000000000000000000000000000000042612262565b6040516315d5220f60e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301525f9182917f0000000000000000000000000000000000000000000000000000000000000000169063aea9107890602401602060405180830381865afa158015610c35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c59919061224b565b6040516315d5220f60e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301529192505f917f0000000000000000000000000000000000000000000000000000000000000000169063aea9107890602401602060405180830381865afa158015610ce2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d06919061224b565b9050610833848383611941565b5f54604051632474521560e21b81527fe7276a2a84d8de556657ec9cf93a55a7d66f096e529d0582ed08e9e2208b92b5600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa158015610d84573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610da891906121fe565b610de35760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b610deb611db7565b50565b5f54604051632474521560e21b81527f3947e2f542c6c46c543fa4f79cbd1e27fea37ed249bc3caf992570d19123642e600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa158015610e5f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8391906121fe565b610ebe5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b60028290556040518281527f9c922f6d0c990b250e9dd0a427a5c8da7f44b960f697fecb31cbbd8ba79ec8c2906020015b60405180910390a15050565b5f54604051632474521560e21b81527f3947e2f542c6c46c543fa4f79cbd1e27fea37ed249bc3caf992570d19123642e600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa158015610f6c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9091906121fe565b610fcb5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b60018290556040518281527f3c8eb7c49d332f4c1e4d92a27cda93c31cc9452f7a408e0c6109fcddbc9946ea90602001610eef565b5f5f61100a611262565b9050600154811061101c575f91505090565b8060015461102a9190612238565b91505090565b606061103a6118b2565b5f54604051632474521560e21b81527f456cfaf8d1ec98ae5bbe595a448911a58cb2e264d4686992e15dec9d0f363e03600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa1580156110ab573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110cf91906121fe565b61110a5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b5f84118015611120575061111c610af5565b8411155b849061114257604051636450874f60e11b81526004016105e691815260200190565b506104b06003546111539190612262565b421161117257604051635ab1f4a960e01b815260040160405180910390fd5b426003556002545f9061118e9061118887610bad565b90611924565b90508084818110156111bc576040516378e9a2e760e01b8152600481019290925260248201526044016105e6565b5061121390506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000008761195c565b610aec610ae77f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008888611a62565b6040516370a0823160e01b81523060048201525f9081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156112c8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112ec919061224b565b6040516370a0823160e01b81523060048201529091505f9061137b906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611357573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101e2919061224b565b90506113878183612262565b9250505090565b5f54604051632474521560e21b81527f1a6838efa4183e08fe3607359d1259272af9d4716f65e1a7b5921f78fd5a3c6a6004820181905233602483015260609290916101009091046001600160a01b0316906391d1485490604401602060405180830381865afa158015611404573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061142891906121fe565b6114635760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b8267ffffffffffffffff81111561147c5761147c612275565b6040519080825280602002602001820160405280156114af57816020015b606081526020019060019003908161149a5790505b5091505f5b83811015611621575f8585838181106114cf576114cf612289565b90506020028101906114e1919061229d565b6114ef9060208101906121e5565b90505f86868481811061150457611504612289565b9050602002810190611516919061229d565b602001359050365f88888681811061153057611530612289565b9050602002810190611542919061229d565b6115509060408101906122bb565b915091505f5f856001600160a01b0316858585604051611571929190612305565b5f6040518083038185875af1925050503d805f81146115ab576040519150601f19603f3d011682016040523d82523d5f602084013e6115b0565b606091505b50915091508181906115ef576040517f4ad176bb0000000000000000000000000000000000000000000000000000000081526004016105e691906120ff565b508089888151811061160357611603612289565b602002602001018190525050505050505080806001019150506114b4565b505092915050565b5f54604051632474521560e21b81527f1a6838efa4183e08fe3607359d1259272af9d4716f65e1a7b5921f78fd5a3c6a600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa15801561169a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116be91906121fe565b6116f95760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b61170282611e08565b5050565b5f54604051632474521560e21b81527ffcb9fcbfa83b897fb2d5cf4b58962164105c1e71489a37ef3ae0db3fdce576f6600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa158015611777573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061179b91906121fe565b6117d65760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b610deb611e77565b5f54604051632474521560e21b81527f5f33620cda06d02d58df96005b92bc83bd059a566e48e016372f3fbdc974e371600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa15801561184f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061187391906121fe565b6118ae5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b610deb5b5f5460ff16156118ee576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6117026001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168284611eb3565b5f6119388383670de0b6b3a7640000611941565b90505b92915050565b5f825f190484118302158202611955575f5ffd5b5091020490565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526119db8482611ee9565b611a5c576040516001600160a01b0384811660248301525f6044830152611a5291869182169063095ea7b3906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611f32565b611a5c8482611f32565b50505050565b611add6040518061018001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f63ffffffff1681526020015f81526020015f81526020015f81526020015f151581526020015f81526020015f81525090565b604051806101800160405280866001600160a01b03168152602001856001600160a01b03168152602001306001600160a01b031681526020018481526020018381526020016104b042611b309190612262565b63ffffffff1681527f3cac71ef99d0dfbf5b937334b5b7ab672b679ba2bbd4d6fe8e0c54a2dab3110960208201525f604082018190527ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775606083015260808201527f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc960a0820181905260c09091015295945050505050565b60605f7f000000000000000000000000000000000000000000000000000000000000000090505f611cbf84836001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c2f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c53919061224b565b601f1990910180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b604080516038808252606082019092529192505f9190602082018180368337019050509050611cf48183308860a00151611fb7565b6040517fec6cb13f0000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063ec6cb13f90611d3c908490600190600401612314565b5f604051808303815f87803b158015611d53575f5ffd5b505af1158015611d65573d5f5f3e3d5ffd5b50505050427f63521d767ee2dda07d9815cec18770071f08ed7902feacb2cb193196bb8e9aad82878860a001518960800151604051611da79493929190612337565b60405180910390a2949350505050565b611dbf61201a565b5f805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b5f80546001600160a01b038381166101008181027fffffffffffffffffffffff0000000000000000000000000000000000000000ff851617855560405193049190911692909183917f9209b7c8c06dcfd261686a663e7c55989337b18d59da5433c6f2835fb697092091a35050565b611e7f6118b2565b5f805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611deb3390565b6040516001600160a01b03838116602483015260448201839052611ee491859182169063a9059cbb90606401611a0b565b505050565b5f5f5f5f60205f8651602088015f8a5af192503d91505f519050828015611f2857508115611f1a5780600114611f28565b5f866001600160a01b03163b115b9695505050505050565b5f5f60205f8451602086015f885af180611f51576040513d5f823e3d81fd5b50505f513d91508115611f68578060011415611f75565b6001600160a01b0384163b155b15611a5c576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016105e6565b60388451146120085760405162461bcd60e51b815260206004820152601960248201527f475076323a2075696420627566666572206f766572666c6f770000000000000060448201526064016105e6565b60388401526034830152602090910152565b5f5460ff166118ee576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80356001600160a01b038116811461206b575f5ffd5b919050565b5f5f60408385031215612081575f5ffd5b8235915061209160208401612055565b90509250929050565b5f602082840312156120aa575f5ffd5b5035919050565b5f5f604083850312156120c2575f5ffd5b50508035926020909101359150565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61193860208301846120d1565b5f5f60208385031215612122575f5ffd5b823567ffffffffffffffff811115612138575f5ffd5b8301601f81018513612148575f5ffd5b803567ffffffffffffffff81111561215e575f5ffd5b8560208260051b8401011115612172575f5ffd5b6020919091019590945092505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b828110156121d957603f198786030184526121c48583516120d1565b945060209384019391909101906001016121a8565b50929695505050505050565b5f602082840312156121f5575f5ffd5b61193882612055565b5f6020828403121561220e575f5ffd5b8151801515811461221d575f5ffd5b9392505050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561193b5761193b612224565b5f6020828403121561225b575f5ffd5b5051919050565b8082018082111561193b5761193b612224565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f8235605e198336030181126122b1575f5ffd5b9190910192915050565b5f5f8335601e198436030181126122d0575f5ffd5b83018035915067ffffffffffffffff8211156122ea575f5ffd5b6020019150368190038213156122fe575f5ffd5b9250929050565b818382375f9101908152919050565b604081525f61232660408301856120d1565b905082151560208301529392505050565b6101e081525f61234b6101e08301876120d1565b85516001600160a01b03166020840152905060208501516001600160a01b03811660408401525060408501516001600160a01b03811660608401525060608501516080830152608085015160a083015260a08501516123b260c084018263ffffffff169052565b5060c085015160e083015260e08501516101008301526101008501516101208301526101208501516123e961014084018215159052565b506101408501516101608301526101608501516101808301526124156101a083018563ffffffff169052565b826101c08301529594505050505056fea26469706673582212200079bae2ee0ed4408b0ceb6239b1cfd07432143c49b2a8d970f32a2cf93666ea64736f6c634300081c0033000000000000000000000000f6d48735eccf12bdc1df2674b1ce3fcb3bd25490000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34970000000000000000000000007a5c5dba4fbd0e1e1a2ecdbe752fae55f6e842b30000000000000000000000000000000000000000000000000000000000093a800000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41000000000000000000000000c92e8bdf79f0507f65a392b0ab4667716bfe0110
Deployed Bytecode
0x6080604052600436106101a3575f3560e01c80635c975abb116100e75780638456cb59116100875780639b552cc2116100625780639b552cc21461047f578063d0e30db0146104b2578063ea42418b146104c6578063f2f4eb26146104f9575f5ffd5b80638456cb59146104235780638c04166f146104375780639624e83e1461044c575f5ffd5b806371a97305116100c257806371a97305146103bb578063761a1ea3146103cf5780637df3927e146103e45780638000963014610404575f5ffd5b80635c975abb146103675780636083e59a146103885780636de66ab81461039c575f5ffd5b806329d955a1116101525780633f4ba83a1161012d5780633f4ba83a146103005780633ffb788e1461031457806343f68a491461032957806347786d3714610348575f5ffd5b806329d955a1146102995780633517c604146102b8578063355274ea146102eb575f5ffd5b806316c78ddf1161018257806316c78ddf146102455780631a68650214610271578063204f83f914610285575f5ffd5b8062f714ce146101a757806307a2d13a146101c85780631083f761146101fa575b5f5ffd5b3480156101b2575f5ffd5b506101c66101c1366004612070565b61051a565b005b3480156101d3575f5ffd5b506101e76101e236600461209a565b6106cd565b6040519081526020015b60405180910390f35b348015610205575f5ffd5b5061022d7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b6040516001600160a01b0390911681526020016101f1565b348015610250575f5ffd5b5061026461025f3660046120b1565b61083b565b6040516101f191906120ff565b34801561027c575f5ffd5b506101e7610af5565b348015610290575f5ffd5b506101e7610b82565b3480156102a4575f5ffd5b506101e76102b336600461209a565b610bad565b3480156102c3575f5ffd5b5061022d7f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a349781565b3480156102f6575f5ffd5b506101e760015481565b34801561030b575f5ffd5b506101c6610d13565b34801561031f575f5ffd5b506101e76104b081565b348015610334575f5ffd5b506101c661034336600461209a565b610dee565b348015610353575f5ffd5b506101c661036236600461209a565b610efb565b348015610372575f5ffd5b505f5460ff1660405190151581526020016101f1565b348015610393575f5ffd5b506101e7611000565b3480156103a7575f5ffd5b506102646103b63660046120b1565b611030565b3480156103c6575f5ffd5b506101e7611262565b3480156103da575f5ffd5b506101e760035481565b6103f76103f2366004612111565b61138e565b6040516101f19190612182565b34801561040f575f5ffd5b506101c661041e3660046121e5565b611629565b34801561042e575f5ffd5b506101c6611706565b348015610442575f5ffd5b506101e760025481565b348015610457575f5ffd5b5061022d7f0000000000000000000000007a5c5dba4fbd0e1e1a2ecdbe752fae55f6e842b381565b34801561048a575f5ffd5b5061022d7f000000000000000000000000c92e8bdf79f0507f65a392b0ab4667716bfe011081565b3480156104bd575f5ffd5b506101c66117de565b3480156104d1575f5ffd5b5061022d7f0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab4181565b348015610504575f5ffd5b505f5461010090046001600160a01b031661022d565b5f54604051632474521560e21b81527f5f33620cda06d02d58df96005b92bc83bd059a566e48e016372f3fbdc974e371600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa15801561058b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105af91906121fe565b6105ef5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064015b60405180910390fd5b6105f76118b2565b5f610600611262565b905061060c84846118f0565b5f610615611262565b90505f6106228284612238565b90505f61063a6002548361192490919063ffffffff16565b9050808781811015610681576040517f76baadda000000000000000000000000000000000000000000000000000000008152600481019290925260248201526044016105e6565b505060408051428152602081018690529081018490527f35a901c4413e585f9121eb5cf07e67760bd4ac498dd031249e5cd2cd225f74e49060600160405180910390a150505050505050565b6040516315d5220f60e31b81526001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811660048301525f9182917f0000000000000000000000007a5c5dba4fbd0e1e1a2ecdbe752fae55f6e842b3169063aea9107890602401602060405180830381865afa158015610755573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610779919061224b565b6040516315d5220f60e31b81526001600160a01b037f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a3497811660048301529192505f917f0000000000000000000000007a5c5dba4fbd0e1e1a2ecdbe752fae55f6e842b3169063aea9107890602401602060405180830381865afa158015610802573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610826919061224b565b9050610833848284611941565b949350505050565b60606108456118b2565b5f54604051632474521560e21b81527f456cfaf8d1ec98ae5bbe595a448911a58cb2e264d4686992e15dec9d0f363e03600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa1580156108b6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108da91906121fe565b6109155760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b5f841180156109a957506040516370a0823160e01b81523060048201527f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34976001600160a01b0316906370a0823190602401602060405180830381865afa158015610981573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109a5919061224b565b8411155b84906109cb57604051636450874f60e11b81526004016105e691815260200190565b506104b06003546109dc9190612262565b42116109fb57604051635ab1f4a960e01b815260040160405180910390fd5b426003556002545f90610a13906101e2908790611924565b9050808481811015610a41576040516378e9a2e760e01b8152600481019290925260248201526044016105e6565b50610a9890506001600160a01b037f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a3497167f000000000000000000000000c92e8bdf79f0507f65a392b0ab4667716bfe01108761195c565b610aec610ae77f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34977f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488888611a62565b611bc8565b95945050505050565b6040516370a0823160e01b81523060048201525f907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa158015610b59573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b7d919061224b565b905090565b5f610b7d7f0000000000000000000000000000000000000000000000000000000000093a8042612262565b6040516315d5220f60e31b81526001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811660048301525f9182917f0000000000000000000000007a5c5dba4fbd0e1e1a2ecdbe752fae55f6e842b3169063aea9107890602401602060405180830381865afa158015610c35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c59919061224b565b6040516315d5220f60e31b81526001600160a01b037f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a3497811660048301529192505f917f0000000000000000000000007a5c5dba4fbd0e1e1a2ecdbe752fae55f6e842b3169063aea9107890602401602060405180830381865afa158015610ce2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d06919061224b565b9050610833848383611941565b5f54604051632474521560e21b81527fe7276a2a84d8de556657ec9cf93a55a7d66f096e529d0582ed08e9e2208b92b5600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa158015610d84573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610da891906121fe565b610de35760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b610deb611db7565b50565b5f54604051632474521560e21b81527f3947e2f542c6c46c543fa4f79cbd1e27fea37ed249bc3caf992570d19123642e600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa158015610e5f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8391906121fe565b610ebe5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b60028290556040518281527f9c922f6d0c990b250e9dd0a427a5c8da7f44b960f697fecb31cbbd8ba79ec8c2906020015b60405180910390a15050565b5f54604051632474521560e21b81527f3947e2f542c6c46c543fa4f79cbd1e27fea37ed249bc3caf992570d19123642e600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa158015610f6c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9091906121fe565b610fcb5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b60018290556040518281527f3c8eb7c49d332f4c1e4d92a27cda93c31cc9452f7a408e0c6109fcddbc9946ea90602001610eef565b5f5f61100a611262565b9050600154811061101c575f91505090565b8060015461102a9190612238565b91505090565b606061103a6118b2565b5f54604051632474521560e21b81527f456cfaf8d1ec98ae5bbe595a448911a58cb2e264d4686992e15dec9d0f363e03600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa1580156110ab573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110cf91906121fe565b61110a5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b5f84118015611120575061111c610af5565b8411155b849061114257604051636450874f60e11b81526004016105e691815260200190565b506104b06003546111539190612262565b421161117257604051635ab1f4a960e01b815260040160405180910390fd5b426003556002545f9061118e9061118887610bad565b90611924565b90508084818110156111bc576040516378e9a2e760e01b8152600481019290925260248201526044016105e6565b5061121390506001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48167f000000000000000000000000c92e8bdf79f0507f65a392b0ab4667716bfe01108761195c565b610aec610ae77f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb487f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34978888611a62565b6040516370a0823160e01b81523060048201525f9081906001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816906370a0823190602401602060405180830381865afa1580156112c8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112ec919061224b565b6040516370a0823160e01b81523060048201529091505f9061137b906001600160a01b037f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a349716906370a0823190602401602060405180830381865afa158015611357573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101e2919061224b565b90506113878183612262565b9250505090565b5f54604051632474521560e21b81527f1a6838efa4183e08fe3607359d1259272af9d4716f65e1a7b5921f78fd5a3c6a6004820181905233602483015260609290916101009091046001600160a01b0316906391d1485490604401602060405180830381865afa158015611404573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061142891906121fe565b6114635760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b8267ffffffffffffffff81111561147c5761147c612275565b6040519080825280602002602001820160405280156114af57816020015b606081526020019060019003908161149a5790505b5091505f5b83811015611621575f8585838181106114cf576114cf612289565b90506020028101906114e1919061229d565b6114ef9060208101906121e5565b90505f86868481811061150457611504612289565b9050602002810190611516919061229d565b602001359050365f88888681811061153057611530612289565b9050602002810190611542919061229d565b6115509060408101906122bb565b915091505f5f856001600160a01b0316858585604051611571929190612305565b5f6040518083038185875af1925050503d805f81146115ab576040519150601f19603f3d011682016040523d82523d5f602084013e6115b0565b606091505b50915091508181906115ef576040517f4ad176bb0000000000000000000000000000000000000000000000000000000081526004016105e691906120ff565b508089888151811061160357611603612289565b602002602001018190525050505050505080806001019150506114b4565b505092915050565b5f54604051632474521560e21b81527f1a6838efa4183e08fe3607359d1259272af9d4716f65e1a7b5921f78fd5a3c6a600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa15801561169a573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116be91906121fe565b6116f95760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b61170282611e08565b5050565b5f54604051632474521560e21b81527ffcb9fcbfa83b897fb2d5cf4b58962164105c1e71489a37ef3ae0db3fdce576f6600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa158015611777573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061179b91906121fe565b6117d65760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b610deb611e77565b5f54604051632474521560e21b81527f5f33620cda06d02d58df96005b92bc83bd059a566e48e016372f3fbdc974e371600482018190523360248301529161010090046001600160a01b0316906391d1485490604401602060405180830381865afa15801561184f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061187391906121fe565b6118ae5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064016105e6565b610deb5b5f5460ff16156118ee576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6117026001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48168284611eb3565b5f6119388383670de0b6b3a7640000611941565b90505b92915050565b5f825f190484118302158202611955575f5ffd5b5091020490565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526119db8482611ee9565b611a5c576040516001600160a01b0384811660248301525f6044830152611a5291869182169063095ea7b3906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611f32565b611a5c8482611f32565b50505050565b611add6040518061018001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f63ffffffff1681526020015f81526020015f81526020015f81526020015f151581526020015f81526020015f81525090565b604051806101800160405280866001600160a01b03168152602001856001600160a01b03168152602001306001600160a01b031681526020018481526020018381526020016104b042611b309190612262565b63ffffffff1681527f3cac71ef99d0dfbf5b937334b5b7ab672b679ba2bbd4d6fe8e0c54a2dab3110960208201525f604082018190527ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775606083015260808201527f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc960a0820181905260c09091015295945050505050565b60605f7f0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab4190505f611cbf84836001600160a01b031663f698da256040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c2f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c53919061224b565b601f1990910180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b604080516038808252606082019092529192505f9190602082018180368337019050509050611cf48183308860a00151611fb7565b6040517fec6cb13f0000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063ec6cb13f90611d3c908490600190600401612314565b5f604051808303815f87803b158015611d53575f5ffd5b505af1158015611d65573d5f5f3e3d5ffd5b50505050427f63521d767ee2dda07d9815cec18770071f08ed7902feacb2cb193196bb8e9aad82878860a001518960800151604051611da79493929190612337565b60405180910390a2949350505050565b611dbf61201a565b5f805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b5f80546001600160a01b038381166101008181027fffffffffffffffffffffff0000000000000000000000000000000000000000ff851617855560405193049190911692909183917f9209b7c8c06dcfd261686a663e7c55989337b18d59da5433c6f2835fb697092091a35050565b611e7f6118b2565b5f805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611deb3390565b6040516001600160a01b03838116602483015260448201839052611ee491859182169063a9059cbb90606401611a0b565b505050565b5f5f5f5f60205f8651602088015f8a5af192503d91505f519050828015611f2857508115611f1a5780600114611f28565b5f866001600160a01b03163b115b9695505050505050565b5f5f60205f8451602086015f885af180611f51576040513d5f823e3d81fd5b50505f513d91508115611f68578060011415611f75565b6001600160a01b0384163b155b15611a5c576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016105e6565b60388451146120085760405162461bcd60e51b815260206004820152601960248201527f475076323a2075696420627566666572206f766572666c6f770000000000000060448201526064016105e6565b60388401526034830152602090910152565b5f5460ff166118ee576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80356001600160a01b038116811461206b575f5ffd5b919050565b5f5f60408385031215612081575f5ffd5b8235915061209160208401612055565b90509250929050565b5f602082840312156120aa575f5ffd5b5035919050565b5f5f604083850312156120c2575f5ffd5b50508035926020909101359150565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61193860208301846120d1565b5f5f60208385031215612122575f5ffd5b823567ffffffffffffffff811115612138575f5ffd5b8301601f81018513612148575f5ffd5b803567ffffffffffffffff81111561215e575f5ffd5b8560208260051b8401011115612172575f5ffd5b6020919091019590945092505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b828110156121d957603f198786030184526121c48583516120d1565b945060209384019391909101906001016121a8565b50929695505050505050565b5f602082840312156121f5575f5ffd5b61193882612055565b5f6020828403121561220e575f5ffd5b8151801515811461221d575f5ffd5b9392505050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561193b5761193b612224565b5f6020828403121561225b575f5ffd5b5051919050565b8082018082111561193b5761193b612224565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f8235605e198336030181126122b1575f5ffd5b9190910192915050565b5f5f8335601e198436030181126122d0575f5ffd5b83018035915067ffffffffffffffff8211156122ea575f5ffd5b6020019150368190038213156122fe575f5ffd5b9250929050565b818382375f9101908152919050565b604081525f61232660408301856120d1565b905082151560208301529392505050565b6101e081525f61234b6101e08301876120d1565b85516001600160a01b03166020840152905060208501516001600160a01b03811660408401525060408501516001600160a01b03811660608401525060608501516080830152608085015160a083015260a08501516123b260c084018263ffffffff169052565b5060c085015160e083015260e08501516101008301526101008501516101208301526101208501516123e961014084018215159052565b506101408501516101608301526101608501516101808301526124156101a083018563ffffffff169052565b826101c08301529594505050505056fea26469706673582212200079bae2ee0ed4408b0ceb6239b1cfd07432143c49b2a8d970f32a2cf93666ea64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000f6d48735eccf12bdc1df2674b1ce3fcb3bd25490000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34970000000000000000000000007a5c5dba4fbd0e1e1a2ecdbe752fae55f6e842b30000000000000000000000000000000000000000000000000000000000093a800000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41000000000000000000000000c92e8bdf79f0507f65a392b0ab4667716bfe0110
-----Decoded View---------------
Arg [0] : _core (address): 0xF6d48735EcCf12bDC1DF2674b1ce3fcb3bD25490
Arg [1] : _assetToken (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [2] : _wrapToken (address): 0x9D39A5DE30e57443BfF2A8307A4256c8797A3497
Arg [3] : _accounting (address): 0x7A5C5dbA4fbD0e1e1A2eCDBe752fAe55f6E842B3
Arg [4] : _duration (uint256): 604800
Arg [5] : _settlementContract (address): 0x9008D19f58AAbD9eD0D60971565AA8510560ab41
Arg [6] : _vaultRelayer (address): 0xC92E8bdf79f0507f65a392b0ab4667716BFE0110
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000f6d48735eccf12bdc1df2674b1ce3fcb3bd25490
Arg [1] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [2] : 0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a3497
Arg [3] : 0000000000000000000000007a5c5dba4fbd0e1e1a2ecdbe752fae55f6e842b3
Arg [4] : 0000000000000000000000000000000000000000000000000000000000093a80
Arg [5] : 0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41
Arg [6] : 000000000000000000000000c92e8bdf79f0507f65a392b0ab4667716bfe0110
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.