Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 7 from a total of 7 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Bore Well | 20264128 | 87 days ago | IN | 0 ETH | 0.0021478 | ||||
Bore Well | 20234293 | 91 days ago | IN | 0 ETH | 0.00684648 | ||||
Bore Well | 20234243 | 91 days ago | IN | 0 ETH | 0.00626585 | ||||
Bore Well | 20232031 | 91 days ago | IN | 0 ETH | 0.00569406 | ||||
Bore Well | 17978134 | 407 days ago | IN | 0 ETH | 0.01094977 | ||||
Bore Well | 17978071 | 407 days ago | IN | 0 ETH | 0.01113028 | ||||
0x60808060 | 17977905 | 407 days ago | IN | 0 ETH | 0.0373978 |
Latest 25 internal transactions (View All)
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Aquifer
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 1000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ReentrancyGuard} from "lib/openzeppelin-contracts/contracts/security/ReentrancyGuard.sol"; import {IAquifer} from "src/interfaces/IAquifer.sol"; import {IWell} from "src/Well.sol"; import {LibClone} from "src/libraries/LibClone.sol"; /** * @title Aquifer * @author Publius, Silo Chad, Brean * @notice Aquifer is a permissionless Well registry and factory. * @dev Aquifer deploys Wells by cloning a pre-deployed Well implementation. */ contract Aquifer is IAquifer, ReentrancyGuard { using LibClone for address; // A mapping of Well address to the Well implementation addresses // Mapping gets set on Well deployment mapping(address => address) public wellImplementation; constructor() ReentrancyGuard() {} /** * @dev * Use `salt == 0` to deploy a new Well with `create` * Use `salt > 0` to deploy a new Well with `create2` */ function boreWell( address implementation, bytes calldata immutableData, bytes calldata initFunctionCall, bytes32 salt ) external nonReentrant returns (address well) { if (immutableData.length > 0) { if (salt != bytes32(0)) { // Encode the salt with the `msg.sender` address to prevent frontrunning attack salt = keccak256(abi.encode(msg.sender, salt)); well = implementation.cloneDeterministic(immutableData, salt); } else { well = implementation.clone(immutableData); } } else { if (salt != bytes32(0)) { // Encode the salt with the `msg.sender` address to prevent frontrunning attack salt = keccak256(abi.encode(msg.sender, salt)); well = implementation.cloneDeterministic(salt); } else { well = implementation.clone(); } } if (initFunctionCall.length > 0) { (bool success, bytes memory returnData) = well.call(initFunctionCall); if (!success) { // Next 5 lines are based on https://ethereum.stackexchange.com/a/83577 if (returnData.length < 68) revert InitFailed(""); assembly { returnData := add(returnData, 0x04) } revert InitFailed(abi.decode(returnData, (string))); } } if (!IWell(well).isInitialized()) { revert WellNotInitialized(); } // The Aquifer address MUST be set, either (a) via immutable data during cloning, // or (b) as a storage variable during an init function call. In either case, // the address MUST match the address of the Aquifer that performed deployment. if (IWell(well).aquifer() != address(this)) { revert InvalidConfig(); } // Save implementation wellImplementation[well] = implementation; emit BoreWell( well, implementation, IWell(well).tokens(), IWell(well).wellFunction(), IWell(well).pumps(), IWell(well).wellData() ); } function predictWellAddress( address implementation, bytes calldata immutableData, bytes32 salt ) external view returns (address well) { // Aquifer doesn't support using a salt of 0 to deploy a Well at a deterministic address. if (salt == bytes32(0)) { revert InvalidSalt(); } salt = keccak256(abi.encode(msg.sender, salt)); if (immutableData.length > 0) { well = implementation.predictDeterministicAddress(immutableData, salt, address(this)); } else { well = implementation.predictDeterministicAddress(salt, address(this)); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.0; interface IERC5267Upgradeable { /** * @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) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils//AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils//Initializable.sol"; /** * @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 ReentrancyGuardUpgradeable is Initializable { // 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; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _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; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "./extensions/IERC20MetadataUpgradeable.sol"; import "../../utils//ContextUpgradeable.sol"; import "../../proxy/utils//Initializable.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 ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { 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. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _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 {} /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[45] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/ERC20Permit.sol) pragma solidity ^0.8.0; import "./IERC20PermitUpgradeable.sol"; import "../ERC20Upgradeable.sol"; import "../../../utils//cryptography/ECDSAUpgradeable.sol"; import "../../../utils//cryptography/EIP712Upgradeable.sol"; import "../../../utils//CountersUpgradeable.sol"; import "../../../proxy/utils//Initializable.sol"; /** * @dev Implementation 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. * * _Available since v3.4._ * * @custom:storage-size 51 */ abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IERC20PermitUpgradeable, EIP712Upgradeable { using CountersUpgradeable for CountersUpgradeable.Counter; mapping(address => CountersUpgradeable.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private constant _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); /** * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`. * However, to ensure consistency with the upgradeable transpiler, we will continue * to reserve a slot. * @custom:oz-renamed-from _PERMIT_TYPEHASH */ // solhint-disable-next-line var-name-mixedcase bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT; /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC20 token name. */ function __ERC20Permit_init(string memory name) internal onlyInitializing { __EIP712_init_unchained(name, "1"); } function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {} /** * @dev See {IERC20Permit-permit}. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSAUpgradeable.recover(hash, v, r, s); require(signer == owner, "ERC20Permit: invalid signature"); _approve(owner, spender, value); } /** * @dev See {IERC20Permit-nonces}. */ function nonces(address owner) public view virtual override returns (uint256) { return _nonces[owner].current(); } /** * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } /** * @dev "Consume a nonce": return the current value and increment. * * _Available since v4.1._ */ function _useNonce(address owner) internal virtual returns (uint256 current) { CountersUpgradeable.Counter storage nonce = _nonces[owner]; current = nonce.current(); nonce.increment(); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @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 IERC20PermitUpgradeable { /** * @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 IERC20Upgradeable { /** * @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.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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; import "../proxy/utils//Initializable.sol"; /** * @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 ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library CountersUpgradeable { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../StringsUpgradeable.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 ECDSAUpgradeable { 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", StringsUpgradeable.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 "./ECDSAUpgradeable.sol"; import "../../interfaces/IERC5267Upgradeable.sol"; import "../../proxy/utils//Initializable.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:storage-size 52 */ abstract contract EIP712Upgradeable is Initializable, IERC5267Upgradeable { bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /// @custom:oz-renamed-from _HASHED_NAME bytes32 private _hashedName; /// @custom:oz-renamed-from _HASHED_VERSION bytes32 private _hashedVersion; string private _name; string private _version; /** * @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]. */ function __EIP712_init(string memory name, string memory version) internal onlyInitializing { __EIP712_init_unchained(name, version); } function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing { _name = name; _version = version; // Reset prior values in storage if upgrading _hashedName = 0; _hashedVersion = 0; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { return _buildDomainSeparator(); } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), 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 ECDSAUpgradeable.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 ) { // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized // and the EIP712 domain is not reliable, as it will be missing name and version. require(_hashedName == 0 && _hashedVersion == 0, "EIP712: Uninitialized"); return ( hex"0f", // 01111 _EIP712Name(), _EIP712Version(), block.chainid, address(this), bytes32(0), new uint256[](0) ); } /** * @dev The name parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Name() internal virtual view returns (string memory) { return _name; } /** * @dev The version parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712Version() internal virtual view returns (string memory) { return _version; } /** * @dev The hash of the name parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead. */ function _EIP712NameHash() internal view returns (bytes32) { string memory name = _EIP712Name(); if (bytes(name).length > 0) { return keccak256(bytes(name)); } else { // If the name is empty, the contract may have been upgraded without initializing the new storage. // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design. bytes32 hashedName = _hashedName; if (hashedName != 0) { return hashedName; } else { return keccak256(""); } } } /** * @dev The hash of the version parameter for the EIP712 domain. * * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead. */ function _EIP712VersionHash() internal view returns (bytes32) { string memory version = _EIP712Version(); if (bytes(version).length > 0) { return keccak256(bytes(version)); } else { // If the version is empty, the contract may have been upgraded without initializing the new storage. // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design. bytes32 hashedVersion = _hashedVersion; if (hashedVersion != 0) { return hashedVersion; } else { return keccak256(""); } } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[48] private __gap; }
// 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 MathUpgradeable { 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 SignedMathUpgradeable { /** * @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/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; import "./math/SignedMathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { 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 = MathUpgradeable.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(SignedMathUpgradeable.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, MathUpgradeable.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 // 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/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 pragma solidity ^0.8.20; import {IERC20, SafeERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {IWell, Call} from "src/interfaces/IWell.sol"; /** * @title IAquifer * @author Publius * @notice Interface for the Aquifer, a permissionless Well deployer and registry. */ interface IAquifer { /** * @notice Thrown when the {init} function call on the Well reverts. */ error InitFailed(string reason); /** * @notice Thrown when the user attempts to bore a Well with invalid configuration. */ error InvalidConfig(); /** * @notice Thrown a Well is bored, but not initialized. */ error WellNotInitialized(); /** * @notice Thrown when the user attempts to predict a Well's deterministic address with a salt of 0. */ error InvalidSalt(); /** * @notice Emitted when a Well is deployed. * @param well The address of the new Well * @param implementation The Well implementation address * @param tokens The tokens in the Well * @param wellFunction The Well function * @param pumps The pumps to bore in the Well * @param wellData The Well data to implement into the Well */ event BoreWell( address well, address implementation, IERC20[] tokens, Call wellFunction, Call[] pumps, bytes wellData ); /** * @notice Deploys a Well. * @param implementation The Well implementation to clone. * @param immutableData The data to append to the bytecode of the contract. * @param initFunctionCall The function call to initialize the Well. Set to empty bytes for no call. * @param salt The salt to deploy the Well with (`bytes32(0)` for none). See {LibClone}. * @return wellAddress The address of the new Well */ function boreWell( address implementation, bytes calldata immutableData, bytes calldata initFunctionCall, bytes32 salt ) external returns (address wellAddress); /** * @notice Returns the implementation that a given Well was deployed with. * @param well The Well to get the implementation of * @return implementation The address of the implementation of a Well. * @dev Always verify that a Well was deployed by a trusted Aquifer using a trusted implementation before using. * If `wellImplementation == address(0)`, then the Aquifer did not deploy the Well. */ function wellImplementation(address well) external view returns (address implementation); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; /** * @title Call is the struct that contains the target address and extra calldata of a generic call. */ struct Call { address target; // The address the call is executed on. bytes data; // Extra calldata to be passed during the call } /** * @title IWell is the interface for the Well contract. * * In order for a Well to be verified using a permissionless on-chain registry, a Well Implementation should: * - Not be able to self-destruct (Aquifer's registry would be vulnerable to a metamorphic contract attack) * - Not be able to change its tokens, Well Function, Pumps and Well Data */ interface IWell { /** * @notice Emitted when a Swap occurs. * @param fromToken The token swapped from * @param toToken The token swapped to * @param amountIn The amount of `fromToken` transferred into the Well * @param amountOut The amount of `toToken` transferred out of the Well * @param recipient The address that received `toToken` */ event Swap(IERC20 fromToken, IERC20 toToken, uint256 amountIn, uint256 amountOut, address recipient); /** * @notice Emitted when liquidity is added to the Well. * @param tokenAmountsIn The amount of each token added to the Well * @param lpAmountOut The amount of LP tokens minted * @param recipient The address that received the LP tokens */ event AddLiquidity(uint256[] tokenAmountsIn, uint256 lpAmountOut, address recipient); /** * @notice Emitted when liquidity is removed from the Well as multiple underlying tokens. * @param lpAmountIn The amount of LP tokens burned * @param tokenAmountsOut The amount of each underlying token removed * @param recipient The address that received the underlying tokens * @dev Gas cost scales with `n` tokens. */ event RemoveLiquidity(uint256 lpAmountIn, uint256[] tokenAmountsOut, address recipient); /** * @notice Emitted when liquidity is removed from the Well as a single underlying token. * @param lpAmountIn The amount of LP tokens burned * @param tokenOut The underlying token removed * @param tokenAmountOut The amount of `tokenOut` removed * @param recipient The address that received the underlying tokens * @dev Emitting a separate event when removing liquidity as a single token * saves gas, since `tokenAmountsOut` in {RemoveLiquidity} must emit a value * for each token in the Well. */ event RemoveLiquidityOneToken(uint256 lpAmountIn, IERC20 tokenOut, uint256 tokenAmountOut, address recipient); /** * @notice Emitted when a Shift occurs. * @param reserves The ending reserves after a shift * @param toToken The token swapped to * @param amountOut The amount of `toToken` transferred out of the Well * @param recipient The address that received `toToken` */ event Shift(uint256[] reserves, IERC20 toToken, uint256 amountOut, address recipient); /** * @notice Emitted when a Sync occurs. * @param reserves The ending reserves after a sync * @param lpAmountOut The amount of LP tokens received from the sync. * @param recipient The address that received the LP tokens */ event Sync(uint256[] reserves, uint256 lpAmountOut, address recipient); //////////////////// WELL DEFINITION //////////////////// /** * @notice Returns a list of ERC20 tokens supported by the Well. */ function tokens() external view returns (IERC20[] memory); /** * @notice Returns the Well function as a Call struct. * @dev Contains the address of the Well function contract and extra data to * pass during calls. * * **Well functions** define a relationship between the reserves of the * tokens in the Well and the number of LP tokens. * * A Well function MUST implement {IWellFunction}. */ function wellFunction() external view returns (Call memory); /** * @notice Returns the Pumps attached to the Well as Call structs. * @dev Contains the addresses of the Pumps contract and extra data to pass * during calls. * * **Pumps** are on-chain oracles that are updated every time the Well is * interacted with. * * A Pump is not required for Well operation. For Wells without a Pump: * `pumps().length = 0`. * * An attached Pump MUST implement {IPump}. */ function pumps() external view returns (Call[] memory); /** * @notice Returns the Well data that the Well was bored with. * @dev The existence and signature of Well data is determined by each individual implementation. */ function wellData() external view returns (bytes memory); /** * @notice Returns the Aquifer that created this Well. * @dev Wells can be permissionlessly bored in an Aquifer. * * Aquifers stores the implementation that was used to bore the Well. */ function aquifer() external view returns (address); /** * @notice Returns the tokens, Well Function, Pumps and Well Data associated * with the Well as well as the Aquifer that deployed the Well. */ function well() external view returns ( IERC20[] memory _tokens, Call memory _wellFunction, Call[] memory _pumps, bytes memory _wellData, address _aquifer ); //////////////////// SWAP: FROM //////////////////// /** * @notice Swaps from an exact amount of `fromToken` to a minimum amount of `toToken`. * @param fromToken The token to swap from * @param toToken The token to swap to * @param amountIn The amount of `fromToken` to spend * @param minAmountOut The minimum amount of `toToken` to receive * @param recipient The address to receive `toToken` * @param deadline The timestamp after which this operation is invalid * @return amountOut The amount of `toToken` received */ function swapFrom( IERC20 fromToken, IERC20 toToken, uint256 amountIn, uint256 minAmountOut, address recipient, uint256 deadline ) external returns (uint256 amountOut); /** * @notice Swaps from an exact amount of `fromToken` to a minimum amount of `toToken` and supports fee on transfer tokens. * @param fromToken The token to swap from * @param toToken The token to swap to * @param amountIn The amount of `fromToken` to spend * @param minAmountOut The minimum amount of `toToken` to take from the Well. Note that if `toToken` charges a fee on transfer, `recipient` will receive less than this amount. * @param recipient The address to receive `toToken` * @param deadline The timestamp after which this operation is invalid * @return amountOut The amount of `toToken` transferred from the Well. Note that if `toToken` charges a fee on transfer, `recipient` may receive less than this amount. * @dev Can also be used for tokens without a fee on transfer, but is less gas efficient. */ function swapFromFeeOnTransfer( IERC20 fromToken, IERC20 toToken, uint256 amountIn, uint256 minAmountOut, address recipient, uint256 deadline ) external returns (uint256 amountOut); /** * @notice Gets the amount of one token received for swapping an amount of another token. * @param fromToken The token to swap from * @param toToken The token to swap to * @param amountIn The amount of `fromToken` to spend * @return amountOut The amount of `toToken` to receive */ function getSwapOut(IERC20 fromToken, IERC20 toToken, uint256 amountIn) external view returns (uint256 amountOut); //////////////////// SWAP: TO //////////////////// /** * @notice Swaps from a maximum amount of `fromToken` to an exact amount of `toToken`. * @param fromToken The token to swap from * @param toToken The token to swap to * @param maxAmountIn The maximum amount of `fromToken` to spend * @param amountOut The amount of `toToken` to receive * @param recipient The address to receive `toToken` * @param deadline The timestamp after which this operation is invalid * @return amountIn The amount of `toToken` received */ function swapTo( IERC20 fromToken, IERC20 toToken, uint256 maxAmountIn, uint256 amountOut, address recipient, uint256 deadline ) external returns (uint256 amountIn); /** * @notice Gets the amount of one token that must be spent to receive an amount of another token during a swap. * @param fromToken The token to swap from * @param toToken The token to swap to * @param amountOut The amount of `toToken` desired * @return amountIn The amount of `fromToken` that must be spent */ function getSwapIn(IERC20 fromToken, IERC20 toToken, uint256 amountOut) external view returns (uint256 amountIn); //////////////////// SHIFT //////////////////// /** * @notice Shifts at least `minAmountOut` excess tokens held by the Well into `tokenOut` and delivers to `recipient`. * @param tokenOut The token to shift into * @param minAmountOut The minimum amount of `tokenOut` to receive * @param recipient The address to receive the token * @return amountOut The amount of `tokenOut` received * @dev Can be used in a multicall using a contract like Pipeline to perform gas efficient swaps. * No deadline is needed since this function does not use the user's assets. If adding liquidity in a multicall, * then a deadline check can be added to the multicall. */ function shift(IERC20 tokenOut, uint256 minAmountOut, address recipient) external returns (uint256 amountOut); /** * @notice Calculates the amount of the token out received from shifting excess tokens held by the Well. * @param tokenOut The token to shift into * @return amountOut The amount of `tokenOut` received */ function getShiftOut(IERC20 tokenOut) external returns (uint256 amountOut); //////////////////// ADD LIQUIDITY //////////////////// /** * @notice Adds liquidity to the Well as multiple tokens in any ratio. * @param tokenAmountsIn The amount of each token to add; MUST match the indexing of {Well.tokens} * @param minLpAmountOut The minimum amount of LP tokens to receive * @param recipient The address to receive the LP tokens * @param deadline The timestamp after which this operation is invalid * @return lpAmountOut The amount of LP tokens received */ function addLiquidity( uint256[] memory tokenAmountsIn, uint256 minLpAmountOut, address recipient, uint256 deadline ) external returns (uint256 lpAmountOut); /** * @notice Adds liquidity to the Well as multiple tokens in any ratio and supports * fee on transfer tokens. * @param tokenAmountsIn The amount of each token to add; MUST match the indexing of {Well.tokens} * @param minLpAmountOut The minimum amount of LP tokens to receive * @param recipient The address to receive the LP tokens * @param deadline The timestamp after which this operation is invalid * @return lpAmountOut The amount of LP tokens received * @dev Can also be used for tokens without a fee on transfer, but is less gas efficient. */ function addLiquidityFeeOnTransfer( uint256[] memory tokenAmountsIn, uint256 minLpAmountOut, address recipient, uint256 deadline ) external returns (uint256 lpAmountOut); /** * @notice Gets the amount of LP tokens received from adding liquidity as multiple tokens in any ratio. * @param tokenAmountsIn The amount of each token to add; MUST match the indexing of {Well.tokens} * @return lpAmountOut The amount of LP tokens received */ function getAddLiquidityOut(uint256[] memory tokenAmountsIn) external view returns (uint256 lpAmountOut); //////////////////// REMOVE LIQUIDITY: BALANCED //////////////////// /** * @notice Removes liquidity from the Well as all underlying tokens in a balanced ratio. * @param lpAmountIn The amount of LP tokens to burn * @param minTokenAmountsOut The minimum amount of each underlying token to receive; MUST match the indexing of {Well.tokens} * @param recipient The address to receive the underlying tokens * @param deadline The timestamp after which this operation is invalid * @return tokenAmountsOut The amount of each underlying token received */ function removeLiquidity( uint256 lpAmountIn, uint256[] calldata minTokenAmountsOut, address recipient, uint256 deadline ) external returns (uint256[] memory tokenAmountsOut); /** * @notice Gets the amount of each underlying token received from removing liquidity in a balanced ratio. * @param lpAmountIn The amount of LP tokens to burn * @return tokenAmountsOut The amount of each underlying token received */ function getRemoveLiquidityOut(uint256 lpAmountIn) external view returns (uint256[] memory tokenAmountsOut); //////////////////// REMOVE LIQUIDITY: ONE TOKEN //////////////////// /** * @notice Removes liquidity from the Well as a single underlying token. * @param lpAmountIn The amount of LP tokens to burn * @param tokenOut The underlying token to receive * @param minTokenAmountOut The minimum amount of `tokenOut` to receive * @param recipient The address to receive the underlying tokens * @param deadline The timestamp after which this operation is invalid * @return tokenAmountOut The amount of `tokenOut` received */ function removeLiquidityOneToken( uint256 lpAmountIn, IERC20 tokenOut, uint256 minTokenAmountOut, address recipient, uint256 deadline ) external returns (uint256 tokenAmountOut); /** * @notice Gets the amount received from removing liquidity from the Well as a single underlying token. * @param lpAmountIn The amount of LP tokens to burn * @param tokenOut The underlying token to receive * @return tokenAmountOut The amount of `tokenOut` received * */ function getRemoveLiquidityOneTokenOut( uint256 lpAmountIn, IERC20 tokenOut ) external view returns (uint256 tokenAmountOut); //////////////////// REMOVE LIQUIDITY: IMBALANCED //////////////////// /** * @notice Removes liquidity from the Well as multiple underlying tokens in any ratio. * @param maxLpAmountIn The maximum amount of LP tokens to burn * @param tokenAmountsOut The amount of each underlying token to receive; MUST match the indexing of {Well.tokens} * @param recipient The address to receive the underlying tokens * @return lpAmountIn The amount of LP tokens burned */ function removeLiquidityImbalanced( uint256 maxLpAmountIn, uint256[] calldata tokenAmountsOut, address recipient, uint256 deadline ) external returns (uint256 lpAmountIn); /** * @notice Gets the amount of LP tokens to burn from removing liquidity as multiple underlying tokens in any ratio. * @param tokenAmountsOut The amount of each underlying token to receive; MUST match the indexing of {Well.tokens} * @return lpAmountIn The amount of LP tokens burned */ function getRemoveLiquidityImbalancedIn(uint256[] calldata tokenAmountsOut) external view returns (uint256 lpAmountIn); //////////////////// RESERVES //////////////////// /** * @notice Syncs the Well's reserves with the Well's balances of underlying tokens. If the reserves * increase, mints at least `minLpAmountOut` LP Tokens to `recipient`. * @param recipient The address to receive the LP tokens * @param minLpAmountOut The minimum amount of LP tokens to receive * @return lpAmountOut The amount of LP tokens received * @dev Can be used in a multicall using a contract like Pipeline to perform gas efficient additions of liquidity. * No deadline is needed since this function does not use the user's assets. If adding liquidity in a multicall, * then a deadline check can be added to the multicall. * If `sync` decreases the Well's reserves, then no LP tokens are minted and `lpAmountOut` must be 0. */ function sync(address recipient, uint256 minLpAmountOut) external returns (uint256 lpAmountOut); /** * @notice Calculates the amount of LP Tokens received from syncing the Well's reserves with the Well's balances. * @return lpAmountOut The amount of LP tokens received */ function getSyncOut() external view returns (uint256 lpAmountOut); /** * @notice Sends excess tokens held by the Well to the `recipient`. * @param recipient The address to send the tokens * @return skimAmounts The amount of each token skimmed * @dev No deadline is needed since this function does not use the user's assets. */ function skim(address recipient) external returns (uint256[] memory skimAmounts); /** * @notice Gets the reserves of each token held by the Well. */ function getReserves() external view returns (uint256[] memory reserves); /** * @notice Returns whether or not the Well is initialized if it requires initialization. * If a Well does not require initialization, it should always return `true`. */ function isInitialized() external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; /** * @title IWellErrors defines all Well errors. * @dev The errors are separated into a different interface as not all Well * implementations may share the same errors. */ interface IWellErrors { /** * @notice Thrown when an operation would deliver fewer tokens than `minAmountOut`. */ error SlippageOut(uint256 amountOut, uint256 minAmountOut); /** * @notice Thrown when an operation would require more tokens than `maxAmountIn`. */ error SlippageIn(uint256 amountIn, uint256 maxAmountIn); /** * @notice Thrown if one or more tokens used in the operation are not supported by the Well. */ error InvalidTokens(); /** * @notice Thrown if this operation would cause an incorrect change in Well reserves. */ error InvalidReserves(); /** * @notice Thrown when a Well is bored with duplicate tokens. */ error DuplicateTokens(IERC20 token); /** * @notice Thrown if an operation is executed after the provided `deadline` has passed. */ error Expired(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @title IWellFunction * @notice Defines a relationship between token reserves and LP token supply. * @dev Well Functions can contain arbitrary logic, but should be deterministic * if expected to be used alongside a Pump. When interacing with a Well or * Well Function, always verify that the Well Function is valid. */ interface IWellFunction { /** * @notice Thrown if the user inputs a `j` value is out of bounds. */ error InvalidJArgument(); /** * @notice Calculates the `j`th reserve given a list of `reserves` and `lpTokenSupply`. * @param reserves A list of token reserves. The jth reserve will be ignored, but a placeholder must be provided. * @param j The index of the reserve to solve for * @param lpTokenSupply The supply of LP tokens * @param data Extra Well function data provided on every call * @return reserve The resulting reserve at the jth index * @dev Should round up to ensure that Well reserves are marginally higher to enforce calcLpTokenSupply(...) >= totalSupply() */ function calcReserve( uint256[] memory reserves, uint256 j, uint256 lpTokenSupply, bytes calldata data ) external view returns (uint256 reserve); /** * @notice Gets the LP token supply given a list of reserves. * @param reserves A list of token reserves * @param data Extra Well function data provided on every call * @return lpTokenSupply The resulting supply of LP tokens * @dev Should round down to ensure so that the Well Token supply is marignally lower to enforce calcLpTokenSupply(...) >= totalSupply() */ function calcLpTokenSupply( uint256[] memory reserves, bytes calldata data ) external view returns (uint256 lpTokenSupply); /** * @notice Calculates the amount of each reserve token underlying a given amount of LP tokens. * @param lpTokenAmount An amount of LP tokens * @param reserves A list of token reserves * @param lpTokenSupply The current supply of LP tokens * @param data Extra Well function data provided on every call * @return underlyingAmounts The amount of each reserve token that underlies the LP tokens * @dev The constraint totalSupply() <= calcLPTokenSupply(...) must be held in the case where * `lpTokenAmount` LP tokens are burned in exchanged for `underlyingAmounts`. If the constraint * does not hold, then the Well Function is invalid. */ function calcLPTokenUnderlying( uint256 lpTokenAmount, uint256[] memory reserves, uint256 lpTokenSupply, bytes calldata data ) external view returns (uint256[] memory underlyingAmounts); /** * @notice Returns the name of the Well function. */ function name() external view returns (string memory); /** * @notice Returns the symbol of the Well function. */ function symbol() external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @title IPump defines the interface for a Pump. * * @dev Pumps are on-chain oracles that are updated upon each interaction with a {IWell}. * When reading a Pump, always verify the Pump's functionality. */ interface IPump { /** * @notice Updates the Pump with the given reserves. * @param reserves The previous reserves of the tokens in the Well. * @param data data specific to the Well * @dev Pumps are updated every time a user swaps, adds liquidity, or * removes liquidity from a Well. */ function update(uint256[] calldata reserves, bytes calldata data) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @title LibBytes * @author Publius * @notice Contains byte operations used during storage reads & writes. * * {LibBytes} tightly packs an array of `uint256` values into `n / 2` storage * slots, where `n` is number of items to pack. * * Each value must be `<= type(uint128).max` in order pack properly. */ library LibBytes { uint256 constant MAX_UINT128 = 340_282_366_920_938_463_463_374_607_431_768_211_455; // type(uint128).max /** * @dev Store packed uint128 `reserves` starting at storage position `slot`. * Balances are passed as an uint256[], but values must be <= max uint128 * to allow for packing into a single storage slot. */ function storeUint128(bytes32 slot, uint256[] memory reserves) internal { // Shortcut: two reserves can be packed into one slot without a loop if (reserves.length == 2) { require(reserves[0] <= MAX_UINT128, "ByteStorage: too large"); require(reserves[1] <= MAX_UINT128, "ByteStorage: too large"); assembly { sstore(slot, add(mload(add(reserves, 32)), shl(128, mload(add(reserves, 64))))) } } else { uint256 maxI = reserves.length / 2; // number of fully-packed slots uint256 iByte; // byte offset of the current reserve for (uint256 i; i < maxI; ++i) { require(reserves[2 * i] <= MAX_UINT128, "ByteStorage: too large"); require(reserves[2 * i + 1] <= MAX_UINT128, "ByteStorage: too large"); iByte = i * 64; assembly { sstore( add(slot, i), add(mload(add(reserves, add(iByte, 32))), shl(128, mload(add(reserves, add(iByte, 64))))) ) } } // If there is an odd number of reserves, create a slot with the last reserve // Since `i < maxI` above, the next byte offset `maxI * 64` // Equivalent to "reserves.length % 2 == 1", but cheaper. if (reserves.length & 1 == 1) { require(reserves[reserves.length - 1] <= MAX_UINT128, "ByteStorage: too large"); iByte = maxI * 64; assembly { sstore( add(slot, maxI), add(mload(add(reserves, add(iByte, 32))), shr(128, shl(128, sload(add(slot, maxI))))) ) } } } } /** * @dev Read `n` packed uint128 reserves at storage position `slot`. */ function readUint128(bytes32 slot, uint256 n) internal view returns (uint256[] memory reserves) { // Initialize array with length `n`, fill it in via assembly reserves = new uint256[](n); // Shortcut: two reserves can be quickly unpacked from one slot if (n == 2) { assembly { mstore(add(reserves, 32), shr(128, shl(128, sload(slot)))) mstore(add(reserves, 64), shr(128, sload(slot))) } return reserves; } uint256 iByte; for (uint256 i = 1; i <= n; ++i) { // `iByte` is the byte position for the current slot: // i 1 2 3 4 5 6 // iByte 0 0 1 1 2 2 iByte = (i - 1) / 2; // Equivalent to "i % 2 == 1", but cheaper. if (i & 1 == 1) { assembly { mstore( // store at index i * 32; i = 0 is skipped by loop add(reserves, mul(i, 32)), shr(128, shl(128, sload(add(slot, iByte)))) ) } } else { assembly { mstore(add(reserves, mul(i, 32)), shr(128, sload(add(slot, iByte)))) } } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /// @notice Minimal proxy library. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibClone.sol) /// @author Minimal proxy by 0age (https://github.com/0age) /// @author Clones with immutable args by wighawag, zefram.eth, Saw-mon & Natalie /// (https://github.com/Saw-mon-and-Natalie/clones-with-immutable-args) /// /// @dev Minimal proxy: /// Although the sw0nt pattern saves 5 gas over the erc-1167 pattern during runtime, /// it is not supported out-of-the-box on Etherscan. Hence, we choose to use the 0age pattern, /// which saves 4 gas over the erc-1167 pattern during runtime, and has the smallest bytecode. /// /// @dev Clones with immutable args (CWIA): /// The implementation of CWIA here implements a `receive()` method that emits the /// `ReceiveETH(uint256)` event. This skips the `DELEGATECALL` when there is no calldata, /// enabling us to accept hard gas-capped `sends` & `transfers` for maximum backwards /// composability. The minimal proxy implementation does not offer this feature. library LibClone { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unable to deploy the clone. error DeploymentFailed(); /// @dev The salt must start with either the zero address or the caller. error SaltDoesNotStartWithCaller(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MINIMAL PROXY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a clone of `implementation`. function clone(address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { /** * --------------------------------------------------------------------------+ * CREATION (9 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * 60 runSize | PUSH1 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * --------------------------------------------------------------------------| * RUNTIME (44 bytes) | * --------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * --------------------------------------------------------------------------| * | * ::: keep some values in stack ::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | | * 3d | RETURNDATASIZE | 0 0 | | * 3d | RETURNDATASIZE | 0 0 0 | | * 3d | RETURNDATASIZE | 0 0 0 0 | | * | * ::: copy calldata to memory ::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 0 0 | | * 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | | * 3d | RETURNDATASIZE | 0 0 cds 0 0 0 0 | | * 37 | CALLDATACOPY | 0 0 0 0 | [0..cds): calldata | * | * ::: delegate call to the implementation contract :::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds 0 0 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | [0..cds): calldata | * 73 addr | PUSH20 addr | addr 0 cds 0 0 0 0 | [0..cds): calldata | * 5a | GAS | gas addr 0 cds 0 0 0 0 | [0..cds): calldata | * f4 | DELEGATECALL | success 0 0 | [0..cds): calldata | * | * ::: copy return data to memory :::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata | * 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata | * 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata | * 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata | * | * 60 0x2a | PUSH1 0x2a | 0x2a success 0 rds | [0..rds): returndata | * 57 | JUMPI | 0 rds | [0..rds): returndata | * | * ::: revert :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * fd | REVERT | | [0..rds): returndata | * | * ::: return :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | 0 rds | [0..rds): returndata | * f3 | RETURN | | [0..rds): returndata | * --------------------------------------------------------------------------+ */ mstore(0x21, 0x5af43d3d93803e602a57fd5bf3) mstore(0x14, implementation) mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) instance := create(0, 0x0c, 0x35) // Restore the part of the free memory pointer that has been overwritten. mstore(0x21, 0) // If `instance` is zero, revert. if iszero(instance) { // Store the function selector of `DeploymentFailed()`. mstore(0x00, 0x30116425) // Revert with (offset, size). revert(0x1c, 0x04) } } } /// @dev Deploys a deterministic clone of `implementation` with `salt`. function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { mstore(0x21, 0x5af43d3d93803e602a57fd5bf3) mstore(0x14, implementation) mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) instance := create2(0, 0x0c, 0x35, salt) // Restore the part of the free memory pointer that has been overwritten. mstore(0x21, 0) // If `instance` is zero, revert. if iszero(instance) { // Store the function selector of `DeploymentFailed()`. mstore(0x00, 0x30116425) // Revert with (offset, size). revert(0x1c, 0x04) } } } /// @dev Returns the initialization code hash of the clone of `implementation`. /// Used for mining vanity addresses with create2crunch. function initCodeHash(address implementation) internal pure returns (bytes32 hash) { /// @solidity memory-safe-assembly assembly { mstore(0x21, 0x5af43d3d93803e602a57fd5bf3) mstore(0x14, implementation) mstore(0x00, 0x602c3d8160093d39f33d3d3d3d363d3d37363d73) hash := keccak256(0x0c, 0x35) // Restore the part of the free memory pointer that has been overwritten. mstore(0x21, 0) } } /// @dev Returns the address of the deterministic clone of `implementation`, /// with `salt` by `deployer`. function predictDeterministicAddress(address implementation, bytes32 salt, address deployer) internal pure returns (address predicted) { bytes32 hash = initCodeHash(implementation); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CLONES WITH IMMUTABLE ARGS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Deploys a minimal proxy with `implementation`, /// using immutable arguments encoded in `data`. function clone(address implementation, bytes memory data) internal returns (address instance) { assembly { // Compute the boundaries of the data and cache the memory slots around it. let mBefore3 := mload(sub(data, 0x60)) let mBefore2 := mload(sub(data, 0x40)) let mBefore1 := mload(sub(data, 0x20)) let dataLength := mload(data) let dataEnd := add(add(data, 0x20), dataLength) let mAfter1 := mload(dataEnd) // +2 bytes for telling how much data there is appended to the call. let extraLength := add(dataLength, 2) // The `creationSize` is `extraLength + 108` // The `runSize` is `creationSize - 10`. /** * ---------------------------------------------------------------------------------------------------+ * CREATION (10 bytes) | * ---------------------------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------------------------| * 61 runSize | PUSH2 runSize | r | | * 3d | RETURNDATASIZE | 0 r | | * 81 | DUP2 | r 0 r | | * 60 offset | PUSH1 offset | o r 0 r | | * 3d | RETURNDATASIZE | 0 o r 0 r | | * 39 | CODECOPY | 0 r | [0..runSize): runtime code | * f3 | RETURN | | [0..runSize): runtime code | * ---------------------------------------------------------------------------------------------------| * RUNTIME (98 bytes + extraLength) | * ---------------------------------------------------------------------------------------------------| * Opcode | Mnemonic | Stack | Memory | * ---------------------------------------------------------------------------------------------------| * | * ::: if no calldata, emit event & return w/o `DELEGATECALL` ::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 60 0x2c | PUSH1 0x2c | 0x2c cds | | * 57 | JUMPI | | | * 34 | CALLVALUE | cv | | * 3d | RETURNDATASIZE | 0 cv | | * 52 | MSTORE | | [0..0x20): callvalue | * 7f sig | PUSH32 0x9e.. | sig | [0..0x20): callvalue | * 59 | MSIZE | 0x20 sig | [0..0x20): callvalue | * 3d | RETURNDATASIZE | 0 0x20 sig | [0..0x20): callvalue | * a1 | LOG1 | | [0..0x20): callvalue | * 00 | STOP | | [0..0x20): callvalue | * 5b | JUMPDEST | | | * | * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds | | * 3d | RETURNDATASIZE | 0 cds | | * 3d | RETURNDATASIZE | 0 0 cds | | * 37 | CALLDATACOPY | | [0..cds): calldata | * | * ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 0 | [0..cds): calldata | * 3d | RETURNDATASIZE | 0 0 0 0 | [0..cds): calldata | * 61 extra | PUSH2 extra | e 0 0 0 0 | [0..cds): calldata | * | * ::: copy extra data to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 80 | DUP1 | e e 0 0 0 0 | [0..cds): calldata | * 60 0x62 | PUSH1 0x62 | 0x62 e e 0 0 0 0 | [0..cds): calldata | * 36 | CALLDATASIZE | cds 0x62 e e 0 0 0 0 | [0..cds): calldata | * 39 | CODECOPY | e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * | * ::: delegate call to the implementation contract ::::::::::::::::::::::::::::::::::::::::::::::::: | * 36 | CALLDATASIZE | cds e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 01 | ADD | cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 3d | RETURNDATASIZE | 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 73 addr | PUSH20 addr | addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 5a | GAS | gas addr 0 cds+e 0 0 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * f4 | DELEGATECALL | success 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * | * ::: copy return data to memory ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 3d | RETURNDATASIZE | rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 3d | RETURNDATASIZE | rds rds success 0 0 | [0..cds): calldata, [cds..cds+e): extraData | * 93 | SWAP4 | 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData | * 80 | DUP1 | 0 0 rds success 0 rds | [0..cds): calldata, [cds..cds+e): extraData | * 3e | RETURNDATACOPY | success 0 rds | [0..rds): returndata | * | * 60 0x60 | PUSH1 0x60 | 0x60 success 0 rds | [0..rds): returndata | * 57 | JUMPI | 0 rds | [0..rds): returndata | * | * ::: revert ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * fd | REVERT | | [0..rds): returndata | * | * ::: return ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | * 5b | JUMPDEST | 0 rds | [0..rds): returndata | * f3 | RETURN | | [0..rds): returndata | * ---------------------------------------------------------------------------------------------------+ */ // Write the bytecode before the data. mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the address of the implementation. mstore(sub(data, 0x0d), implementation) // Write the rest of the bytecode. mstore( sub(data, 0x21), or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73) ) // `keccak256("ReceiveETH(uint256)")` mstore( sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff ) mstore( sub(data, 0x5a), or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f) ) mstore(dataEnd, shl(0xf0, extraLength)) // Create the instance. instance := create(0, sub(data, 0x4c), add(extraLength, 0x6c)) // If `instance` is zero, revert. if iszero(instance) { // Store the function selector of `DeploymentFailed()`. mstore(0x00, 0x30116425) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the overwritten memory surrounding `data`. mstore(dataEnd, mAfter1) mstore(data, dataLength) mstore(sub(data, 0x20), mBefore1) mstore(sub(data, 0x40), mBefore2) mstore(sub(data, 0x60), mBefore3) } } /// @dev Deploys a deterministic clone of `implementation`, /// using immutable arguments encoded in `data`, with `salt`. function cloneDeterministic(address implementation, bytes memory data, bytes32 salt) internal returns (address instance) { assembly { // Compute the boundaries of the data and cache the memory slots around it. let mBefore3 := mload(sub(data, 0x60)) let mBefore2 := mload(sub(data, 0x40)) let mBefore1 := mload(sub(data, 0x20)) let dataLength := mload(data) let dataEnd := add(add(data, 0x20), dataLength) let mAfter1 := mload(dataEnd) // +2 bytes for telling how much data there is appended to the call. let extraLength := add(dataLength, 2) // Write the bytecode before the data. mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the address of the implementation. mstore(sub(data, 0x0d), implementation) // Write the rest of the bytecode. mstore( sub(data, 0x21), or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73) ) // `keccak256("ReceiveETH(uint256)")` mstore( sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff ) mstore( sub(data, 0x5a), or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f) ) mstore(dataEnd, shl(0xf0, extraLength)) // Create the instance. instance := create2(0, sub(data, 0x4c), add(extraLength, 0x6c), salt) // If `instance` is zero, revert. if iszero(instance) { // Store the function selector of `DeploymentFailed()`. mstore(0x00, 0x30116425) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the overwritten memory surrounding `data`. mstore(dataEnd, mAfter1) mstore(data, dataLength) mstore(sub(data, 0x20), mBefore1) mstore(sub(data, 0x40), mBefore2) mstore(sub(data, 0x60), mBefore3) } } /// @dev Returns the initialization code hash of the clone of `implementation` /// using immutable arguments encoded in `data`. /// Used for mining vanity addresses with create2crunch. function initCodeHash(address implementation, bytes memory data) internal pure returns (bytes32 hash) { assembly { // Compute the boundaries of the data and cache the memory slots around it. let mBefore3 := mload(sub(data, 0x60)) let mBefore2 := mload(sub(data, 0x40)) let mBefore1 := mload(sub(data, 0x20)) let dataLength := mload(data) let dataEnd := add(add(data, 0x20), dataLength) let mAfter1 := mload(dataEnd) // +2 bytes for telling how much data there is appended to the call. let extraLength := add(dataLength, 2) // Write the bytecode before the data. mstore(data, 0x5af43d3d93803e606057fd5bf3) // Write the address of the implementation. mstore(sub(data, 0x0d), implementation) // Write the rest of the bytecode. mstore( sub(data, 0x21), or(shl(0x48, extraLength), 0x593da1005b363d3d373d3d3d3d610000806062363936013d73) ) // `keccak256("ReceiveETH(uint256)")` mstore( sub(data, 0x3a), 0x9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff ) mstore( sub(data, 0x5a), or(shl(0x78, add(extraLength, 0x62)), 0x6100003d81600a3d39f336602c57343d527f) ) mstore(dataEnd, shl(0xf0, extraLength)) // Compute and store the bytecode hash. hash := keccak256(sub(data, 0x4c), add(extraLength, 0x6c)) // Restore the overwritten memory surrounding `data`. mstore(dataEnd, mAfter1) mstore(data, dataLength) mstore(sub(data, 0x20), mBefore1) mstore(sub(data, 0x40), mBefore2) mstore(sub(data, 0x60), mBefore3) } } /// @dev Returns the address of the deterministic clone of /// `implementation` using immutable arguments encoded in `data`, with `salt`, by `deployer`. function predictDeterministicAddress( address implementation, bytes memory data, bytes32 salt, address deployer ) internal pure returns (address predicted) { bytes32 hash = initCodeHash(implementation, data); predicted = predictDeterministicAddress(hash, salt, deployer); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OTHER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the address when a contract with initialization code hash, /// `hash`, is deployed with `salt`, by `deployer`. function predictDeterministicAddress(bytes32 hash, bytes32 salt, address deployer) internal pure returns (address predicted) { /// @solidity memory-safe-assembly assembly { // Compute and store the bytecode hash. mstore8(0x00, 0xff) // Write the prefix. mstore(0x35, hash) mstore(0x01, shl(96, deployer)) mstore(0x15, salt) predicted := keccak256(0x00, 0x55) // Restore the part of the free memory pointer that has been overwritten. mstore(0x35, 0) } } /// @dev Reverts if `salt` does not start with either the zero address or the caller. function checkStartsWithCaller(bytes32 salt) internal view { /// @solidity memory-safe-assembly assembly { // If the salt does not start with the zero address or the caller. if iszero(or(iszero(shr(96, salt)), eq(caller(), shr(96, salt)))) { // Store the function selector of `SaltDoesNotStartWithCaller()`. mstore(0x00, 0x2f634836) // Revert with (offset, size). revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: BSD pragma solidity ^0.8.20; /// @title Clone /// @author zefram.eth, Saw-mon & Natalie /// @notice Provides helper functions for reading immutable args from calldata contract Clone { uint256 internal constant ONE_WORD = 0x20; /// @notice Reads an immutable arg with type address /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgAddress(uint256 argOffset) internal pure returns (address arg) { uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly { arg := shr(0x60, calldataload(add(offset, argOffset))) } } /// @notice Reads an immutable arg with type uint256 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgUint256(uint256 argOffset) internal pure returns (uint256 arg) { uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly { arg := calldataload(add(offset, argOffset)) } } /// @notice Reads a uint256 array stored in the immutable args. /// @param argOffset The offset of the arg in the packed data /// @param arrLen Number of elements in the array /// @return arr The array function _getArgUint256Array(uint256 argOffset, uint256 arrLen) internal pure returns (uint256[] memory arr) { uint256 offset = _getImmutableArgsOffset() + argOffset; arr = new uint256[](arrLen); // solhint-disable-next-line no-inline-assembly assembly { calldatacopy( add(arr, ONE_WORD), offset, shl(5, arrLen) ) } } /// @notice Reads an immutable arg with type uint64 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgUint64(uint256 argOffset) internal pure returns (uint64 arg) { uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly { arg := shr(0xc0, calldataload(add(offset, argOffset))) } } /// @notice Reads an immutable arg with type uint8 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgUint8(uint256 argOffset) internal pure returns (uint8 arg) { uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly { arg := shr(0xf8, calldataload(add(offset, argOffset))) } } /// @return offset The offset of the packed immutable args in calldata function _getImmutableArgsOffset() internal pure returns (uint256 offset) { // solhint-disable-next-line no-inline-assembly assembly { offset := sub( calldatasize(), shr(0xf0, calldataload(sub(calldatasize(), 2))) ) } } }
// SPDX-License-Identifier: BSD pragma solidity ^0.8.20; import {Clone} from "./Clone.sol"; import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; /// @title ClonePlus /// @notice Extends Clone with additional helper functions contract ClonePlus is Clone { /// @notice Reads a IERC20 array stored in the immutable args. /// @param argOffset The offset of the arg in the packed data /// @param arrLen Number of elements in the array /// @return arr The array function _getArgIERC20Array(uint256 argOffset, uint256 arrLen) internal pure returns (IERC20[] memory arr) { uint256 offset = _getImmutableArgsOffset() + argOffset; arr = new IERC20[](arrLen); // solhint-disable-next-line no-inline-assembly assembly { calldatacopy(add(arr, ONE_WORD), offset, shl(5, arrLen)) } } /// @notice Reads a bytes data stored in the immutable args. /// @param argOffset The offset of the arg in the packed data /// @param bytesLen Number of bytes in the data /// @return data the bytes data function _getArgBytes(uint256 argOffset, uint256 bytesLen) internal pure returns (bytes memory data) { if (bytesLen == 0) return data; uint256 offset = _getImmutableArgsOffset() + argOffset; data = new bytes(bytesLen); // solhint-disable-next-line no-inline-assembly assembly { calldatacopy(add(data, ONE_WORD), offset, bytesLen) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ReentrancyGuardUpgradeable} from "lib/openzeppelin-contracts-upgradeable/contracts/security/ReentrancyGuardUpgradeable.sol"; import {ERC20Upgradeable, ERC20PermitUpgradeable} from "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PermitUpgradeable.sol"; import {IERC20, SafeERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {IWell, Call} from "src/interfaces/IWell.sol"; import {IWellErrors} from "src/interfaces/IWellErrors.sol"; import {IPump} from "src/interfaces/pumps/IPump.sol"; import {IWellFunction} from "src/interfaces/IWellFunction.sol"; import {LibBytes} from "src/libraries/LibBytes.sol"; import {ClonePlus} from "src/utils/ClonePlus.sol"; /** * @title Well * @author Publius, Silo Chad, Brean * @dev A Well is a constant function AMM allowing the provisioning of liquidity * into a single pooled on-chain liquidity position. * * Rebasing Tokens: * - Positive rebasing tokens are supported by Wells, but any tokens recieved from a * rebase will not be rewarded to LP holders and instead can be extracted by anyone * using `skim`, `sync` or `shift`. * - Negative rebasing tokens should not be used in Well as the effect of a negative * rebase will be realized by users interacting with the Well, not LP token holders. * * Fee on Tranfer (FoT) Tokens: * - When transferring fee on transfer tokens to a Well (swapping from or adding liquidity), * use `swapFromFeeOnTrasfer` or `addLiquidityFeeOnTransfer`. `swapTo` does not support * fee on transfer tokens (See {swapTo}). * - When recieving fee on transfer tokens from a Well (swapping to and removing liquidity), * INCLUDE the fee that is taken on transfer when calculating amount out values. */ contract Well is ERC20PermitUpgradeable, IWell, IWellErrors, ReentrancyGuardUpgradeable, ClonePlus { using SafeERC20 for IERC20; uint256 private constant PACKED_ADDRESS = 20; uint256 private constant ONE_WORD_PLUS_PACKED_ADDRESS = 52; // For gas efficiency purposes bytes32 private constant RESERVES_STORAGE_SLOT = 0x4bba01c388049b5ebd30398b65e8ad45b632802c5faf4964e58085ea8ab03715; // bytes32(uint256(keccak256("reserves.storage.slot")) - 1); constructor() { // Disable Initializers to prevent the init function from being callable on the implementation contract _disableInitializers(); } function init(string memory _name, string memory _symbol) external initializer { __ERC20Permit_init(_name); __ERC20_init(_name, _symbol); __ReentrancyGuard_init(); IERC20[] memory _tokens = tokens(); uint256 tokensLength = _tokens.length; for (uint256 i; i < tokensLength - 1; ++i) { for (uint256 j = i + 1; j < tokensLength; ++j) { if (_tokens[i] == _tokens[j]) { revert DuplicateTokens(_tokens[i]); } } } } function isInitialized() external view returns (bool) { return _getInitializedVersion() > 0; } //////////////////// WELL DEFINITION //////////////////// /// This Well uses a dynamic immutable storage layout. Immutable storage is /// used for gas-efficient reads during Well operation. The Well must be /// created by cloning with a pre-encoded byte string containing immutable /// data. /// /// Let n = number of tokens /// m = length of well function data (bytes) /// /// TYPE NAME LOCATION (CONSTANT) /// ============================================================== /// address aquifer() 0 (LOC_AQUIFER_ADDR) /// uint256 numberOfTokens() 20 (LOC_TOKENS_COUNT) /// address wellFunctionAddress() 52 (LOC_WELL_FUNCTION_ADDR) /// uint256 wellFunctionDataLength() 72 (LOC_WELL_FUNCTION_DATA_LENGTH) /// uint256 numberOfPumps() 104 (LOC_PUMPS_COUNT) /// -------------------------------------------------------------- /// address token0 136 (LOC_VARIABLE) /// ... /// address tokenN 136 + (n-1) * 32 /// -------------------------------------------------------------- /// byte wellFunctionData0 136 + n * 32 /// ... /// byte wellFunctionDataM 136 + n * 32 + m /// -------------------------------------------------------------- /// address pump1Address 136 + n * 32 + m /// uint256 pump1DataLength 136 + n * 32 + m + 20 /// byte pump1Data 136 + n * 32 + m + 52 /// ... /// ============================================================== uint256 private constant LOC_AQUIFER_ADDR = 0; uint256 private constant LOC_TOKENS_COUNT = 20; // LOC_AQUIFER_ADDR + PACKED_ADDRESS uint256 private constant LOC_WELL_FUNCTION_ADDR = 52; // LOC_TOKENS_COUNT + ONE_WORD uint256 private constant LOC_WELL_FUNCTION_DATA_LENGTH = 72; // LOC_WELL_FUNCTION_ADDR + PACKED_ADDRESS; uint256 private constant LOC_PUMPS_COUNT = 104; // LOC_WELL_FUNCTION_DATA_LENGTH + ONE_WORD; uint256 private constant LOC_VARIABLE = 136; // LOC_PUMPS_COUNT + ONE_WORD; function tokens() public pure returns (IERC20[] memory _tokens) { _tokens = _getArgIERC20Array(LOC_VARIABLE, numberOfTokens()); } function wellFunction() public pure returns (Call memory _wellFunction) { _wellFunction.target = wellFunctionAddress(); _wellFunction.data = _getArgBytes(LOC_VARIABLE + numberOfTokens() * ONE_WORD, wellFunctionDataLength()); } function pumps() public pure returns (Call[] memory _pumps) { uint256 _numberOfPumps = numberOfPumps(); if (_numberOfPumps == 0) return _pumps; _pumps = new Call[](_numberOfPumps); uint256 dataLoc = LOC_VARIABLE + numberOfTokens() * ONE_WORD + wellFunctionDataLength(); uint256 pumpDataLength; for (uint256 i; i < _pumps.length; ++i) { _pumps[i].target = _getArgAddress(dataLoc); dataLoc += PACKED_ADDRESS; pumpDataLength = _getArgUint256(dataLoc); dataLoc += ONE_WORD; _pumps[i].data = _getArgBytes(dataLoc, pumpDataLength); dataLoc += pumpDataLength; } } /** * @dev {wellData} is unused in this implementation. */ function wellData() public pure returns (bytes memory) {} function aquifer() public pure override returns (address) { return _getArgAddress(LOC_AQUIFER_ADDR); } function well() external pure returns ( IERC20[] memory _tokens, Call memory _wellFunction, Call[] memory _pumps, bytes memory _wellData, address _aquifer ) { _tokens = tokens(); _wellFunction = wellFunction(); _pumps = pumps(); _wellData = wellData(); _aquifer = aquifer(); } //////////////////// WELL DEFINITION: HELPERS //////////////////// /** * @notice Returns the number of tokens that are tradable in this Well. * @dev Length of the `tokens()` array. */ function numberOfTokens() public pure returns (uint256) { return _getArgUint256(LOC_TOKENS_COUNT); } /** * @notice Returns the address of the Well Function. */ function wellFunctionAddress() public pure returns (address) { return _getArgAddress(LOC_WELL_FUNCTION_ADDR); } /** * @notice Returns the length of the configurable `data` parameter passed during calls to the Well Function. */ function wellFunctionDataLength() public pure returns (uint256) { return _getArgUint256(LOC_WELL_FUNCTION_DATA_LENGTH); } /** * @notice Returns the number of Pumps which this Well was initialized with. */ function numberOfPumps() public pure returns (uint256) { return _getArgUint256(LOC_PUMPS_COUNT); } /** * @notice Returns address & data used to call the first Pump. * @dev Provided as an optimization in the case where {numberOfPumps} returns 1. */ function firstPump() public pure returns (Call memory _pump) { uint256 dataLoc = LOC_VARIABLE + numberOfTokens() * ONE_WORD + wellFunctionDataLength(); _pump.target = _getArgAddress(dataLoc); _pump.data = _getArgBytes(dataLoc + ONE_WORD_PLUS_PACKED_ADDRESS, _getArgUint256(dataLoc + PACKED_ADDRESS)); } //////////////////// SWAP: FROM //////////////////// /** * @dev MUST revert if a fee on transfer token is used. The requisite check * is performed in {_setReserves}. */ function swapFrom( IERC20 fromToken, IERC20 toToken, uint256 amountIn, uint256 minAmountOut, address recipient, uint256 deadline ) external nonReentrant expire(deadline) returns (uint256 amountOut) { fromToken.safeTransferFrom(msg.sender, address(this), amountIn); amountOut = _swapFrom(fromToken, toToken, amountIn, minAmountOut, recipient); } /** * @dev Note that `amountOut` is the amount *transferred* by the Well; if a fee * is charged on transfers of `toToken`, the amount received by `recipient` * will be less than `amountOut`. */ function swapFromFeeOnTransfer( IERC20 fromToken, IERC20 toToken, uint256 amountIn, uint256 minAmountOut, address recipient, uint256 deadline ) external nonReentrant expire(deadline) returns (uint256 amountOut) { amountIn = _safeTransferFromFeeOnTransfer(fromToken, msg.sender, amountIn); amountOut = _swapFrom(fromToken, toToken, amountIn, minAmountOut, recipient); } function _swapFrom( IERC20 fromToken, IERC20 toToken, uint256 amountIn, uint256 minAmountOut, address recipient ) internal returns (uint256 amountOut) { IERC20[] memory _tokens = tokens(); (uint256 i, uint256 j) = _getIJ(_tokens, fromToken, toToken); uint256[] memory reserves = _updatePumps(_tokens.length); reserves[i] += amountIn; uint256 reserveJBefore = reserves[j]; reserves[j] = _calcReserve(wellFunction(), reserves, j, totalSupply()); // Note: The rounding approach of the Well function determines whether // slippage from imprecision goes to the Well or to the User. amountOut = reserveJBefore - reserves[j]; if (amountOut < minAmountOut) { revert SlippageOut(amountOut, minAmountOut); } toToken.safeTransfer(recipient, amountOut); emit Swap(fromToken, toToken, amountIn, amountOut, recipient); _setReserves(_tokens, reserves); } /** * @dev Assumes both tokens incur no fee on transfer. */ function getSwapOut( IERC20 fromToken, IERC20 toToken, uint256 amountIn ) external view readOnlyNonReentrant returns (uint256 amountOut) { IERC20[] memory _tokens = tokens(); (uint256 i, uint256 j) = _getIJ(_tokens, fromToken, toToken); uint256[] memory reserves = _getReserves(_tokens.length); reserves[i] += amountIn; // underflow is desired; Well Function SHOULD NOT increase reserves of both `i` and `j` amountOut = reserves[j] - _calcReserve(wellFunction(), reserves, j, totalSupply()); } //////////////////// SWAP: TO //////////////////// /** * @dev {swapTo} does not support fee on transfer tokens, and no corresponding * "swapToFeeOnTransfer" function is provided as this would require either: * (a) inclusion of the fee as a parameter with verification; or * (b) iterative transfers which attempts to back-calculate the fee. */ function swapTo( IERC20 fromToken, IERC20 toToken, uint256 maxAmountIn, uint256 amountOut, address recipient, uint256 deadline ) external nonReentrant expire(deadline) returns (uint256 amountIn) { IERC20[] memory _tokens = tokens(); (uint256 i, uint256 j) = _getIJ(_tokens, fromToken, toToken); uint256[] memory reserves = _updatePumps(_tokens.length); reserves[j] -= amountOut; uint256 reserveIBefore = reserves[i]; reserves[i] = _calcReserve(wellFunction(), reserves, i, totalSupply()); // Note: The rounding approach of the Well function determines whether // slippage from imprecision goes to the Well or to the User. amountIn = reserves[i] - reserveIBefore; if (amountIn > maxAmountIn) { revert SlippageIn(amountIn, maxAmountIn); } _swapTo(fromToken, toToken, amountIn, amountOut, recipient); _setReserves(_tokens, reserves); } /** * @dev Executes token transfers and emits Swap event. Used by {swapTo} to * avoid stack too deep errors. */ function _swapTo( IERC20 fromToken, IERC20 toToken, uint256 amountIn, uint256 amountOut, address recipient ) internal { fromToken.safeTransferFrom(msg.sender, address(this), amountIn); toToken.safeTransfer(recipient, amountOut); emit Swap(fromToken, toToken, amountIn, amountOut, recipient); } /** * @dev Assumes both tokens incur no fee on transfer. */ function getSwapIn( IERC20 fromToken, IERC20 toToken, uint256 amountOut ) external view readOnlyNonReentrant returns (uint256 amountIn) { IERC20[] memory _tokens = tokens(); (uint256 i, uint256 j) = _getIJ(_tokens, fromToken, toToken); uint256[] memory reserves = _getReserves(_tokens.length); reserves[j] -= amountOut; amountIn = _calcReserve(wellFunction(), reserves, i, totalSupply()) - reserves[i]; } //////////////////// SHIFT //////////////////// /** * @dev When using Wells for a multi-hop swap in 1 single transaction using a * multicall contract like Pipeline, costs can be reduced by "shifting" tokens * from one Well to another rather than returning them to the multicall router. * * Example multi-hop swap: WETH -> DAI -> USDC * * 1. Using a router without {shift}: * WETH.transfer(sender=0xUSER, recipient=0xROUTER) [1] * Call the router, which performs: * Well1.swapFrom(fromToken=WETH, toToken=DAI, recipient=0xROUTER) * WETH.transfer(sender=0xROUTER, recipient=Well1) [2] * DAI.transfer(sender=Well1, recipient=0xROUTER) [3] * Well2.swapFrom(fromToken=DAI, toToken=USDC, recipient=0xROUTER) * DAI.transfer(sender=0xROUTER, recipient=Well2) [4] * USDC.transfer(sender=Well2, recipient=0xROUTER) [5] * USDC.transfer(sender=0xROUTER, recipient=0xUSER) [6] * * Note: this could be optimized by configuring the router to deliver * tokens from the last swap directly to the user. * * 2. Using a router with {shift}: * WETH.transfer(sender=0xUSER, recipient=Well1) [1] * Call the router, which performs: * Well1.shift(tokenOut=DAI, recipient=Well2) * DAI.transfer(sender=Well1, recipient=Well2) [2] * Well2.shift(tokenOut=USDC, recipient=0xUSER) * USDC.transfer(sender=Well2, recipient=0xUSER) [3] */ function shift( IERC20 tokenOut, uint256 minAmountOut, address recipient ) external nonReentrant returns (uint256 amountOut) { IERC20[] memory _tokens = tokens(); uint256 tokensLength = _tokens.length; _updatePumps(tokensLength); uint256[] memory reserves = new uint256[](tokensLength); // Use the balances of the pool instead of the stored reserves. // If there is a change in token balances relative to the currently // stored reserves, the extra tokens can be shifted into `tokenOut`. for (uint256 i; i < tokensLength; ++i) { reserves[i] = _tokens[i].balanceOf(address(this)); } uint256 j = _getJ(_tokens, tokenOut); amountOut = reserves[j] - _calcReserve(wellFunction(), reserves, j, totalSupply()); if (amountOut >= minAmountOut) { tokenOut.safeTransfer(recipient, amountOut); reserves[j] -= amountOut; _setReserves(_tokens, reserves); emit Shift(reserves, tokenOut, amountOut, recipient); } else { revert SlippageOut(amountOut, minAmountOut); } } function getShiftOut(IERC20 tokenOut) external view readOnlyNonReentrant returns (uint256 amountOut) { IERC20[] memory _tokens = tokens(); uint256 tokensLength = _tokens.length; uint256[] memory reserves = new uint256[](tokensLength); for (uint256 i; i < tokensLength; ++i) { reserves[i] = _tokens[i].balanceOf(address(this)); } uint256 j = _getJ(_tokens, tokenOut); amountOut = reserves[j] - _calcReserve(wellFunction(), reserves, j, totalSupply()); } //////////////////// ADD LIQUIDITY //////////////////// function addLiquidity( uint256[] memory tokenAmountsIn, uint256 minLpAmountOut, address recipient, uint256 deadline ) external nonReentrant expire(deadline) returns (uint256 lpAmountOut) { lpAmountOut = _addLiquidity(tokenAmountsIn, minLpAmountOut, recipient, false); } function addLiquidityFeeOnTransfer( uint256[] memory tokenAmountsIn, uint256 minLpAmountOut, address recipient, uint256 deadline ) external nonReentrant expire(deadline) returns (uint256 lpAmountOut) { lpAmountOut = _addLiquidity(tokenAmountsIn, minLpAmountOut, recipient, true); } /** * @dev Gas optimization: {IWell.AddLiquidity} is emitted even if `lpAmountOut` is 0. */ function _addLiquidity( uint256[] memory tokenAmountsIn, uint256 minLpAmountOut, address recipient, bool feeOnTransfer ) internal returns (uint256 lpAmountOut) { IERC20[] memory _tokens = tokens(); uint256 tokensLength = _tokens.length; uint256[] memory reserves = _updatePumps(tokensLength); uint256 _tokenAmountIn; if (feeOnTransfer) { for (uint256 i; i < tokensLength; ++i) { _tokenAmountIn = tokenAmountsIn[i]; if (_tokenAmountIn == 0) continue; _tokenAmountIn = _safeTransferFromFeeOnTransfer(_tokens[i], msg.sender, _tokenAmountIn); reserves[i] += _tokenAmountIn; tokenAmountsIn[i] = _tokenAmountIn; } } else { for (uint256 i; i < tokensLength; ++i) { _tokenAmountIn = tokenAmountsIn[i]; if (_tokenAmountIn == 0) continue; _tokens[i].safeTransferFrom(msg.sender, address(this), _tokenAmountIn); reserves[i] += _tokenAmountIn; } } lpAmountOut = _calcLpTokenSupply(wellFunction(), reserves) - totalSupply(); if (lpAmountOut < minLpAmountOut) { revert SlippageOut(lpAmountOut, minLpAmountOut); } _mint(recipient, lpAmountOut); _setReserves(_tokens, reserves); emit AddLiquidity(tokenAmountsIn, lpAmountOut, recipient); } /** * @dev Assumes that no tokens involved incur a fee on transfer. */ function getAddLiquidityOut(uint256[] memory tokenAmountsIn) external view readOnlyNonReentrant returns (uint256 lpAmountOut) { IERC20[] memory _tokens = tokens(); uint256 tokensLength = _tokens.length; uint256[] memory reserves = _getReserves(tokensLength); for (uint256 i; i < tokensLength; ++i) { reserves[i] += tokenAmountsIn[i]; } lpAmountOut = _calcLpTokenSupply(wellFunction(), reserves) - totalSupply(); } //////////////////// REMOVE LIQUIDITY: BALANCED //////////////////// function removeLiquidity( uint256 lpAmountIn, uint256[] calldata minTokenAmountsOut, address recipient, uint256 deadline ) external nonReentrant expire(deadline) returns (uint256[] memory tokenAmountsOut) { IERC20[] memory _tokens = tokens(); uint256 tokensLength = _tokens.length; uint256[] memory reserves = _updatePumps(tokensLength); tokenAmountsOut = _calcLPTokenUnderlying(wellFunction(), lpAmountIn, reserves, totalSupply()); _burn(msg.sender, lpAmountIn); uint256 _tokenAmountOut; for (uint256 i; i < tokensLength; ++i) { _tokenAmountOut = tokenAmountsOut[i]; if (_tokenAmountOut < minTokenAmountsOut[i]) { revert SlippageOut(_tokenAmountOut, minTokenAmountsOut[i]); } _tokens[i].safeTransfer(recipient, _tokenAmountOut); reserves[i] -= _tokenAmountOut; } _setReserves(_tokens, reserves); emit RemoveLiquidity(lpAmountIn, tokenAmountsOut, recipient); } function getRemoveLiquidityOut(uint256 lpAmountIn) external view readOnlyNonReentrant returns (uint256[] memory tokenAmountsOut) { IERC20[] memory _tokens = tokens(); uint256[] memory reserves = _getReserves(_tokens.length); uint256 lpTokenSupply = totalSupply(); tokenAmountsOut = _calcLPTokenUnderlying(wellFunction(), lpAmountIn, reserves, lpTokenSupply); } //////////////////// REMOVE LIQUIDITY: ONE TOKEN //////////////////// function removeLiquidityOneToken( uint256 lpAmountIn, IERC20 tokenOut, uint256 minTokenAmountOut, address recipient, uint256 deadline ) external nonReentrant expire(deadline) returns (uint256 tokenAmountOut) { IERC20[] memory _tokens = tokens(); uint256[] memory reserves = _updatePumps(_tokens.length); uint256 j = _getJ(_tokens, tokenOut); tokenAmountOut = _getRemoveLiquidityOneTokenOut(lpAmountIn, j, reserves); if (tokenAmountOut < minTokenAmountOut) { revert SlippageOut(tokenAmountOut, minTokenAmountOut); } _burn(msg.sender, lpAmountIn); tokenOut.safeTransfer(recipient, tokenAmountOut); reserves[j] -= tokenAmountOut; _setReserves(_tokens, reserves); emit RemoveLiquidityOneToken(lpAmountIn, tokenOut, tokenAmountOut, recipient); } function getRemoveLiquidityOneTokenOut( uint256 lpAmountIn, IERC20 tokenOut ) external view readOnlyNonReentrant returns (uint256 tokenAmountOut) { IERC20[] memory _tokens = tokens(); uint256[] memory reserves = _getReserves(_tokens.length); tokenAmountOut = _getRemoveLiquidityOneTokenOut(lpAmountIn, _getJ(_tokens, tokenOut), reserves); } /** * @dev Shared logic for removing a single token from liquidity. * Calculates change in reserve `j` given a change in LP token supply. * * Note: `lpAmountIn` is the amount of LP the user is burning in exchange * for some amount of token `j`. */ function _getRemoveLiquidityOneTokenOut( uint256 lpAmountIn, uint256 j, uint256[] memory reserves ) private view returns (uint256 tokenAmountOut) { uint256 newReserveJ = _calcReserve(wellFunction(), reserves, j, totalSupply() - lpAmountIn); tokenAmountOut = reserves[j] - newReserveJ; } //////////// REMOVE LIQUIDITY: IMBALANCED //////////// function removeLiquidityImbalanced( uint256 maxLpAmountIn, uint256[] calldata tokenAmountsOut, address recipient, uint256 deadline ) external nonReentrant expire(deadline) returns (uint256 lpAmountIn) { IERC20[] memory _tokens = tokens(); uint256 tokensLength = _tokens.length; uint256[] memory reserves = _updatePumps(tokensLength); uint256 _tokenAmountOut; for (uint256 i; i < tokensLength; ++i) { _tokenAmountOut = tokenAmountsOut[i]; _tokens[i].safeTransfer(recipient, _tokenAmountOut); reserves[i] -= _tokenAmountOut; } lpAmountIn = totalSupply() - _calcLpTokenSupply(wellFunction(), reserves); if (lpAmountIn > maxLpAmountIn) { revert SlippageIn(lpAmountIn, maxLpAmountIn); } _burn(msg.sender, lpAmountIn); _setReserves(_tokens, reserves); emit RemoveLiquidity(lpAmountIn, tokenAmountsOut, recipient); } function getRemoveLiquidityImbalancedIn(uint256[] calldata tokenAmountsOut) external view readOnlyNonReentrant returns (uint256 lpAmountIn) { IERC20[] memory _tokens = tokens(); uint256 tokensLength = _tokens.length; uint256[] memory reserves = _getReserves(tokensLength); for (uint256 i; i < tokensLength; ++i) { reserves[i] -= tokenAmountsOut[i]; } lpAmountIn = totalSupply() - _calcLpTokenSupply(wellFunction(), reserves); } //////////////////// RESERVES //////////////////// /** * @dev Can be used in a multicall to add liquidity similar to how `shift` can be used to swap. * See {shift} for examples of how to use in a multicall. */ function sync(address recipient, uint256 minLpAmountOut) external nonReentrant returns (uint256 lpAmountOut) { IERC20[] memory _tokens = tokens(); uint256 tokensLength = _tokens.length; _updatePumps(tokensLength); uint256[] memory reserves = new uint256[](tokensLength); for (uint256 i; i < tokensLength; ++i) { reserves[i] = _tokens[i].balanceOf(address(this)); } uint256 newTokenSupply = _calcLpTokenSupply(wellFunction(), reserves); uint256 oldTokenSupply = totalSupply(); if (newTokenSupply > oldTokenSupply) { lpAmountOut = newTokenSupply - oldTokenSupply; _mint(recipient, lpAmountOut); } if (lpAmountOut < minLpAmountOut) { revert SlippageOut(lpAmountOut, minLpAmountOut); } _setReserves(_tokens, reserves); emit Sync(reserves, lpAmountOut, recipient); } function getSyncOut() external view readOnlyNonReentrant returns (uint256 lpAmountOut) { IERC20[] memory _tokens = tokens(); uint256 tokensLength = _tokens.length; uint256[] memory reserves = new uint256[](tokensLength); for (uint256 i; i < tokensLength; ++i) { reserves[i] = _tokens[i].balanceOf(address(this)); } uint256 newTokenSupply = _calcLpTokenSupply(wellFunction(), reserves); uint256 oldTokenSupply = totalSupply(); if (newTokenSupply > oldTokenSupply) { lpAmountOut = newTokenSupply - oldTokenSupply; } } /** * @dev Transfer excess tokens held by the Well to `recipient`. */ function skim(address recipient) external nonReentrant returns (uint256[] memory skimAmounts) { IERC20[] memory _tokens = tokens(); uint256 tokensLength = _tokens.length; uint256[] memory reserves = _getReserves(tokensLength); skimAmounts = new uint256[](tokensLength); for (uint256 i; i < tokensLength; ++i) { skimAmounts[i] = _tokens[i].balanceOf(address(this)) - reserves[i]; if (skimAmounts[i] > 0) { _tokens[i].safeTransfer(recipient, skimAmounts[i]); } } } function getReserves() external view readOnlyNonReentrant returns (uint256[] memory reserves) { reserves = _getReserves(numberOfTokens()); } /** * @dev Gets the Well's token reserves by reading from byte storage. */ function _getReserves(uint256 _numberOfTokens) internal view returns (uint256[] memory reserves) { reserves = LibBytes.readUint128(RESERVES_STORAGE_SLOT, _numberOfTokens); } /** * @dev Checks that the balance of each ERC-20 token is >= the reserves and * sets the Well's reserves of each token by writing to byte storage. */ function _setReserves(IERC20[] memory _tokens, uint256[] memory reserves) internal { for (uint256 i; i < reserves.length; ++i) { if (reserves[i] > _tokens[i].balanceOf(address(this))) revert InvalidReserves(); } LibBytes.storeUint128(RESERVES_STORAGE_SLOT, reserves); } //////////////////// INTERNAL: UPDATE PUMPS //////////////////// /** * @dev Fetches the current token reserves of the Well and updates the Pumps. * Typically called before an operation that modifies the Well's reserves. */ function _updatePumps(uint256 _numberOfTokens) internal returns (uint256[] memory reserves) { reserves = _getReserves(_numberOfTokens); uint256 _numberOfPumps = numberOfPumps(); if (_numberOfPumps == 0) { return reserves; } // gas optimization: avoid looping if there is only one pump if (_numberOfPumps == 1) { Call memory _pump = firstPump(); // Don't revert if the update call fails. try IPump(_pump.target).update(reserves, _pump.data) {} catch { // ignore reversion. If an external shutoff mechanism is added to a Pump, it could be called here. } } else { Call[] memory _pumps = pumps(); for (uint256 i; i < _pumps.length; ++i) { // Don't revert if the update call fails. try IPump(_pumps[i].target).update(reserves, _pumps[i].data) {} catch { // ignore reversion. If an external shutoff mechanism is added to a Pump, it could be called here. } } } } //////////////////// INTERNAL: WELL FUNCTION INTERACTION //////////////////// /** * @dev Calculates the LP token supply given a list of `reserves` using the * provided `_wellFunction`. Wraps {IWellFunction.calcLpTokenSupply}. * * The Well function is passed as a parameter to minimize gas in instances * where it is called multiple times in one transaction. */ function _calcLpTokenSupply( Call memory _wellFunction, uint256[] memory reserves ) internal view returns (uint256 lpTokenSupply) { lpTokenSupply = IWellFunction(_wellFunction.target).calcLpTokenSupply(reserves, _wellFunction.data); } /** * @dev Calculates the `j`th reserve given a list of `reserves` and `lpTokenSupply` * using the provided `_wellFunction`. Wraps {IWellFunction.calcReserve}. * * The Well function is passed as a parameter to minimize gas in instances * where it is called multiple times in one transaction. */ function _calcReserve( Call memory _wellFunction, uint256[] memory reserves, uint256 j, uint256 lpTokenSupply ) internal view returns (uint256 reserve) { reserve = IWellFunction(_wellFunction.target).calcReserve(reserves, j, lpTokenSupply, _wellFunction.data); } /** * @dev Calculates the amount of tokens that underly a given amount of LP tokens * Wraps {IWellFunction.calcLPTokenAmount}. * * Used to determine the how many tokens to send to a user when they remove LP. * * The Well function is passed as a parameter to minimize gas in instances * where it is called multiple times in one transaction. */ function _calcLPTokenUnderlying( Call memory _wellFunction, uint256 lpTokenAmount, uint256[] memory reserves, uint256 lpTokenSupply ) internal view returns (uint256[] memory tokenAmounts) { tokenAmounts = IWellFunction(_wellFunction.target).calcLPTokenUnderlying( lpTokenAmount, reserves, lpTokenSupply, _wellFunction.data ); } //////////////////// INTERNAL: WELL TOKEN INDEXING //////////////////// /** * @dev Returns the indices of `iToken` and `jToken` in `_tokens`. * Reverts if either token is not in `_tokens`. * Reverts if `iToken` and `jToken` are the same. */ function _getIJ( IERC20[] memory _tokens, IERC20 iToken, IERC20 jToken ) internal pure returns (uint256 i, uint256 j) { bool foundOne; for (uint256 k; k < _tokens.length; ++k) { if (iToken == _tokens[k]) { i = k; if (foundOne) return (i, j); foundOne = true; } else if (jToken == _tokens[k]) { j = k; if (foundOne) return (i, j); foundOne = true; } } revert InvalidTokens(); } /** * @dev Returns the index of `jToken` in `_tokens`. Reverts if `jToken` is * not in `_tokens`. * * If `_tokens` contains multiple instances of `jToken`, this will return * the first one. A {Well} with duplicate tokens has been misconfigured. */ function _getJ(IERC20[] memory _tokens, IERC20 jToken) internal pure returns (uint256 j) { for (j; j < _tokens.length; ++j) { if (jToken == _tokens[j]) { return j; } } revert InvalidTokens(); } //////////////////// INTERNAL: TRANSFER HELPERS //////////////////// /** * @dev Calculates the change in token balance of the Well across a transfer. * Used when a fee might be incurred during safeTransferFrom. */ function _safeTransferFromFeeOnTransfer( IERC20 token, address from, uint256 amount ) internal returns (uint256 amountTransferred) { uint256 balanceBefore = token.balanceOf(address(this)); token.safeTransferFrom(from, address(this), amount); amountTransferred = token.balanceOf(address(this)) - balanceBefore; } //////////////////// INTERNAL: EXPIRY //////////////////// /** * @dev Reverts if the deadline has passed. */ modifier expire(uint256 deadline) { if (block.timestamp > deadline) { revert Expired(); } _; } //////////////////// INTERNAL: Read Only Reentrancy //////////////////// /** * @dev Reverts if the reentrncy guard has been entered. */ modifier readOnlyNonReentrant() { // Use the same error as `ReentrancyGuardUpgradeable` instead of using a custom error for consistency. require(!_reentrancyGuardEntered(), "ReentrancyGuard: reentrant call"); _; } }
{ "optimizer": { "enabled": true, "runs": 1000 }, "viaIR": true, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"reason","type":"string"}],"name":"InitFailed","type":"error"},{"inputs":[],"name":"InvalidConfig","type":"error"},{"inputs":[],"name":"InvalidSalt","type":"error"},{"inputs":[],"name":"WellNotInitialized","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"well","type":"address"},{"indexed":false,"internalType":"address","name":"implementation","type":"address"},{"indexed":false,"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"indexed":false,"internalType":"struct Call","name":"wellFunction","type":"tuple"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"indexed":false,"internalType":"struct Call[]","name":"pumps","type":"tuple[]"},{"indexed":false,"internalType":"bytes","name":"wellData","type":"bytes"}],"name":"BoreWell","type":"event"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"},{"internalType":"bytes","name":"immutableData","type":"bytes"},{"internalType":"bytes","name":"initFunctionCall","type":"bytes"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"boreWell","outputs":[{"internalType":"address","name":"well","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"},{"internalType":"bytes","name":"immutableData","type":"bytes"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"predictWellAddress","outputs":[{"internalType":"address","name":"well","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wellImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6080806040523461001a5760015f55610f98908161001f8239f35b5f80fdfe604060808152600480361015610013575f80fd5b5f803560e01c92836317ab4806146105d65783637d48af8e146100465750505063ee97527414610041575f80fd5b610654565b346105d25760803660031901126105d25782359261006384610611565b67ffffffffffffffff926024358481116105d2576100849036908401610626565b90946044359081116105ce5761009d9036908501610626565b959091606435600285541461057157600285558493929190811561053157801561051557875133602082019081526040820192909252610105936100ff9290916100f481606081015b03601f19810183528261079a565b5190209236916107dd565b89610daa565b955b80610486575b505083517f392e53cd0000000000000000000000000000000000000000000000000000000081526001600160a01b03868116979250602091828187818c5afa908115610369578591610459575b50156104315785517f038f6f61000000000000000000000000000000000000000000000000000000008152828187818c5afa928315610369578593610402575b5050309116036103da576101f6816101c3876001600160a01b03165f52600160205260405f2090565b906001600160a01b03167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b8351917f9d63848a000000000000000000000000000000000000000000000000000000008352808385818a5afa9283156103695781936103b6575b508451967f10dd083000000000000000000000000000000000000000000000000000000000885281888681845afa978815610369578298610392575b5085517fa1d89d9600000000000000000000000000000000000000000000000000000000815282818781855afa918215610369578391829361036e575b508751968780927fc12323c90000000000000000000000000000000000000000000000000000000082525afa90811561036957610340987fff64a5823907c85a1e7c0400576024f76bd1640c74350033bd0d689f793202f2968461031c9594610344575b505087519586958a87610bba565b0390a161032860015f55565b516001600160a01b0390911681529081906020820190565b0390f35b6103619294503d8091833e610359818361079a565b810190610b1a565b918a8061030e565b61092f565b61038b9193503d8084833e610383818361079a565b810190610a84565b918a6102aa565b6103af9198503d8084833e6103a7818361079a565b810190610a5e565b968861026d565b6103d39193503d8085833e6103cb818361079a565b810190610967565b9187610231565b8284517f35be3ac8000000000000000000000000000000000000000000000000000000008152fd5b610422929350803d1061042a575b61041a818361079a565b81019061093a565b90888061019a565b503d610410565b8486517fe51b38a9000000000000000000000000000000000000000000000000000000008152fd5b6104799150833d851161047f575b610471818361079a565b810190610917565b8961015a565b503d610467565b8291610496875180938193610813565b039082885af16104a4610820565b90156104b25780829161010d565b905060448151106104ef576104d581602480856104eb95015183010191016108a7565b925192839263080f2d0b60e41b84528301610906565b0390fd5b506104eb915191829163080f2d0b60e41b83528201604090602081525f60208201520190565b5061052b916105259136916107dd565b88610cd7565b95610107565b91505080156105675785513360208201908152604082019290925261052b919061055e81606081016100e6565b51902088610c99565b5061052b87610c4e565b60648660208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152fd5b8280fd5b5080fd5b82346105ce5760203660031901126105ce5735916105f383610611565b6001600160a01b038093168152600160205220541660805260206080f35b6001600160a01b0381160361062257565b5f80fd5b9181601f840112156106225782359167ffffffffffffffff8311610622576020838186019501011161062257565b346106225760603660031901126106225760043561067181610611565b60243567ffffffffffffffff811161062257610691903690600401610626565b604435925f9084156107435760408051336020820190815291810196909652610340956106c181606081016100e6565b5190209183156106fc57506106dc6106e294309436916107dd565b90610e7b565b6040516001600160a01b0390911681529081906020820190565b925061073e93506c5af43d3d93803e602a57fd5bf360215260145273602c3d8160093d39f33d3d3d3d363d3d37363d7382526035600c20916021523091610f44565b6106e2565b60046040517f81e69d9b000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff8211176107bc57604052565b61076d565b67ffffffffffffffff81116107bc57601f01601f191660200190565b9291926107e9826107c1565b916107f7604051938461079a565b829481845281830111610622578281602093845f960137010152565b908092918237015f815290565b3d1561084a573d90610831826107c1565b9161083f604051938461079a565b82523d5f602084013e565b606090565b5f5b8381106108605750505f910152565b8181015183820152602001610851565b9092919261087d816107c1565b9161088b604051938461079a565b8294828452828201116106225760206108a593019061084f565b565b6020818303126106225780519067ffffffffffffffff821161062257019080601f830112156106225781516108de92602001610870565b90565b906020916108fa8151809281855285808601910161084f565b601f01601f1916010190565b9060206108de9281815201906108e1565b90816020910312610622575180151581036106225790565b6040513d5f823e3d90fd5b9081602091031261062257516108de81610611565b67ffffffffffffffff81116107bc5760051b60200190565b60209081818403126106225780519067ffffffffffffffff821161062257019180601f8401121561062257825161099d8161094f565b936109ab604051958661079a565b818552838086019260051b820101928311610622578301905b8282106109d2575050505090565b83809183516109e081610611565b8152019101906109c4565b9080601f830112156106225781516108de92602001610870565b91909160408184031261062257604080519167ffffffffffffffff918301828111848210176107bc5760405282948151610a3e81610611565b8452602082015192831161062257602092610a5992016109eb565b910152565b9060208282031261062257815167ffffffffffffffff8111610622576108de9201610a05565b90602090818382031261062257825167ffffffffffffffff93848211610622570181601f82011215610622578051610abb8161094f565b94610ac9604051968761079a565b818652848087019260051b8401019380851161062257858401925b858410610af5575050505050505090565b8351838111610622578791610b0f848480948a0101610a05565b815201930192610ae4565b9060208282031261062257815167ffffffffffffffff8111610622576108de92016109eb565b90604060206108de936001600160a01b03815116845201519181602082015201906108e1565b90815180825260208092019182818360051b85019501935f915b848310610b905750505050505090565b9091929394958480610baa83856001950387528a51610b40565b9801930193019194939290610b80565b9492919695939660c08601906001600160a01b03809316875282602091168188015260c0604088015283518092528060e088019401925f905b838210610c3557505050505090610c19826108de969786610c2795036060880152610b40565b908482036080860152610b66565b9160a08184039101526108e1565b8451811686529482019493820193600190910190610bf3565b6c5af43d3d93803e602a57fd5bf360215260145273602c3d8160093d39f33d3d3d3d363d3d37363d735f526035600c5ff0905f6021528115610c8c57565b63301164255f526004601cfd5b6c5af43d3d93803e602a57fd5bf360215260145273602c3d8160093d39f33d3d3d3d363d3d37363d735f526035600c5ff5905f6021528115610c8c57565b605f1982018051603f1984018051601f1986018051875180890160200180516c5af43d3d93803e606057fd5bf38b52600c198b019990995260028201604881901b78593da1005b363d3d373d3d3d3d610000806062363936013d73176020198c01527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff6039198c01526064830160781b716100003d81600a3d39f336602c57343d527f176059198c015260f01b81529998959793959193909190606e8301604b1983015ff09a8b15610c8c575252525252565b929192605f19820190815192603f19810190815192601f198201908151928051916020838301019a8b519160028501906c5af43d3d93803e606057fd5bf38552600c1985015278593da1005b363d3d373d3d3d3d610000806062363936013d738160481b176020198501527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff603919850152716100003d81600a3d39f336602c57343d527f6064860160781b1760591985015260f01b8c52606e8401604b1984015ff59a8b15610c8c575252525252565b6108de939291605f198101805191603f198101805191601f1981018051918051906020828201019889519060028401906c5af43d3d93803e606057fd5bf38452600c1984015278593da1005b363d3d373d3d3d3d610000806062363936013d738160481b176020198401527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff603919840152716100003d81600a3d39f336602c57343d527f6064850160781b1760591984015260f01b8a52606e8301604b198301209952525252525b91909160ff5f5360355260601b60015260155260555f20905f60355256fea26469706673582212209b28b60da22974074e5d5b2397911359b0e4328946504a8dec77201f9aab61b364736f6c63430008140033
Deployed Bytecode
0x604060808152600480361015610013575f80fd5b5f803560e01c92836317ab4806146105d65783637d48af8e146100465750505063ee97527414610041575f80fd5b610654565b346105d25760803660031901126105d25782359261006384610611565b67ffffffffffffffff926024358481116105d2576100849036908401610626565b90946044359081116105ce5761009d9036908501610626565b959091606435600285541461057157600285558493929190811561053157801561051557875133602082019081526040820192909252610105936100ff9290916100f481606081015b03601f19810183528261079a565b5190209236916107dd565b89610daa565b955b80610486575b505083517f392e53cd0000000000000000000000000000000000000000000000000000000081526001600160a01b03868116979250602091828187818c5afa908115610369578591610459575b50156104315785517f038f6f61000000000000000000000000000000000000000000000000000000008152828187818c5afa928315610369578593610402575b5050309116036103da576101f6816101c3876001600160a01b03165f52600160205260405f2090565b906001600160a01b03167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b8351917f9d63848a000000000000000000000000000000000000000000000000000000008352808385818a5afa9283156103695781936103b6575b508451967f10dd083000000000000000000000000000000000000000000000000000000000885281888681845afa978815610369578298610392575b5085517fa1d89d9600000000000000000000000000000000000000000000000000000000815282818781855afa918215610369578391829361036e575b508751968780927fc12323c90000000000000000000000000000000000000000000000000000000082525afa90811561036957610340987fff64a5823907c85a1e7c0400576024f76bd1640c74350033bd0d689f793202f2968461031c9594610344575b505087519586958a87610bba565b0390a161032860015f55565b516001600160a01b0390911681529081906020820190565b0390f35b6103619294503d8091833e610359818361079a565b810190610b1a565b918a8061030e565b61092f565b61038b9193503d8084833e610383818361079a565b810190610a84565b918a6102aa565b6103af9198503d8084833e6103a7818361079a565b810190610a5e565b968861026d565b6103d39193503d8085833e6103cb818361079a565b810190610967565b9187610231565b8284517f35be3ac8000000000000000000000000000000000000000000000000000000008152fd5b610422929350803d1061042a575b61041a818361079a565b81019061093a565b90888061019a565b503d610410565b8486517fe51b38a9000000000000000000000000000000000000000000000000000000008152fd5b6104799150833d851161047f575b610471818361079a565b810190610917565b8961015a565b503d610467565b8291610496875180938193610813565b039082885af16104a4610820565b90156104b25780829161010d565b905060448151106104ef576104d581602480856104eb95015183010191016108a7565b925192839263080f2d0b60e41b84528301610906565b0390fd5b506104eb915191829163080f2d0b60e41b83528201604090602081525f60208201520190565b5061052b916105259136916107dd565b88610cd7565b95610107565b91505080156105675785513360208201908152604082019290925261052b919061055e81606081016100e6565b51902088610c99565b5061052b87610c4e565b60648660208951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152fd5b8280fd5b5080fd5b82346105ce5760203660031901126105ce5735916105f383610611565b6001600160a01b038093168152600160205220541660805260206080f35b6001600160a01b0381160361062257565b5f80fd5b9181601f840112156106225782359167ffffffffffffffff8311610622576020838186019501011161062257565b346106225760603660031901126106225760043561067181610611565b60243567ffffffffffffffff811161062257610691903690600401610626565b604435925f9084156107435760408051336020820190815291810196909652610340956106c181606081016100e6565b5190209183156106fc57506106dc6106e294309436916107dd565b90610e7b565b6040516001600160a01b0390911681529081906020820190565b925061073e93506c5af43d3d93803e602a57fd5bf360215260145273602c3d8160093d39f33d3d3d3d363d3d37363d7382526035600c20916021523091610f44565b6106e2565b60046040517f81e69d9b000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff8211176107bc57604052565b61076d565b67ffffffffffffffff81116107bc57601f01601f191660200190565b9291926107e9826107c1565b916107f7604051938461079a565b829481845281830111610622578281602093845f960137010152565b908092918237015f815290565b3d1561084a573d90610831826107c1565b9161083f604051938461079a565b82523d5f602084013e565b606090565b5f5b8381106108605750505f910152565b8181015183820152602001610851565b9092919261087d816107c1565b9161088b604051938461079a565b8294828452828201116106225760206108a593019061084f565b565b6020818303126106225780519067ffffffffffffffff821161062257019080601f830112156106225781516108de92602001610870565b90565b906020916108fa8151809281855285808601910161084f565b601f01601f1916010190565b9060206108de9281815201906108e1565b90816020910312610622575180151581036106225790565b6040513d5f823e3d90fd5b9081602091031261062257516108de81610611565b67ffffffffffffffff81116107bc5760051b60200190565b60209081818403126106225780519067ffffffffffffffff821161062257019180601f8401121561062257825161099d8161094f565b936109ab604051958661079a565b818552838086019260051b820101928311610622578301905b8282106109d2575050505090565b83809183516109e081610611565b8152019101906109c4565b9080601f830112156106225781516108de92602001610870565b91909160408184031261062257604080519167ffffffffffffffff918301828111848210176107bc5760405282948151610a3e81610611565b8452602082015192831161062257602092610a5992016109eb565b910152565b9060208282031261062257815167ffffffffffffffff8111610622576108de9201610a05565b90602090818382031261062257825167ffffffffffffffff93848211610622570181601f82011215610622578051610abb8161094f565b94610ac9604051968761079a565b818652848087019260051b8401019380851161062257858401925b858410610af5575050505050505090565b8351838111610622578791610b0f848480948a0101610a05565b815201930192610ae4565b9060208282031261062257815167ffffffffffffffff8111610622576108de92016109eb565b90604060206108de936001600160a01b03815116845201519181602082015201906108e1565b90815180825260208092019182818360051b85019501935f915b848310610b905750505050505090565b9091929394958480610baa83856001950387528a51610b40565b9801930193019194939290610b80565b9492919695939660c08601906001600160a01b03809316875282602091168188015260c0604088015283518092528060e088019401925f905b838210610c3557505050505090610c19826108de969786610c2795036060880152610b40565b908482036080860152610b66565b9160a08184039101526108e1565b8451811686529482019493820193600190910190610bf3565b6c5af43d3d93803e602a57fd5bf360215260145273602c3d8160093d39f33d3d3d3d363d3d37363d735f526035600c5ff0905f6021528115610c8c57565b63301164255f526004601cfd5b6c5af43d3d93803e602a57fd5bf360215260145273602c3d8160093d39f33d3d3d3d363d3d37363d735f526035600c5ff5905f6021528115610c8c57565b605f1982018051603f1984018051601f1986018051875180890160200180516c5af43d3d93803e606057fd5bf38b52600c198b019990995260028201604881901b78593da1005b363d3d373d3d3d3d610000806062363936013d73176020198c01527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff6039198c01526064830160781b716100003d81600a3d39f336602c57343d527f176059198c015260f01b81529998959793959193909190606e8301604b1983015ff09a8b15610c8c575252525252565b929192605f19820190815192603f19810190815192601f198201908151928051916020838301019a8b519160028501906c5af43d3d93803e606057fd5bf38552600c1985015278593da1005b363d3d373d3d3d3d610000806062363936013d738160481b176020198501527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff603919850152716100003d81600a3d39f336602c57343d527f6064860160781b1760591985015260f01b8c52606e8401604b1984015ff59a8b15610c8c575252525252565b6108de939291605f198101805191603f198101805191601f1981018051918051906020828201019889519060028401906c5af43d3d93803e606057fd5bf38452600c1984015278593da1005b363d3d373d3d3d3d610000806062363936013d738160481b176020198401527f9e4ac34f21c619cefc926c8bd93b54bf5a39c7ab2127a895af1cc0691d7e3dff603919840152716100003d81600a3d39f336602c57343d527f6064850160781b1760591984015260f01b8a52606e8301604b198301209952525252525b91909160ff5f5360355260601b60015260155260555f20905f60355256fea26469706673582212209b28b60da22974074e5d5b2397911359b0e4328946504a8dec77201f9aab61b364736f6c63430008140033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 27 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ 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.