Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 52 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Deposit | 21548384 | 2 days ago | IN | 0 ETH | 0.0010277 | ||||
Redeem | 21528144 | 5 days ago | IN | 0 ETH | 0.00090655 | ||||
Deposit | 21528124 | 5 days ago | IN | 0 ETH | 0.00079566 | ||||
Redeem | 21528049 | 5 days ago | IN | 0 ETH | 0.00063063 | ||||
Redeem | 21518081 | 6 days ago | IN | 0 ETH | 0.00211113 | ||||
Redeem | 21505656 | 8 days ago | IN | 0 ETH | 0.00089203 | ||||
Deposit | 21500080 | 9 days ago | IN | 0 ETH | 0.00080412 | ||||
Deposit | 21494682 | 10 days ago | IN | 0 ETH | 0.00244931 | ||||
Deposit | 21489145 | 10 days ago | IN | 0 ETH | 0.00106694 | ||||
Transfer | 21461862 | 14 days ago | IN | 0 ETH | 0.00016518 | ||||
Deposit | 21461797 | 14 days ago | IN | 0 ETH | 0.00094765 | ||||
Redeem | 21438427 | 17 days ago | IN | 0 ETH | 0.01121282 | ||||
Redeem | 21402311 | 22 days ago | IN | 0 ETH | 0.00234201 | ||||
Redeem | 21384720 | 25 days ago | IN | 0 ETH | 0.00301386 | ||||
Redeem | 21378258 | 26 days ago | IN | 0 ETH | 0.00207144 | ||||
Redeem | 21378115 | 26 days ago | IN | 0 ETH | 0.00185984 | ||||
Deposit | 21370626 | 27 days ago | IN | 0 ETH | 0.0018934 | ||||
Redeem | 21370447 | 27 days ago | IN | 0 ETH | 0.00233841 | ||||
Deposit | 21364559 | 28 days ago | IN | 0 ETH | 0.00213045 | ||||
Deposit | 21363267 | 28 days ago | IN | 0 ETH | 0.00166838 | ||||
Deposit | 21362520 | 28 days ago | IN | 0 ETH | 0.00173004 | ||||
Deposit | 21362328 | 28 days ago | IN | 0 ETH | 0.00179196 | ||||
Deposit | 21354231 | 29 days ago | IN | 0 ETH | 0.00142011 | ||||
Redeem | 21354225 | 29 days ago | IN | 0 ETH | 0.00161454 | ||||
Deposit | 21343496 | 31 days ago | IN | 0 ETH | 0.00245767 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
OrigamiSuperSavingsUsdsVault
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 9999 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (investments/sky/OrigamiSuperSavingsUsdsVault.sol) import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { IOrigamiDelegated4626Vault } from "contracts/interfaces/investments/erc4626/IOrigamiDelegated4626Vault.sol"; import { IOrigamiSuperSavingsUsdsManager } from "contracts/interfaces/investments/sky/IOrigamiSuperSavingsUsdsManager.sol"; import { ITokenPrices } from "contracts/interfaces/common/ITokenPrices.sol"; import { IOrigamiErc4626 } from "contracts/interfaces/common/IOrigamiErc4626.sol"; import { OrigamiErc4626 } from "contracts/common/OrigamiErc4626.sol"; import { CommonEventsAndErrors } from "contracts/libraries/CommonEventsAndErrors.sol"; /** * @title Origami sUSDS+s ERC-4626 Vault * @notice The logic to farm the sUSDS is delegated to a manager. */ contract OrigamiSuperSavingsUsdsVault is OrigamiErc4626, IOrigamiDelegated4626Vault { using SafeERC20 for IERC20; /// @inheritdoc IOrigamiDelegated4626Vault ITokenPrices public override tokenPrices; /// @dev The manager which handles the farming of USDS IOrigamiSuperSavingsUsdsManager private _manager; constructor( address initialOwner_, string memory name_, string memory symbol_, IERC20 asset_, address tokenPrices_ ) OrigamiErc4626(initialOwner_, name_, symbol_, asset_) { tokenPrices = ITokenPrices(tokenPrices_); } /// @inheritdoc IOrigamiDelegated4626Vault function setManager(address newManager) external override onlyElevatedAccess { if (newManager == address(0)) revert CommonEventsAndErrors.InvalidAddress(address(0)); emit ManagerSet(newManager); _manager = IOrigamiSuperSavingsUsdsManager(newManager); } /// @inheritdoc IOrigamiDelegated4626Vault function setTokenPrices(address _tokenPrices) external override onlyElevatedAccess { if (_tokenPrices == address(0)) revert CommonEventsAndErrors.InvalidAddress(address(0)); emit TokenPricesSet(_tokenPrices); tokenPrices = ITokenPrices(_tokenPrices); } /** * @notice Emit an event from the vault when the performance fees are updated */ function logPerformanceFeesSet(uint256 performanceFees) external { if (msg.sender != address(_manager)) revert CommonEventsAndErrors.InvalidAccess(); emit PerformanceFeeSet(performanceFees); } /// @inheritdoc IERC4626 function totalAssets() public view override(IERC4626, OrigamiErc4626) returns (uint256) { return _manager.totalAssets(); } /// @inheritdoc IOrigamiErc4626 function areDepositsPaused() external virtual override(IOrigamiErc4626, OrigamiErc4626) view returns (bool) { return _manager.areDepositsPaused(); } /// @inheritdoc IOrigamiErc4626 function areWithdrawalsPaused() external virtual override(IOrigamiErc4626, OrigamiErc4626) view returns (bool) { return _manager.areWithdrawalsPaused(); } /// @inheritdoc IOrigamiDelegated4626Vault function manager() external override view returns (address) { return address(_manager); } /// @inheritdoc IOrigamiDelegated4626Vault function performanceFeeBps() external override view returns (uint48) { // Return the total fee for both the caller (to pay for gas) and origami (uint48 callerFeeBps, uint48 origamiFeeBps) = _manager.performanceFeeBps(); return callerFeeBps + origamiFeeBps; } /// @dev Pull freshly deposited sUSDS and deposit into the manager function _depositHook(address caller, uint256 assets) internal override { SafeERC20.safeTransferFrom(_asset, caller, address(_manager), assets); _manager.deposit(type(uint256).max); } /// @dev Pull sUSDS from the manager which also sends to the receiver function _withdrawHook( uint256 assets, address receiver ) internal override { _manager.withdraw(assets, receiver); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol"; import "../token/ERC20/extensions/IERC20Metadata.sol"; /** * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. * * _Available since v4.7._ */ interface IERC4626 is IERC20, IERC20Metadata { event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /** * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. * * - MUST be an ERC-20 token contract. * - MUST NOT revert. */ function asset() external view returns (address assetTokenAddress); /** * @dev Returns the total amount of the underlying asset that is “managed” by Vault. * * - SHOULD include any compounding that occurs from yield. * - MUST be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT revert. */ function totalAssets() external view returns (uint256 totalManagedAssets); /** * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToShares(uint256 assets) external view returns (uint256 shares); /** * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToAssets(uint256 shares) external view returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, * through a deposit call. * * - MUST return a limited value if receiver is subject to some deposit limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. * - MUST NOT revert. */ function maxDeposit(address receiver) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given * current on-chain conditions. * * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called * in the same transaction. * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the * deposit would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewDeposit(uint256 assets) external view returns (uint256 shares); /** * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * deposit execution, and are accounted for during deposit. * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function deposit(uint256 assets, address receiver) external returns (uint256 shares); /** * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. * - MUST return a limited value if receiver is subject to some mint limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. * - MUST NOT revert. */ function maxMint(address receiver) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given * current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the * same transaction. * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint * would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by minting. */ function previewMint(uint256 shares) external view returns (uint256 assets); /** * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint * execution, and are accounted for during mint. * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function mint(uint256 shares, address receiver) external returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the * Vault, through a withdraw call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST NOT revert. */ function maxWithdraw(address owner) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, * given current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if * called * in the same transaction. * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though * the withdrawal would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewWithdraw(uint256 assets) external view returns (uint256 shares); /** * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * withdraw execution, and are accounted for during withdraw. * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); /** * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, * through a redeem call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. * - MUST NOT revert. */ function maxRedeem(address owner) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, * given current on-chain conditions. * * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the * same transaction. * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the * redemption would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by redeeming. */ function previewRedeem(uint256 shares) external view returns (uint256 assets); /** * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * redeem execution, and are accounted for during redeem. * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.0; interface IERC5267 { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.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 making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.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}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * 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 ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these 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 override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override 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 override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override 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 `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` 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 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * 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 `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `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. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` 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. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ 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 v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ 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 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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 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 { using Address for address; /** * @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.encodeWithSelector(token.transfer.selector, 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.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 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. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @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. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @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). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @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 silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.8; import "./ECDSA.sol"; import "../ShortStrings.sol"; import "../../interfaces/IERC5267.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * _Available since v3.4._ * * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment */ abstract contract EIP712 is IERC5267 { using ShortStrings for *; bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; uint256 private immutable _cachedChainId; address private immutable _cachedThis; bytes32 private immutable _hashedName; bytes32 private immutable _hashedVersion; ShortString private immutable _name; ShortString private immutable _version; string private _nameFallback; string private _versionFallback; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { _name = name.toShortStringWithFallback(_nameFallback); _version = version.toShortStringWithFallback(_versionFallback); _hashedName = keccak256(bytes(name)); _hashedVersion = keccak256(bytes(version)); _cachedChainId = block.chainid; _cachedDomainSeparator = _buildDomainSeparator(); _cachedThis = address(this); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (address(this) == _cachedThis && block.chainid == _cachedChainId) { return _cachedDomainSeparator; } else { return _buildDomainSeparator(); } } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {EIP-5267}. * * _Available since v4.9._ */ function eip712Domain() public view virtual override returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { return ( hex"0f", // 01111 _name.toStringWithFallback(_nameFallback), _version.toStringWithFallback(_versionFallback), block.chainid, address(this), bytes32(0), new uint256[](0) ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({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[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return 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 up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice 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 + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * 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 + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol) pragma solidity ^0.8.8; import "./StorageSlot.sol"; // | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | // | length | 0x BB | type ShortString is bytes32; /** * @dev This library provides functions to convert short memory strings * into a `ShortString` type that can be used as an immutable variable. * * Strings of arbitrary length can be optimized using this library if * they are short enough (up to 31 bytes) by packing them with their * length (1 byte) in a single EVM word (32 bytes). Additionally, a * fallback mechanism can be used for every other case. * * Usage example: * * ```solidity * contract Named { * using ShortStrings for *; * * ShortString private immutable _name; * string private _nameFallback; * * constructor(string memory contractName) { * _name = contractName.toShortStringWithFallback(_nameFallback); * } * * function name() external view returns (string memory) { * return _name.toStringWithFallback(_nameFallback); * } * } * ``` */ library ShortStrings { // Used as an identifier for strings longer than 31 bytes. bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; error StringTooLong(string str); error InvalidShortString(); /** * @dev Encode a string of at most 31 chars into a `ShortString`. * * This will trigger a `StringTooLong` error is the input string is too long. */ function toShortString(string memory str) internal pure returns (ShortString) { bytes memory bstr = bytes(str); if (bstr.length > 31) { revert StringTooLong(str); } return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); } /** * @dev Decode a `ShortString` back to a "normal" string. */ function toString(ShortString sstr) internal pure returns (string memory) { uint256 len = byteLength(sstr); // using `new string(len)` would work locally but is not memory safe. string memory str = new string(32); /// @solidity memory-safe-assembly assembly { mstore(str, len) mstore(add(str, 0x20), sstr) } return str; } /** * @dev Return the length of a `ShortString`. */ function byteLength(ShortString sstr) internal pure returns (uint256) { uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; if (result > 31) { revert InvalidShortString(); } return result; } /** * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. */ function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { if (bytes(value).length < 32) { return toShortString(value); } else { StorageSlot.getStringSlot(store).value = value; return ShortString.wrap(_FALLBACK_SENTINEL); } } /** * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. */ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { return toString(value); } else { return store; } } /** * @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}. * * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. */ function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { return byteLength(value); } else { return bytes(store).length; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.0; /** * @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 ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 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) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { 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) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { 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) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.19; // Common.sol // // Common mathematical functions needed by both SD59x18 and UD60x18. Note that these global functions do not // always operate with SD59x18 and UD60x18 numbers. /*////////////////////////////////////////////////////////////////////////// CUSTOM ERRORS //////////////////////////////////////////////////////////////////////////*/ /// @notice Thrown when the resultant value in {mulDiv} overflows uint256. error PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator); /// @notice Thrown when the resultant value in {mulDiv18} overflows uint256. error PRBMath_MulDiv18_Overflow(uint256 x, uint256 y); /// @notice Thrown when one of the inputs passed to {mulDivSigned} is `type(int256).min`. error PRBMath_MulDivSigned_InputTooSmall(); /// @notice Thrown when the resultant value in {mulDivSigned} overflows int256. error PRBMath_MulDivSigned_Overflow(int256 x, int256 y); /*////////////////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////////////////*/ /// @dev The maximum value a uint128 number can have. uint128 constant MAX_UINT128 = type(uint128).max; /// @dev The maximum value a uint40 number can have. uint40 constant MAX_UINT40 = type(uint40).max; /// @dev The unit number, which the decimal precision of the fixed-point types. uint256 constant UNIT = 1e18; /// @dev The unit number inverted mod 2^256. uint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281; /// @dev The the largest power of two that divides the decimal value of `UNIT`. The logarithm of this value is the least significant /// bit in the binary representation of `UNIT`. uint256 constant UNIT_LPOTD = 262144; /*////////////////////////////////////////////////////////////////////////// FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ /// @notice Calculates the binary exponent of x using the binary fraction method. /// @dev Has to use 192.64-bit fixed-point numbers. See https://ethereum.stackexchange.com/a/96594/24693. /// @param x The exponent as an unsigned 192.64-bit fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. /// @custom:smtchecker abstract-function-nondet function exp2(uint256 x) pure returns (uint256 result) { unchecked { // Start from 0.5 in the 192.64-bit fixed-point format. result = 0x800000000000000000000000000000000000000000000000; // The following logic multiplies the result by $\sqrt{2^{-i}}$ when the bit at position i is 1. Key points: // // 1. Intermediate results will not overflow, as the starting point is 2^191 and all magic factors are under 2^65. // 2. The rationale for organizing the if statements into groups of 8 is gas savings. If the result of performing // a bitwise AND operation between x and any value in the array [0x80; 0x40; 0x20; 0x10; 0x08; 0x04; 0x02; 0x01] is 1, // we know that `x & 0xFF` is also 1. if (x & 0xFF00000000000000 > 0) { if (x & 0x8000000000000000 > 0) { result = (result * 0x16A09E667F3BCC909) >> 64; } if (x & 0x4000000000000000 > 0) { result = (result * 0x1306FE0A31B7152DF) >> 64; } if (x & 0x2000000000000000 > 0) { result = (result * 0x1172B83C7D517ADCE) >> 64; } if (x & 0x1000000000000000 > 0) { result = (result * 0x10B5586CF9890F62A) >> 64; } if (x & 0x800000000000000 > 0) { result = (result * 0x1059B0D31585743AE) >> 64; } if (x & 0x400000000000000 > 0) { result = (result * 0x102C9A3E778060EE7) >> 64; } if (x & 0x200000000000000 > 0) { result = (result * 0x10163DA9FB33356D8) >> 64; } if (x & 0x100000000000000 > 0) { result = (result * 0x100B1AFA5ABCBED61) >> 64; } } if (x & 0xFF000000000000 > 0) { if (x & 0x80000000000000 > 0) { result = (result * 0x10058C86DA1C09EA2) >> 64; } if (x & 0x40000000000000 > 0) { result = (result * 0x1002C605E2E8CEC50) >> 64; } if (x & 0x20000000000000 > 0) { result = (result * 0x100162F3904051FA1) >> 64; } if (x & 0x10000000000000 > 0) { result = (result * 0x1000B175EFFDC76BA) >> 64; } if (x & 0x8000000000000 > 0) { result = (result * 0x100058BA01FB9F96D) >> 64; } if (x & 0x4000000000000 > 0) { result = (result * 0x10002C5CC37DA9492) >> 64; } if (x & 0x2000000000000 > 0) { result = (result * 0x1000162E525EE0547) >> 64; } if (x & 0x1000000000000 > 0) { result = (result * 0x10000B17255775C04) >> 64; } } if (x & 0xFF0000000000 > 0) { if (x & 0x800000000000 > 0) { result = (result * 0x1000058B91B5BC9AE) >> 64; } if (x & 0x400000000000 > 0) { result = (result * 0x100002C5C89D5EC6D) >> 64; } if (x & 0x200000000000 > 0) { result = (result * 0x10000162E43F4F831) >> 64; } if (x & 0x100000000000 > 0) { result = (result * 0x100000B1721BCFC9A) >> 64; } if (x & 0x80000000000 > 0) { result = (result * 0x10000058B90CF1E6E) >> 64; } if (x & 0x40000000000 > 0) { result = (result * 0x1000002C5C863B73F) >> 64; } if (x & 0x20000000000 > 0) { result = (result * 0x100000162E430E5A2) >> 64; } if (x & 0x10000000000 > 0) { result = (result * 0x1000000B172183551) >> 64; } } if (x & 0xFF00000000 > 0) { if (x & 0x8000000000 > 0) { result = (result * 0x100000058B90C0B49) >> 64; } if (x & 0x4000000000 > 0) { result = (result * 0x10000002C5C8601CC) >> 64; } if (x & 0x2000000000 > 0) { result = (result * 0x1000000162E42FFF0) >> 64; } if (x & 0x1000000000 > 0) { result = (result * 0x10000000B17217FBB) >> 64; } if (x & 0x800000000 > 0) { result = (result * 0x1000000058B90BFCE) >> 64; } if (x & 0x400000000 > 0) { result = (result * 0x100000002C5C85FE3) >> 64; } if (x & 0x200000000 > 0) { result = (result * 0x10000000162E42FF1) >> 64; } if (x & 0x100000000 > 0) { result = (result * 0x100000000B17217F8) >> 64; } } if (x & 0xFF000000 > 0) { if (x & 0x80000000 > 0) { result = (result * 0x10000000058B90BFC) >> 64; } if (x & 0x40000000 > 0) { result = (result * 0x1000000002C5C85FE) >> 64; } if (x & 0x20000000 > 0) { result = (result * 0x100000000162E42FF) >> 64; } if (x & 0x10000000 > 0) { result = (result * 0x1000000000B17217F) >> 64; } if (x & 0x8000000 > 0) { result = (result * 0x100000000058B90C0) >> 64; } if (x & 0x4000000 > 0) { result = (result * 0x10000000002C5C860) >> 64; } if (x & 0x2000000 > 0) { result = (result * 0x1000000000162E430) >> 64; } if (x & 0x1000000 > 0) { result = (result * 0x10000000000B17218) >> 64; } } if (x & 0xFF0000 > 0) { if (x & 0x800000 > 0) { result = (result * 0x1000000000058B90C) >> 64; } if (x & 0x400000 > 0) { result = (result * 0x100000000002C5C86) >> 64; } if (x & 0x200000 > 0) { result = (result * 0x10000000000162E43) >> 64; } if (x & 0x100000 > 0) { result = (result * 0x100000000000B1721) >> 64; } if (x & 0x80000 > 0) { result = (result * 0x10000000000058B91) >> 64; } if (x & 0x40000 > 0) { result = (result * 0x1000000000002C5C8) >> 64; } if (x & 0x20000 > 0) { result = (result * 0x100000000000162E4) >> 64; } if (x & 0x10000 > 0) { result = (result * 0x1000000000000B172) >> 64; } } if (x & 0xFF00 > 0) { if (x & 0x8000 > 0) { result = (result * 0x100000000000058B9) >> 64; } if (x & 0x4000 > 0) { result = (result * 0x10000000000002C5D) >> 64; } if (x & 0x2000 > 0) { result = (result * 0x1000000000000162E) >> 64; } if (x & 0x1000 > 0) { result = (result * 0x10000000000000B17) >> 64; } if (x & 0x800 > 0) { result = (result * 0x1000000000000058C) >> 64; } if (x & 0x400 > 0) { result = (result * 0x100000000000002C6) >> 64; } if (x & 0x200 > 0) { result = (result * 0x10000000000000163) >> 64; } if (x & 0x100 > 0) { result = (result * 0x100000000000000B1) >> 64; } } if (x & 0xFF > 0) { if (x & 0x80 > 0) { result = (result * 0x10000000000000059) >> 64; } if (x & 0x40 > 0) { result = (result * 0x1000000000000002C) >> 64; } if (x & 0x20 > 0) { result = (result * 0x10000000000000016) >> 64; } if (x & 0x10 > 0) { result = (result * 0x1000000000000000B) >> 64; } if (x & 0x8 > 0) { result = (result * 0x10000000000000006) >> 64; } if (x & 0x4 > 0) { result = (result * 0x10000000000000003) >> 64; } if (x & 0x2 > 0) { result = (result * 0x10000000000000001) >> 64; } if (x & 0x1 > 0) { result = (result * 0x10000000000000001) >> 64; } } // In the code snippet below, two operations are executed simultaneously: // // 1. The result is multiplied by $(2^n + 1)$, where $2^n$ represents the integer part, and the additional 1 // accounts for the initial guess of 0.5. This is achieved by subtracting from 191 instead of 192. // 2. The result is then converted to an unsigned 60.18-decimal fixed-point format. // // The underlying logic is based on the relationship $2^{191-ip} = 2^{ip} / 2^{191}$, where $ip$ denotes the, // integer part, $2^n$. result *= UNIT; result >>= (191 - (x >> 64)); } } /// @notice Finds the zero-based index of the first 1 in the binary representation of x. /// /// @dev See the note on "msb" in this Wikipedia article: https://en.wikipedia.org/wiki/Find_first_set /// /// Each step in this implementation is equivalent to this high-level code: /// /// ```solidity /// if (x >= 2 ** 128) { /// x >>= 128; /// result += 128; /// } /// ``` /// /// Where 128 is replaced with each respective power of two factor. See the full high-level implementation here: /// https://gist.github.com/PaulRBerg/f932f8693f2733e30c4d479e8e980948 /// /// The Yul instructions used below are: /// /// - "gt" is "greater than" /// - "or" is the OR bitwise operator /// - "shl" is "shift left" /// - "shr" is "shift right" /// /// @param x The uint256 number for which to find the index of the most significant bit. /// @return result The index of the most significant bit as a uint256. /// @custom:smtchecker abstract-function-nondet function msb(uint256 x) pure returns (uint256 result) { // 2^128 assembly ("memory-safe") { let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^64 assembly ("memory-safe") { let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^32 assembly ("memory-safe") { let factor := shl(5, gt(x, 0xFFFFFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^16 assembly ("memory-safe") { let factor := shl(4, gt(x, 0xFFFF)) x := shr(factor, x) result := or(result, factor) } // 2^8 assembly ("memory-safe") { let factor := shl(3, gt(x, 0xFF)) x := shr(factor, x) result := or(result, factor) } // 2^4 assembly ("memory-safe") { let factor := shl(2, gt(x, 0xF)) x := shr(factor, x) result := or(result, factor) } // 2^2 assembly ("memory-safe") { let factor := shl(1, gt(x, 0x3)) x := shr(factor, x) result := or(result, factor) } // 2^1 // No need to shift x any more. assembly ("memory-safe") { let factor := gt(x, 0x1) result := or(result, factor) } } /// @notice Calculates x*y÷denominator with 512-bit precision. /// /// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv. /// /// Notes: /// - The result is rounded toward zero. /// /// Requirements: /// - The denominator must not be zero. /// - The result must fit in uint256. /// /// @param x The multiplicand as a uint256. /// @param y The multiplier as a uint256. /// @param denominator The divisor as a uint256. /// @return result The result as a uint256. /// @custom:smtchecker abstract-function-nondet function mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256 result) { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512-bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly ("memory-safe") { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { unchecked { return prod0 / denominator; } } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (prod1 >= denominator) { revert PRBMath_MulDiv_Overflow(x, y, denominator); } //////////////////////////////////////////////////////////////////////////// // 512 by 256 division //////////////////////////////////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly ("memory-safe") { // Compute remainder using the mulmod Yul instruction. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512-bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } unchecked { // Calculate the largest power of two divisor of the denominator using the unary operator ~. This operation cannot overflow // because the denominator cannot be zero at this point in the function execution. The result is always >= 1. // For more detail, see https://cs.stackexchange.com/q/138556/92363. uint256 lpotdod = denominator & (~denominator + 1); uint256 flippedLpotdod; assembly ("memory-safe") { // Factor powers of two out of denominator. denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. prod0 := div(prod0, lpotdod) // Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one. // `sub(0, lpotdod)` produces the two's complement version of `lpotdod`, which is equivalent to flipping all the bits. // However, `div` interprets this value as an unsigned value: https://ethereum.stackexchange.com/q/147168/24693 flippedLpotdod := add(div(sub(0, lpotdod), lpotdod), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * flippedLpotdod; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; } } /// @notice Calculates x*y÷1e18 with 512-bit precision. /// /// @dev A variant of {mulDiv} with constant folding, i.e. in which the denominator is hard coded to 1e18. /// /// Notes: /// - The body is purposely left uncommented; to understand how this works, see the documentation in {mulDiv}. /// - The result is rounded toward zero. /// - We take as an axiom that the result cannot be `MAX_UINT256` when x and y solve the following system of equations: /// /// $$ /// \begin{cases} /// x * y = MAX\_UINT256 * UNIT \\ /// (x * y) \% UNIT \geq \frac{UNIT}{2} /// \end{cases} /// $$ /// /// Requirements: /// - Refer to the requirements in {mulDiv}. /// - The result must fit in uint256. /// /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number. /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. /// @custom:smtchecker abstract-function-nondet function mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) { uint256 prod0; uint256 prod1; assembly ("memory-safe") { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } if (prod1 == 0) { unchecked { return prod0 / UNIT; } } if (prod1 >= UNIT) { revert PRBMath_MulDiv18_Overflow(x, y); } uint256 remainder; assembly ("memory-safe") { remainder := mulmod(x, y, UNIT) result := mul( or( div(sub(prod0, remainder), UNIT_LPOTD), mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1)) ), UNIT_INVERSE ) } } /// @notice Calculates x*y÷denominator with 512-bit precision. /// /// @dev This is an extension of {mulDiv} for signed numbers, which works by computing the signs and the absolute values separately. /// /// Notes: /// - The result is rounded toward zero. /// /// Requirements: /// - Refer to the requirements in {mulDiv}. /// - None of the inputs can be `type(int256).min`. /// - The result must fit in int256. /// /// @param x The multiplicand as an int256. /// @param y The multiplier as an int256. /// @param denominator The divisor as an int256. /// @return result The result as an int256. /// @custom:smtchecker abstract-function-nondet function mulDivSigned(int256 x, int256 y, int256 denominator) pure returns (int256 result) { if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) { revert PRBMath_MulDivSigned_InputTooSmall(); } // Get hold of the absolute values of x, y and the denominator. uint256 xAbs; uint256 yAbs; uint256 dAbs; unchecked { xAbs = x < 0 ? uint256(-x) : uint256(x); yAbs = y < 0 ? uint256(-y) : uint256(y); dAbs = denominator < 0 ? uint256(-denominator) : uint256(denominator); } // Compute the absolute value of x*y÷denominator. The result must fit in int256. uint256 resultAbs = mulDiv(xAbs, yAbs, dAbs); if (resultAbs > uint256(type(int256).max)) { revert PRBMath_MulDivSigned_Overflow(x, y); } // Get the signs of x, y and the denominator. uint256 sx; uint256 sy; uint256 sd; assembly ("memory-safe") { // "sgt" is the "signed greater than" assembly instruction and "sub(0,1)" is -1 in two's complement. sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) sd := sgt(denominator, sub(0, 1)) } // XOR over sx, sy and sd. What this does is to check whether there are 1 or 3 negative signs in the inputs. // If there are, the result should be negative. Otherwise, it should be positive. unchecked { result = sx ^ sy ^ sd == 0 ? -int256(resultAbs) : int256(resultAbs); } } /// @notice Calculates the square root of x using the Babylonian method. /// /// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Notes: /// - If x is not a perfect square, the result is rounded down. /// - Credits to OpenZeppelin for the explanations in comments below. /// /// @param x The uint256 number for which to calculate the square root. /// @return result The result as a uint256. /// @custom:smtchecker abstract-function-nondet function sqrt(uint256 x) pure returns (uint256 result) { if (x == 0) { return 0; } // For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x. // // We know that the "msb" (most significant bit) of x is a power of 2 such that we have: // // $$ // msb(x) <= x <= 2*msb(x)$ // $$ // // We write $msb(x)$ as $2^k$, and we get: // // $$ // k = log_2(x) // $$ // // Thus, we can write the initial inequality as: // // $$ // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\ // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\ // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1} // $$ // // Consequently, $2^{log_2(x) /2} is a good first approximation of sqrt(x) with at least one correct bit. uint256 xAux = uint256(x); result = 1; if (xAux >= 2 ** 128) { xAux >>= 128; result <<= 64; } if (xAux >= 2 ** 64) { xAux >>= 64; result <<= 32; } if (xAux >= 2 ** 32) { xAux >>= 32; result <<= 16; } if (xAux >= 2 ** 16) { xAux >>= 16; result <<= 8; } if (xAux >= 2 ** 8) { xAux >>= 8; result <<= 4; } if (xAux >= 2 ** 4) { xAux >>= 4; result <<= 2; } if (xAux >= 2 ** 2) { result <<= 1; } // At this point, `result` is an estimation with at least one bit of precision. We know the true value has at // most 128 bits, since it is the square root of a uint256. Newton's method converges quadratically (precision // doubles at every iteration). We thus need at most 7 iteration to turn our partial result with one bit of // precision into the expected uint128 result. unchecked { result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; // If x is not a perfect square, round the result toward zero. uint256 roundedResult = x / result; if (result >= roundedResult) { result = roundedResult; } } }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (common/access/OrigamiElevatedAccessBase.sol) import { OrigamiElevatedAccessBase } from "contracts/common/access/OrigamiElevatedAccessBase.sol"; /** * @notice Inherit to add Owner roles for DAO elevated access. */ abstract contract OrigamiElevatedAccess is OrigamiElevatedAccessBase { constructor(address initialOwner) { _init(initialOwner); } }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (common/access/OrigamiElevatedAccessBase.sol) import { IOrigamiElevatedAccess } from "contracts/interfaces/common/access/IOrigamiElevatedAccess.sol"; import { CommonEventsAndErrors } from "contracts/libraries/CommonEventsAndErrors.sol"; /** * @notice Inherit to add Owner roles for DAO elevated access. */ abstract contract OrigamiElevatedAccessBase is IOrigamiElevatedAccess { /** * @notice The address of the current owner. */ address public override owner; /** * @notice Explicit approval for an address to execute a function. * allowedCaller => function selector => true/false */ mapping(address => mapping(bytes4 => bool)) public override explicitFunctionAccess; /// @dev Track proposed owner address private _proposedNewOwner; /// @dev propose this as the new owner before revoking, for 2 step approval address private constant PROPOSED_DEAD_ADDRESS = 0x000000000000000000000000000000000000dEaD; function _init(address initialOwner) internal { if (owner != address(0)) revert CommonEventsAndErrors.InvalidAccess(); if (initialOwner == address(0)) revert CommonEventsAndErrors.InvalidAddress(address(0)); owner = initialOwner; } /** * @notice Revoke ownership. * @dev To enforce a two-step revoke, it must first propose to 0x000...dEaD prior to calling. * This cannot be undone. */ function revokeOwnership() external override onlyElevatedAccess { if (_proposedNewOwner != PROPOSED_DEAD_ADDRESS) revert CommonEventsAndErrors.InvalidAddress(_proposedNewOwner); emit NewOwnerAccepted(owner, address(0)); owner = address(0); } /** * @notice Proposes a new Owner. * Can only be called by the current owner */ function proposeNewOwner(address account) external override onlyElevatedAccess { if (account == address(0)) revert CommonEventsAndErrors.InvalidAddress(account); emit NewOwnerProposed(owner, _proposedNewOwner, account); _proposedNewOwner = account; } /** * @notice Caller accepts the role as new Owner. * Can only be called by the proposed owner */ function acceptOwner() external override { if (msg.sender != _proposedNewOwner) revert CommonEventsAndErrors.InvalidAccess(); emit NewOwnerAccepted(owner, msg.sender); owner = msg.sender; delete _proposedNewOwner; } /** * @notice Grant `allowedCaller` the rights to call the function selectors in the access list. * @dev fnSelector == bytes4(keccak256("fn(argType1,argType2,...)")) */ function setExplicitAccess(address allowedCaller, ExplicitAccess[] calldata access) external override onlyElevatedAccess { if (allowedCaller == address(0)) revert CommonEventsAndErrors.InvalidAddress(allowedCaller); ExplicitAccess memory _access; for (uint256 i; i < access.length; ++i) { _access = access[i]; emit ExplicitAccessSet(allowedCaller, _access.fnSelector, _access.allowed); explicitFunctionAccess[allowedCaller][_access.fnSelector] = _access.allowed; } } function isElevatedAccess(address caller, bytes4 fnSelector) internal view returns (bool) { return ( caller == owner || explicitFunctionAccess[caller][fnSelector] ); } /** * @notice The owner is allowed to call, or if explicit access has been given to the caller. * @dev Important: Only for use when called from an *external* contract. * If a function with this modifier is called internally then the `msg.sig` * will still refer to the top level externally called function. */ modifier onlyElevatedAccess() { if (!isElevatedAccess(msg.sender, msg.sig)) revert CommonEventsAndErrors.InvalidAccess(); _; } }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (common/OrigamiErc4626.sol) import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { IOrigamiErc4626 } from "contracts/interfaces/common/IOrigamiErc4626.sol"; import { CommonEventsAndErrors } from "contracts/libraries/CommonEventsAndErrors.sol"; import { OrigamiElevatedAccess } from "contracts/common/access/OrigamiElevatedAccess.sol"; import { OrigamiMath } from "contracts/libraries/OrigamiMath.sol"; import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; /** * @title Origami ERC-4626 * @notice A fork of the openzeppelin ERC-4626, with: * - `_decimalsOffset()` set to zero (OZ defaults to zero anyway) * - Always has decimals() of 18dp (rather than using the underlying asset) * - Deposit and Withdraw fees, which are taken from the _shares_ of the user, * benefiting the existing vault holders. * - Permit support * - IERC165 support * - Reentrancy guard on deposit/mint/withdraw/redeem * - maxRedeem & maxWithdraw for address(0) returns the total vault capacity (given any caps within the implementation) * which can be withdrawn/redeemed (rather than always returning zero) * * For the reference implementation, see: * - https://github.com/OpenZeppelin/openzeppelin-contracts/blob/cae60c595b37b1e7ed7dd50ad0257387ec07c0cf/contracts/token/ERC20/extensions/ERC4626.sol * - https://github.com/OpenZeppelin/openzeppelin-contracts/blob/cae60c595b37b1e7ed7dd50ad0257387ec07c0cf/contracts/token/ERC20/extensions/ERC20Permit.sol */ contract OrigamiErc4626 is ERC20, IERC4626, EIP712, ReentrancyGuard, OrigamiElevatedAccess, IOrigamiErc4626 { using SafeERC20 for IERC20; using OrigamiMath for uint256; // Note the `_maxTotalSupply` is initally set to zero. // It is first set upon elevated access calling `seedDeposit()` uint256 private _maxTotalSupply; bytes32 private constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); IERC20 internal immutable _asset; mapping(address account => uint256) private _nonces; uint8 private constant DECIMALS = 18; /// @dev The scalar to convert from `asset` decimals to 18 decimals uint256 private immutable _assetsToSharesScalar; constructor( address initialOwner_, string memory name_, string memory symbol_, IERC20 asset_ ) OrigamiElevatedAccess(initialOwner_) ERC20(name_, symbol_) EIP712(name_, "1") { uint8 _underlyingDecimals = IERC20Metadata(address(asset_)).decimals(); // Only allow <= 18 decimal places in the underlying // This satisfies the virtual offset requirement where: // > Said otherwise, we use more decimal places to represent the shares than the underlying token does to represent the assets. // https://docs.openzeppelin.com/contracts/4.x/erc4626#defending_with_a_virtual_offset if (_underlyingDecimals > DECIMALS) revert CommonEventsAndErrors.InvalidToken(address(asset_)); _assetsToSharesScalar = 10 ** (DECIMALS - _underlyingDecimals); _asset = asset_; } /// @inheritdoc IOrigamiErc4626 function setMaxTotalSupply(uint256 maxTotalSupply_) public virtual override onlyElevatedAccess { // Cannot set if the totalSupply is zero - seedDeposit should be used first if (totalSupply() == 0) revert CommonEventsAndErrors.InvalidParam(); _maxTotalSupply = maxTotalSupply_; emit MaxTotalSupplySet(maxTotalSupply_); } /// @inheritdoc IOrigamiErc4626 function seedDeposit( uint256 assets, address receiver, uint256 maxTotalSupply_ ) external override onlyElevatedAccess returns (uint256 shares) { // Only to be used for the first deposit if (totalSupply() != 0) revert CommonEventsAndErrors.InvalidParam(); // The new maxTotalSupply needs to be at least the size of the // new shares minted, or the deposit() will revert. _maxTotalSupply = maxTotalSupply_; emit MaxTotalSupplySet(maxTotalSupply_); return deposit(assets, receiver); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXTERNAL ERC20 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @inheritdoc IERC20Metadata function decimals() public view virtual override(IERC20Metadata, ERC20) returns (uint8) { return DECIMALS; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXTERNAL ERC4626 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @inheritdoc IERC4626 function asset() public view virtual override returns (address) { return address(_asset); } /// @inheritdoc IERC4626 function totalAssets() public view virtual override returns (uint256) { return _asset.balanceOf(address(this)); } /// @inheritdoc IERC4626 function convertToShares(uint256 assets) public view virtual override returns (uint256) { return _convertToShares(assets, OrigamiMath.Rounding.ROUND_DOWN); } /// @inheritdoc IERC4626 function convertToAssets(uint256 shares) public view virtual override returns (uint256) { return _convertToAssets(shares, OrigamiMath.Rounding.ROUND_DOWN); } /// @inheritdoc IERC4626 function maxDeposit(address /*receiver*/) public override view returns (uint256 maxAssets) { return _maxDeposit(depositFeeBps()); } /// @inheritdoc IERC4626 function maxMint(address /*receiver*/) public override view returns (uint256 maxShares) { uint256 maxTotalSupply_ = maxTotalSupply(); if (maxTotalSupply_ == type(uint256).max) return type(uint256).max; uint256 _totalSupply = totalSupply(); if (_totalSupply > maxTotalSupply_) return 0; unchecked { maxShares = maxTotalSupply_ - _totalSupply; } } /// @inheritdoc IERC4626 function maxWithdraw(address sharesOwner) public override view returns (uint256 maxAssets) { return _maxWithdraw(sharesOwner, withdrawalFeeBps()); } /// @inheritdoc IERC4626 function maxRedeem(address sharesOwner) public override view returns (uint256 maxShares) { return _maxRedeem(sharesOwner, withdrawalFeeBps()); } /// @inheritdoc IERC4626 function previewDeposit(uint256 assets) public view virtual override returns (uint256 shares) { (shares,) = _previewDeposit(assets, depositFeeBps()); } /// @inheritdoc IERC4626 function previewMint(uint256 shares) public view virtual override returns (uint256 assets) { (assets,) = _previewMint(shares, depositFeeBps()); } /// @inheritdoc IERC4626 function previewWithdraw(uint256 assets) public view virtual override returns (uint256 shares) { (shares,) = _previewWithdraw(assets, withdrawalFeeBps()); } /// @inheritdoc IERC4626 function previewRedeem(uint256 shares) public view virtual override returns (uint256 assets) { (assets,) = _previewRedeem(shares, withdrawalFeeBps()); } /// @inheritdoc IERC4626 function deposit( uint256 assets, address receiver ) public virtual override nonReentrant returns (uint256) { uint256 feeBps = depositFeeBps(); uint256 maxAssets = _maxDeposit(feeBps); if (assets > maxAssets) { revert ERC4626ExceededMaxDeposit(receiver, assets, maxAssets); } (uint256 shares, uint256 shareFeesTaken) = _previewDeposit(assets, feeBps); if (shareFeesTaken > 0) { emit InKindFees(FeeType.DEPOSIT_FEE, feeBps, shareFeesTaken); } _deposit(_msgSender(), receiver, assets, shares); return shares; } /// @inheritdoc IERC4626 function mint( uint256 shares, address receiver ) public virtual override nonReentrant returns (uint256) { uint256 maxShares = maxMint(receiver); if (shares > maxShares) { revert ERC4626ExceededMaxMint(receiver, shares, maxShares); } uint256 feeBps = depositFeeBps(); (uint256 assets, uint256 shareFeesTaken) = _previewMint(shares, feeBps); if (shareFeesTaken > 0) { emit InKindFees(FeeType.DEPOSIT_FEE, feeBps, shareFeesTaken); } _deposit(_msgSender(), receiver, assets, shares); return assets; } /// @inheritdoc IERC4626 function withdraw( uint256 assets, address receiver, address sharesOwner ) public virtual override nonReentrant returns (uint256) { uint256 feeBps = withdrawalFeeBps(); uint256 maxAssets = _maxWithdraw(sharesOwner, feeBps); if (assets > maxAssets) { revert ERC4626ExceededMaxWithdraw(sharesOwner, assets, maxAssets); } (uint256 shares, uint256 shareFeesTaken) = _previewWithdraw(assets, feeBps); if (shareFeesTaken > 0) { emit InKindFees(FeeType.WITHDRAWAL_FEE, feeBps, shareFeesTaken); } _withdraw(_msgSender(), receiver, sharesOwner, assets, shares); return shares; } /// @inheritdoc IERC4626 function redeem( uint256 shares, address receiver, address sharesOwner ) public virtual override nonReentrant returns (uint256) { uint256 feeBps = withdrawalFeeBps(); uint256 maxShares = _maxRedeem(sharesOwner, feeBps); if (shares > maxShares) { revert ERC4626ExceededMaxRedeem(sharesOwner, shares, maxShares); } (uint256 assets, uint256 shareFeesTaken) = _previewRedeem(shares, feeBps); if (shareFeesTaken > 0) { emit InKindFees(FeeType.WITHDRAWAL_FEE, feeBps, shareFeesTaken); } _withdraw(_msgSender(), receiver, sharesOwner, assets, shares); return assets; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXT. IMPLEMENTATIONS TO OVERRIDE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @inheritdoc IOrigamiErc4626 function depositFeeBps() public virtual override view returns (uint256) { return 0; } /// @inheritdoc IOrigamiErc4626 function withdrawalFeeBps() public virtual override view returns (uint256) { return 0; } /// @inheritdoc IOrigamiErc4626 function maxTotalSupply() public virtual override view returns (uint256) { return _maxTotalSupply; } /// @inheritdoc IOrigamiErc4626 function areDepositsPaused() external virtual override view returns (bool) { return false; } /// @inheritdoc IOrigamiErc4626 function areWithdrawalsPaused() external virtual override view returns (bool) { return false; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXTERNAL ERC20Permit */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @inheritdoc IERC20Permit */ function permit( address sharesOwner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public override { if (block.timestamp > deadline) { revert ERC2612ExpiredSignature(deadline); } bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, sharesOwner, spender, value, _useNonce(sharesOwner), deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); if (signer != sharesOwner) { revert ERC2612InvalidSigner(signer, sharesOwner); } _approve(sharesOwner, spender, value); } /// @inheritdoc IERC20Permit function nonces(address sharesOwner) public override view returns (uint256) { return _nonces[sharesOwner]; } /// @inheritdoc IERC20Permit // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external override view virtual returns (bytes32) { return _domainSeparatorV4(); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXTERNAL ERC165 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @inheritdoc IERC165 function supportsInterface(bytes4 interfaceId) public virtual override pure returns (bool) { return interfaceId == type(IERC4626).interfaceId || interfaceId == type(IERC20Permit).interfaceId || interfaceId == type(EIP712).interfaceId || interfaceId == type(IERC165).interfaceId; } /** * @notice Recover any token other than the underlying erc4626 asset. * @param token Token to recover * @param to Recipient address * @param amount Amount to recover */ function recoverToken(address token, address to, uint256 amount) external onlyElevatedAccess { if (token == asset()) revert CommonEventsAndErrors.InvalidToken(token); emit CommonEventsAndErrors.TokenRecovered(to, token, amount); IERC20(token).safeTransfer(to, amount); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL ERC4626 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev Calculate the max number of assets which can be deposited given the available shares * under the maxTotalSupply() * This may revert with an overflow for very extreme/unrealistic cases of either a maxTotalSupply * which is close to but not exactly type(uint256).max, or an extremely unbalanced share price. */ function _maxDeposit(uint256 feeBps) internal view returns (uint256 maxAssets) { uint256 maxTotalSupply_ = maxTotalSupply(); if (maxTotalSupply_ == type(uint256).max) return type(uint256).max; uint256 _totalSupply = totalSupply(); if (_totalSupply > maxTotalSupply_) return 0; uint256 availableShares; unchecked { availableShares = maxTotalSupply_ - _totalSupply; } return _convertToAssets( availableShares.inverseSubtractBps(feeBps, OrigamiMath.Rounding.ROUND_UP), OrigamiMath.Rounding.ROUND_UP ); } /** * @dev Calculate the max number of assets which can be withdrawn given the number of shares * owned by `sharesOwner` * May be overridden to enforce other constraints, such as current assets available to withdraw * from the underlying asset deployment */ function _maxWithdraw( address sharesOwner, uint256 feeBps ) internal virtual view returns (uint256 maxAssets) { if (sharesOwner == address(0)) return type(uint256).max; uint256 shares = balanceOf(sharesOwner); // Withdrawal fees are taken from the shares the user redeems (shares,) = shares.splitSubtractBps(feeBps, OrigamiMath.Rounding.ROUND_DOWN); return _convertToAssets(shares, OrigamiMath.Rounding.ROUND_DOWN); } /** * @dev Calculate the max number of shares which can be redeemed given the number of shares * owned by `sharesOwner` * May be overridden to enforce other constraints, such as current assets available to withdraw * from the underlying asset deployment */ function _maxRedeem( address sharesOwner, uint256 /*feeBps*/ ) internal virtual view returns (uint256 maxShares) { return sharesOwner == address(0) ? type(uint256).max : balanceOf(sharesOwner); } function _previewDeposit(uint256 assets, uint256 feeBps) internal virtual view returns ( uint256 shares, uint256 shareFeesTaken ) { shares = _convertToShares(assets, OrigamiMath.Rounding.ROUND_DOWN); // Deposit fees are taken from the shares in kind (shares, shareFeesTaken) = shares.splitSubtractBps(feeBps, OrigamiMath.Rounding.ROUND_DOWN); } function _previewMint(uint256 shares, uint256 feeBps) internal virtual view returns ( uint256 assets, uint256 shareFeesTaken ) { // Deposit fees are taken from the shares the user would otherwise receive // so calculate the amount of shares required before fees are taken. uint256 sharesPlusFees = shares.inverseSubtractBps(feeBps, OrigamiMath.Rounding.ROUND_UP); unchecked { shareFeesTaken = sharesPlusFees - shares; } assets = _convertToAssets(sharesPlusFees, OrigamiMath.Rounding.ROUND_UP); } function _previewWithdraw(uint256 assets, uint256 feeBps) internal view returns ( uint256 shares, uint256 shareFeesTaken ) { uint256 sharesExcludingFees = _convertToShares(assets, OrigamiMath.Rounding.ROUND_UP); // Withdrawal fees are taken from the shares the user redeems // so calculate the amount of shares required before fees are taken. shares = sharesExcludingFees.inverseSubtractBps(feeBps, OrigamiMath.Rounding.ROUND_UP); unchecked { shareFeesTaken = shares - sharesExcludingFees; } } function _previewRedeem(uint256 shares, uint256 feeBps) internal view returns ( uint256 assets, uint256 shareFeesTaken ) { (shares, shareFeesTaken) = shares.splitSubtractBps(feeBps, OrigamiMath.Rounding.ROUND_DOWN); assets = _convertToAssets(shares, OrigamiMath.Rounding.ROUND_DOWN); } /** * @dev Internal conversion function (from assets to shares) with support for rounding direction. */ function _convertToShares(uint256 assets, OrigamiMath.Rounding rounding) internal view virtual returns (uint256) { return assets.mulDiv(totalSupply() + _assetsToSharesScalar, totalAssets() + 1, rounding); } /** * @dev Internal conversion function (from shares to assets) with support for rounding direction. */ function _convertToAssets(uint256 shares, OrigamiMath.Rounding rounding) internal view virtual returns (uint256) { return shares.mulDiv(totalAssets() + 1, totalSupply() + _assetsToSharesScalar, rounding); } /** * @dev Deposit/mint common workflow. */ function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual { _depositHook(caller, assets); _mint(receiver, shares); emit Deposit(caller, receiver, assets, shares); } /** * @dev A hook for the implementation to do something with the deposited assets */ function _depositHook(address caller, uint256 assets) internal virtual { // The default implementation assumes the assets are just pulled into this contract. SafeERC20.safeTransferFrom(_asset, caller, address(this), assets); } /** * @dev Withdraw/redeem common workflow. */ function _withdraw( address caller, address receiver, address sharesOwner, uint256 assets, uint256 shares ) internal virtual { if (caller != sharesOwner) { _spendAllowance(sharesOwner, caller, shares); } // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer, // calls the vault, which is assumed not malicious. // // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the // shares are burned and after the assets are transferred, which is a valid state. _burn(sharesOwner, shares); // If the vault has been fully exited, then reset the maxTotalSupply to zero, as if it were newly created. if (totalSupply() == 0) _maxTotalSupply = 0; _withdrawHook(assets, receiver); emit Withdraw(caller, receiver, sharesOwner, assets, shares); } /** * @dev A hook for the implementation to pull and send assets to the receiver */ function _withdrawHook( uint256 assets, address receiver ) internal virtual { // The default implementation assumes the assets are just sitting in this contract. SafeERC20.safeTransfer(_asset, receiver, assets); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL ERC20Permit */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev Consumes a nonce. * Returns the current value and increments nonce. */ function _useNonce(address sharesOwner) internal returns (uint256) { // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be // decremented or reset. This guarantees that the nonce never overflows. unchecked { // It is important to do x++ and not ++x here. return _nonces[sharesOwner]++; } } }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (interfaces/common/access/IOrigamiElevatedAccess.sol) /** * @notice Inherit to add Owner roles for DAO elevated access. */ interface IOrigamiElevatedAccess { event ExplicitAccessSet(address indexed account, bytes4 indexed fnSelector, bool indexed value); event NewOwnerProposed(address indexed oldOwner, address indexed oldProposedOwner, address indexed newProposedOwner); event NewOwnerAccepted(address indexed oldOwner, address indexed newOwner); struct ExplicitAccess { bytes4 fnSelector; bool allowed; } /** * @notice The address of the current owner. */ function owner() external view returns (address); /** * @notice Explicit approval for an address to execute a function. * allowedCaller => function selector => true/false */ function explicitFunctionAccess(address contractAddr, bytes4 functionSelector) external view returns (bool); /** * @notice Revoke ownership. Be very certain before calling this, as no * further elevated access can be called. */ function revokeOwnership() external; /** * @notice Proposes a new Owner. * Can only be called by the current owner */ function proposeNewOwner(address account) external; /** * @notice Caller accepts the role as new Owner. * Can only be called by the proposed owner */ function acceptOwner() external; /** * @notice Grant `allowedCaller` the rights to call the function selectors in the access list. * @dev fnSelector == bytes4(keccak256("fn(argType1,argType2,...)")) */ function setExplicitAccess(address allowedCaller, ExplicitAccess[] calldata access) external; }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (interfaces/common/IOrigamiErc4626.sol) import { IERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; import { IERC5267 } from "@openzeppelin/contracts/interfaces/IERC5267.sol"; import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol"; /** * @title Origami ERC-4626 * @notice A fork of the openzeppelin ERC-4626, with: * - `_decimalsOffset()` set to zero (OZ defaults to zero anyway) * - Always has decimals() of 18dp (rather than using the underlying asset) * - Deposit and Withdraw fees, which are taken from the _shares_ of the user, * benefiting the existing vault holders. * - Permit support * - IERC165 support * - Reentrancy guard on deposit/mint/withdraw/redeem * - maxRedeem & maxWithdraw for address(0) returns the total vault capacity (given any caps within the implementation) * which can be withdrawn/redeemed (rather than always returning zero) */ interface IOrigamiErc4626 is IERC4626, IERC20Permit, IERC165, IERC5267 { /// @dev Attempted to deposit more assets than the max amount for `receiver`. error ERC4626ExceededMaxDeposit(address receiver, uint256 assets, uint256 max); /// @dev Attempted to mint more shares than the max amount for `receiver`. error ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max); /// @dev Attempted to withdraw more assets than the max amount for `receiver`. error ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max); /// @dev Attempted to redeem more shares than the max amount for `receiver`. error ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max); /// @dev Permit deadline has expired. error ERC2612ExpiredSignature(uint256 deadline); /// @dev Mismatched signature. error ERC2612InvalidSigner(address signer, address tokensOwner); /// @dev What kind of fees - either Deposit or withdrawal enum FeeType { DEPOSIT_FEE, WITHDRAWAL_FEE } /// @dev Either deposit or withdrawal fees have been updated event FeeBpsSet(FeeType feeType, uint256 feeBps); /// @dev Either deposit or withdrawal fees have been applied event InKindFees(FeeType feeType, uint256 feeBps, uint256 feeAmount); /// @dev A client implementation may emit if the max total supply has been changed event MaxTotalSupplySet(uint256 maxTotalSupply); /// @notice Set the max total supply allowed for this vault /// @dev Will revert if the current totalSupply is zero as /// `seedDeposit()` needs to be called first function setMaxTotalSupply(uint256 maxTotalSupply) external; /// @notice Origami protocol seeds the initial deposit /// @dev The new maxTotalSupply is set and a trusted deposit /// is made function seedDeposit( uint256 assets, address receiver, uint256 maxTotalSupply ) external returns (uint256 shares); /// @notice The current deposit fee in basis points. function depositFeeBps() external view returns (uint256); /// @notice The current withdrawal fee in basis points. function withdrawalFeeBps() external view returns (uint256); /// @notice The current maximum total supply of vault tokens. function maxTotalSupply() external view returns (uint256); /// @notice Whether deposit/mint is currently paused function areDepositsPaused() external view returns (bool); /// @notice Whether withdrawal/redeem is currently paused function areWithdrawalsPaused() external view returns (bool); }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (interfaces/common/ITokenPrices.sol) /// @title Token Prices /// @notice A utility contract to pull token prices from on-chain. /// @dev composable functions (uisng encoded function calldata) to build up price formulas interface ITokenPrices { /// @notice How many decimals places are the token prices reported in function decimals() external view returns (uint8); /// @notice Retrieve the price for a given token. /// @dev If not mapped, or an underlying error occurs, FailedPriceLookup will be thrown. /// @dev 0x000...0 is the native chain token (ETH/AVAX/etc) function tokenPrice(address token) external view returns (uint256 price); /// @notice Retrieve the price for a list of tokens. /// @dev If any aren't mapped, or an underlying error occurs, FailedPriceLookup will be thrown. /// @dev Not particularly gas efficient - wouldn't recommend to use on-chain function tokenPrices(address[] memory tokens) external view returns (uint256[] memory prices); }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (interfaces/common/oracle/IOrigamiOracle.sol) import { OrigamiMath } from "contracts/libraries/OrigamiMath.sol"; /** * @notice An oracle which returns prices for pairs of assets, where an asset * could refer to a token (eg DAI) or a currency (eg USD) * Convention is the same as the FX market. Given the DAI/USD pair: * - DAI = Base Asset (LHS of pair) * - USD = Quote Asset (RHS of pair) * This price defines how many USD you get if selling 1 DAI * * Further, an oracle can define two PriceType's: * - SPOT_PRICE: The latest spot price, for example from a chainlink oracle * - HISTORIC_PRICE: An expected (eg 1:1 peg) or calculated historic price (eg TWAP) * * For assets which do are not tokens (eg USD), an internal address reference will be used * since this is for internal purposes only */ interface IOrigamiOracle { error InvalidPrice(address oracle, int256 price); error InvalidOracleData(address oracle); error StalePrice(address oracle, uint256 lastUpdatedAt, int256 price); error UnknownPriceType(uint8 priceType); error BelowMinValidRange(address oracle, uint256 price, uint128 floor); error AboveMaxValidRange(address oracle, uint256 price, uint128 ceiling); event ValidPriceRangeSet(uint128 validFloor, uint128 validCeiling); enum PriceType { /// @notice The current spot price of this Oracle SPOT_PRICE, /// @notice The historic price of this Oracle. /// It may be a fixed expectation (eg DAI/USD would be fixed to 1) /// or use a TWAP or some other moving average, etc. HISTORIC_PRICE } /** * @dev Wrapped in a struct to remove stack-too-deep constraints */ struct BaseOracleParams { string description; address baseAssetAddress; uint8 baseAssetDecimals; address quoteAssetAddress; uint8 quoteAssetDecimals; } /** * @notice The address used to reference the baseAsset for amount conversions */ function baseAsset() external view returns (address); /** * @notice The address used to reference the quoteAsset for amount conversions */ function quoteAsset() external view returns (address); /** * @notice The number of decimals of precision the price is returned as */ function decimals() external view returns (uint8); /** * @notice The precision that the cross rate oracle price is returned as: `10^decimals` */ function precision() external view returns (uint256); /** * @notice A human readable description for this oracle */ function description() external view returns (string memory); /** * @notice Return the latest oracle price, to `decimals` precision * @dev This may still revert - eg if deemed stale, div by 0, negative price * @param priceType What kind of price - Spot or Historic * @param roundingMode Round the price at each intermediate step such that the final price rounds in the specified direction. */ function latestPrice( PriceType priceType, OrigamiMath.Rounding roundingMode ) external view returns (uint256 price); /** * @notice Same as `latestPrice()` but for two separate prices from this oracle */ function latestPrices( PriceType priceType1, OrigamiMath.Rounding roundingMode1, PriceType priceType2, OrigamiMath.Rounding roundingMode2 ) external view returns ( uint256 price1, uint256 price2, address oracleBaseAsset, address oracleQuoteAsset ); /** * @notice Convert either the baseAsset->quoteAsset or quoteAsset->baseAsset * @dev The `fromAssetAmount` needs to be in it's natural fixed point precision (eg USDC=6dp) * The `toAssetAmount` will also be returned in it's natural fixed point precision */ function convertAmount( address fromAsset, uint256 fromAssetAmount, PriceType priceType, OrigamiMath.Rounding roundingMode ) external view returns (uint256 toAssetAmount); /** * @notice Match whether a pair of assets match the base and quote asset on this oracle, in either order */ function matchAssets(address asset1, address asset2) external view returns (bool); }
// SPDX-FileCopyrightText: © 2019-2021 Synthetix // SPDX-FileCopyrightText: © 2023 Dai Foundation <www.daifoundation.org> // SPDX-License-Identifier: MIT AND AGPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. pragma solidity ^0.8.16; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; // https://docs.synthetix.io/contracts/source/interfaces/istakingrewards interface ISkyStakingRewards { // Views function balanceOf(address account) external view returns (uint256); function earned(address account) external view returns (uint256); function rewardRate() external view returns (uint256); function getRewardForDuration() external view returns (uint256); function lastTimeRewardApplicable() external view returns (uint256); function rewardPerToken() external view returns (uint256); function rewardsDistribution() external view returns (address); function rewardsToken() external view returns (IERC20); function stakingToken() external view returns (IERC20); function totalSupply() external view returns (uint256); // Mutative function exit() external; function getReward() external; function stake(uint256 amount) external; function stake(uint256 amount, uint16 referral) external; function withdraw(uint256 amount) external; function notifyRewardAmount(uint256 reward) external; function setRewardsDistribution(address _rewardsDistribution) external; function setRewardsDuration(uint256 _rewardsDuration) external; }
// SPDX-License-Identifier: AGPL-3.0-or-later // Copyright (C) 2021 Dai Foundation // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. pragma solidity >=0.8.0; interface ISkySUsds { function totalSupply() external view returns (uint256); function balanceOf(address) external view returns (uint256); function allowance(address, address) external view returns (uint256); function approve(address, uint256) external returns (bool); function transfer(address, uint256) external returns (bool); function transferFrom(address, address, uint256) external returns (bool); function name() external view returns (string memory); function symbol() external view returns (string memory); function version() external view returns (string memory); function decimals() external view returns (uint8); function PERMIT_TYPEHASH() external view returns (bytes32); function DOMAIN_SEPARATOR() external view returns (bytes32); function nonces(address) external view returns (uint256); function vat() external view returns (address); function vow() external view returns (address); function usdsJoin() external view returns (address); function usds() external view returns (address); function ssr() external view returns (uint256); function chi() external view returns (uint256); function rho() external view returns (uint256); function asset() external view returns (address); function totalAssets() external view returns (uint256); function convertToShares(uint256) external view returns (uint256); function convertToAssets(uint256) external view returns (uint256); function maxDeposit(address) external view returns (uint256); function previewDeposit(uint256) external view returns (uint256); function drip() external view returns (uint256); function deposit(uint256, address) external returns (uint256); function deposit(uint256, address, uint16) external returns (uint256); function maxMint(address) external view returns (uint256); function previewMint(uint256) external view returns (uint256); function mint(uint256, address) external returns (uint256); function mint(uint256, address, uint16) external returns (uint256); function maxWithdraw(address) external view returns (uint256); function previewWithdraw(uint256) external view returns (uint256); function withdraw(uint256, address, address) external returns (uint256); function maxRedeem(address) external view returns (uint256); function previewRedeem(uint256) external view returns (uint256); function redeem(uint256, address, address) external returns (uint256); function permit(address, address, uint256, uint256, bytes memory) external; function permit(address, address, uint256, uint256, uint8, bytes32, bytes32) external; }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (investments/erc4626/IOrigamiDelegated4626Vault.sol) import { ITokenPrices } from "contracts/interfaces/common/ITokenPrices.sol"; import { IOrigamiErc4626 } from "contracts/interfaces/common/IOrigamiErc4626.sol"; /** * @title Origami Delegated ERC4626 Vault * @notice An Origami ERC4626 Vault, which delegates the handling of deposited assets * to a manager */ interface IOrigamiDelegated4626Vault is IOrigamiErc4626 { event TokenPricesSet(address indexed _tokenPrices); event ManagerSet(address indexed manager); event PerformanceFeeSet(uint256 fee); /** * @notice Set the helper to calculate current off-chain/subgraph integration */ function setTokenPrices(address tokenPrices) external; /** * @notice Set the Origami delegated manager */ function setManager(address manager) external; /** * @notice The performance fee to Origami treasury * Represented in basis points */ function performanceFeeBps() external view returns (uint48); /** * @notice The helper contract to retrieve Origami USD prices * @dev Required for off-chain/subgraph integration */ function tokenPrices() external view returns (ITokenPrices); /** * @notice The Origami contract managing the application of * the deposit tokens into the underlying protocol */ function manager() external view returns (address); }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (investments/erc4626/IOrigamiDelegated4626VaultManager.sol) import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol"; import { IOrigamiDelegated4626Vault } from "contracts/interfaces/investments/erc4626/IOrigamiDelegated4626Vault.sol"; import { DynamicFees } from "contracts/libraries/DynamicFees.sol"; /** * @title Origami Delegated ERC4626 Vault Manager * @notice An Origami ERC4626 Vault Manager, which handles the deposited assets from a * IOrigamiDelegated4626Vault */ interface IOrigamiDelegated4626VaultManager is IERC165 { event FeeBpsSet(uint16 depositFeeBps, uint16 withdrawalFeeBps); event InKindFees(DynamicFees.FeeType feeType, uint256 feeBps, uint256 feeAmount); event FeeCollectorSet(address indexed feeCollector); /// @notice Deposit tokens into the underlying protocol /// @dev Implementation may assume the tokens have already been sent to this contract /// type(uint256).max is accepted, meaning the entire balance function deposit(uint256 assetsAmount) external returns ( uint256 assetsDeposited ); /// @notice Withdraw tokens from the underlying protocol to a given receiver /// @dev /// - Fails if it can't withdraw that amount /// - type(uint256).max is accepted, meaning the entire balance function withdraw( uint256 assetsAmount, address receiver ) external returns (uint256 assetsWithdrawn); /// @notice The Origami vault this is managing function vault() external view returns (IOrigamiDelegated4626Vault); /// @notice Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. /// @dev /// - MUST be an ERC-20 token contract. /// - MUST NOT revert. function asset() external view returns (address assetTokenAddress); /// @notice Returns the total amount of the underlying asset that is “managed” by Vault. /// @dev /// - SHOULD include any compounding that occurs from yield. /// - MUST be inclusive of any fees that are charged against assets in the Vault. /// - MUST NOT revert. function totalAssets() external view returns (uint256 totalManagedAssets); /// @notice Whether deposits and mints are currently paused function areDepositsPaused() external view returns (bool); /// @notice Whether withdrawals and redemptions are currently paused function areWithdrawalsPaused() external view returns (bool); }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (interfaces/sky/IOrigamiSuperSavingsUsdsManager.sol) import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ISkySUsds } from "contracts/interfaces/external/sky/ISkySUsds.sol"; import { IOrigamiDelegated4626VaultManager } from "contracts/interfaces/investments/erc4626/IOrigamiDelegated4626VaultManager.sol"; import { ISkyStakingRewards } from "contracts/interfaces/external/sky/ISkyStakingRewards.sol"; /** * @title Origami sUSDS+s Manager * @notice Handles USDS deposits and switching between farms */ interface IOrigamiSuperSavingsUsdsManager is IOrigamiDelegated4626VaultManager { error InvalidFarm(uint32 farmIndex); error FarmStillInUse(uint32 farmIndex); error BeforeCooldownEnd(); error MaxFarms(); error FarmExistsAlready(address stakingAddress); event FarmReferralCodeSet(uint32 indexed farmIndex, uint16 referralCode); event SwitchFarmCooldownSet(uint32 cooldown); event SwapperSet(address indexed newSwapper); event FarmAdded( uint32 indexed farmIndex, address indexed stakingAddress, address indexed rewardsToken, uint16 referralCode ); event FarmRemoved( uint32 indexed farmIndex, address indexed stakingAddress, address indexed rewardsToken ); event SwitchedFarms( uint32 indexed oldFarmIndex, uint32 indexed newFarmIndex, uint256 amountWithdrawn, uint256 amountDeposited ); event ClaimedReward( uint32 indexed farmIndex, address indexed rewardsToken, uint256 amountForCaller, uint256 amountForOrigami, uint256 amountForVault ); /// @dev Configuration required for a USDS farm struct Farm { /// @dev The address of the Synthetix-like USDS staking contract ISkyStakingRewards staking; /// @dev The rewards token for this given staking contract IERC20 rewardsToken; /// @dev The referral code representing Origami uint16 referral; } /** * @notice Set the performance fees for the caller and origami * @dev Total fees cannot increase, but the ratio can be changed. * Fees are distributed when claimFarmRewards() is called */ function setPerformanceFees(uint16 callerFeeBps, uint16 origamiFeeBps) external; /** * @notice Set the address used to collect the Origami performance fees. */ function setFeeCollector(address _feeCollector) external; /** * @notice Set the swapper contract responsible for swapping * farm reward tokens into USDS */ function setSwapper(address swapper) external; /** * @notice Set the cooldown for how frequently this contract is allowed to switch between * farms. Used to avoid thrashing. */ function setSwitchFarmCooldown(uint32 cooldown) external; /** * @notice Add a new USDS farm configuation * @dev Only a maximum of 100 farms can be added. Will revert if the same `stakingAddress` is * added a second time. */ function addFarm( address stakingAddress, uint16 referralCode ) external returns ( uint32 newFarmIndex ); /** * @notice Remove a deprecated farm configuration item for house keeping * @dev This will revert if there's still a staked balance or rewards to claim. * If a farm is removed, the `maxFarmIndex` doesn't decrease */ function removeFarm(uint32 farmIndex) external; /** * @notice Set the referral code for a given USDS staking contract */ function setFarmReferralCode( uint32 farmIndex, uint16 referralCode ) external; /** * @notice Elevated access can decide to switch which farm to use if the yield is greater */ function switchFarms(uint32 newFarmIndex) external returns ( uint256 amountWithdrawn, uint256 amountDeposited ); /** * @notice A permisionless function to claim farm rewards from a given farm * - The caller can nominate an address to receive a portion of these rewards (to compensate for gas) * - Origami will earn a portion of these rewards (as performance fee) * - The remainder is sent to a swapper contract to swap for USDS. * USDS proceeds from the swap will sent back to this contract, ready to add to the * current farm on the next deposit. */ function claimFarmRewards( uint32[] calldata farmIndexes, address incentivesReceiver ) external; /** * @notice The Sky USDS contract */ function USDS() external view returns (IERC20); /** * @notice The Sky sUSDS contract */ function sUSDS() external view returns (ISkySUsds); /** * @notice The performance fee to the caller (to compensate for gas) and Origami treasury * Represented in basis points */ function performanceFeeBps() external view returns (uint16 forCaller, uint16 forOrigami); /** * @notice The address used to collect the Origami performance fees. */ function feeCollector() external view returns (address); /** * @notice The referral code representing Origami when depositing into sUSDS */ function sUsdsReferral() external view returns (uint16); /** * @notice The swapper contract responsible for swapping * farm reward tokens into USDS */ function swapper() external view returns (address); /** * @notice The cooldown for how frequently this contract is allowed to switch between * farms. Used to avoid thrashing. */ function switchFarmCooldown() external view returns (uint32); /** * @notice The last time that the farm was switched */ function lastSwitchTime() external view returns (uint32); /** * @notice The number of Sky USDS farms, not including sUSDS */ function maxFarmIndex() external view returns (uint32); /** * @notice The currently selected farm for deposits. * @dev * - index 0: sUSDS * - index 1+: A Sky USDS staking contract */ function currentFarmIndex() external view returns (uint32); /** * @notice The farm config of a particular index * @dev Does not revert - A farm index is invalid if the returned * `farm.staking` is address(0) */ function getFarm(uint256 farmIndex) external view returns (Farm memory farm); struct FarmDetails { /// @dev The farm configuration Farm farm; /// @dev The amount of USDS staked in the farm /// For sUSDS, this is the current amount of USDS /// which can be withdrawn uint256 stakedBalance; /// @dev The total amount of USDS staked in the farm across /// all stakers /// For sUSDS, this is the total amount of USDS assets uint256 totalSupply; /// @dev The current rate of emissions from the farm /// For sUSDS, this is current interest rate uint256 rewardRate; /// @dev The amount of emissions earned which can /// currently be claimed. /// For sUSDS, this will always be zero uint256 unclaimedRewards; } /** * @notice A helper to show the current positions for a set of farm indexes. * @dev If the farmIndex is not valid/removed that item will remain * empty */ function farmDetails(uint32[] calldata farmIndexes) external view returns ( FarmDetails[] memory ); }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (libraries/CommonEventsAndErrors.sol) /// @notice A collection of common events and errors thrown within the Origami contracts library CommonEventsAndErrors { error InsufficientBalance(address token, uint256 required, uint256 balance); error InvalidToken(address token); error InvalidParam(); error InvalidAddress(address addr); error InvalidAmount(address token, uint256 amount); error ExpectedNonZero(); error Slippage(uint256 minAmountExpected, uint256 actualAmount); error IsPaused(); error UnknownExecuteError(bytes returndata); error InvalidAccess(); error BreachedMaxTotalSupply(uint256 totalSupply, uint256 maxTotalSupply); event TokenRecovered(address indexed to, address indexed token, uint256 amount); }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (libraries/DynamicFees.sol) import { IOrigamiOracle } from "contracts/interfaces/common/oracle/IOrigamiOracle.sol"; import { OrigamiMath } from "contracts/libraries/OrigamiMath.sol"; import { CommonEventsAndErrors } from "contracts/libraries/CommonEventsAndErrors.sol"; /** * @notice A helper to calculate dynamic entry and exit fees based off the difference * between an oracle historic vs spot price */ library DynamicFees { using OrigamiMath for uint256; enum FeeType { DEPOSIT_FEE, EXIT_FEE } /** * @notice The current deposit or exit fee based on market conditions. * Fees are applied to the portion of lovToken shares the depositor * would have received. Instead that fee portion isn't minted (benefiting remaining users) * Ignoring the minFeeBps, deposit vs exit fees are symmetric: * - A 0.004 cent increase in price (away from expected historic) should result a deposit fee of X bps * - A 0.004 cent decrease in price (away from expected historic) should result an exit fee, also of X bps * ie X is the same in both cases. * @dev feeLeverageFactor has 4dp precision */ function dynamicFeeBps( FeeType feeType, IOrigamiOracle oracle, address expectedBaseAsset, uint64 minFeeBps, uint256 feeLeverageFactor ) internal view returns (uint256) { // Pull the spot and expected historic price from the oracle. // Round up for both to be consistent no matter if the oracle is in expected quoted order or not. (uint256 _spotPrice, uint256 _histPrice, address _baseAsset, address _quoteAsset) = oracle.latestPrices( IOrigamiOracle.PriceType.SPOT_PRICE, OrigamiMath.Rounding.ROUND_UP, IOrigamiOracle.PriceType.HISTORIC_PRICE, OrigamiMath.Rounding.ROUND_UP ); // Whether the expected 'base' asset of the oracle is indeed the base asset. // If not, then the delta and denominator is switched bool _inQuotedOrder; if (_baseAsset == expectedBaseAsset) { _inQuotedOrder = true; } else if (_quoteAsset != expectedBaseAsset) { revert CommonEventsAndErrors.InvalidToken(expectedBaseAsset); } uint256 _delta; uint256 _denominator; if (feeType == FeeType.DEPOSIT_FEE) { // If spot price is > than the expected historic, then they are exiting // at a price better than expected. The exit fee is based off the relative // difference of the expected spotPrice - historicPrice. // Or opposite if the oracle order is inverted unchecked { if (_inQuotedOrder) { if (_spotPrice < _histPrice) { (_delta, _denominator) = (_histPrice - _spotPrice, _histPrice); } } else { if (_spotPrice > _histPrice) { (_delta, _denominator) = (_spotPrice - _histPrice, _spotPrice); } } } } else { // If spot price is > than the expected historic, then they are exiting // at a price better than expected. The exit fee is based off the relative // difference of the expected spotPrice - historicPrice. // Or opposite if the oracle order is inverted unchecked { if (_inQuotedOrder) { if (_spotPrice > _histPrice) { (_delta, _denominator) = (_spotPrice - _histPrice, _histPrice); } } else { if (_spotPrice < _histPrice) { (_delta, _denominator) = (_histPrice - _spotPrice, _spotPrice); } } } } // If no delta, just return the min fee if (_delta == 0) { return minFeeBps; } // Relative diff multiply by a leverage factor to match the worst case lovToken // effective exposure // Result is in basis points, since `feeLeverageFactor` has 4dp precision uint256 _fee = _delta.mulDiv( feeLeverageFactor, _denominator, OrigamiMath.Rounding.ROUND_UP ); // Use the maximum of the calculated fee and a pre-set minimum. return minFeeBps > _fee ? minFeeBps : _fee; } }
pragma solidity 0.8.19; // SPDX-License-Identifier: AGPL-3.0-or-later // Origami (libraries/OrigamiMath.sol) import { mulDiv as prbMulDiv, PRBMath_MulDiv_Overflow } from "@prb/math/src/Common.sol"; import { CommonEventsAndErrors } from "contracts/libraries/CommonEventsAndErrors.sol"; /** * @notice Utilities to operate on fixed point math multipliation and division * taking rounding into consideration */ library OrigamiMath { enum Rounding { ROUND_DOWN, ROUND_UP } uint256 public constant BASIS_POINTS_DIVISOR = 10_000; function scaleUp(uint256 amount, uint256 scalar) internal pure returns (uint256) { // Special case for scalar == 1, as it's common for token amounts to not need // scaling if decimal places are the same return scalar == 1 ? amount : amount * scalar; } function scaleDown( uint256 amount, uint256 scalar, Rounding roundingMode ) internal pure returns (uint256 result) { // Special case for scalar == 1, as it's common for token amounts to not need // scaling if decimal places are the same unchecked { if (scalar == 1) { result = amount; } else if (roundingMode == Rounding.ROUND_DOWN) { result = amount / scalar; } else { // ROUND_UP uses the same logic as OZ Math.ceilDiv() result = amount == 0 ? 0 : (amount - 1) / scalar + 1; } } } /** * @notice Calculates x * y / denominator with full precision, * rounding up */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding roundingMode ) internal pure returns (uint256 result) { result = prbMulDiv(x, y, denominator); if (roundingMode == Rounding.ROUND_UP) { if (mulmod(x, y, denominator) != 0) { if (result < type(uint256).max) { unchecked { result = result + 1; } } else { revert PRBMath_MulDiv_Overflow(x, y, denominator); } } } } function subtractBps( uint256 inputAmount, uint256 basisPoints, Rounding roundingMode ) internal pure returns (uint256 result) { uint256 numeratorBps; unchecked { numeratorBps = BASIS_POINTS_DIVISOR - basisPoints; } result = basisPoints < BASIS_POINTS_DIVISOR ? mulDiv( inputAmount, numeratorBps, BASIS_POINTS_DIVISOR, roundingMode ) : 0; } function addBps( uint256 inputAmount, uint256 basisPoints, Rounding roundingMode ) internal pure returns (uint256 result) { uint256 numeratorBps; unchecked { numeratorBps = BASIS_POINTS_DIVISOR + basisPoints; } // Round up for max amounts out expected result = mulDiv( inputAmount, numeratorBps, BASIS_POINTS_DIVISOR, roundingMode ); } /** * @notice Split the `inputAmount` into two parts based on the `basisPoints` fraction. * eg: 3333 BPS (33.3%) can be used to split an input amount of 600 into: (result=400, removed=200). * @dev The rounding mode is applied to the `result` */ function splitSubtractBps( uint256 inputAmount, uint256 basisPoints, Rounding roundingMode ) internal pure returns (uint256 result, uint256 removed) { result = subtractBps(inputAmount, basisPoints, roundingMode); unchecked { removed = inputAmount - result; } } /** * @notice Reverse the fractional amount of an input. * eg: For 3333 BPS (33.3%) and the remainder=400, the result is 600 */ function inverseSubtractBps( uint256 remainderAmount, uint256 basisPoints, Rounding roundingMode ) internal pure returns (uint256 result) { if (basisPoints == 0) return remainderAmount; // gas shortcut for 0 if (basisPoints >= BASIS_POINTS_DIVISOR) revert CommonEventsAndErrors.InvalidParam(); uint256 denominatorBps; unchecked { denominatorBps = BASIS_POINTS_DIVISOR - basisPoints; } result = mulDiv( remainderAmount, BASIS_POINTS_DIVISOR, denominatorBps, roundingMode ); } /** * @notice Calculate the relative difference of a value to a reference * @dev `value` and `referenceValue` must have the same precision * The denominator is always the referenceValue */ function relativeDifferenceBps( uint256 value, uint256 referenceValue, Rounding roundingMode ) internal pure returns (uint256) { if (referenceValue == 0) revert CommonEventsAndErrors.InvalidParam(); uint256 absDelta; unchecked { absDelta = value < referenceValue ? referenceValue - value : value - referenceValue; } return mulDiv( absDelta, BASIS_POINTS_DIVISOR, referenceValue, roundingMode ); } }
{ "optimizer": { "enabled": true, "runs": 9999 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"initialOwner_","type":"address"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"contract IERC20","name":"asset_","type":"address"},{"internalType":"address","name":"tokenPrices_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ERC2612ExpiredSignature","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"tokensOwner","type":"address"}],"name":"ERC2612InvalidSigner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"ERC4626ExceededMaxDeposit","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"ERC4626ExceededMaxMint","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"ERC4626ExceededMaxRedeem","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"ERC4626ExceededMaxWithdraw","type":"error"},{"inputs":[],"name":"InvalidAccess","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidParam","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"InvalidToken","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"PRBMath_MulDiv_Overflow","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bytes4","name":"fnSelector","type":"bytes4"},{"indexed":true,"internalType":"bool","name":"value","type":"bool"}],"name":"ExplicitAccessSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IOrigamiErc4626.FeeType","name":"feeType","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"feeBps","type":"uint256"}],"name":"FeeBpsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IOrigamiErc4626.FeeType","name":"feeType","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"feeBps","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"InKindFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"manager","type":"address"}],"name":"ManagerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxTotalSupply","type":"uint256"}],"name":"MaxTotalSupplySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"NewOwnerAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"oldProposedOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newProposedOwner","type":"address"}],"name":"NewOwnerProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"PerformanceFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_tokenPrices","type":"address"}],"name":"TokenPricesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"areDepositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"areWithdrawalsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"explicitFunctionAccess","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"performanceFees","type":"uint256"}],"name":"logPerformanceFeesSet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"manager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sharesOwner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sharesOwner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sharesOwner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"performanceFeeBps","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sharesOwner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"proposeNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"sharesOwner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revokeOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"maxTotalSupply_","type":"uint256"}],"name":"seedDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"allowedCaller","type":"address"},{"components":[{"internalType":"bytes4","name":"fnSelector","type":"bytes4"},{"internalType":"bool","name":"allowed","type":"bool"}],"internalType":"struct IOrigamiElevatedAccess.ExplicitAccess[]","name":"access","type":"tuple[]"}],"name":"setExplicitAccess","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newManager","type":"address"}],"name":"setManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxTotalSupply_","type":"uint256"}],"name":"setMaxTotalSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenPrices","type":"address"}],"name":"setTokenPrices","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenPrices","outputs":[{"internalType":"contract ITokenPrices","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"sharesOwner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101a06040523480156200001257600080fd5b506040516200422e3803806200422e833981016040819052620000359162000411565b848484848383604051806040016040528060018152602001603160f81b815250858581600390816200006891906200054c565b5060046200007782826200054c565b50620000899150839050600562000236565b610120526200009a81600662000236565b61014052815160208084019190912060e052815190820120610100524660a0526200012860e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052600160075562000141816200026f565b506000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000183573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001a9919062000618565b9050601260ff82161115620001e15760405163961c9a4f60e01b81526001600160a01b03831660048201526024015b60405180910390fd5b620001ee8160126200065a565b620001fb90600a62000773565b61018052506001600160a01b0390811661016052600d80546001600160a01b031916959091169490941790935550620007de95505050505050565b600060208351101562000256576200024e83620002e8565b905062000269565b816200026384826200054c565b5060ff90505b92915050565b6008546001600160a01b0316156200029a57604051633006171960e21b815260040160405180910390fd5b6001600160a01b038116620002c657604051634726455360e11b815260006004820152602401620001d8565b600880546001600160a01b0319166001600160a01b0392909216919091179055565b600080829050601f8151111562000316578260405163305a27a960e01b8152600401620001d8919062000784565b80516200032382620007b9565b179392505050565b6001600160a01b03811681146200034157600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620003775781810151838201526020016200035d565b50506000910152565b600082601f8301126200039257600080fd5b81516001600160401b0380821115620003af57620003af62000344565b604051601f8301601f19908116603f01168101908282118183101715620003da57620003da62000344565b81604052838152866020858801011115620003f457600080fd5b620004078460208301602089016200035a565b9695505050505050565b600080600080600060a086880312156200042a57600080fd5b855162000437816200032b565b60208701519095506001600160401b03808211156200045557600080fd5b6200046389838a0162000380565b955060408801519150808211156200047a57600080fd5b50620004898882890162000380565b93505060608601516200049c816200032b565b6080870151909250620004af816200032b565b809150509295509295909350565b600181811c90821680620004d257607f821691505b602082108103620004f357634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200054757600081815260208120601f850160051c81016020861015620005225750805b601f850160051c820191505b8181101562000543578281556001016200052e565b5050505b505050565b81516001600160401b0381111562000568576200056862000344565b6200058081620005798454620004bd565b84620004f9565b602080601f831160018114620005b857600084156200059f5750858301515b600019600386901b1c1916600185901b17855562000543565b600085815260208120601f198616915b82811015620005e957888601518255948401946001909101908401620005c8565b5085821015620006085787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200062b57600080fd5b815160ff811681146200063d57600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b60ff828116828216039081111562000269576200026962000644565b600181815b80851115620006b75781600019048211156200069b576200069b62000644565b80851615620006a957918102915b93841c93908002906200067b565b509250929050565b600082620006d05750600162000269565b81620006df5750600062000269565b8160018114620006f85760028114620007035762000723565b600191505062000269565b60ff84111562000717576200071762000644565b50506001821b62000269565b5060208310610133831016604e8410600b841016171562000748575081810a62000269565b62000754838362000676565b80600019048211156200076b576200076b62000644565b029392505050565b60006200063d60ff841683620006bf565b6020815260008251806020840152620007a58160408501602087016200035a565b601f01601f19169190910160400192915050565b80516020808301519190811015620004f35760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161016051610180516139ca6200086460003960008181611d5f015261278301526000818161042a015281816110dd015261295201526000610e7b01526000610e50015260006122de015260006122b6015260006122110152600061223b0152600061226501526139ca6000f3fe608060405234801561001057600080fd5b506004361061034c5760003560e01c806395d89b41116101bd578063c63d75b6116100f9578063d905777e116100a2578063dd62ed3e1161007c578063dd62ed3e14610718578063ebbc496514610751578063ef8b30f714610759578063f20976111461076c57600080fd5b8063d905777e146106c4578063daeccc79146106d7578063db686a921461070557600080fd5b8063d0ebdbe7116100d3578063d0ebdbe714610696578063d505accf146106a9578063d6c9b0dc146106bc57600080fd5b8063c63d75b61461065d578063c6e6f59214610670578063ce96cb771461068357600080fd5b8063b1f8100d11610166578063b9d4e87911610140578063b9d4e87914610605578063ba08765214610624578063be2f503914610637578063bfccf0ec1461064a57600080fd5b8063b1f8100d146105cc578063b3d7f6b9146105df578063b460af94146105f257600080fd5b8063a9059cbb11610197578063a9059cbb146105a6578063ab8798271461038f578063b1e1fca4146105b957600080fd5b806395d89b4114610578578063a457c2d714610580578063a7229fd91461059357600080fd5b806338d52e0f1161028c57806365c1e09e116102355780637ecebe001161020f5780637ecebe001461050e57806384b0196e146105375780638da5cb5b1461055257806394bf804d1461056557600080fd5b806365c1e09e146104bf5780636e553f65146104d257806370a08231146104e557600080fd5b8063402d267d11610266578063402d267d14610488578063481c6a751461049b5780634cdad506146104ac57600080fd5b806338d52e0f1461042857806339509351146104625780633f3e4c111461047557600080fd5b80630a28a477116102f95780632ab4d052116102d35780632ab4d052146103ff5780632b96895814610407578063313ce567146104115780633644e5151461042057600080fd5b80630a28a477146103d157806318160ddd146103e457806323b872dd146103ec57600080fd5b806306fdde031161032a57806306fdde031461039657806307a2d13a146103ab578063095ea7b3146103be57600080fd5b806301e1d1141461035157806301ffc9a71461036c57806304336bb31461038f575b600080fd5b610359610774565b6040519081526020015b60405180910390f35b61037f61037a3660046132f1565b610800565b6040519015158152602001610363565b6000610359565b61039e610931565b604051610363919061337a565b6103596103b936600461338d565b6109c3565b61037f6103cc3660046133bd565b6109d0565b6103596103df36600461338d565b6109e8565b600254610359565b61037f6103fa3660046133e7565b6109fb565b600b54610359565b61040f610a21565b005b60405160128152602001610363565b610359610b41565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b039091168152602001610363565b61037f6104703660046133bd565b610b4b565b61040f61048336600461338d565b610b8a565b610359610496366004613423565b610c66565b600e546001600160a01b031661044a565b6103596104ba36600461338d565b610c71565b6103596104cd36600461343e565b610c7d565b6103596104e0366004613463565b610d67565b6103596104f3366004613423565b6001600160a01b031660009081526020819052604090205490565b61035961051c366004613423565b6001600160a01b03166000908152600c602052604090205490565b61053f610e42565b604051610363979695949392919061348f565b60085461044a906001600160a01b031681565b610359610573366004613463565b610ee7565b61039e610fb3565b61037f61058e3660046133bd565b610fc2565b61040f6105a13660046133e7565b611077565b61037f6105b43660046133bd565b6111b7565b600d5461044a906001600160a01b031681565b61040f6105da366004613423565b6111c5565b6103596105ed36600461338d565b6112ee565b610359610600366004613541565b6112fa565b61060d6113d7565b60405165ffffffffffff9091168152602001610363565b610359610632366004613541565b61146e565b61040f610645366004613423565b61153c565b61040f61065836600461357d565b611651565b61035961066b366004613423565b611839565b61035961067e36600461338d565b611881565b610359610691366004613423565b61188e565b61040f6106a4366004613423565b61189a565b61040f6106b7366004613603565b6119af565b61037f611b1b565b6103596106d2366004613423565b611ba2565b61037f6106e5366004613676565b600960209081526000928352604080842090915290825290205460ff1681565b61040f61071336600461338d565b611bae565b6103596107263660046136a0565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b61040f611c22565b61035961076736600461338d565b611cd6565b61037f611ce2565b600e54604080517f01e1d11400000000000000000000000000000000000000000000000000000000815290516000926001600160a01b0316916301e1d1149160048083019260209291908290030181865afa1580156107d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fb91906136ca565b905090565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f87dfe5a000000000000000000000000000000000000000000000000000000000148061089357507fffffffff0000000000000000000000000000000000000000000000000000000082167f9d8ff7da00000000000000000000000000000000000000000000000000000000145b806108df57507fffffffff0000000000000000000000000000000000000000000000000000000082167f84b0196e00000000000000000000000000000000000000000000000000000000145b8061092b57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b606060038054610940906136e3565b80601f016020809104026020016040519081016040528092919081815260200182805461096c906136e3565b80156109b95780601f1061098e576101008083540402835291602001916109b9565b820191906000526020600020905b81548152906001019060200180831161099c57829003601f168201915b5050505050905090565b600061092b826000611d45565b6000336109de818585611d9a565b5060019392505050565b60006109f48282611ef2565b5092915050565b600033610a09858285611f1c565b610a14858585611fae565b60019150505b9392505050565b610a4f336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b610a85576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a546001600160a01b031661dead14610adf57600a546040517f8e4c8aa60000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024015b60405180910390fd5b6008546040516000916001600160a01b0316907f5cd6b24c0149d980c82592262b3a81294b39f8f6e3c004126aaf0828c787d554908390a3600880547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60006107fb612204565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091906109de9082908690610b85908790613765565b611d9a565b610bb8336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b610bee576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600254600003610c2a576040517fd252903400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b8190556040518181527f0120f799fc820eabb910038e9cce6e8024add369b4d780181846e300df284484906020015b60405180910390a150565b600061092b8161232f565b60006109f48282612391565b6000610cad336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b610ce3576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025415610d1d576040517fd252903400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b8290556040518281527f0120f799fc820eabb910038e9cce6e8024add369b4d780181846e300df2844849060200160405180910390a1610d5f8484610d67565b949350505050565b6000610d716123b8565b600080610d7d8261232f565b905080851115610dd2576040517f79012fb20000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024810186905260448101829052606401610ad6565b600080610ddf8785612411565b90925090508015610e27577f7e81c1439e2f6851efe3288a5d0ae235c1729a6272f98ed0a4b5eb780914042760008583604051610e1e939291906137a7565b60405180910390a15b610e3333878985612438565b509250505061092b6001600755565b600060608082808083610e767f000000000000000000000000000000000000000000000000000000000000000060056124a8565b610ea17f000000000000000000000000000000000000000000000000000000000000000060066124a8565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b6000610ef16123b8565b6000610efc83611839565b905080841115610f51576040517f284ff6670000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810185905260448101829052606401610ad6565b60008080610f5f8784612553565b90925090508015610fa7577f7e81c1439e2f6851efe3288a5d0ae235c1729a6272f98ed0a4b5eb780914042760008483604051610f9e939291906137a7565b60405180910390a15b610e333387848a612438565b606060048054610940906136e3565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091908381101561105f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610ad6565b61106c8286868403611d9a565b506001949350505050565b6110a5336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b6110db576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031603611151576040517f961c9a4f0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610ad6565b826001600160a01b0316826001600160a01b03167f879f92dded0f26b83c3e00b12e0395dc72cfc3077343d1854ed6988edd1f90968360405161119691815260200190565b60405180910390a36111b26001600160a01b038416838361257f565b505050565b6000336109de818585611fae565b6111f3336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b611229576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116611274576040517f8e4c8aa60000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ad6565b600a546008546040516001600160a01b038085169381169216907f64420d4a41c6ed4de2bccbf33192eea18e576c5b23c79c3a722d4e9534c2e8d890600090a4600a80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60006109f48282612553565b60006113046123b8565b6000806113118483612646565b905080861115611366576040517ffe9cceec0000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024810187905260448101829052606401610ad6565b6000806113738885611ef2565b909250905080156113bb577f7e81c1439e2f6851efe3288a5d0ae235c1729a6272f98ed0a4b5eb7809140427600185836040516113b2939291906137a7565b60405180910390a15b6113c83388888b86612694565b5092505050610a1a6001600755565b6000806000600e60009054906101000a90046001600160a01b03166001600160a01b031663b9d4e8796040518163ffffffff1660e01b81526004016040805180830381865afa15801561142e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114529190613808565b61ffff91821693501690506114678183613832565b9250505090565b60006114786123b8565b6000806114858483612743565b9050808611156114da576040517fb94abeec0000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024810187905260448101829052606401610ad6565b6000806114e78885612391565b9092509050801561152f577f7e81c1439e2f6851efe3288a5d0ae235c1729a6272f98ed0a4b5eb780914042760018583604051611526939291906137a7565b60405180910390a15b6113c8338888858c612694565b61156a336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b6115a0576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381166115e3576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815260006004820152602401610ad6565b6040516001600160a01b038216907f2781e03d8cf8be1845f40e150af1187b0cdb48dccd761a708f5e5b612a865d1d90600090a2600d80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b61167f336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b6116b5576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316611700576040517f8e4c8aa60000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610ad6565b604080518082019091526000808252602082015260005b828110156118325783838281811061173157611731613851565b905060400201803603810190611747919061388e565b91508160200151151582600001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916866001600160a01b03167ff5736e75de2c751f775d4c5ed517289f77074f8c337f451ba4c0c3ed1dd7f9ad60405160405180910390a46020828101516001600160a01b038716600090815260098352604080822086517fffffffff000000000000000000000000000000000000000000000000000000001683529093529190912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561182b81613912565b9050611717565b5050505050565b600080611845600b5490565b9050600019810361185a575060001992915050565b600061186560025490565b905081811115611879575060009392505050565b900392915050565b600061092b82600061277c565b600061092b8282612646565b6118c8336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b6118fe576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116611941576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815260006004820152602401610ad6565b6040516001600160a01b038216907f60a0f5b9f9e81e98216071b85826681c796256fe3d1354ecb675580fba64fa6990600090a2600e80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b834211156119ec576040517f6279130200000000000000000000000000000000000000000000000000000000815260048101859052602401610ad6565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888611a398c6001600160a01b03166000908152600c6020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000611a94826127c8565b90506000611aa482878787612810565b9050896001600160a01b0316816001600160a01b031614611b04576040517f4b800e460000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301528b166024820152604401610ad6565b611b0f8a8a8a611d9a565b50505050505050505050565b600e54604080517fd6c9b0dc00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163d6c9b0dc9160048083019260209291908290030181865afa158015611b7e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fb919061392c565b600061092b8282612743565b600e546001600160a01b03163314611bf2576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518181527fceb20f7f0b19335681096ee1eaa9bb2a6ef5a9a69ba48b6b488e7b7eff2ef04d90602001610c5b565b600a546001600160a01b03163314611c66576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085460405133916001600160a01b0316907f5cd6b24c0149d980c82592262b3a81294b39f8f6e3c004126aaf0828c787d55490600090a3600880547fffffffffffffffffffffffff00000000000000000000000000000000000000009081163317909155600a80549091169055565b60006109f48282612411565b600e54604080517ff209761100000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163f20976119160048083019260209291908290030181865afa158015611b7e573d6000803e3d6000fd5b6000610a1a611d52610774565b611d5d906001613765565b7f0000000000000000000000000000000000000000000000000000000000000000611d8760025490565b611d919190613765565b85919085612838565b6001600160a01b038316611e155760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b038216611e915760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000806000611f0285600161277c565b9050611f10818560016128cb565b95908603945092505050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114611fa85781811015611f9b5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610ad6565b611fa88484848403611d9a565b50505050565b6001600160a01b03831661202a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b0382166120a65760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b038316600090815260208190526040902054818110156121355760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611fa8565b6008546000906001600160a01b0384811691161480610a1a5750506001600160a01b039190911660009081526009602090815260408083207fffffffff000000000000000000000000000000000000000000000000000000009094168352929052205460ff1690565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561225d57507f000000000000000000000000000000000000000000000000000000000000000046145b1561228757507f000000000000000000000000000000000000000000000000000000000000000090565b6107fb604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60008061233b600b5490565b90506000198103612350575060001992915050565b600061235b60025490565b90508181111561236f575060009392505050565b808203612388612381828760016128cb565b6001611d45565b95945050505050565b60008061239f84848361292e565b90945090506123af846000611d45565b91509250929050565b60026007540361240a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610ad6565b6002600755565b60008061241f84600061277c565b915061242d8284600061292e565b909590945092505050565b6124428483612949565b61244c8382612a0d565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161249a929190918252602082015260400190565b60405180910390a350505050565b606060ff83146124c2576124bb83612acc565b905061092b565b8180546124ce906136e3565b80601f01602080910402602001604051908101604052809291908181526020018280546124fa906136e3565b80156125475780601f1061251c57610100808354040283529160200191612547565b820191906000526020600020905b81548152906001019060200180831161252a57829003601f168201915b5050505050905061092b565b60008080612563858560016128cb565b90508481039150612575816001611d45565b9250509250929050565b6040516001600160a01b0383166024820152604481018290526111b29084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612b0b565b60006001600160a01b03831661265f575060001961092b565b6001600160a01b03831660009081526020819052604081205490506126868184600061292e565b509050610d5f816000611d45565b826001600160a01b0316856001600160a01b0316146126b8576126b8838683611f1c565b6126c28382612bf3565b6002546000036126d2576000600b555b6126dc8285612d5c565b826001600160a01b0316846001600160a01b0316866001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db8585604051612734929190918252602082015260400190565b60405180910390a45050505050565b60006001600160a01b03831615612772576001600160a01b038316600090815260208190526040902054610a1a565b5060001992915050565b6000610a1a7f00000000000000000000000000000000000000000000000000000000000000006127ab60025490565b6127b59190613765565b6127bd610774565b611d91906001613765565b600061092b6127d5612204565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b600080600061282187878787612dac565b9150915061282e81612e8e565b5095945050505050565b6000612845858585612ff6565b9050600182600181111561285b5761285b613778565b03610d5f57828061286e5761286e613949565b84860915610d5f5760001981101561288857600101610d5f565b6040517f63a05778000000000000000000000000000000000000000000000000000000008152600481018690526024810185905260448101849052606401610ad6565b6000826000036128dc575082610a1a565b6127108310612917576040517fd252903400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083612710039050612388856127108386612838565b60008061293c8585856130e3565b9594869003949350505050565b600e54612983907f00000000000000000000000000000000000000000000000000000000000000009084906001600160a01b031684613107565b600e546040517fb6b55f2500000000000000000000000000000000000000000000000000000000815260001960048201526001600160a01b039091169063b6b55f25906024015b6020604051808303816000875af11580156129e9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b291906136ca565b6001600160a01b038216612a635760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610ad6565b8060026000828254612a759190613765565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b60606000612ad983613158565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6000612b60826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131999092919063ffffffff16565b9050805160001480612b81575080806020019051810190612b81919061392c565b6111b25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b038216612c6f5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b03821660009081526020819052604090205481811015612cfe5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b600e546040517ef714ce000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b0383811660248301529091169062f714ce906044016129ca565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612de35750600090506003612e85565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612e37573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001519150506001600160a01b038116612e7e57600060019250925050612e85565b9150600090505b94509492505050565b6000816004811115612ea257612ea2613778565b03612eaa5750565b6001816004811115612ebe57612ebe613778565b03612f0b5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610ad6565b6002816004811115612f1f57612f1f613778565b03612f6c5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610ad6565b6003816004811115612f8057612f80613778565b03612ff35760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610ad6565b50565b60008080600019858709858702925082811083820303915050806000036130305783828161302657613026613949565b0492505050610a1a565b83811061307a576040517f63a05778000000000000000000000000000000000000000000000000000000008152600481018790526024810186905260448101859052606401610ad6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006127108381039084106130f9576000612388565b612388858261271086612838565b6040516001600160a01b0380851660248301528316604482015260648101829052611fa89085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016125c4565b600060ff8216601f81111561092b576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060610d5f848460008585600080866001600160a01b031685876040516131c09190613978565b60006040518083038185875af1925050503d80600081146131fd576040519150601f19603f3d011682016040523d82523d6000602084013e613202565b606091505b50915091506132138783838761321e565b979650505050505050565b6060831561328d578251600003613286576001600160a01b0385163b6132865760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ad6565b5081610d5f565b610d5f83838151156132a25781518083602001fd5b8060405162461bcd60e51b8152600401610ad6919061337a565b80357fffffffff00000000000000000000000000000000000000000000000000000000811681146132ec57600080fd5b919050565b60006020828403121561330357600080fd5b610a1a826132bc565b60005b8381101561332757818101518382015260200161330f565b50506000910152565b6000815180845261334881602086016020860161330c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610a1a6020830184613330565b60006020828403121561339f57600080fd5b5035919050565b80356001600160a01b03811681146132ec57600080fd5b600080604083850312156133d057600080fd5b6133d9836133a6565b946020939093013593505050565b6000806000606084860312156133fc57600080fd5b613405846133a6565b9250613413602085016133a6565b9150604084013590509250925092565b60006020828403121561343557600080fd5b610a1a826133a6565b60008060006060848603121561345357600080fd5b83359250613413602085016133a6565b6000806040838503121561347657600080fd5b82359150613486602084016133a6565b90509250929050565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e0818401526134cb60e084018a613330565b83810360408501526134dd818a613330565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b8181101561352f57835183529284019291840191600101613513565b50909c9b505050505050505050505050565b60008060006060848603121561355657600080fd5b83359250613566602085016133a6565b9150613574604085016133a6565b90509250925092565b60008060006040848603121561359257600080fd5b61359b846133a6565b9250602084013567ffffffffffffffff808211156135b857600080fd5b818601915086601f8301126135cc57600080fd5b8135818111156135db57600080fd5b8760208260061b85010111156135f057600080fd5b6020830194508093505050509250925092565b600080600080600080600060e0888a03121561361e57600080fd5b613627886133a6565b9650613635602089016133a6565b95506040880135945060608801359350608088013560ff8116811461365957600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561368957600080fd5b613692836133a6565b9150613486602084016132bc565b600080604083850312156136b357600080fd5b6136bc836133a6565b9150613486602084016133a6565b6000602082840312156136dc57600080fd5b5051919050565b600181811c908216806136f757607f821691505b602082108103613730577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561092b5761092b613736565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60608101600285106137e2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b938152602081019290925260409091015290565b805161ffff811681146132ec57600080fd5b6000806040838503121561381b57600080fd5b613824836137f6565b9150613486602084016137f6565b65ffffffffffff8181168382160190808211156109f4576109f4613736565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8015158114612ff357600080fd5b6000604082840312156138a057600080fd5b6040516040810181811067ffffffffffffffff821117156138ea577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040526138f6836132bc565b8152602083013561390681613880565b60208201529392505050565b6000600019820361392557613925613736565b5060010190565b60006020828403121561393e57600080fd5b8151610a1a81613880565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000825161398a81846020870161330c565b919091019291505056fea264697066735822122026c2b56e51f444ef376ac7742606058012590df27b95f1ac3dba06fd4f96ac4164736f6c63430008130033000000000000000000000000b20aae0fe007519b7ce6f090a2ab8353b3da5d8000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f00000000000000000000000043a3cb2cf5ea2331174c166214302f0c3bba6a8500000000000000000000000000000000000000000000000000000000000000194f726967616d69207355534453202b20536b79204661726d7300000000000000000000000000000000000000000000000000000000000000000000000000000773555344532b7300000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061034c5760003560e01c806395d89b41116101bd578063c63d75b6116100f9578063d905777e116100a2578063dd62ed3e1161007c578063dd62ed3e14610718578063ebbc496514610751578063ef8b30f714610759578063f20976111461076c57600080fd5b8063d905777e146106c4578063daeccc79146106d7578063db686a921461070557600080fd5b8063d0ebdbe7116100d3578063d0ebdbe714610696578063d505accf146106a9578063d6c9b0dc146106bc57600080fd5b8063c63d75b61461065d578063c6e6f59214610670578063ce96cb771461068357600080fd5b8063b1f8100d11610166578063b9d4e87911610140578063b9d4e87914610605578063ba08765214610624578063be2f503914610637578063bfccf0ec1461064a57600080fd5b8063b1f8100d146105cc578063b3d7f6b9146105df578063b460af94146105f257600080fd5b8063a9059cbb11610197578063a9059cbb146105a6578063ab8798271461038f578063b1e1fca4146105b957600080fd5b806395d89b4114610578578063a457c2d714610580578063a7229fd91461059357600080fd5b806338d52e0f1161028c57806365c1e09e116102355780637ecebe001161020f5780637ecebe001461050e57806384b0196e146105375780638da5cb5b1461055257806394bf804d1461056557600080fd5b806365c1e09e146104bf5780636e553f65146104d257806370a08231146104e557600080fd5b8063402d267d11610266578063402d267d14610488578063481c6a751461049b5780634cdad506146104ac57600080fd5b806338d52e0f1461042857806339509351146104625780633f3e4c111461047557600080fd5b80630a28a477116102f95780632ab4d052116102d35780632ab4d052146103ff5780632b96895814610407578063313ce567146104115780633644e5151461042057600080fd5b80630a28a477146103d157806318160ddd146103e457806323b872dd146103ec57600080fd5b806306fdde031161032a57806306fdde031461039657806307a2d13a146103ab578063095ea7b3146103be57600080fd5b806301e1d1141461035157806301ffc9a71461036c57806304336bb31461038f575b600080fd5b610359610774565b6040519081526020015b60405180910390f35b61037f61037a3660046132f1565b610800565b6040519015158152602001610363565b6000610359565b61039e610931565b604051610363919061337a565b6103596103b936600461338d565b6109c3565b61037f6103cc3660046133bd565b6109d0565b6103596103df36600461338d565b6109e8565b600254610359565b61037f6103fa3660046133e7565b6109fb565b600b54610359565b61040f610a21565b005b60405160128152602001610363565b610359610b41565b7f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f5b6040516001600160a01b039091168152602001610363565b61037f6104703660046133bd565b610b4b565b61040f61048336600461338d565b610b8a565b610359610496366004613423565b610c66565b600e546001600160a01b031661044a565b6103596104ba36600461338d565b610c71565b6103596104cd36600461343e565b610c7d565b6103596104e0366004613463565b610d67565b6103596104f3366004613423565b6001600160a01b031660009081526020819052604090205490565b61035961051c366004613423565b6001600160a01b03166000908152600c602052604090205490565b61053f610e42565b604051610363979695949392919061348f565b60085461044a906001600160a01b031681565b610359610573366004613463565b610ee7565b61039e610fb3565b61037f61058e3660046133bd565b610fc2565b61040f6105a13660046133e7565b611077565b61037f6105b43660046133bd565b6111b7565b600d5461044a906001600160a01b031681565b61040f6105da366004613423565b6111c5565b6103596105ed36600461338d565b6112ee565b610359610600366004613541565b6112fa565b61060d6113d7565b60405165ffffffffffff9091168152602001610363565b610359610632366004613541565b61146e565b61040f610645366004613423565b61153c565b61040f61065836600461357d565b611651565b61035961066b366004613423565b611839565b61035961067e36600461338d565b611881565b610359610691366004613423565b61188e565b61040f6106a4366004613423565b61189a565b61040f6106b7366004613603565b6119af565b61037f611b1b565b6103596106d2366004613423565b611ba2565b61037f6106e5366004613676565b600960209081526000928352604080842090915290825290205460ff1681565b61040f61071336600461338d565b611bae565b6103596107263660046136a0565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b61040f611c22565b61035961076736600461338d565b611cd6565b61037f611ce2565b600e54604080517f01e1d11400000000000000000000000000000000000000000000000000000000815290516000926001600160a01b0316916301e1d1149160048083019260209291908290030181865afa1580156107d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fb91906136ca565b905090565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f87dfe5a000000000000000000000000000000000000000000000000000000000148061089357507fffffffff0000000000000000000000000000000000000000000000000000000082167f9d8ff7da00000000000000000000000000000000000000000000000000000000145b806108df57507fffffffff0000000000000000000000000000000000000000000000000000000082167f84b0196e00000000000000000000000000000000000000000000000000000000145b8061092b57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b606060038054610940906136e3565b80601f016020809104026020016040519081016040528092919081815260200182805461096c906136e3565b80156109b95780601f1061098e576101008083540402835291602001916109b9565b820191906000526020600020905b81548152906001019060200180831161099c57829003601f168201915b5050505050905090565b600061092b826000611d45565b6000336109de818585611d9a565b5060019392505050565b60006109f48282611ef2565b5092915050565b600033610a09858285611f1c565b610a14858585611fae565b60019150505b9392505050565b610a4f336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b610a85576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a546001600160a01b031661dead14610adf57600a546040517f8e4c8aa60000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024015b60405180910390fd5b6008546040516000916001600160a01b0316907f5cd6b24c0149d980c82592262b3a81294b39f8f6e3c004126aaf0828c787d554908390a3600880547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60006107fb612204565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091906109de9082908690610b85908790613765565b611d9a565b610bb8336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b610bee576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600254600003610c2a576040517fd252903400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b8190556040518181527f0120f799fc820eabb910038e9cce6e8024add369b4d780181846e300df284484906020015b60405180910390a150565b600061092b8161232f565b60006109f48282612391565b6000610cad336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b610ce3576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025415610d1d576040517fd252903400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b8290556040518281527f0120f799fc820eabb910038e9cce6e8024add369b4d780181846e300df2844849060200160405180910390a1610d5f8484610d67565b949350505050565b6000610d716123b8565b600080610d7d8261232f565b905080851115610dd2576040517f79012fb20000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024810186905260448101829052606401610ad6565b600080610ddf8785612411565b90925090508015610e27577f7e81c1439e2f6851efe3288a5d0ae235c1729a6272f98ed0a4b5eb780914042760008583604051610e1e939291906137a7565b60405180910390a15b610e3333878985612438565b509250505061092b6001600755565b600060608082808083610e767f4f726967616d69207355534453202b20536b79204661726d730000000000001960056124a8565b610ea17f310000000000000000000000000000000000000000000000000000000000000160066124a8565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b6000610ef16123b8565b6000610efc83611839565b905080841115610f51576040517f284ff6670000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810185905260448101829052606401610ad6565b60008080610f5f8784612553565b90925090508015610fa7577f7e81c1439e2f6851efe3288a5d0ae235c1729a6272f98ed0a4b5eb780914042760008483604051610f9e939291906137a7565b60405180910390a15b610e333387848a612438565b606060048054610940906136e3565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091908381101561105f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610ad6565b61106c8286868403611d9a565b506001949350505050565b6110a5336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b6110db576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f6001600160a01b0316836001600160a01b031603611151576040517f961c9a4f0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610ad6565b826001600160a01b0316826001600160a01b03167f879f92dded0f26b83c3e00b12e0395dc72cfc3077343d1854ed6988edd1f90968360405161119691815260200190565b60405180910390a36111b26001600160a01b038416838361257f565b505050565b6000336109de818585611fae565b6111f3336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b611229576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116611274576040517f8e4c8aa60000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ad6565b600a546008546040516001600160a01b038085169381169216907f64420d4a41c6ed4de2bccbf33192eea18e576c5b23c79c3a722d4e9534c2e8d890600090a4600a80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60006109f48282612553565b60006113046123b8565b6000806113118483612646565b905080861115611366576040517ffe9cceec0000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024810187905260448101829052606401610ad6565b6000806113738885611ef2565b909250905080156113bb577f7e81c1439e2f6851efe3288a5d0ae235c1729a6272f98ed0a4b5eb7809140427600185836040516113b2939291906137a7565b60405180910390a15b6113c83388888b86612694565b5092505050610a1a6001600755565b6000806000600e60009054906101000a90046001600160a01b03166001600160a01b031663b9d4e8796040518163ffffffff1660e01b81526004016040805180830381865afa15801561142e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114529190613808565b61ffff91821693501690506114678183613832565b9250505090565b60006114786123b8565b6000806114858483612743565b9050808611156114da576040517fb94abeec0000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024810187905260448101829052606401610ad6565b6000806114e78885612391565b9092509050801561152f577f7e81c1439e2f6851efe3288a5d0ae235c1729a6272f98ed0a4b5eb780914042760018583604051611526939291906137a7565b60405180910390a15b6113c8338888858c612694565b61156a336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b6115a0576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381166115e3576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815260006004820152602401610ad6565b6040516001600160a01b038216907f2781e03d8cf8be1845f40e150af1187b0cdb48dccd761a708f5e5b612a865d1d90600090a2600d80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b61167f336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b6116b5576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316611700576040517f8e4c8aa60000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610ad6565b604080518082019091526000808252602082015260005b828110156118325783838281811061173157611731613851565b905060400201803603810190611747919061388e565b91508160200151151582600001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916866001600160a01b03167ff5736e75de2c751f775d4c5ed517289f77074f8c337f451ba4c0c3ed1dd7f9ad60405160405180910390a46020828101516001600160a01b038716600090815260098352604080822086517fffffffff000000000000000000000000000000000000000000000000000000001683529093529190912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561182b81613912565b9050611717565b5050505050565b600080611845600b5490565b9050600019810361185a575060001992915050565b600061186560025490565b905081811115611879575060009392505050565b900392915050565b600061092b82600061277c565b600061092b8282612646565b6118c8336000357fffffffff000000000000000000000000000000000000000000000000000000001661219b565b6118fe576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116611941576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815260006004820152602401610ad6565b6040516001600160a01b038216907f60a0f5b9f9e81e98216071b85826681c796256fe3d1354ecb675580fba64fa6990600090a2600e80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b834211156119ec576040517f6279130200000000000000000000000000000000000000000000000000000000815260048101859052602401610ad6565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888611a398c6001600160a01b03166000908152600c6020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000611a94826127c8565b90506000611aa482878787612810565b9050896001600160a01b0316816001600160a01b031614611b04576040517f4b800e460000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301528b166024820152604401610ad6565b611b0f8a8a8a611d9a565b50505050505050505050565b600e54604080517fd6c9b0dc00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163d6c9b0dc9160048083019260209291908290030181865afa158015611b7e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fb919061392c565b600061092b8282612743565b600e546001600160a01b03163314611bf2576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518181527fceb20f7f0b19335681096ee1eaa9bb2a6ef5a9a69ba48b6b488e7b7eff2ef04d90602001610c5b565b600a546001600160a01b03163314611c66576040517fc0185c6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085460405133916001600160a01b0316907f5cd6b24c0149d980c82592262b3a81294b39f8f6e3c004126aaf0828c787d55490600090a3600880547fffffffffffffffffffffffff00000000000000000000000000000000000000009081163317909155600a80549091169055565b60006109f48282612411565b600e54604080517ff209761100000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163f20976119160048083019260209291908290030181865afa158015611b7e573d6000803e3d6000fd5b6000610a1a611d52610774565b611d5d906001613765565b7f0000000000000000000000000000000000000000000000000000000000000001611d8760025490565b611d919190613765565b85919085612838565b6001600160a01b038316611e155760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b038216611e915760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000806000611f0285600161277c565b9050611f10818560016128cb565b95908603945092505050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114611fa85781811015611f9b5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610ad6565b611fa88484848403611d9a565b50505050565b6001600160a01b03831661202a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b0382166120a65760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b038316600090815260208190526040902054818110156121355760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611fa8565b6008546000906001600160a01b0384811691161480610a1a5750506001600160a01b039190911660009081526009602090815260408083207fffffffff000000000000000000000000000000000000000000000000000000009094168352929052205460ff1690565b6000306001600160a01b037f0000000000000000000000000f90a6962e86b5587b4c11ba2b9697dc3ba848001614801561225d57507f000000000000000000000000000000000000000000000000000000000000000146145b1561228757507f86f89c9b2dc6d63fb7bc4560958524436a12863e8630d61354e48e1bd74c0ec590565b6107fb604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0adb97cb2236051163b98383b7a231b4f3fa57645814c3278360ec81ef891da2918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60008061233b600b5490565b90506000198103612350575060001992915050565b600061235b60025490565b90508181111561236f575060009392505050565b808203612388612381828760016128cb565b6001611d45565b95945050505050565b60008061239f84848361292e565b90945090506123af846000611d45565b91509250929050565b60026007540361240a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610ad6565b6002600755565b60008061241f84600061277c565b915061242d8284600061292e565b909590945092505050565b6124428483612949565b61244c8382612a0d565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161249a929190918252602082015260400190565b60405180910390a350505050565b606060ff83146124c2576124bb83612acc565b905061092b565b8180546124ce906136e3565b80601f01602080910402602001604051908101604052809291908181526020018280546124fa906136e3565b80156125475780601f1061251c57610100808354040283529160200191612547565b820191906000526020600020905b81548152906001019060200180831161252a57829003601f168201915b5050505050905061092b565b60008080612563858560016128cb565b90508481039150612575816001611d45565b9250509250929050565b6040516001600160a01b0383166024820152604481018290526111b29084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612b0b565b60006001600160a01b03831661265f575060001961092b565b6001600160a01b03831660009081526020819052604081205490506126868184600061292e565b509050610d5f816000611d45565b826001600160a01b0316856001600160a01b0316146126b8576126b8838683611f1c565b6126c28382612bf3565b6002546000036126d2576000600b555b6126dc8285612d5c565b826001600160a01b0316846001600160a01b0316866001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db8585604051612734929190918252602082015260400190565b60405180910390a45050505050565b60006001600160a01b03831615612772576001600160a01b038316600090815260208190526040902054610a1a565b5060001992915050565b6000610a1a7f00000000000000000000000000000000000000000000000000000000000000016127ab60025490565b6127b59190613765565b6127bd610774565b611d91906001613765565b600061092b6127d5612204565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b600080600061282187878787612dac565b9150915061282e81612e8e565b5095945050505050565b6000612845858585612ff6565b9050600182600181111561285b5761285b613778565b03610d5f57828061286e5761286e613949565b84860915610d5f5760001981101561288857600101610d5f565b6040517f63a05778000000000000000000000000000000000000000000000000000000008152600481018690526024810185905260448101849052606401610ad6565b6000826000036128dc575082610a1a565b6127108310612917576040517fd252903400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083612710039050612388856127108386612838565b60008061293c8585856130e3565b9594869003949350505050565b600e54612983907f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f9084906001600160a01b031684613107565b600e546040517fb6b55f2500000000000000000000000000000000000000000000000000000000815260001960048201526001600160a01b039091169063b6b55f25906024015b6020604051808303816000875af11580156129e9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b291906136ca565b6001600160a01b038216612a635760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610ad6565b8060026000828254612a759190613765565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b60606000612ad983613158565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6000612b60826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131999092919063ffffffff16565b9050805160001480612b81575080806020019051810190612b81919061392c565b6111b25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b038216612c6f5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b03821660009081526020819052604090205481811015612cfe5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610ad6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b600e546040517ef714ce000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b0383811660248301529091169062f714ce906044016129ca565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612de35750600090506003612e85565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612e37573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001519150506001600160a01b038116612e7e57600060019250925050612e85565b9150600090505b94509492505050565b6000816004811115612ea257612ea2613778565b03612eaa5750565b6001816004811115612ebe57612ebe613778565b03612f0b5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610ad6565b6002816004811115612f1f57612f1f613778565b03612f6c5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610ad6565b6003816004811115612f8057612f80613778565b03612ff35760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610ad6565b50565b60008080600019858709858702925082811083820303915050806000036130305783828161302657613026613949565b0492505050610a1a565b83811061307a576040517f63a05778000000000000000000000000000000000000000000000000000000008152600481018790526024810186905260448101859052606401610ad6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006127108381039084106130f9576000612388565b612388858261271086612838565b6040516001600160a01b0380851660248301528316604482015260648101829052611fa89085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016125c4565b600060ff8216601f81111561092b576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060610d5f848460008585600080866001600160a01b031685876040516131c09190613978565b60006040518083038185875af1925050503d80600081146131fd576040519150601f19603f3d011682016040523d82523d6000602084013e613202565b606091505b50915091506132138783838761321e565b979650505050505050565b6060831561328d578251600003613286576001600160a01b0385163b6132865760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ad6565b5081610d5f565b610d5f83838151156132a25781518083602001fd5b8060405162461bcd60e51b8152600401610ad6919061337a565b80357fffffffff00000000000000000000000000000000000000000000000000000000811681146132ec57600080fd5b919050565b60006020828403121561330357600080fd5b610a1a826132bc565b60005b8381101561332757818101518382015260200161330f565b50506000910152565b6000815180845261334881602086016020860161330c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610a1a6020830184613330565b60006020828403121561339f57600080fd5b5035919050565b80356001600160a01b03811681146132ec57600080fd5b600080604083850312156133d057600080fd5b6133d9836133a6565b946020939093013593505050565b6000806000606084860312156133fc57600080fd5b613405846133a6565b9250613413602085016133a6565b9150604084013590509250925092565b60006020828403121561343557600080fd5b610a1a826133a6565b60008060006060848603121561345357600080fd5b83359250613413602085016133a6565b6000806040838503121561347657600080fd5b82359150613486602084016133a6565b90509250929050565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e0818401526134cb60e084018a613330565b83810360408501526134dd818a613330565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b8181101561352f57835183529284019291840191600101613513565b50909c9b505050505050505050505050565b60008060006060848603121561355657600080fd5b83359250613566602085016133a6565b9150613574604085016133a6565b90509250925092565b60008060006040848603121561359257600080fd5b61359b846133a6565b9250602084013567ffffffffffffffff808211156135b857600080fd5b818601915086601f8301126135cc57600080fd5b8135818111156135db57600080fd5b8760208260061b85010111156135f057600080fd5b6020830194508093505050509250925092565b600080600080600080600060e0888a03121561361e57600080fd5b613627886133a6565b9650613635602089016133a6565b95506040880135945060608801359350608088013560ff8116811461365957600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561368957600080fd5b613692836133a6565b9150613486602084016132bc565b600080604083850312156136b357600080fd5b6136bc836133a6565b9150613486602084016133a6565b6000602082840312156136dc57600080fd5b5051919050565b600181811c908216806136f757607f821691505b602082108103613730577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561092b5761092b613736565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60608101600285106137e2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b938152602081019290925260409091015290565b805161ffff811681146132ec57600080fd5b6000806040838503121561381b57600080fd5b613824836137f6565b9150613486602084016137f6565b65ffffffffffff8181168382160190808211156109f4576109f4613736565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8015158114612ff357600080fd5b6000604082840312156138a057600080fd5b6040516040810181811067ffffffffffffffff821117156138ea577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040526138f6836132bc565b8152602083013561390681613880565b60208201529392505050565b6000600019820361392557613925613736565b5060010190565b60006020828403121561393e57600080fd5b8151610a1a81613880565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000825161398a81846020870161330c565b919091019291505056fea264697066735822122026c2b56e51f444ef376ac7742606058012590df27b95f1ac3dba06fd4f96ac4164736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b20aae0fe007519b7ce6f090a2ab8353b3da5d8000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f00000000000000000000000043a3cb2cf5ea2331174c166214302f0c3bba6a8500000000000000000000000000000000000000000000000000000000000000194f726967616d69207355534453202b20536b79204661726d7300000000000000000000000000000000000000000000000000000000000000000000000000000773555344532b7300000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : initialOwner_ (address): 0xb20AaE0Fe007519b7cE6f090a2aB8353B3Da5d80
Arg [1] : name_ (string): Origami sUSDS + Sky Farms
Arg [2] : symbol_ (string): sUSDS+s
Arg [3] : asset_ (address): 0xdC035D45d973E3EC169d2276DDab16f1e407384F
Arg [4] : tokenPrices_ (address): 0x43A3cb2cf5eA2331174c166214302f0C3BbA6A85
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 000000000000000000000000b20aae0fe007519b7ce6f090a2ab8353b3da5d80
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [2] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [3] : 000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f
Arg [4] : 00000000000000000000000043a3cb2cf5ea2331174c166214302f0c3bba6a85
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000019
Arg [6] : 4f726967616d69207355534453202b20536b79204661726d7300000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [8] : 73555344532b7300000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.