Contract
0x77a7e60555bC18B4Be44C181b2575eee46212d44
1
Contract Overview
My Name Tag:
Not Available, login to update
Txn Hash | Method |
Block
|
From
|
To
|
Value | [Txn Fee] | |||
---|---|---|---|---|---|---|---|---|---|
0xb5d8a463b1d9f5ca42b98b942b181620f6af0a7543359b33eccab52f535225b9 | Claim Aave Rewar... | 8637836 | 522 days 4 hrs ago | New Order: Deployer | IN | 0x77a7e60555bc18b4be44c181b2575eee46212d44 | 0 AVAX | 0.005497858698 | |
0x9ce54fced2fcf3bdb162897de9ae787b4afee0c2df090169ce0eab0ed62a650e | Transfer Ownersh... | 7771553 | 542 days 8 hrs ago | New Order: Deployer | IN | 0x77a7e60555bc18b4be44c181b2575eee46212d44 | 0 AVAX | 0.000717975 | |
0x12b396cc8042cffa966b8642df744a0a13e3aa20fc8d8053542a0904dacd1b81 | Claim Aave Rewar... | 7770769 | 542 days 8 hrs ago | New Order: Deployer | IN | 0x77a7e60555bc18b4be44c181b2575eee46212d44 | 0 AVAX | 0.0013798 | |
0x7e0d4aada2b53f35ecb950afcc1ca0663668f4d06d463cd78f722f49e882c293 | Claim Aave Rewar... | 7770641 | 542 days 8 hrs ago | New Order: Deployer | IN | 0x77a7e60555bc18b4be44c181b2575eee46212d44 | 0 AVAX | 0.002679525 | |
0xd914a22ffbf5c47999e2f4b2682ece40ef6daa4962abf886b31e262c1bc5dfd4 | Claim Aave Rewar... | 7770574 | 542 days 8 hrs ago | New Order: Deployer | IN | 0x77a7e60555bc18b4be44c181b2575eee46212d44 | 0 AVAX | 0.0013798 | |
0x63f344978468a4a73ad15c02e3ae00a8638f9ad0390a0a38081d34dc14f9108e | Claim Aave Rewar... | 7381715 | 551 days 10 hrs ago | New Order: Deployer | IN | 0x77a7e60555bc18b4be44c181b2575eee46212d44 | 0 AVAX | 0.008813591616 | |
0xe7eb82ad39891cb84634b27d5469e13b261e03c7c7f09c35bd94fdf64d2d9bf5 | Claim Aave Rewar... | 7380826 | 551 days 10 hrs ago | New Order: Deployer | IN | 0x77a7e60555bc18b4be44c181b2575eee46212d44 | 0 AVAX | 0.014681694624 | |
0x7910bb04d9ed33e29634a4cf52a3004d256bcfefbef9026e697855a9f35c60f2 | Set Reward Recei... | 7380780 | 551 days 10 hrs ago | New Order: Deployer | IN | 0x77a7e60555bc18b4be44c181b2575eee46212d44 | 0 AVAX | 0.00361626781 | |
0x40614904b9900f0a17d9990e4a99f4ff48fb9f1b87b0f0eca438f6e42f545df0 | Claim Aave Rewar... | 7380728 | 551 days 10 hrs ago | New Order: Deployer | IN | 0x77a7e60555bc18b4be44c181b2575eee46212d44 | 0 AVAX | 0.012793383348 | |
0xf4ea34149e1bcbf1dea170452751f115bd6c0804f515e3a2aeb3ce0996584ab6 | Claim Aave Rewar... | 7380697 | 551 days 10 hrs ago | New Order: Deployer | IN | 0x77a7e60555bc18b4be44c181b2575eee46212d44 | 0 AVAX | 0.00498427873 | |
0x1722cf749e330606f0b2f82ce72fe830698da6224fb0a8994e37fa155714ba10 | Add Liquidity | 7380504 | 551 days 11 hrs ago | New Order: Deployer | IN | 0x77a7e60555bc18b4be44c181b2575eee46212d44 | 0 AVAX | 0.056649452328 | |
0x525f5ad9bdc87e57faaa5d2f52648246332e6bd3fd24f713b07cc269e82afa2f | Initialize | 7378408 | 551 days 12 hrs ago | New Order: Deployer | IN | 0x77a7e60555bc18b4be44c181b2575eee46212d44 | 0 AVAX | 0.043260908791 | |
0xeec66ecd00697ca68c9c935ea0fbc203e357a14054645054a45e5a0638148e0f | 0x60806040 | 7378400 | 551 days 12 hrs ago | New Order: Deployer | IN | Create: AaveSwap | 0 AVAX | 0.17517609908 |
[ Download CSV Export ]
Latest 1 internal transaction
Parent Txn Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
0x525f5ad9bdc87e57faaa5d2f52648246332e6bd3fd24f713b07cc269e82afa2f | 7378408 | 551 days 12 hrs ago | 0x77a7e60555bc18b4be44c181b2575eee46212d44 | Contract Creation | 0 AVAX |
[ Download CSV Export ]
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:
AaveSwap
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal initializer { __Context_init_unchained(); __Ownable_init_unchained(); } function __Ownable_init_unchained() internal initializer { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMathUpgradeable { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity >=0.4.24 <0.8.0; 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 a proxied contract can't have 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. * * 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 {UpgradeableProxy-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. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function _isConstructor() private view returns (bool) { return !AddressUpgradeable.isContract(address(this)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../../utils/ContextUpgradeable.sol"; import "./ERC20Upgradeable.sol"; import "../../proxy/Initializable.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20BurnableUpgradeable is Initializable, ContextUpgradeable, ERC20Upgradeable { function __ERC20Burnable_init() internal initializer { __Context_init_unchained(); __ERC20Burnable_init_unchained(); } function __ERC20Burnable_init_unchained() internal initializer { } using SafeMathUpgradeable for uint256; /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance"); _approve(account, _msgSender(), decreasedAllowance); _burn(account, amount); } uint256[50] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../../utils/ContextUpgradeable.sol"; import "./IERC20Upgradeable.sol"; import "../../math/SafeMathUpgradeable.sol"; import "../../proxy/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.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of 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 { using SafeMathUpgradeable for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal initializer { __Context_init_unchained(); __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal initializer { _name = name_; _symbol = symbol_; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return _decimals; } /** * @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: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, 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}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), 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}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); 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) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(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) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is 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: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, 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: * * - `to` 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 = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(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); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(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 Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal virtual { _decimals = decimals_; } /** * @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 to 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 { } uint256[44] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 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://diligence.consensys.net/posts/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.5.11/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"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (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 functionCall(target, data, "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"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(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) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // 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 // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../proxy/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 GSN 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 initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } uint256[50] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./ContextUpgradeable.sol"; import "../proxy/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal initializer { __Context_init_unchained(); __Pausable_init_unchained(); } function __Pausable_init_unchained() internal initializer { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../proxy/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 initializer { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal initializer { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for * deploying minimal proxy contracts, also known as "clones". * * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies * > a minimal bytecode implementation that delegates all calls to a known, fixed address. * * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. * * _Available since v3.4._ */ library Clones { /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `master`. * * This function uses the create opcode, which should never revert. */ function clone(address master) internal returns (address instance) { // solhint-disable-next-line no-inline-assembly assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, master)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create(0, ptr, 0x37) } require(instance != address(0), "ERC1167: create failed"); } /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `master`. * * This function uses the create2 opcode and a `salt` to deterministically deploy * the clone. Using the same `master` and `salt` multiple time will revert, since * the clones cannot be deployed twice at the same address. */ function cloneDeterministic(address master, bytes32 salt) internal returns (address instance) { // solhint-disable-next-line no-inline-assembly assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, master)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create2(0, ptr, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress(address master, bytes32 salt, address deployer) internal pure returns (address predicted) { // solhint-disable-next-line no-inline-assembly assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, master)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000) mstore(add(ptr, 0x38), shl(0x60, deployer)) mstore(add(ptr, 0x4c), salt) mstore(add(ptr, 0x6c), keccak256(ptr, 0x37)) predicted := keccak256(add(ptr, 0x37), 0x55) } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress(address master, bytes32 salt) internal view returns (address predicted) { return predictDeterministicAddress(master, salt, address(this)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../../utils/Context.sol"; import "./IERC20.sol"; import "../../math/SafeMath.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.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory name_, string memory symbol_) public { _name = name_; _symbol = symbol_; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return _decimals; } /** * @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: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, 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}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), 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}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); 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) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(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) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is 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: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, 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: * * - `to` 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 = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(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); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(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 Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal virtual { _decimals = decimals_; } /** * @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 to 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 { } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./IERC20.sol"; import "../../math/SafeMath.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 SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } 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' // solhint-disable-next-line max-line-length 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)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @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"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 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://diligence.consensys.net/posts/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.5.11/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"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (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 functionCall(target, data, "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"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(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) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(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) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // 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 // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "./Swap.sol"; /** * @title AaveSwap - A StableSwap implementation in solidity, integrated with Aave. * @notice This contract is responsible for custody of closely pegged assets (eg. group of stablecoins) * and automatic market making system. Users become an LP (Liquidity Provider) by depositing their tokens * in desired ratios for an exchange of the pool token that represents their share of the pool. * Users can burn pool tokens and withdraw their share of token(s). * * Each time a swap between the pooled tokens happens, a set fee incurs which effectively gets * distributed to the LPs. * * In case of emergencies, admin can pause additional deposits, swaps, or single-asset withdraws - which * stops the ratio of the tokens in the pool from changing. * Users can always withdraw their tokens via multi-asset withdraws. * * @dev Most of the logic is stored as a library `SwapUtils` for the sake of reducing contract's * deployment size. */ contract AaveSwap is Swap { address internal AAVE_REWARDS; address internal AAVE_LENDING_POOL; address internal REWARD_TOKEN; address internal REWARD_RECEIVER; address[] internal AAVE_ASSETS; /** * @notice Initializes this Swap contract with the given parameters. * This will also clone a LPToken contract that represents users' * LP positions. The owner of LPToken will be this contract - which means * only this contract is allowed to mint/burn tokens. * * @param _pooledTokens an array of ERC20s this pool will accept * @param decimals the decimals to use for each pooled token, * eg 8 for WBTC. Cannot be larger than POOL_PRECISION_DECIMALS * @param lpTokenName the long-form name of the token to be deployed * @param lpTokenSymbol the short symbol for the token to be deployed * @param _a the amplification coefficient * n * (n - 1). See the * StableSwap paper for details * @param _fee default swap fee to be initialized with * @param _adminFee default adminFee to be initialized with * @param lpTokenTargetAddress the address of an existing LPToken contract to use as a target */ function initialize( IERC20[] memory _pooledTokens, uint8[] memory decimals, string memory lpTokenName, string memory lpTokenSymbol, uint256 _a, uint256 _fee, uint256 _adminFee, address lpTokenTargetAddress ) public virtual override initializer { Swap.initialize( _pooledTokens, decimals, lpTokenName, lpTokenSymbol, _a, _fee, _adminFee, lpTokenTargetAddress ); AAVE_REWARDS = 0x01D83Fe6A10D2f2B7AF17034343746188272cAc9; AAVE_LENDING_POOL = 0x4F01AeD16D97E3aB5ab2B501154DC9bb0F1A5A2C; REWARD_TOKEN = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7; AAVE_ASSETS = [0x53f7c5869a859F0AeC3D334ee8B4Cf01E3492f21]; REWARD_RECEIVER = msg.sender; } function setRewardReceiver(address _reward_receiver) external onlyOwner { REWARD_RECEIVER = _reward_receiver; } function claimAaveRewards() external { AAVE_REWARDS.call(abi.encodeWithSignature("claimRewards(address[],uint256,address)", AAVE_ASSETS, type(uint256).max, REWARD_RECEIVER)); } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "./SwapUtils.sol"; /** * @title AmplificationUtils library * @notice A library to calculate and ramp the A parameter of a given `SwapUtils.Swap` struct. * This library assumes the struct is fully validated. */ library AmplificationUtils { using SafeMath for uint256; event RampA( uint256 oldA, uint256 newA, uint256 initialTime, uint256 futureTime ); event StopRampA(uint256 currentA, uint256 time); // Constant values used in ramping A calculations uint256 public constant A_PRECISION = 100; uint256 public constant MAX_A = 10**6; uint256 private constant MAX_A_CHANGE = 2; uint256 private constant MIN_RAMP_TIME = 7 days; /** * @notice Return A, the amplification coefficient * n * (n - 1) * @dev See the StableSwap paper for details * @param self Swap struct to read from * @return A parameter */ function getA(SwapUtils.Swap storage self) external view returns (uint256) { return _getAPrecise(self).div(A_PRECISION); } /** * @notice Return A in its raw precision * @dev See the StableSwap paper for details * @param self Swap struct to read from * @return A parameter in its raw precision form */ function getAPrecise(SwapUtils.Swap storage self) external view returns (uint256) { return _getAPrecise(self); } /** * @notice Return A in its raw precision * @dev See the StableSwap paper for details * @param self Swap struct to read from * @return A parameter in its raw precision form */ function _getAPrecise(SwapUtils.Swap storage self) internal view returns (uint256) { uint256 t1 = self.futureATime; // time when ramp is finished uint256 a1 = self.futureA; // final A value when ramp is finished if (block.timestamp < t1) { uint256 t0 = self.initialATime; // time when ramp is started uint256 a0 = self.initialA; // initial A value when ramp is started if (a1 > a0) { // a0 + (a1 - a0) * (block.timestamp - t0) / (t1 - t0) return a0.add( a1.sub(a0).mul(block.timestamp.sub(t0)).div(t1.sub(t0)) ); } else { // a0 - (a0 - a1) * (block.timestamp - t0) / (t1 - t0) return a0.sub( a0.sub(a1).mul(block.timestamp.sub(t0)).div(t1.sub(t0)) ); } } else { return a1; } } /** * @notice Start ramping up or down A parameter towards given futureA_ and futureTime_ * Checks if the change is too rapid, and commits the new A value only when it falls under * the limit range. * @param self Swap struct to update * @param futureA_ the new A to ramp towards * @param futureTime_ timestamp when the new A should be reached */ function rampA( SwapUtils.Swap storage self, uint256 futureA_, uint256 futureTime_ ) external { require( block.timestamp >= self.initialATime.add(1 days), "Wait 1 day before starting ramp" ); require( futureTime_ >= block.timestamp.add(MIN_RAMP_TIME), "Insufficient ramp time" ); require( futureA_ > 0 && futureA_ < MAX_A, "futureA_ must be > 0 and < MAX_A" ); uint256 initialAPrecise = _getAPrecise(self); uint256 futureAPrecise = futureA_.mul(A_PRECISION); if (futureAPrecise < initialAPrecise) { require( futureAPrecise.mul(MAX_A_CHANGE) >= initialAPrecise, "futureA_ is too small" ); } else { require( futureAPrecise <= initialAPrecise.mul(MAX_A_CHANGE), "futureA_ is too large" ); } self.initialA = initialAPrecise; self.futureA = futureAPrecise; self.initialATime = block.timestamp; self.futureATime = futureTime_; emit RampA( initialAPrecise, futureAPrecise, block.timestamp, futureTime_ ); } /** * @notice Stops ramping A immediately. Once this function is called, rampA() * cannot be called for another 24 hours * @param self Swap struct to update */ function stopRampA(SwapUtils.Swap storage self) external { require(self.futureATime > block.timestamp, "Ramp is already stopped"); uint256 currentA = _getAPrecise(self); self.initialA = currentA; self.futureA = currentA; self.initialATime = block.timestamp; self.futureATime = block.timestamp; emit StopRampA(currentA, block.timestamp); } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20BurnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "./interfaces/ISwap.sol"; /** * @title Liquidity Provider Token * @notice This token is an ERC20 detailed token with added capability to be minted by the owner. * It is used to represent user's shares when providing liquidity to swap contracts. * @dev Only Swap contracts should initialize and own LPToken contracts. */ contract LPToken is ERC20BurnableUpgradeable, OwnableUpgradeable { using SafeMathUpgradeable for uint256; /** * @notice Initializes this LPToken contract with the given name and symbol * @dev The caller of this function will become the owner. A Swap contract should call this * in its initializer function. * @param name name of this token * @param symbol symbol of this token */ function initialize(string memory name, string memory symbol) external initializer returns (bool) { __Context_init_unchained(); __ERC20_init_unchained(name, symbol); __Ownable_init_unchained(); return true; } /** * @notice Mints the given amount of LPToken to the recipient. * @dev only owner can call this mint function * @param recipient address of account to receive the tokens * @param amount amount of tokens to mint */ function mint(address recipient, uint256 amount) external onlyOwner { require(amount != 0, "LPToken: cannot mint 0"); _mint(recipient, amount); } /** * @dev Overrides ERC20._beforeTokenTransfer() which get called on every transfers including * minting and burning. * This assumes the owner is set to a Swap contract's address. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual override(ERC20Upgradeable) { super._beforeTokenTransfer(from, to, amount); require(to != address(this), "LPToken: cannot send to itself"); } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts/math/SafeMath.sol"; /** * @title MathUtils library * @notice A library to be used in conjunction with SafeMath. Contains functions for calculating * differences between two uint256. */ library MathUtils { /** * @notice Compares a and b and returns true if the difference between a and b * is less than 1 or equal to each other. * @param a uint256 to compare with * @param b uint256 to compare with * @return True if the difference between a and b is less than 1 or equal, * otherwise return false */ function within1(uint256 a, uint256 b) internal pure returns (bool) { return (difference(a, b) <= 1); } /** * @notice Calculates absolute difference between a and b * @param a uint256 to compare with * @param b uint256 to compare with * @return Difference between a and b */ function difference(uint256 a, uint256 b) internal pure returns (uint256) { if (a > b) { return a - b; } return b - a; } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; /** * @title OwnerPausable * @notice An ownable contract allows the owner to pause and unpause the * contract without a delay. * @dev Only methods using the provided modifiers will be paused. */ abstract contract OwnerPausableUpgradeable is OwnableUpgradeable, PausableUpgradeable { function __OwnerPausable_init() internal initializer { __Context_init_unchained(); __Ownable_init_unchained(); __Pausable_init_unchained(); } /** * @notice Pause the contract. Revert if already paused. */ function pause() external onlyOwner { PausableUpgradeable._pause(); } /** * @notice Unpause the contract. Revert if already unpaused. */ function unpause() external onlyOwner { PausableUpgradeable._unpause(); } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin/contracts/proxy/Clones.sol"; import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import "./OwnerPausableUpgradeable.sol"; import "./SwapUtils.sol"; import "./AmplificationUtils.sol"; /** * @title Swap - A StableSwap implementation in solidity. * @notice This contract is responsible for custody of closely pegged assets (eg. group of stablecoins) * and automatic market making system. Users become an LP (Liquidity Provider) by depositing their tokens * in desired ratios for an exchange of the pool token that represents their share of the pool. * Users can burn pool tokens and withdraw their share of token(s). * * Each time a swap between the pooled tokens happens, a set fee incurs which effectively gets * distributed to the LPs. * * In case of emergencies, admin can pause additional deposits, swaps, or single-asset withdraws - which * stops the ratio of the tokens in the pool from changing. * Users can always withdraw their tokens via multi-asset withdraws. * * @dev Most of the logic is stored as a library `SwapUtils` for the sake of reducing contract's * deployment size. */ contract Swap is OwnerPausableUpgradeable, ReentrancyGuardUpgradeable { using SafeERC20 for IERC20; using SafeMath for uint256; using SwapUtils for SwapUtils.Swap; using AmplificationUtils for SwapUtils.Swap; // Struct storing data responsible for automatic market maker functionalities. In order to // access this data, this contract uses SwapUtils library. For more details, see SwapUtils.sol SwapUtils.Swap public swapStorage; // Maps token address to an index in the pool. Used to prevent duplicate tokens in the pool. // getTokenIndex function also relies on this mapping to retrieve token index. mapping(address => uint8) private tokenIndexes; /*** EVENTS ***/ // events replicated from SwapUtils to make the ABI easier for dumb // clients event TokenSwap( address indexed buyer, uint256 tokensSold, uint256 tokensBought, uint128 soldId, uint128 boughtId ); event AddLiquidity( address indexed provider, uint256[] tokenAmounts, uint256[] fees, uint256 invariant, uint256 lpTokenSupply ); event RemoveLiquidity( address indexed provider, uint256[] tokenAmounts, uint256 lpTokenSupply ); event RemoveLiquidityOne( address indexed provider, uint256 lpTokenAmount, uint256 lpTokenSupply, uint256 boughtId, uint256 tokensBought ); event RemoveLiquidityImbalance( address indexed provider, uint256[] tokenAmounts, uint256[] fees, uint256 invariant, uint256 lpTokenSupply ); event NewAdminFee(uint256 newAdminFee); event NewSwapFee(uint256 newSwapFee); event RampA( uint256 oldA, uint256 newA, uint256 initialTime, uint256 futureTime ); event StopRampA(uint256 currentA, uint256 time); /** * @notice Initializes this Swap contract with the given parameters. * This will also clone a LPToken contract that represents users' * LP positions. The owner of LPToken will be this contract - which means * only this contract is allowed to mint/burn tokens. * * @param _pooledTokens an array of ERC20s this pool will accept * @param decimals the decimals to use for each pooled token, * eg 8 for WBTC. Cannot be larger than POOL_PRECISION_DECIMALS * @param lpTokenName the long-form name of the token to be deployed * @param lpTokenSymbol the short symbol for the token to be deployed * @param _a the amplification coefficient * n * (n - 1). See the * StableSwap paper for details * @param _fee default swap fee to be initialized with * @param _adminFee default adminFee to be initialized with * @param lpTokenTargetAddress the address of an existing LPToken contract to use as a target */ function initialize( IERC20[] memory _pooledTokens, uint8[] memory decimals, string memory lpTokenName, string memory lpTokenSymbol, uint256 _a, uint256 _fee, uint256 _adminFee, address lpTokenTargetAddress ) public virtual initializer { __OwnerPausable_init(); __ReentrancyGuard_init(); // Check _pooledTokens and precisions parameter require(_pooledTokens.length > 1, "_pooledTokens.length <= 1"); require(_pooledTokens.length <= 32, "_pooledTokens.length > 32"); require( _pooledTokens.length == decimals.length, "_pooledTokens decimals mismatch" ); uint256[] memory precisionMultipliers = new uint256[](decimals.length); for (uint8 i = 0; i < _pooledTokens.length; i++) { if (i > 0) { // Check if index is already used. Check if 0th element is a duplicate. require( tokenIndexes[address(_pooledTokens[i])] == 0 && _pooledTokens[0] != _pooledTokens[i], "Duplicate tokens" ); } require( address(_pooledTokens[i]) != address(0), "The 0 address isn't an ERC-20" ); require( decimals[i] <= SwapUtils.POOL_PRECISION_DECIMALS, "Token decimals exceeds max" ); precisionMultipliers[i] = 10 ** uint256(SwapUtils.POOL_PRECISION_DECIMALS).sub( uint256(decimals[i]) ); tokenIndexes[address(_pooledTokens[i])] = i; } // Check _a, _fee, _adminFee parameters require(_a < AmplificationUtils.MAX_A, "_a exceeds maximum"); require(_fee < SwapUtils.MAX_SWAP_FEE, "_fee exceeds maximum"); require( _adminFee < SwapUtils.MAX_ADMIN_FEE, "_adminFee exceeds maximum" ); // Clone and initialize a LPToken contract LPToken lpToken = LPToken(Clones.clone(lpTokenTargetAddress)); require( lpToken.initialize(lpTokenName, lpTokenSymbol), "could not init lpToken clone" ); // Initialize swapStorage struct swapStorage.lpToken = lpToken; swapStorage.pooledTokens = _pooledTokens; swapStorage.tokenPrecisionMultipliers = precisionMultipliers; swapStorage.balances = new uint256[](_pooledTokens.length); swapStorage.initialA = _a.mul(AmplificationUtils.A_PRECISION); swapStorage.futureA = _a.mul(AmplificationUtils.A_PRECISION); // swapStorage.initialATime = 0; // swapStorage.futureATime = 0; swapStorage.swapFee = _fee; swapStorage.adminFee = _adminFee; } /*** MODIFIERS ***/ /** * @notice Modifier to check deadline against current timestamp * @param deadline latest timestamp to accept this transaction */ modifier deadlineCheck(uint256 deadline) { require(block.timestamp <= deadline, "Deadline not met"); _; } /*** VIEW FUNCTIONS ***/ /** * @notice Return A, the amplification coefficient * n * (n - 1) * @dev See the StableSwap paper for details * @return A parameter */ function getA() external view virtual returns (uint256) { return swapStorage.getA(); } /** * @notice Return A in its raw precision form * @dev See the StableSwap paper for details * @return A parameter in its raw precision form */ function getAPrecise() external view virtual returns (uint256) { return swapStorage.getAPrecise(); } /** * @notice Return address of the pooled token at given index. Reverts if tokenIndex is out of range. * @param index the index of the token * @return address of the token at given index */ function getToken(uint8 index) public view virtual returns (IERC20) { require(index < swapStorage.pooledTokens.length, "Out of range"); return swapStorage.pooledTokens[index]; } /** * @notice Return the index of the given token address. Reverts if no matching * token is found. * @param tokenAddress address of the token * @return the index of the given token address */ function getTokenIndex(address tokenAddress) public view virtual returns (uint8) { uint8 index = tokenIndexes[tokenAddress]; require( address(getToken(index)) == tokenAddress, "Token does not exist" ); return index; } /** * @notice Return current balance of the pooled token at given index * @param index the index of the token * @return current balance of the pooled token at given index with token's native precision */ function getTokenBalance(uint8 index) external view virtual returns (uint256) { require(index < swapStorage.pooledTokens.length, "Index out of range"); return swapStorage.balances[index]; } /** * @notice Get the virtual price, to help calculate profit * @return the virtual price, scaled to the POOL_PRECISION_DECIMALS */ function getVirtualPrice() external view virtual returns (uint256) { return swapStorage.getVirtualPrice(); } /** * @notice Calculate amount of tokens you receive on swap * @param tokenIndexFrom the token the user wants to sell * @param tokenIndexTo the token the user wants to buy * @param dx the amount of tokens the user wants to sell. If the token charges * a fee on transfers, use the amount that gets transferred after the fee. * @return amount of tokens the user will receive */ function calculateSwap( uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx ) external view virtual returns (uint256) { return swapStorage.calculateSwap(tokenIndexFrom, tokenIndexTo, dx); } /** * @notice A simple method to calculate prices from deposits or * withdrawals, excluding fees but including slippage. This is * helpful as an input into the various "min" parameters on calls * to fight front-running * * @dev This shouldn't be used outside frontends for user estimates. * * @param amounts an array of token amounts to deposit or withdrawal, * corresponding to pooledTokens. The amount should be in each * pooled token's native precision. If a token charges a fee on transfers, * use the amount that gets transferred after the fee. * @param deposit whether this is a deposit or a withdrawal * @return token amount the user will receive */ function calculateTokenAmount(uint256[] calldata amounts, bool deposit) external view virtual returns (uint256) { return swapStorage.calculateTokenAmount(amounts, deposit); } /** * @notice A simple method to calculate amount of each underlying * tokens that is returned upon burning given amount of LP tokens * @param amount the amount of LP tokens that would be burned on withdrawal * @return array of token balances that the user will receive */ function calculateRemoveLiquidity(uint256 amount) external view virtual returns (uint256[] memory) { return swapStorage.calculateRemoveLiquidity(amount); } /** * @notice Calculate the amount of underlying token available to withdraw * when withdrawing via only single token * @param tokenAmount the amount of LP token to burn * @param tokenIndex index of which token will be withdrawn * @return availableTokenAmount calculated amount of underlying token * available to withdraw */ function calculateRemoveLiquidityOneToken( uint256 tokenAmount, uint8 tokenIndex ) external view virtual returns (uint256 availableTokenAmount) { return swapStorage.calculateWithdrawOneToken(tokenAmount, tokenIndex); } /** * @notice This function reads the accumulated amount of admin fees of the token with given index * @param index Index of the pooled token * @return admin's token balance in the token's precision */ function getAdminBalance(uint256 index) external view virtual returns (uint256) { return swapStorage.getAdminBalance(index); } /*** STATE MODIFYING FUNCTIONS ***/ /** * @notice Swap two tokens using this pool * @param tokenIndexFrom the token the user wants to swap from * @param tokenIndexTo the token the user wants to swap to * @param dx the amount of tokens the user wants to swap from * @param minDy the min amount the user would like to receive, or revert. * @param deadline latest timestamp to accept this transaction */ function swap( uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256 minDy, uint256 deadline ) external virtual nonReentrant whenNotPaused deadlineCheck(deadline) returns (uint256) { return swapStorage.swap(tokenIndexFrom, tokenIndexTo, dx, minDy); } /** * @notice Add liquidity to the pool with the given amounts of tokens * @param amounts the amounts of each token to add, in their native precision * @param minToMint the minimum LP tokens adding this amount of liquidity * should mint, otherwise revert. Handy for front-running mitigation * @param deadline latest timestamp to accept this transaction * @return amount of LP token user minted and received */ function addLiquidity( uint256[] calldata amounts, uint256 minToMint, uint256 deadline ) external virtual nonReentrant whenNotPaused deadlineCheck(deadline) returns (uint256) { return swapStorage.addLiquidity(amounts, minToMint); } /** * @notice Burn LP tokens to remove liquidity from the pool. Withdraw fee that decays linearly * over period of 4 weeks since last deposit will apply. * @dev Liquidity can always be removed, even when the pool is paused. * @param amount the amount of LP tokens to burn * @param minAmounts the minimum amounts of each token in the pool * acceptable for this burn. Useful as a front-running mitigation * @param deadline latest timestamp to accept this transaction * @return amounts of tokens user received */ function removeLiquidity( uint256 amount, uint256[] calldata minAmounts, uint256 deadline ) external virtual nonReentrant deadlineCheck(deadline) returns (uint256[] memory) { return swapStorage.removeLiquidity(amount, minAmounts); } /** * @notice Remove liquidity from the pool all in one token. Withdraw fee that decays linearly * over period of 4 weeks since last deposit will apply. * @param tokenAmount the amount of the token you want to receive * @param tokenIndex the index of the token you want to receive * @param minAmount the minimum amount to withdraw, otherwise revert * @param deadline latest timestamp to accept this transaction * @return amount of chosen token user received */ function removeLiquidityOneToken( uint256 tokenAmount, uint8 tokenIndex, uint256 minAmount, uint256 deadline ) external virtual nonReentrant whenNotPaused deadlineCheck(deadline) returns (uint256) { return swapStorage.removeLiquidityOneToken( tokenAmount, tokenIndex, minAmount ); } /** * @notice Remove liquidity from the pool, weighted differently than the * pool's current balances. Withdraw fee that decays linearly * over period of 4 weeks since last deposit will apply. * @param amounts how much of each token to withdraw * @param maxBurnAmount the max LP token provider is willing to pay to * remove liquidity. Useful as a front-running mitigation. * @param deadline latest timestamp to accept this transaction * @return amount of LP tokens burned */ function removeLiquidityImbalance( uint256[] calldata amounts, uint256 maxBurnAmount, uint256 deadline ) external virtual nonReentrant whenNotPaused deadlineCheck(deadline) returns (uint256) { return swapStorage.removeLiquidityImbalance(amounts, maxBurnAmount); } /*** ADMIN FUNCTIONS ***/ /** * @notice Withdraw all admin fees to the contract owner */ function withdrawAdminFees() external onlyOwner { swapStorage.withdrawAdminFees(owner()); } /** * @notice Update the admin fee. Admin fee takes portion of the swap fee. * @param newAdminFee new admin fee to be applied on future transactions */ function setAdminFee(uint256 newAdminFee) external onlyOwner { swapStorage.setAdminFee(newAdminFee); } /** * @notice Update the swap fee to be applied on swaps * @param newSwapFee new swap fee to be applied on future transactions */ function setSwapFee(uint256 newSwapFee) external onlyOwner { swapStorage.setSwapFee(newSwapFee); } /** * @notice Start ramping up or down A parameter towards given futureA and futureTime * Checks if the change is too rapid, and commits the new A value only when it falls under * the limit range. * @param futureA the new A to ramp towards * @param futureTime timestamp when the new A should be reached */ function rampA(uint256 futureA, uint256 futureTime) external onlyOwner { swapStorage.rampA(futureA, futureTime); } /** * @notice Stop ramping A immediately. Reverts if ramp A is already stopped. */ function stopRampA() external onlyOwner { swapStorage.stopRampA(); } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "./AmplificationUtils.sol"; import "./LPToken.sol"; import "./MathUtils.sol"; /** * @title SwapUtils library * @notice A library to be used within Swap.sol. Contains functions responsible for custody and AMM functionalities. * @dev Contracts relying on this library must initialize SwapUtils.Swap struct then use this library * for SwapUtils.Swap struct. Note that this library contains both functions called by users and admins. * Admin functions should be protected within contracts using this library. */ library SwapUtils { using SafeERC20 for IERC20; using SafeMath for uint256; using MathUtils for uint256; /*** EVENTS ***/ event TokenSwap( address indexed buyer, uint256 tokensSold, uint256 tokensBought, uint128 soldId, uint128 boughtId ); event AddLiquidity( address indexed provider, uint256[] tokenAmounts, uint256[] fees, uint256 invariant, uint256 lpTokenSupply ); event RemoveLiquidity( address indexed provider, uint256[] tokenAmounts, uint256 lpTokenSupply ); event RemoveLiquidityOne( address indexed provider, uint256 lpTokenAmount, uint256 lpTokenSupply, uint256 boughtId, uint256 tokensBought ); event RemoveLiquidityImbalance( address indexed provider, uint256[] tokenAmounts, uint256[] fees, uint256 invariant, uint256 lpTokenSupply ); event NewAdminFee(uint256 newAdminFee); event NewSwapFee(uint256 newSwapFee); struct Swap { // variables around the ramp management of A, // the amplification coefficient * n * (n - 1) // see https://www.curve.fi/stableswap-paper.pdf for details uint256 initialA; uint256 futureA; uint256 initialATime; uint256 futureATime; // fee calculation uint256 swapFee; uint256 adminFee; LPToken lpToken; // contract references for all tokens being pooled IERC20[] pooledTokens; // multipliers for each pooled token's precision to get to POOL_PRECISION_DECIMALS // for example, TBTC has 18 decimals, so the multiplier should be 1. WBTC // has 8, so the multiplier should be 10 ** 18 / 10 ** 8 => 10 ** 10 uint256[] tokenPrecisionMultipliers; // the pool balance of each token, in the token's precision // the contract's actual token balance might differ uint256[] balances; } // Struct storing variables used in calculations in the // calculateWithdrawOneTokenDY function to avoid stack too deep errors struct CalculateWithdrawOneTokenDYInfo { uint256 d0; uint256 d1; uint256 newY; uint256 feePerToken; uint256 preciseA; } // Struct storing variables used in calculations in the // {add,remove}Liquidity functions to avoid stack too deep errors struct ManageLiquidityInfo { uint256 d0; uint256 d1; uint256 d2; uint256 preciseA; LPToken lpToken; uint256 totalSupply; uint256[] balances; uint256[] multipliers; } // the precision all pools tokens will be converted to uint8 public constant POOL_PRECISION_DECIMALS = 18; // the denominator used to calculate admin and LP fees. For example, an // LP fee might be something like tradeAmount.mul(fee).div(FEE_DENOMINATOR) uint256 private constant FEE_DENOMINATOR = 10**10; // Max swap fee is 1% or 100bps of each swap uint256 public constant MAX_SWAP_FEE = 10**8; // Max adminFee is 100% of the swapFee // adminFee does not add additional fee on top of swapFee // Instead it takes a certain % of the swapFee. Therefore it has no impact on the // users but only on the earnings of LPs uint256 public constant MAX_ADMIN_FEE = 10**10; // Constant value used as max loop limit uint256 private constant MAX_LOOP_LIMIT = 256; /*** VIEW & PURE FUNCTIONS ***/ function _getAPrecise(Swap storage self) internal view returns (uint256) { return AmplificationUtils._getAPrecise(self); } /** * @notice Calculate the dy, the amount of selected token that user receives and * the fee of withdrawing in one token * @param tokenAmount the amount to withdraw in the pool's precision * @param tokenIndex which token will be withdrawn * @param self Swap struct to read from * @return the amount of token user will receive */ function calculateWithdrawOneToken( Swap storage self, uint256 tokenAmount, uint8 tokenIndex ) external view returns (uint256) { (uint256 availableTokenAmount, ) = _calculateWithdrawOneToken( self, tokenAmount, tokenIndex, self.lpToken.totalSupply() ); return availableTokenAmount; } function _calculateWithdrawOneToken( Swap storage self, uint256 tokenAmount, uint8 tokenIndex, uint256 totalSupply ) internal view returns (uint256, uint256) { uint256 dy; uint256 newY; uint256 currentY; (dy, newY, currentY) = calculateWithdrawOneTokenDY( self, tokenIndex, tokenAmount, totalSupply ); // dy_0 (without fees) // dy, dy_0 - dy uint256 dySwapFee = currentY .sub(newY) .div(self.tokenPrecisionMultipliers[tokenIndex]) .sub(dy); return (dy, dySwapFee); } /** * @notice Calculate the dy of withdrawing in one token * @param self Swap struct to read from * @param tokenIndex which token will be withdrawn * @param tokenAmount the amount to withdraw in the pools precision * @return the d and the new y after withdrawing one token */ function calculateWithdrawOneTokenDY( Swap storage self, uint8 tokenIndex, uint256 tokenAmount, uint256 totalSupply ) internal view returns ( uint256, uint256, uint256 ) { // Get the current D, then solve the stableswap invariant // y_i for D - tokenAmount uint256[] memory xp = _xp(self); require(tokenIndex < xp.length, "Token index out of range"); CalculateWithdrawOneTokenDYInfo memory v = CalculateWithdrawOneTokenDYInfo(0, 0, 0, 0, 0); v.preciseA = _getAPrecise(self); v.d0 = getD(xp, v.preciseA); v.d1 = v.d0.sub(tokenAmount.mul(v.d0).div(totalSupply)); require(tokenAmount <= xp[tokenIndex], "Withdraw exceeds available"); v.newY = getYD(v.preciseA, tokenIndex, xp, v.d1); uint256[] memory xpReduced = new uint256[](xp.length); v.feePerToken = _feePerToken(self.swapFee, xp.length); for (uint256 i = 0; i < xp.length; i++) { uint256 xpi = xp[i]; // if i == tokenIndex, dxExpected = xp[i] * d1 / d0 - newY // else dxExpected = xp[i] - (xp[i] * d1 / d0) // xpReduced[i] -= dxExpected * fee / FEE_DENOMINATOR xpReduced[i] = xpi.sub( ( (i == tokenIndex) ? xpi.mul(v.d1).div(v.d0).sub(v.newY) : xpi.sub(xpi.mul(v.d1).div(v.d0)) ) .mul(v.feePerToken) .div(FEE_DENOMINATOR) ); } uint256 dy = xpReduced[tokenIndex].sub( getYD(v.preciseA, tokenIndex, xpReduced, v.d1) ); dy = dy.sub(1).div(self.tokenPrecisionMultipliers[tokenIndex]); return (dy, v.newY, xp[tokenIndex]); } /** * @notice Calculate the price of a token in the pool with given * precision-adjusted balances and a particular D. * * @dev This is accomplished via solving the invariant iteratively. * See the StableSwap paper and Curve.fi implementation for further details. * * x_1**2 + x1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A) * x_1**2 + b*x_1 = c * x_1 = (x_1**2 + c) / (2*x_1 + b) * * @param a the amplification coefficient * n * (n - 1). See the StableSwap paper for details. * @param tokenIndex Index of token we are calculating for. * @param xp a precision-adjusted set of pool balances. Array should be * the same cardinality as the pool. * @param d the stableswap invariant * @return the price of the token, in the same precision as in xp */ function getYD( uint256 a, uint8 tokenIndex, uint256[] memory xp, uint256 d ) internal pure returns (uint256) { uint256 numTokens = xp.length; require(tokenIndex < numTokens, "Token not found"); uint256 c = d; uint256 s; uint256 nA = a.mul(numTokens); for (uint256 i = 0; i < numTokens; i++) { if (i != tokenIndex) { s = s.add(xp[i]); c = c.mul(d).div(xp[i].mul(numTokens)); // If we were to protect the division loss we would have to keep the denominator separate // and divide at the end. However this leads to overflow with large numTokens or/and D. // c = c * D * D * D * ... overflow! } } c = c.mul(d).mul(AmplificationUtils.A_PRECISION).div(nA.mul(numTokens)); uint256 b = s.add(d.mul(AmplificationUtils.A_PRECISION).div(nA)); uint256 yPrev; uint256 y = d; for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) { yPrev = y; y = y.mul(y).add(c).div(y.mul(2).add(b).sub(d)); if (y.within1(yPrev)) { return y; } } revert("Approximation did not converge"); } /** * @notice Get D, the StableSwap invariant, based on a set of balances and a particular A. * @param xp a precision-adjusted set of pool balances. Array should be the same cardinality * as the pool. * @param a the amplification coefficient * n * (n - 1) in A_PRECISION. * See the StableSwap paper for details * @return the invariant, at the precision of the pool */ function getD(uint256[] memory xp, uint256 a) internal pure returns (uint256) { uint256 numTokens = xp.length; uint256 s; for (uint256 i = 0; i < numTokens; i++) { s = s.add(xp[i]); } if (s == 0) { return 0; } uint256 prevD; uint256 d = s; uint256 nA = a.mul(numTokens); for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) { uint256 dP = d; for (uint256 j = 0; j < numTokens; j++) { dP = dP.mul(d).div(xp[j].mul(numTokens)); // If we were to protect the division loss we would have to keep the denominator separate // and divide at the end. However this leads to overflow with large numTokens or/and D. // dP = dP * D * D * D * ... overflow! } prevD = d; d = nA .mul(s) .div(AmplificationUtils.A_PRECISION) .add(dP.mul(numTokens)) .mul(d) .div( nA .sub(AmplificationUtils.A_PRECISION) .mul(d) .div(AmplificationUtils.A_PRECISION) .add(numTokens.add(1).mul(dP)) ); if (d.within1(prevD)) { return d; } } // Convergence should occur in 4 loops or less. If this is reached, there may be something wrong // with the pool. If this were to occur repeatedly, LPs should withdraw via `removeLiquidity()` // function which does not rely on D. revert("D does not converge"); } /** * @notice Given a set of balances and precision multipliers, return the * precision-adjusted balances. * * @param balances an array of token balances, in their native precisions. * These should generally correspond with pooled tokens. * * @param precisionMultipliers an array of multipliers, corresponding to * the amounts in the balances array. When multiplied together they * should yield amounts at the pool's precision. * * @return an array of amounts "scaled" to the pool's precision */ function _xp( uint256[] memory balances, uint256[] memory precisionMultipliers ) internal pure returns (uint256[] memory) { uint256 numTokens = balances.length; require( numTokens == precisionMultipliers.length, "Balances must match multipliers" ); uint256[] memory xp = new uint256[](numTokens); for (uint256 i = 0; i < numTokens; i++) { xp[i] = balances[i].mul(precisionMultipliers[i]); } return xp; } /** * @notice Return the precision-adjusted balances of all tokens in the pool * @param self Swap struct to read from * @return the pool balances "scaled" to the pool's precision, allowing * them to be more easily compared. */ function _xp(Swap storage self) internal view returns (uint256[] memory) { return _xp(self.balances, self.tokenPrecisionMultipliers); } /** * @notice Get the virtual price, to help calculate profit * @param self Swap struct to read from * @return the virtual price, scaled to precision of POOL_PRECISION_DECIMALS */ function getVirtualPrice(Swap storage self) external view returns (uint256) { uint256 d = getD(_xp(self), _getAPrecise(self)); LPToken lpToken = self.lpToken; uint256 supply = lpToken.totalSupply(); if (supply > 0) { return d.mul(10**uint256(POOL_PRECISION_DECIMALS)).div(supply); } return 0; } /** * @notice Calculate the new balances of the tokens given the indexes of the token * that is swapped from (FROM) and the token that is swapped to (TO). * This function is used as a helper function to calculate how much TO token * the user should receive on swap. * * @param preciseA precise form of amplification coefficient * @param tokenIndexFrom index of FROM token * @param tokenIndexTo index of TO token * @param x the new total amount of FROM token * @param xp balances of the tokens in the pool * @return the amount of TO token that should remain in the pool */ function getY( uint256 preciseA, uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 x, uint256[] memory xp ) internal pure returns (uint256) { uint256 numTokens = xp.length; require( tokenIndexFrom != tokenIndexTo, "Can't compare token to itself" ); require( tokenIndexFrom < numTokens && tokenIndexTo < numTokens, "Tokens must be in pool" ); uint256 d = getD(xp, preciseA); uint256 c = d; uint256 s; uint256 nA = numTokens.mul(preciseA); uint256 _x; for (uint256 i = 0; i < numTokens; i++) { if (i == tokenIndexFrom) { _x = x; } else if (i != tokenIndexTo) { _x = xp[i]; } else { continue; } s = s.add(_x); c = c.mul(d).div(_x.mul(numTokens)); // If we were to protect the division loss we would have to keep the denominator separate // and divide at the end. However this leads to overflow with large numTokens or/and D. // c = c * D * D * D * ... overflow! } c = c.mul(d).mul(AmplificationUtils.A_PRECISION).div(nA.mul(numTokens)); uint256 b = s.add(d.mul(AmplificationUtils.A_PRECISION).div(nA)); uint256 yPrev; uint256 y = d; // iterative approximation for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) { yPrev = y; y = y.mul(y).add(c).div(y.mul(2).add(b).sub(d)); if (y.within1(yPrev)) { return y; } } revert("Approximation did not converge"); } /** * @notice Externally calculates a swap between two tokens. * @param self Swap struct to read from * @param tokenIndexFrom the token to sell * @param tokenIndexTo the token to buy * @param dx the number of tokens to sell. If the token charges a fee on transfers, * use the amount that gets transferred after the fee. * @return dy the number of tokens the user will get */ function calculateSwap( Swap storage self, uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx ) external view returns (uint256 dy) { (dy, ) = _calculateSwap( self, tokenIndexFrom, tokenIndexTo, dx, self.balances ); } /** * @notice Internally calculates a swap between two tokens. * * @dev The caller is expected to transfer the actual amounts (dx and dy) * using the token contracts. * * @param self Swap struct to read from * @param tokenIndexFrom the token to sell * @param tokenIndexTo the token to buy * @param dx the number of tokens to sell. If the token charges a fee on transfers, * use the amount that gets transferred after the fee. * @return dy the number of tokens the user will get * @return dyFee the associated fee */ function _calculateSwap( Swap storage self, uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256[] memory balances ) internal view returns (uint256 dy, uint256 dyFee) { uint256[] memory multipliers = self.tokenPrecisionMultipliers; uint256[] memory xp = _xp(balances, multipliers); require( tokenIndexFrom < xp.length && tokenIndexTo < xp.length, "Token index out of range" ); uint256 x = dx.mul(multipliers[tokenIndexFrom]).add(xp[tokenIndexFrom]); uint256 y = getY(_getAPrecise(self), tokenIndexFrom, tokenIndexTo, x, xp); dy = xp[tokenIndexTo].sub(y).sub(1); dyFee = dy.mul(self.swapFee).div(FEE_DENOMINATOR); dy = dy.sub(dyFee).div(multipliers[tokenIndexTo]); } /** * @notice A simple method to calculate amount of each underlying * tokens that is returned upon burning given amount of * LP tokens * * @param amount the amount of LP tokens that would to be burned on * withdrawal * @return array of amounts of tokens user will receive */ function calculateRemoveLiquidity(Swap storage self, uint256 amount) external view returns (uint256[] memory) { return _calculateRemoveLiquidity( self.balances, amount, self.lpToken.totalSupply() ); } function _calculateRemoveLiquidity( uint256[] memory balances, uint256 amount, uint256 totalSupply ) internal pure returns (uint256[] memory) { require(amount <= totalSupply, "Cannot exceed total supply"); uint256[] memory amounts = new uint256[](balances.length); for (uint256 i = 0; i < balances.length; i++) { amounts[i] = balances[i].mul(amount).div(totalSupply); } return amounts; } /** * @notice A simple method to calculate prices from deposits or * withdrawals, excluding fees but including slippage. This is * helpful as an input into the various "min" parameters on calls * to fight front-running * * @dev This shouldn't be used outside frontends for user estimates. * * @param self Swap struct to read from * @param amounts an array of token amounts to deposit or withdrawal, * corresponding to pooledTokens. The amount should be in each * pooled token's native precision. If a token charges a fee on transfers, * use the amount that gets transferred after the fee. * @param deposit whether this is a deposit or a withdrawal * @return if deposit was true, total amount of lp token that will be minted and if * deposit was false, total amount of lp token that will be burned */ function calculateTokenAmount( Swap storage self, uint256[] calldata amounts, bool deposit ) external view returns (uint256) { uint256 a = _getAPrecise(self); uint256[] memory balances = self.balances; uint256[] memory multipliers = self.tokenPrecisionMultipliers; uint256 d0 = getD(_xp(balances, multipliers), a); for (uint256 i = 0; i < balances.length; i++) { if (deposit) { balances[i] = balances[i].add(amounts[i]); } else { balances[i] = balances[i].sub( amounts[i], "Cannot withdraw more than available" ); } } uint256 d1 = getD(_xp(balances, multipliers), a); uint256 totalSupply = self.lpToken.totalSupply(); if (deposit) { return d1.sub(d0).mul(totalSupply).div(d0); } else { return d0.sub(d1).mul(totalSupply).div(d0); } } /** * @notice return accumulated amount of admin fees of the token with given index * @param self Swap struct to read from * @param index Index of the pooled token * @return admin balance in the token's precision */ function getAdminBalance(Swap storage self, uint256 index) external view returns (uint256) { require(index < self.pooledTokens.length, "Token index out of range"); return self.pooledTokens[index].balanceOf(address(this)).sub( self.balances[index] ); } /** * @notice internal helper function to calculate fee per token multiplier used in * swap fee calculations * @param swapFee swap fee for the tokens * @param numTokens number of tokens pooled */ function _feePerToken(uint256 swapFee, uint256 numTokens) internal pure returns (uint256) { return swapFee.mul(numTokens).div(numTokens.sub(1).mul(4)); } /*** STATE MODIFYING FUNCTIONS ***/ /** * @notice swap two tokens in the pool * @param self Swap struct to read from and write to * @param tokenIndexFrom the token the user wants to sell * @param tokenIndexTo the token the user wants to buy * @param dx the amount of tokens the user wants to sell * @param minDy the min amount the user would like to receive, or revert. * @return amount of token user received on swap */ function swap( Swap storage self, uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256 minDy ) external returns (uint256) { { IERC20 tokenFrom = self.pooledTokens[tokenIndexFrom]; require( dx <= tokenFrom.balanceOf(msg.sender), "Cannot swap more than you own" ); // Transfer tokens first to see if a fee was charged on transfer uint256 beforeBalance = tokenFrom.balanceOf(address(this)); tokenFrom.safeTransferFrom(msg.sender, address(this), dx); // Use the actual transferred amount for AMM math dx = tokenFrom.balanceOf(address(this)).sub(beforeBalance); } uint256 dy; uint256 dyFee; uint256[] memory balances = self.balances; (dy, dyFee) = _calculateSwap( self, tokenIndexFrom, tokenIndexTo, dx, balances ); require(dy >= minDy, "Swap didn't result in min tokens"); uint256 dyAdminFee = dyFee.mul(self.adminFee).div(FEE_DENOMINATOR).div( self.tokenPrecisionMultipliers[tokenIndexTo] ); self.balances[tokenIndexFrom] = balances[tokenIndexFrom].add(dx); self.balances[tokenIndexTo] = balances[tokenIndexTo].sub(dy).sub( dyAdminFee ); self.pooledTokens[tokenIndexTo].safeTransfer(msg.sender, dy); emit TokenSwap(msg.sender, dx, dy, tokenIndexFrom, tokenIndexTo); return dy; } /** * @notice Add liquidity to the pool * @param self Swap struct to read from and write to * @param amounts the amounts of each token to add, in their native precision * @param minToMint the minimum LP tokens adding this amount of liquidity * should mint, otherwise revert. Handy for front-running mitigation * allowed addresses. If the pool is not in the guarded launch phase, this parameter will be ignored. * @return amount of LP token user received */ function addLiquidity( Swap storage self, uint256[] memory amounts, uint256 minToMint ) external returns (uint256) { IERC20[] memory pooledTokens = self.pooledTokens; require( amounts.length == pooledTokens.length, "Amounts must match pooled tokens" ); // current state ManageLiquidityInfo memory v = ManageLiquidityInfo( 0, 0, 0, _getAPrecise(self), self.lpToken, 0, self.balances, self.tokenPrecisionMultipliers ); v.totalSupply = v.lpToken.totalSupply(); if (v.totalSupply != 0) { v.d0 = getD(_xp(v.balances, v.multipliers), v.preciseA); } uint256[] memory newBalances = new uint256[](pooledTokens.length); for (uint256 i = 0; i < pooledTokens.length; i++) { require( v.totalSupply != 0 || amounts[i] > 0, "Must supply all tokens in pool" ); // Transfer tokens first to see if a fee was charged on transfer if (amounts[i] != 0) { uint256 beforeBalance = pooledTokens[i].balanceOf(address(this)); pooledTokens[i].safeTransferFrom( msg.sender, address(this), amounts[i] ); // Update the amounts[] with actual transfer amount amounts[i] = pooledTokens[i].balanceOf(address(this)).sub( beforeBalance ); } newBalances[i] = v.balances[i].add(amounts[i]); } // invariant after change v.d1 = getD(_xp(newBalances, v.multipliers), v.preciseA); require(v.d1 > v.d0, "D should increase"); // updated to reflect fees and calculate the user's LP tokens v.d2 = v.d1; uint256[] memory fees = new uint256[](pooledTokens.length); if (v.totalSupply != 0) { uint256 feePerToken = _feePerToken(self.swapFee, pooledTokens.length); for (uint256 i = 0; i < pooledTokens.length; i++) { uint256 idealBalance = v.d1.mul(v.balances[i]).div(v.d0); fees[i] = feePerToken .mul(idealBalance.difference(newBalances[i])) .div(FEE_DENOMINATOR); self.balances[i] = newBalances[i].sub( fees[i].mul(self.adminFee).div(FEE_DENOMINATOR) ); newBalances[i] = newBalances[i].sub(fees[i]); } v.d2 = getD(_xp(newBalances, v.multipliers), v.preciseA); } else { // the initial depositor doesn't pay fees self.balances = newBalances; } uint256 toMint; if (v.totalSupply == 0) { toMint = v.d1; } else { toMint = v.d2.sub(v.d0).mul(v.totalSupply).div(v.d0); } require(toMint >= minToMint, "Couldn't mint min requested"); // mint the user's LP tokens v.lpToken.mint(msg.sender, toMint); emit AddLiquidity( msg.sender, amounts, fees, v.d1, v.totalSupply.add(toMint) ); return toMint; } /** * @notice Burn LP tokens to remove liquidity from the pool. * @dev Liquidity can always be removed, even when the pool is paused. * @param self Swap struct to read from and write to * @param amount the amount of LP tokens to burn * @param minAmounts the minimum amounts of each token in the pool * acceptable for this burn. Useful as a front-running mitigation * @return amounts of tokens the user received */ function removeLiquidity( Swap storage self, uint256 amount, uint256[] calldata minAmounts ) external returns (uint256[] memory) { LPToken lpToken = self.lpToken; IERC20[] memory pooledTokens = self.pooledTokens; require(amount <= lpToken.balanceOf(msg.sender), ">LP.balanceOf"); require( minAmounts.length == pooledTokens.length, "minAmounts must match poolTokens" ); uint256[] memory balances = self.balances; uint256 totalSupply = lpToken.totalSupply(); uint256[] memory amounts = _calculateRemoveLiquidity(balances, amount, totalSupply); for (uint256 i = 0; i < amounts.length; i++) { require(amounts[i] >= minAmounts[i], "amounts[i] < minAmounts[i]"); self.balances[i] = balances[i].sub(amounts[i]); pooledTokens[i].safeTransfer(msg.sender, amounts[i]); } lpToken.burnFrom(msg.sender, amount); emit RemoveLiquidity(msg.sender, amounts, totalSupply.sub(amount)); return amounts; } /** * @notice Remove liquidity from the pool all in one token. * @param self Swap struct to read from and write to * @param tokenAmount the amount of the lp tokens to burn * @param tokenIndex the index of the token you want to receive * @param minAmount the minimum amount to withdraw, otherwise revert * @return amount chosen token that user received */ function removeLiquidityOneToken( Swap storage self, uint256 tokenAmount, uint8 tokenIndex, uint256 minAmount ) external returns (uint256) { LPToken lpToken = self.lpToken; IERC20[] memory pooledTokens = self.pooledTokens; require(tokenAmount <= lpToken.balanceOf(msg.sender), ">LP.balanceOf"); require(tokenIndex < pooledTokens.length, "Token not found"); uint256 totalSupply = lpToken.totalSupply(); (uint256 dy, uint256 dyFee) = _calculateWithdrawOneToken( self, tokenAmount, tokenIndex, totalSupply ); require(dy >= minAmount, "dy < minAmount"); self.balances[tokenIndex] = self.balances[tokenIndex].sub( dy.add(dyFee.mul(self.adminFee).div(FEE_DENOMINATOR)) ); lpToken.burnFrom(msg.sender, tokenAmount); pooledTokens[tokenIndex].safeTransfer(msg.sender, dy); emit RemoveLiquidityOne( msg.sender, tokenAmount, totalSupply, tokenIndex, dy ); return dy; } /** * @notice Remove liquidity from the pool, weighted differently than the * pool's current balances. * * @param self Swap struct to read from and write to * @param amounts how much of each token to withdraw * @param maxBurnAmount the max LP token provider is willing to pay to * remove liquidity. Useful as a front-running mitigation. * @return actual amount of LP tokens burned in the withdrawal */ function removeLiquidityImbalance( Swap storage self, uint256[] memory amounts, uint256 maxBurnAmount ) public returns (uint256) { ManageLiquidityInfo memory v = ManageLiquidityInfo( 0, 0, 0, _getAPrecise(self), self.lpToken, 0, self.balances, self.tokenPrecisionMultipliers ); v.totalSupply = v.lpToken.totalSupply(); IERC20[] memory pooledTokens = self.pooledTokens; require( amounts.length == pooledTokens.length, "Amounts should match pool tokens" ); require( maxBurnAmount <= v.lpToken.balanceOf(msg.sender) && maxBurnAmount != 0, ">LP.balanceOf" ); uint256 feePerToken = _feePerToken(self.swapFee, pooledTokens.length); uint256[] memory fees = new uint256[](pooledTokens.length); { uint256[] memory balances1 = new uint256[](pooledTokens.length); v.d0 = getD(_xp(v.balances, v.multipliers), v.preciseA); for (uint256 i = 0; i < pooledTokens.length; i++) { balances1[i] = v.balances[i].sub( amounts[i], "Cannot withdraw more than available" ); } v.d1 = getD(_xp(balances1, v.multipliers), v.preciseA); for (uint256 i = 0; i < pooledTokens.length; i++) { uint256 idealBalance = v.d1.mul(v.balances[i]).div(v.d0); uint256 difference = idealBalance.difference(balances1[i]); fees[i] = feePerToken.mul(difference).div(FEE_DENOMINATOR); self.balances[i] = balances1[i].sub( fees[i].mul(self.adminFee).div(FEE_DENOMINATOR) ); balances1[i] = balances1[i].sub(fees[i]); } v.d2 = getD(_xp(balances1, v.multipliers), v.preciseA); } uint256 tokenAmount = v.d0.sub(v.d2).mul(v.totalSupply).div(v.d0); require(tokenAmount != 0, "Burnt amount cannot be zero"); tokenAmount = tokenAmount.add(1); require(tokenAmount <= maxBurnAmount, "tokenAmount > maxBurnAmount"); v.lpToken.burnFrom(msg.sender, tokenAmount); for (uint256 i = 0; i < pooledTokens.length; i++) { pooledTokens[i].safeTransfer(msg.sender, amounts[i]); } emit RemoveLiquidityImbalance( msg.sender, amounts, fees, v.d1, v.totalSupply.sub(tokenAmount) ); return tokenAmount; } /** * @notice withdraw all admin fees to a given address * @param self Swap struct to withdraw fees from * @param to Address to send the fees to */ function withdrawAdminFees(Swap storage self, address to) external { IERC20[] memory pooledTokens = self.pooledTokens; for (uint256 i = 0; i < pooledTokens.length; i++) { IERC20 token = pooledTokens[i]; uint256 balance = token.balanceOf(address(this)).sub(self.balances[i]); if (balance != 0) { token.safeTransfer(to, balance); } } } /** * @notice Sets the admin fee * @dev adminFee cannot be higher than 100% of the swap fee * @param self Swap struct to update * @param newAdminFee new admin fee to be applied on future transactions */ function setAdminFee(Swap storage self, uint256 newAdminFee) external { require(newAdminFee <= MAX_ADMIN_FEE, "Fee is too high"); self.adminFee = newAdminFee; emit NewAdminFee(newAdminFee); } /** * @notice update the swap fee * @dev fee cannot be higher than 1% of each swap * @param self Swap struct to update * @param newSwapFee new swap fee to be applied on future transactions */ function setSwapFee(Swap storage self, uint256 newSwapFee) external { require(newSwapFee <= MAX_SWAP_FEE, "Fee is too high"); self.swapFee = newSwapFee; emit NewSwapFee(newSwapFee); } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; interface ISwap { // pool data view functions function getA() external view returns (uint256); function getToken(uint8 index) external view returns (IERC20); function getTokenIndex(address tokenAddress) external view returns (uint8); function getTokenBalance(uint8 index) external view returns (uint256); function getVirtualPrice() external view returns (uint256); // min return calculation functions function calculateSwap( uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx ) external view returns (uint256); function calculateTokenAmount(uint256[] calldata amounts, bool deposit) external view returns (uint256); function calculateRemoveLiquidity(uint256 amount) external view returns (uint256[] memory); function calculateRemoveLiquidityOneToken( uint256 tokenAmount, uint8 tokenIndex ) external view returns (uint256 availableTokenAmount); // state modifying functions function initialize( IERC20[] memory pooledTokens, uint8[] memory decimals, string memory lpTokenName, string memory lpTokenSymbol, uint256 a, uint256 fee, uint256 adminFee, address lpTokenTargetAddress ) external; function swap( uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256 minDy, uint256 deadline ) external returns (uint256); function addLiquidity( uint256[] calldata amounts, uint256 minToMint, uint256 deadline ) external returns (uint256); function removeLiquidity( uint256 amount, uint256[] calldata minAmounts, uint256 deadline ) external returns (uint256[] memory); function removeLiquidityOneToken( uint256 tokenAmount, uint8 tokenIndex, uint256 minAmount, uint256 deadline ) external returns (uint256); function removeLiquidityImbalance( uint256[] calldata amounts, uint256 maxBurnAmount, uint256 deadline ) external returns (uint256); }
{ "evmVersion": "istanbul", "libraries": { "contracts/amm/AaveSwap.sol:AaveSwap": { "SwapUtils": "0x9508BF380c1e6f751D97604732eF1Bae6673f299", "AmplificationUtils": "0x20B587484E75752Adac381aE577a7562E7f358c5" } }, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 10000 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"fees","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"invariant","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpTokenSupply","type":"uint256"}],"name":"AddLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newAdminFee","type":"uint256"}],"name":"NewAdminFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newSwapFee","type":"uint256"}],"name":"NewSwapFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"initialTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"futureTime","type":"uint256"}],"name":"RampA","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"lpTokenSupply","type":"uint256"}],"name":"RemoveLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"fees","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"invariant","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpTokenSupply","type":"uint256"}],"name":"RemoveLiquidityImbalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"lpTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpTokenSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"boughtId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensBought","type":"uint256"}],"name":"RemoveLiquidityOne","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"currentA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"StopRampA","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokensSold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensBought","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"soldId","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"boughtId","type":"uint128"}],"name":"TokenSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"minToMint","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"calculateRemoveLiquidity","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint8","name":"tokenIndex","type":"uint8"}],"name":"calculateRemoveLiquidityOneToken","outputs":[{"internalType":"uint256","name":"availableTokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"tokenIndexFrom","type":"uint8"},{"internalType":"uint8","name":"tokenIndexTo","type":"uint8"},{"internalType":"uint256","name":"dx","type":"uint256"}],"name":"calculateSwap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bool","name":"deposit","type":"bool"}],"name":"calculateTokenAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimAaveRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAPrecise","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getAdminBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"getToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"getTokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"getTokenIndex","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVirtualPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"_pooledTokens","type":"address[]"},{"internalType":"uint8[]","name":"decimals","type":"uint8[]"},{"internalType":"string","name":"lpTokenName","type":"string"},{"internalType":"string","name":"lpTokenSymbol","type":"string"},{"internalType":"uint256","name":"_a","type":"uint256"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_adminFee","type":"uint256"},{"internalType":"address","name":"lpTokenTargetAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"futureA","type":"uint256"},{"internalType":"uint256","name":"futureTime","type":"uint256"}],"name":"rampA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256[]","name":"minAmounts","type":"uint256[]"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"maxBurnAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityImbalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint8","name":"tokenIndex","type":"uint8"},{"internalType":"uint256","name":"minAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityOneToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newAdminFee","type":"uint256"}],"name":"setAdminFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_reward_receiver","type":"address"}],"name":"setRewardReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newSwapFee","type":"uint256"}],"name":"setSwapFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopRampA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"tokenIndexFrom","type":"uint8"},{"internalType":"uint8","name":"tokenIndexTo","type":"uint8"},{"internalType":"uint256","name":"dx","type":"uint256"},{"internalType":"uint256","name":"minDy","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapStorage","outputs":[{"internalType":"uint256","name":"initialA","type":"uint256"},{"internalType":"uint256","name":"futureA","type":"uint256"},{"internalType":"uint256","name":"initialATime","type":"uint256"},{"internalType":"uint256","name":"futureATime","type":"uint256"},{"internalType":"uint256","name":"swapFee","type":"uint256"},{"internalType":"uint256","name":"adminFee","type":"uint256"},{"internalType":"contract LPToken","name":"lpToken","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAdminFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50613608806100206000396000f3fe608060405234801561001057600080fd5b50600436106101e55760003560e01c80638456cb591161010f578063c4db7fa0116100a2578063e6ab280611610071578063e6ab280614610895578063ef0a712f14610907578063f2fad2b614610924578063f2fde38b14610941576101e5565b8063c4db7fa014610857578063d46300fd1461085f578063dae254dd14610867578063e25aa5fa1461088d576101e5565b806391695586116100de578063916955861461057b57806391ceb3eb146105b7578063a95b089f146105d7578063b28cb6dc14610607576101e5565b80638456cb59146104d857806384cdd9bc146104e05780638beb60b6146105565780638da5cb5b14610573576101e5565b80633f4ba83a116101875780635fd65f0f116101565780635fd65f0f1461040f57806366c0bd2414610458578063715018a61461049457806382b866001461049c576101e5565b80633f4ba83a146103525780634d49e87d1461035a578063593d132c146103d05780635c975abb146103f3576101e5565b8063342a87a1116101c3578063342a87a1146102d557806334e19907146102fb578063377d7c9f146103185780633e3a156014610320576101e5565b80630419b45a146101ea5780630ba81959146101f457806331cd52b01461020e575b600080fd5b6101f2610967565b005b6101fc610a5d565b60408051918252519081900360200190f35b6102856004803603606081101561022457600080fd5b8135919081019060408101602082013564010000000081111561024657600080fd5b82018360208201111561025857600080fd5b8035906020019184602083028401116401000000008311171561027a57600080fd5b919350915035610ae2565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156102c15781810151838201526020016102a9565b505050509050019250505060405180910390f35b6101fc600480360360408110156102eb57600080fd5b508035906020013560ff16610d1f565b6101f26004803603602081101561031157600080fd5b5035610dd3565b6101f2610ed4565b6101fc6004803603608081101561033657600080fd5b5080359060ff60208201351690604081013590606001356110ab565b6101f2611277565b6101fc6004803603606081101561037057600080fd5b81019060208101813564010000000081111561038b57600080fd5b82018360208201111561039d57600080fd5b803590602001918460208302840111640100000000831117156103bf57600080fd5b9193509150803590602001356112f5565b6101f2600480360360408110156103e657600080fd5b5080359060200135611495565b6103fb61159e565b604080519115158252519081900360200190f35b6104176115a7565b604080519788526020880196909652868601949094526060860192909252608085015260a08401526001600160a01b031660c0830152519081900360e00190f35b61047e6004803603602081101561046e57600080fd5b50356001600160a01b03166115c8565b6040805160ff9092168252519081900360200190f35b6101f2611655565b6104bc600480360360208110156104b257600080fd5b503560ff1661172b565b604080516001600160a01b039092168252519081900360200190f35b6101f26117b3565b6101fc600480360360608110156104f657600080fd5b81019060208101813564010000000081111561051157600080fd5b82018360208201111561052357600080fd5b8035906020019184602083028401116401000000008311171561054557600080fd5b91935091508035906020013561182f565b6101f26004803603602081101561056c57600080fd5b50356119cf565b6104bc611ab5565b6101fc600480360360a081101561059157600080fd5b5060ff813581169160208101359091169060408101359060608101359060800135611ac4565b6101fc600480360360208110156105cd57600080fd5b503560ff16611c99565b6101fc600480360360608110156105ed57600080fd5b5060ff813581169160208101359091169060400135611d18565b6101f2600480360361010081101561061e57600080fd5b81019060208101813564010000000081111561063957600080fd5b82018360208201111561064b57600080fd5b8035906020019184602083028401116401000000008311171561066d57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156106bd57600080fd5b8201836020820111156106cf57600080fd5b803590602001918460208302840111640100000000831117156106f157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561074157600080fd5b82018360208201111561075357600080fd5b8035906020019184600183028401116401000000008311171561077557600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092959493602081019350359150506401000000008111156107c857600080fd5b8201836020820111156107da57600080fd5b803590602001918460018302840111640100000000831117156107fc57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050823593505050602081013590604081013590606001356001600160a01b0316611dd3565b6101f2611f66565b6101fc612045565b6101f26004803603602081101561087d57600080fd5b50356001600160a01b0316612099565b6101fc612147565b6101fc600480360360408110156108ab57600080fd5b8101906020810181356401000000008111156108c657600080fd5b8201836020820111156108d857600080fd5b803590602001918460208302840111640100000000831117156108fa57600080fd5b919350915035151561219b565b6101fc6004803603602081101561091d57600080fd5b5035612230565b6102856004803603602081101561093a57600080fd5b50356122be565b6101f26004803603602081101561095757600080fd5b50356001600160a01b0316612408565b61096f612535565b6001600160a01b0316610980611ab5565b6001600160a01b0316146109db576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b739508bf380c1e6f751d97604732ef1bae6673f2996324c5c75160c96109ff611ab5565b6040518363ffffffff1660e01b815260040180838152602001826001600160a01b031681526020019250505060006040518083038186803b158015610a4357600080fd5b505af4158015610a57573d6000803e3d6000fd5b50505050565b600060c97320b587484e75752adac381ae577a7562e7f358c563c9b64dcb90916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610ab157600080fd5b505af4158015610ac5573d6000803e3d6000fd5b505050506040513d6020811015610adb57600080fd5b5051905090565b606060026097541415610b3c576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026097558142811015610b97576040805162461bcd60e51b815260206004820152601060248201527f446561646c696e65206e6f74206d657400000000000000000000000000000000604482015290519081900360640190fd5b60c9739508bf380c1e6f751d97604732ef1bae6673f2996373fd6b3e90918888886040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925060200280828437600081840152601f19601f8201169050808301925050509550505050505060006040518083038186803b158015610c2857600080fd5b505af4158015610c3c573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526020811015610c8357600080fd5b8101908080516040519392919084640100000000821115610ca357600080fd5b908301906020820185811115610cb857600080fd5b8251866020820283011164010000000082111715610cd557600080fd5b82525081516020918201928201910280838360005b83811015610d02578181015183820152602001610cea565b505050509050016040525050509150506001609755949350505050565b604080517fe069274200000000000000000000000000000000000000000000000000000000815260c960048201526024810184905260ff831660448201529051600091739508bf380c1e6f751d97604732ef1bae6673f2999163e069274291606480820192602092909190829003018186803b158015610d9e57600080fd5b505af4158015610db2573d6000803e3d6000fd5b505050506040513d6020811015610dc857600080fd5b505190505b92915050565b610ddb612535565b6001600160a01b0316610dec611ab5565b6001600160a01b031614610e47576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b604080517f467e186c00000000000000000000000000000000000000000000000000000000815260c96004820152602481018390529051739508bf380c1e6f751d97604732ef1bae6673f2999163467e186c916044808301926000929190829003018186803b158015610eb957600080fd5b505af4158015610ecd573d6000803e3d6000fd5b5050505050565b60d45460d7546040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff604482018190526001600160a01b039283166064830181905260606024840190815260d8805460848601819052959096169594929391929091829160a49091019086908015610f7657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610f58575b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f3111e7b300000000000000000000000000000000000000000000000000000000178152905182519297509550859450925090508083835b6020831061103f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611002565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146110a1576040519150601f19603f3d011682016040523d82523d6000602084013e6110a6565b606091505b505050565b600060026097541415611105576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600260975561111261159e565b15611164576040805162461bcd60e51b815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b81804211156111ba576040805162461bcd60e51b815260206004820152601060248201527f446561646c696e65206e6f74206d657400000000000000000000000000000000604482015290519081900360640190fd5b604080517fe7a4db8100000000000000000000000000000000000000000000000000000000815260c960048201526024810188905260ff87166044820152606481018690529051739508bf380c1e6f751d97604732ef1bae6673f2999163e7a4db81916084808301926020929190829003018186803b15801561123c57600080fd5b505af4158015611250573d6000803e3d6000fd5b505050506040513d602081101561126657600080fd5b505160016097559695505050505050565b61127f612535565b6001600160a01b0316611290611ab5565b6001600160a01b0316146112eb576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6112f3612539565b565b60006002609754141561134f576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600260975561135c61159e565b156113ae576040805162461bcd60e51b815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b8180421115611404576040805162461bcd60e51b815260206004820152601060248201527f446561646c696e65206e6f74206d657400000000000000000000000000000000604482015290519081900360640190fd5b60c9739508bf380c1e6f751d97604732ef1bae6673f2996340370edf90918888886040518563ffffffff1660e01b815260040180858152602001806020018381526020018281038252858582818152602001925060200280828437600081840152601f19601f8201169050808301925050509550505050505060206040518083038186803b15801561123c57600080fd5b61149d612535565b6001600160a01b03166114ae611ab5565b6001600160a01b031614611509576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b604080517f58fdd79b00000000000000000000000000000000000000000000000000000000815260c96004820152602481018490526044810183905290517320b587484e75752adac381ae577a7562e7f358c5916358fdd79b916064808301926000929190829003018186803b15801561158257600080fd5b505af4158015611596573d6000803e3d6000fd5b505050505050565b60655460ff1690565b60c95460ca5460cb5460cc5460cd5460ce5460cf546001600160a01b031687565b6001600160a01b038116600081815260d36020526040812054909160ff909116906115f28261172b565b6001600160a01b03161461164d576040805162461bcd60e51b815260206004820152601460248201527f546f6b656e20646f6573206e6f74206578697374000000000000000000000000604482015290519081900360640190fd5b90505b919050565b61165d612535565b6001600160a01b031661166e611ab5565b6001600160a01b0316146116c9576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6033546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603380547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60d05460009060ff831610611787576040805162461bcd60e51b815260206004820152600c60248201527f4f7574206f662072616e67650000000000000000000000000000000000000000604482015290519081900360640190fd5b60d0805460ff841690811061179857fe5b6000918252602090912001546001600160a01b031692915050565b6117bb612535565b6001600160a01b03166117cc611ab5565b6001600160a01b031614611827576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6112f36125e2565b600060026097541415611889576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600260975561189661159e565b156118e8576040805162461bcd60e51b815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b818042111561193e576040805162461bcd60e51b815260206004820152601060248201527f446561646c696e65206e6f74206d657400000000000000000000000000000000604482015290519081900360640190fd5b60c9739508bf380c1e6f751d97604732ef1bae6673f2996341b91c2690918888886040518563ffffffff1660e01b815260040180858152602001806020018381526020018281038252858582818152602001925060200280828437600081840152601f19601f8201169050808301925050509550505050505060206040518083038186803b15801561123c57600080fd5b6119d7612535565b6001600160a01b03166119e8611ab5565b6001600160a01b031614611a43576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b604080517f7046727600000000000000000000000000000000000000000000000000000000815260c96004820152602481018390529051739508bf380c1e6f751d97604732ef1bae6673f299916370467276916044808301926000929190829003018186803b158015610eb957600080fd5b6033546001600160a01b031690565b600060026097541415611b1e576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002609755611b2b61159e565b15611b7d576040805162461bcd60e51b815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b8180421115611bd3576040805162461bcd60e51b815260206004820152601060248201527f446561646c696e65206e6f74206d657400000000000000000000000000000000604482015290519081900360640190fd5b604080517fa5397b2200000000000000000000000000000000000000000000000000000000815260c9600482015260ff808a1660248301528816604482015260648101879052608481018690529051739508bf380c1e6f751d97604732ef1bae6673f2999163a5397b229160a4808301926020929190829003018186803b158015611c5d57600080fd5b505af4158015611c71573d6000803e3d6000fd5b505050506040513d6020811015611c8757600080fd5b50516001609755979650505050505050565b60d05460009060ff831610611cf5576040805162461bcd60e51b815260206004820152601260248201527f496e646578206f7574206f662072616e67650000000000000000000000000000604482015290519081900360640190fd5b60d2805460ff8416908110611d0657fe5b90600052602060002001549050919050565b604080517f4b23603c00000000000000000000000000000000000000000000000000000000815260c9600482015260ff808616602483015284166044820152606481018390529051600091739508bf380c1e6f751d97604732ef1bae6673f29991634b23603c91608480820192602092909190829003018186803b158015611d9f57600080fd5b505af4158015611db3573d6000803e3d6000fd5b505050506040513d6020811015611dc957600080fd5b5051949350505050565b600054610100900460ff1680611dec5750611dec612672565b80611dfa575060005460ff16155b611e355760405162461bcd60e51b815260040180806020018281038252602e815260200180613584602e913960400191505060405180910390fd5b600054610100900460ff16158015611e60576000805460ff1961ff0019909116610100171660011790555b611e708989898989898989612683565b60d480547fffffffffffffffffffffffff00000000000000000000000000000000000000009081167301d83fe6a10d2f2b7af17034343746188272cac91790915560d580548216734f01aed16d97e3ab5ab2b501154dc9bb0f1a5a2c17905560d6805490911673b31f66aa3c1e785363f0875a1b74e27b85fd66c717905560408051602081019091527353f7c5869a859f0aec3d334ee8b4cf01e3492f218152611f1e9060d890600161344d565b5060d780547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790558015611f5b576000805461ff00191690555b505050505050505050565b611f6e612535565b6001600160a01b0316611f7f611ab5565b6001600160a01b031614611fda576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b604080517ff14e211e00000000000000000000000000000000000000000000000000000000815260c9600482015290517320b587484e75752adac381ae577a7562e7f358c59163f14e211e916024808301926000929190829003018186803b158015610a4357600080fd5b600060c97320b587484e75752adac381ae577a7562e7f358c563b0a14cfc90916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610ab157600080fd5b6120a1612535565b6001600160a01b03166120b2611ab5565b6001600160a01b03161461210d576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b60d780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b600060c9739508bf380c1e6f751d97604732ef1bae6673f2996371906c2c90916040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610ab157600080fd5b600060c9739508bf380c1e6f751d97604732ef1bae6673f29963834b491090918686866040518563ffffffff1660e01b8152600401808581526020018060200183151581526020018281038252858582818152602001925060200280828437600081840152601f19601f8201169050808301925050509550505050505060206040518083038186803b158015611d9f57600080fd5b600060c9739508bf380c1e6f751d97604732ef1bae6673f299637d0481609091846040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b15801561228c57600080fd5b505af41580156122a0573d6000803e3d6000fd5b505050506040513d60208110156122b657600080fd5b505192915050565b606060c9739508bf380c1e6f751d97604732ef1bae6673f2996370703e4a9091846040518363ffffffff1660e01b8152600401808381526020018281526020019250505060006040518083038186803b15801561231a57600080fd5b505af415801561232e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561237557600080fd5b810190808051604051939291908464010000000082111561239557600080fd5b9083019060208201858111156123aa57600080fd5b82518660208202830111640100000000821117156123c757600080fd5b82525081516020918201928201910280838360005b838110156123f45781810151838201526020016123dc565b505050509050016040525050509050919050565b612410612535565b6001600160a01b0316612421611ab5565b6001600160a01b03161461247c576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b0381166124c15760405162461bcd60e51b815260040180806020018281038252602681526020018061355e6026913960400191505060405180910390fd5b6033546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b3390565b61254161159e565b612592576040805162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b6065805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6125c5612535565b604080516001600160a01b039092168252519081900360200190a1565b6125ea61159e565b1561263c576040805162461bcd60e51b815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586125c5612535565b600061267d30612e7e565b15905090565b600054610100900460ff168061269c575061269c612672565b806126aa575060005460ff16155b6126e55760405162461bcd60e51b815260040180806020018281038252602e815260200180613584602e913960400191505060405180910390fd5b600054610100900460ff16158015612710576000805460ff1961ff0019909116610100171660011790555b612718612e84565b612720612f3e565b6001895111612776576040805162461bcd60e51b815260206004820152601960248201527f5f706f6f6c6564546f6b656e732e6c656e677468203c3d203100000000000000604482015290519081900360640190fd5b6020895111156127cd576040805162461bcd60e51b815260206004820152601960248201527f5f706f6f6c6564546f6b656e732e6c656e677468203e20333200000000000000604482015290519081900360640190fd5b8751895114612823576040805162461bcd60e51b815260206004820152601f60248201527f5f706f6f6c6564546f6b656e7320646563696d616c73206d69736d6174636800604482015290519081900360640190fd5b6060885167ffffffffffffffff8111801561283d57600080fd5b50604051908082528060200260200182016040528015612867578160200160208202803683370190505b50905060005b8a518160ff161015612ae55760ff8116156129565760d360008c8360ff168151811061289557fe5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff1615801561290557508a8160ff16815181106128d357fe5b60200260200101516001600160a01b03168b6000815181106128f157fe5b60200260200101516001600160a01b031614155b612956576040805162461bcd60e51b815260206004820152601060248201527f4475706c696361746520746f6b656e7300000000000000000000000000000000604482015290519081900360640190fd5b60006001600160a01b03168b8260ff168151811061297057fe5b60200260200101516001600160a01b031614156129d4576040805162461bcd60e51b815260206004820152601d60248201527f546865203020616464726573732069736e277420616e204552432d3230000000604482015290519081900360640190fd5b601260ff168a8260ff16815181106129e857fe5b602002602001015160ff161115612a46576040805162461bcd60e51b815260206004820152601a60248201527f546f6b656e20646563696d616c732065786365656473206d6178000000000000604482015290519081900360640190fd5b612a768a8260ff1681518110612a5857fe5b602002602001015160ff16601260ff16612fd390919063ffffffff16565b600a0a828260ff1681518110612a8857fe5b6020026020010181815250508060d360008d8460ff1681518110612aa857fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191660ff9290921691909117905560010161286d565b50620f42408610612b3d576040805162461bcd60e51b815260206004820152601260248201527f5f612065786365656473206d6178696d756d0000000000000000000000000000604482015290519081900360640190fd5b6305f5e1008510612b95576040805162461bcd60e51b815260206004820152601460248201527f5f6665652065786365656473206d6178696d756d000000000000000000000000604482015290519081900360640190fd5b6402540be4008410612bee576040805162461bcd60e51b815260206004820152601960248201527f5f61646d696e4665652065786365656473206d6178696d756d00000000000000604482015290519081900360640190fd5b6000612bf984613030565b9050806001600160a01b0316634cd88b768a8a6040518363ffffffff1660e01b8152600401808060200180602001838103835285818151815260200191508051906020019080838360005b83811015612c5c578181015183820152602001612c44565b50505050905090810190601f168015612c895780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b83811015612cbc578181015183820152602001612ca4565b50505050905090810190601f168015612ce95780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b158015612d0a57600080fd5b505af1158015612d1e573d6000803e3d6000fd5b505050506040513d6020811015612d3457600080fd5b5051612d87576040805162461bcd60e51b815260206004820152601c60248201527f636f756c64206e6f7420696e6974206c70546f6b656e20636c6f6e6500000000604482015290519081900360640190fd5b60cf80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790558a51612dcd9060d09060208e019061344d565b508151612de19060d19060208501906134ca565b508a5167ffffffffffffffff81118015612dfa57600080fd5b50604051908082528060200260200182016040528015612e24578160200160208202803683370190505b508051612e399160d2916020909101906134ca565b50612e458760646130eb565b60c955612e538760646130eb565b60ca55505060cd84905560ce8390558015611f5b576000805461ff0019169055505050505050505050565b3b151590565b600054610100900460ff1680612e9d5750612e9d612672565b80612eab575060005460ff16155b612ee65760405162461bcd60e51b815260040180806020018281038252602e815260200180613584602e913960400191505060405180910390fd5b600054610100900460ff16158015612f11576000805460ff1961ff0019909116610100171660011790555b612f1961314b565b612f216131eb565b612f296132fc565b8015612f3b576000805461ff00191690555b50565b600054610100900460ff1680612f575750612f57612672565b80612f65575060005460ff16155b612fa05760405162461bcd60e51b815260040180806020018281038252602e815260200180613584602e913960400191505060405180910390fd5b600054610100900460ff16158015612fcb576000805460ff1961ff0019909116610100171660011790555b612f296133a7565b60008282111561302a576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60006040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528260601b60148201527f5af43d82803e903d91602b57fd5bf3000000000000000000000000000000000060288201526037816000f09150506001600160a01b038116611650576040805162461bcd60e51b815260206004820152601660248201527f455243313136373a20637265617465206661696c656400000000000000000000604482015290519081900360640190fd5b6000826130fa57506000610dcd565b8282028284828161310757fe5b04146131445760405162461bcd60e51b81526004018080602001828103825260218152602001806135b26021913960400191505060405180910390fd5b9392505050565b600054610100900460ff16806131645750613164612672565b80613172575060005460ff16155b6131ad5760405162461bcd60e51b815260040180806020018281038252602e815260200180613584602e913960400191505060405180910390fd5b600054610100900460ff16158015612f29576000805460ff1961ff0019909116610100171660011790558015612f3b576000805461ff001916905550565b600054610100900460ff16806132045750613204612672565b80613212575060005460ff16155b61324d5760405162461bcd60e51b815260040180806020018281038252602e815260200180613584602e913960400191505060405180910390fd5b600054610100900460ff16158015613278576000805460ff1961ff0019909116610100171660011790555b6000613282612535565b603380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3508015612f3b576000805461ff001916905550565b600054610100900460ff16806133155750613315612672565b80613323575060005460ff16155b61335e5760405162461bcd60e51b815260040180806020018281038252602e815260200180613584602e913960400191505060405180910390fd5b600054610100900460ff16158015613389576000805460ff1961ff0019909116610100171660011790555b6065805460ff191690558015612f3b576000805461ff001916905550565b600054610100900460ff16806133c057506133c0612672565b806133ce575060005460ff16155b6134095760405162461bcd60e51b815260040180806020018281038252602e815260200180613584602e913960400191505060405180910390fd5b600054610100900460ff16158015613434576000805460ff1961ff0019909116610100171660011790555b60016097558015612f3b576000805461ff001916905550565b8280548282559060005260206000209081019282156134ba579160200282015b828111156134ba57825182547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0390911617825560209092019160019091019061346d565b506134c6929150613511565b5090565b828054828255906000526020600020908101928215613505579160200282015b828111156135055782518255916020019190600101906134ea565b506134c6929150613548565b5b808211156134c65780547fffffffffffffffffffffffff0000000000000000000000000000000000000000168155600101613512565b5b808211156134c6576000815560010161354956fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a26469706673582212203d1493199233d4d48c644299a5ef2cc537c2b80e715194dc051043b6a5585a8464736f6c634300060c0033
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.