Address Details
contract
0xC77E5db3168B551c04605F1B593d7EC6d4BDB92e
- Contract Name
- SpiralsStakingMigration
- Creator
- 0xe1c46d–097af5 at 0x7b9e00–4b9814
- Balance
- 0 CELO ( )
- Locked CELO Balance
- 0.00 CELO
- Voting CELO Balance
- 0.00 CELO
- Pending Unlocked Gold
- 0.00 CELO
- Tokens
-
Fetching tokens...
- Transactions
- 0 Transactions
- Transfers
- 0 Transfers
- Gas Used
- Fetching gas used...
- Last Balance Update
- 15196809
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- SpiralsStakingMigration
- Optimization enabled
- true
- Compiler version
- v0.8.11+commit.d7f03943
- Optimization runs
- 200
- EVM Version
- london
- Verified at
- 2022-09-20T02:05:47.221023Z
src/staking/migration/SpiralsStakingMigration.sol
// SPDX-License-Identifier: Apache-2.0 // https://docs.soliditylang.org/en/v0.8.10/style-guide.html pragma solidity 0.8.11; import "src/staking/SpiralsStakingV2.sol"; import "src/staking/migration/IMigrationToImpactVault.sol"; import "src/vaults/ImpactVault.sol"; import "src/vaults/SpiralsCeloImpactVault.sol"; /// @title SpiralsStakingMigration /// @author @douglasqian /// contract SpiralsStakingMigration is IMigrationToImpactVault, SpiralsStakingV2 { /// @notice Helper function for withdrawing the full amount staked /// for an individual staker to prepare for migration. function withdrawAllForMigration() external onlyOwner whenPaused { // Revoke as much as you can. uint256 totalRevoked; uint256 activeVotes = getActiveVotes(); if (activeVotes > 0) { revokeActive(activeVotes); totalRevoked += activeVotes; } (uint256 pendingVotes, ) = getPendingVotes(); if (pendingVotes > 0) { revokePending(pendingVotes); totalRevoked += pendingVotes; } unlock(totalRevoked); // 3 days later Celo will land in this contract. } /// @notice Pt 2 when we transfer to SpiralsCeloImpactVault. /// @param _yields values will come from subgraph function transferAssetsToImpactVault( address[] memory _addrs, ImpactVault _vault, uint256[] memory _yields ) external onlyOwner whenPaused { for (uint256 i = 0; i < _addrs.length; i++) { transferAssetsToImpactVaultForAddress( _addrs[i], _vault, _yields[i] ); } } function transferAssetsToImpactVaultForAddress( address _address, ImpactVault _vault, uint256 _yield ) public onlyOwner whenPaused { StakerInfo memory s = stakers[_address]; uint256 celoStaked = s.stakedValue + s.withdrawalValue; // withdraw everything! uint256 totalCelo = celoStaked + _yield; if (totalCelo == 0) { return; } stakers[_address].stakedValue = 0; stakers[_address].withdrawalValue = 0; stakers[_address].withdrawalTimestamp = 0; SpiralsCeloImpactVault celoVault = SpiralsCeloImpactVault( payable(address(_vault)) ); IERC20Upgradeable(getGoldToken()).approve(address(_vault), totalCelo); celoVault.depositWithYield(celoStaked, _address, _yield); emit AssetsTransferredToImpactVault( _address, celoStaked, _yield, address(_vault) ); // This event will decrease celo staked count on Spirals subgraph // Should be fine as long as value increases proportionally on // Celo impact vault. emit UserCeloUnstaked(_address, validatorGroup, celoStaked); } /// @dev Returns an Election.sol interface for interacting with the smart contract. function getGoldToken() internal view returns (IERC20Upgradeable) { address electionAddr = c_celoRegistry.getAddressForStringOrDie( "GoldToken" ); return IERC20Upgradeable(electionAddr); } }
/lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlEnumerableUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol) pragma solidity ^0.8.0; import "./IAccessControlEnumerableUpgradeable.sol"; import "./AccessControlUpgradeable.sol"; import "../utils/structs/EnumerableSetUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Extension of {AccessControl} that allows enumerating the members of each role. */ abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerableUpgradeable, AccessControlUpgradeable { function __AccessControlEnumerable_init() internal onlyInitializing { } function __AccessControlEnumerable_init_unchained() internal onlyInitializing { } using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; mapping(bytes32 => EnumerableSetUpgradeable.AddressSet) private _roleMembers; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlEnumerableUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) { return _roleMembers[role].at(index); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) { return _roleMembers[role].length(); } /** * @dev Overload {_grantRole} to track enumerable memberships */ function _grantRole(bytes32 role, address account) internal virtual override { super._grantRole(role, account); _roleMembers[role].add(account); } /** * @dev Overload {_revokeRole} to track enumerable memberships */ function _revokeRole(bytes32 role, address account) internal virtual override { super._revokeRole(role, account); _roleMembers[role].remove(account); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
/lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControlUpgradeable.sol"; import "../utils/ContextUpgradeable.sol"; import "../utils/StringsUpgradeable.sol"; import "../utils/introspection/ERC165Upgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable { function __AccessControl_init() internal onlyInitializing { } function __AccessControl_init_unchained() internal onlyInitializing { } struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", StringsUpgradeable.toHexString(account), " is missing role ", StringsUpgradeable.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
/lib/openzeppelin-contracts-upgradeable/contracts/access/IAccessControlEnumerableUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol) pragma solidity ^0.8.0; import "./IAccessControlUpgradeable.sol"; /** * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. */ interface IAccessControlEnumerableUpgradeable is IAccessControlUpgradeable { /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) external view returns (address); /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) external view returns (uint256); }
/lib/openzeppelin-contracts-upgradeable/contracts/access/IAccessControlUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControlUpgradeable { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
/lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/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 onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { 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 { _transferOwnership(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"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
/lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original * initialization step. This is essential to configure modules that are added through upgrades and that require * initialization. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } }
/lib/openzeppelin-contracts-upgradeable/contracts/security/PausableUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/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 onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { 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()); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
/lib/openzeppelin-contracts-upgradeable/contracts/security/ReentrancyGuardUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { // 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; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "./extensions/IERC20MetadataUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[45] private __gap; }
/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/IERC20Upgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20BurnableUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol) pragma solidity ^0.8.0; import "../ERC20Upgradeable.sol"; import "../../../utils/ContextUpgradeable.sol"; import "../../../proxy/utils/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 onlyInitializing { } function __ERC20Burnable_init_unchained() internal onlyInitializing { } /** * @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 { _spendAllowance(account, _msgSender(), amount); _burn(account, amount); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PausableUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/ERC20Pausable.sol) pragma solidity ^0.8.0; import "../ERC20Upgradeable.sol"; import "../../../security/PausableUpgradeable.sol"; import "../../../proxy/utils/Initializable.sol"; /** * @dev ERC20 token with pausable token transfers, minting and burning. * * Useful for scenarios such as preventing trades until the end of an evaluation * period, or having an emergency switch for freezing all token transfers in the * event of a large bug. */ abstract contract ERC20PausableUpgradeable is Initializable, ERC20Upgradeable, PausableUpgradeable { function __ERC20Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __ERC20Pausable_init_unchained() internal onlyInitializing { } /** * @dev See {ERC20-_beforeTokenTransfer}. * * Requirements: * * - the contract must not be paused. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual override { super._beforeTokenTransfer(from, to, amount); require(!paused(), "ERC20Pausable: token transfer while paused"); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/presets/ERC20PresetMinterPauserUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/presets/ERC20PresetMinterPauser.sol) pragma solidity ^0.8.0; import "../ERC20Upgradeable.sol"; import "../extensions/ERC20BurnableUpgradeable.sol"; import "../extensions/ERC20PausableUpgradeable.sol"; import "../../../access/AccessControlEnumerableUpgradeable.sol"; import "../../../utils/ContextUpgradeable.sol"; import "../../../proxy/utils/Initializable.sol"; /** * @dev {ERC20} token, including: * * - ability for holders to burn (destroy) their tokens * - a minter role that allows for token minting (creation) * - a pauser role that allows to stop all token transfers * * This contract uses {AccessControl} to lock permissioned functions using the * different roles - head to its documentation for details. * * The account that deploys the contract will be granted the minter and pauser * roles, as well as the default admin role, which will let it grant both minter * and pauser roles to other accounts. * * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._ */ contract ERC20PresetMinterPauserUpgradeable is Initializable, ContextUpgradeable, AccessControlEnumerableUpgradeable, ERC20BurnableUpgradeable, ERC20PausableUpgradeable { function initialize(string memory name, string memory symbol) public virtual initializer { __ERC20PresetMinterPauser_init(name, symbol); } bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); /** * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the * account that deploys the contract. * * See {ERC20-constructor}. */ function __ERC20PresetMinterPauser_init(string memory name, string memory symbol) internal onlyInitializing { __ERC20_init_unchained(name, symbol); __Pausable_init_unchained(); __ERC20PresetMinterPauser_init_unchained(name, symbol); } function __ERC20PresetMinterPauser_init_unchained(string memory, string memory) internal onlyInitializing { _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); _setupRole(MINTER_ROLE, _msgSender()); _setupRole(PAUSER_ROLE, _msgSender()); } /** * @dev Creates `amount` new tokens for `to`. * * See {ERC20-_mint}. * * Requirements: * * - the caller must have the `MINTER_ROLE`. */ function mint(address to, uint256 amount) public virtual { require(hasRole(MINTER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have minter role to mint"); _mint(to, amount); } /** * @dev Pauses all token transfers. * * See {ERC20Pausable} and {Pausable-_pause}. * * Requirements: * * - the caller must have the `PAUSER_ROLE`. */ function pause() public virtual { require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have pauser role to pause"); _pause(); } /** * @dev Unpauses all token transfers. * * See {ERC20Pausable} and {Pausable-_unpause}. * * Requirements: * * - the caller must have the `PAUSER_ROLE`. */ function unpause() public virtual { require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have pauser role to unpause"); _unpause(); } function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual override(ERC20Upgradeable, ERC20PausableUpgradeable) { super._beforeTokenTransfer(from, to, amount); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/utils/SafeERC20Upgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/draft-IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.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 SafeERC20Upgradeable { using AddressUpgradeable for address; function safeTransfer( IERC20Upgradeable token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20Upgradeable 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( IERC20Upgradeable token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20PermitUpgradeable token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable 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 require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
/lib/openzeppelin-contracts-upgradeable/contracts/utils/AddressUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://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"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
/lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
/lib/openzeppelin-contracts-upgradeable/contracts/utils/StringsUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
/lib/openzeppelin-contracts-upgradeable/contracts/utils/introspection/ERC165Upgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165Upgradeable).interfaceId; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
/lib/openzeppelin-contracts-upgradeable/contracts/utils/introspection/IERC165Upgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165Upgradeable { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
/lib/openzeppelin-contracts-upgradeable/contracts/utils/math/MathUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`. // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`. // Using an algorithm similar to the msb computation, we are able to compute `result = 2**(k/2)` which is a // good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1; uint256 x = a; if (x >> 128 > 0) { x >>= 128; result <<= 64; } if (x >> 64 > 0) { x >>= 64; result <<= 32; } if (x >> 32 > 0) { x >>= 32; result <<= 16; } if (x >> 16 > 0) { x >>= 16; result <<= 8; } if (x >> 8 > 0) { x >>= 8; result <<= 4; } if (x >> 4 > 0) { x >>= 4; result <<= 2; } if (x >> 2 > 0) { result <<= 1; } // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { uint256 result = sqrt(a); if (rounding == Rounding.Up && result * result < a) { result += 1; } return result; } }
/lib/openzeppelin-contracts-upgradeable/contracts/utils/structs/EnumerableSetUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol) pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. * ==== */ library EnumerableSetUpgradeable { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return _values(set._inner); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
/src/interfaces/IAccounts.sol
// SPDX-License-Identifier: Apache-2.0 // https://github.com/celo-org/celo-monorepo/tree/master/packages/protocol/contracts/governance/interfaces/ILockedGold.sol pragma solidity >=0.5.13; interface IAccounts { function isAccount(address) external view returns (bool); function voteSignerToAccount(address) external view returns (address); function validatorSignerToAccount(address) external view returns (address); function attestationSignerToAccount(address) external view returns (address); function signerToAccount(address) external view returns (address); function getAttestationSigner(address) external view returns (address); function getValidatorSigner(address) external view returns (address); function getVoteSigner(address) external view returns (address); function hasAuthorizedVoteSigner(address) external view returns (bool); function hasAuthorizedValidatorSigner(address) external view returns (bool); function hasAuthorizedAttestationSigner(address) external view returns (bool); function setAccountDataEncryptionKey(bytes calldata) external; function setMetadataURL(string calldata) external; function setName(string calldata) external; function setWalletAddress( address, uint8, bytes32, bytes32 ) external; function setAccount( string calldata, bytes calldata, address, uint8, bytes32, bytes32 ) external; function getDataEncryptionKey(address) external view returns (bytes memory); function getWalletAddress(address) external view returns (address); function getMetadataURL(address) external view returns (string memory); function batchGetMetadataURL(address[] calldata) external view returns (uint256[] memory, bytes memory); function getName(address) external view returns (string memory); function authorizeVoteSigner( address, uint8, bytes32, bytes32 ) external; function authorizeValidatorSigner( address, uint8, bytes32, bytes32 ) external; function authorizeValidatorSignerWithPublicKey( address, uint8, bytes32, bytes32, bytes calldata ) external; function authorizeValidatorSignerWithKeys( address, uint8, bytes32, bytes32, bytes calldata, bytes calldata, bytes calldata ) external; function authorizeAttestationSigner( address, uint8, bytes32, bytes32 ) external; function createAccount() external returns (bool); function setPaymentDelegation(address, uint256) external; function getPaymentDelegation(address) external view returns (address, uint256); }
/src/interfaces/IElection.sol
// SPDX-License-Identifier: Apache-2.0 // https://github.com/celo-org/celo-monorepo/tree/master/packages/protocol/contracts/governance/interfaces/IElection.sol pragma solidity >=0.5.13; interface IElection { function electValidatorSigners() external view returns (address[] memory); function electNValidatorSigners(uint256, uint256) external view returns (address[] memory); function vote( address, uint256, address, address ) external returns (bool); function activate(address) external returns (bool); function revokeActive( address, uint256, address, address, uint256 ) external returns (bool); function revokeAllActive( address, address, address, uint256 ) external returns (bool); function revokePending( address, uint256, address, address, uint256 ) external returns (bool); function markGroupIneligible(address) external; function markGroupEligible( address, address, address ) external; function forceDecrementVotes( address, uint256, address[] calldata, address[] calldata, uint256[] calldata ) external returns (uint256); // view functions function maxNumGroupsVotedFor() external view returns (uint256); function getEpochNumber() external view returns (uint256); function getEpochSize() external view returns (uint256); function getElectableValidators() external view returns (uint256, uint256); function getElectabilityThreshold() external view returns (uint256); function getNumVotesReceivable(address) external view returns (uint256); function getTotalVotes() external view returns (uint256); function getActiveVotes() external view returns (uint256); function getTotalVotesByAccount(address) external view returns (uint256); function getPendingVotesForGroupByAccount(address, address) external view returns (uint256); function getActiveVotesForGroupByAccount(address, address) external view returns (uint256); function getTotalVotesForGroupByAccount(address, address) external view returns (uint256); function getActiveVoteUnitsForGroupByAccount(address, address) external view returns (uint256); function getTotalVotesForGroup(address) external view returns (uint256); function getActiveVotesForGroup(address) external view returns (uint256); function getPendingVotesForGroup(address) external view returns (uint256); function getGroupEligibility(address) external view returns (bool); function getGroupEpochRewards( address, uint256, uint256[] calldata ) external view returns (uint256); function getGroupsVotedForByAccount(address) external view returns (address[] memory); function getEligibleValidatorGroups() external view returns (address[] memory); function getTotalVotesForEligibleValidatorGroups() external view returns (address[] memory, uint256[] memory); function getCurrentValidatorSigners() external view returns (address[] memory); function canReceiveVotes(address, uint256) external view returns (bool); function hasActivatablePendingVotes(address, address) external view returns (bool); // only owner function setElectableValidators(uint256, uint256) external returns (bool); function setMaxNumGroupsVotedFor(uint256) external returns (bool); function setElectabilityThreshold(uint256) external returns (bool); // only VM function distributeEpochRewards( address, uint256, address, address ) external; event ElectableValidatorsSet(uint256 min, uint256 max); event MaxNumGroupsVotedForSet(uint256 maxNumGroupsVotedFor); event ElectabilityThresholdSet(uint256 electabilityThreshold); event ValidatorGroupMarkedEligible(address indexed group); event ValidatorGroupMarkedIneligible(address indexed group); event ValidatorGroupVoteCast( address indexed account, address indexed group, uint256 value ); event ValidatorGroupVoteActivated( address indexed account, address indexed group, uint256 value, uint256 units ); event ValidatorGroupPendingVoteRevoked( address indexed account, address indexed group, uint256 value ); event ValidatorGroupActiveVoteRevoked( address indexed account, address indexed group, uint256 value, uint256 units ); event EpochRewardsDistributedToVoters(address indexed group, uint256 value); }
/src/interfaces/ILockedGold.sol
// SPDX-License-Identifier: Apache-2.0 // https://github.com/celo-org/celo-monorepo/tree/master/packages/protocol/contracts/governance/interfaces/ILockedGold.sol pragma solidity 0.8.11; interface ILockedGold { function incrementNonvotingAccountBalance(address, uint256) external; function decrementNonvotingAccountBalance(address, uint256) external; function getAccountTotalLockedGold(address) external view returns (uint256); function getAccountNonvotingLockedGold(address) external view returns (uint256); function unlockingPeriod() external view returns (uint256); function getTotalLockedGold() external view returns (uint256); function getPendingWithdrawal(address, uint256) external view returns (uint256, uint256); function getPendingWithdrawals(address) external view returns (uint256[] memory, uint256[] memory); function getTotalPendingWithdrawals(address) external view returns (uint256); function lock() external payable; function unlock(uint256) external; function relock(uint256, uint256) external; function withdraw(uint256) external; function slash( address account, uint256 penalty, address reporter, uint256 reward, address[] calldata lessers, address[] calldata greaters, uint256[] calldata indices ) external; function isSlasher(address) external view returns (bool); }
/src/interfaces/IManaged.sol
// SPDX-License-Identifier: Apache-2.0 // https://docs.soliditylang.org/en/v0.8.10/style-guide.html pragma solidity 0.8.11; interface IManaged { function manager() external view returns (address); }
/src/interfaces/IManager.sol
// SPDX-License-Identifier: Apache-2.0 // https://docs.soliditylang.org/en/v0.8.10/style-guide.html pragma solidity 0.8.11; interface IManager { function deposit() external payable; function withdraw(uint256 stCeloAmount) external; function toCelo(uint256 stCeloAmount) external view returns (uint256); function toStakedCelo(uint256 celoAmount) external view returns (uint256); }
/src/interfaces/IRegistry.sol
// SPDX-License-Identifier: Apache-2.0 // https://docs.soliditylang.org/en/v0.8.10/style-guide.html pragma solidity 0.8.11; interface IRegistry { function setAddressFor(string calldata, address) external; function getAddressForOrDie(bytes32) external view returns (address); function getAddressFor(bytes32) external view returns (address); function getAddressForStringOrDie(string calldata identifier) external view returns (address); function getAddressForString(string calldata identifier) external view returns (address); function isOneOf(bytes32[] calldata, address) external view returns (bool); }
/src/interfaces/ISortedOracles.sol
// SPDX-License-Identifier: Apache-2.0 // https://docs.soliditylang.org/en/v0.8.10/style-guide.html pragma solidity 0.8.11; interface ISortedOracles { function addOracle(address, address) external; function removeOracle( address, address, uint256 ) external; function report( address, uint256, address, address ) external; function removeExpiredReports(address, uint256) external; function isOldestReportExpired(address token) external view returns (bool, address); function numRates(address) external view returns (uint256); function medianRate(address) external view returns (uint256, uint256); function numTimestamps(address) external view returns (uint256); function medianTimestamp(address) external view returns (uint256); }
/src/interfaces/IValidators.sol
pragma solidity >=0.8.0; interface IValidators { function registerValidator( bytes calldata, bytes calldata, bytes calldata ) external returns (bool); function deregisterValidator(uint256) external returns (bool); function affiliate(address) external returns (bool); function deaffiliate() external returns (bool); function updateBlsPublicKey(bytes calldata, bytes calldata) external returns (bool); function registerValidatorGroup(uint256) external returns (bool); function deregisterValidatorGroup(uint256) external returns (bool); function addMember(address) external returns (bool); function addFirstMember( address, address, address ) external returns (bool); function removeMember(address) external returns (bool); function reorderMember( address, address, address ) external returns (bool); function updateCommission() external; function setNextCommissionUpdate(uint256) external; function resetSlashingMultiplier() external; // only owner function setCommissionUpdateDelay(uint256) external; function setMaxGroupSize(uint256) external returns (bool); function setMembershipHistoryLength(uint256) external returns (bool); function setValidatorScoreParameters(uint256, uint256) external returns (bool); function setGroupLockedGoldRequirements(uint256, uint256) external returns (bool); function setValidatorLockedGoldRequirements(uint256, uint256) external returns (bool); function setSlashingMultiplierResetPeriod(uint256) external; // view functions function getMaxGroupSize() external view returns (uint256); function getCommissionUpdateDelay() external view returns (uint256); function getValidatorScoreParameters() external view returns (uint256, uint256); function getMembershipHistory(address) external view returns ( uint256[] memory, address[] memory, uint256, uint256 ); function calculateEpochScore(uint256) external view returns (uint256); function calculateGroupEpochScore(uint256[] calldata) external view returns (uint256); function getAccountLockedGoldRequirement(address) external view returns (uint256); function meetsAccountLockedGoldRequirements(address) external view returns (bool); function getValidatorBlsPublicKeyFromSigner(address) external view returns (bytes memory); function getValidator(address account) external view returns ( bytes memory, bytes memory, address, uint256, address ); function getValidatorGroup(address) external view returns ( address[] memory, uint256, uint256, uint256, uint256[] memory, uint256, uint256 ); function getGroupNumMembers(address) external view returns (uint256); function getTopGroupValidators(address, uint256) external view returns (address[] memory); function getGroupsNumMembers(address[] calldata accounts) external view returns (uint256[] memory); function getNumRegisteredValidators() external view returns (uint256); function groupMembershipInEpoch( address, uint256, uint256 ) external view returns (address); // only registered contract function updateEcdsaPublicKey( address, address, bytes calldata ) external returns (bool); function updatePublicKeys( address, address, bytes calldata, bytes calldata, bytes calldata ) external returns (bool); function getValidatorLockedGoldRequirements() external view returns (uint256, uint256); function getGroupLockedGoldRequirements() external view returns (uint256, uint256); function getRegisteredValidators() external view returns (address[] memory); function getRegisteredValidatorSigners() external view returns (address[] memory); function getRegisteredValidatorGroups() external view returns (address[] memory); function isValidatorGroup(address) external view returns (bool); function isValidator(address) external view returns (bool); function getValidatorGroupSlashingMultiplier(address) external view returns (uint256); function getMembershipInLastEpoch(address) external view returns (address); function getMembershipInLastEpochFromSigner(address) external view returns (address); // only VM function updateValidatorScoreFromSigner(address, uint256) external; function distributeEpochPaymentsFromSigner(address, uint256) external returns (uint256); // only slasher function forceDeaffiliateIfValidator(address) external; function halveSlashingMultiplier(address) external; }
/src/staking/SpiralsStaking.sol
// SPDX-License-Identifier: Apache-2.0 // https://docs.soliditylang.org/en/v0.8.10/style-guide.html pragma solidity 0.8.11; import "src/interfaces/IAccounts.sol"; import "src/interfaces/ILockedGold.sol"; import "src/interfaces/IElection.sol"; import "src/interfaces/IRegistry.sol"; import "src/interfaces/IValidators.sol"; /// /// ▐▌ ▛ /// █ /// ▗▛▀▀▌ ▗▛▀▀▀▙ ▐▌ ▟▀▀▘▗▛▀▀▀▙ ▙ ▟▀▀▀▖ /// ▝▙▄ ▛ ▝▌ ▐▌ ▌ ▛ ▝▌ ▛ ▐▄▖▖ /// ▀▙ █ ▐▌ ▐▌ ▛ █ ▐▌ █ ▝▀▌ /// ▐▄▄▄▛ █▚▄▄▄▀ ▐▌ ▛ ▝▙▄▄▄▀▙ ▙ ▜▄▄▄▘ /// ▙ /// ▌ /// /// /// @title SpiralsStaking /// @author @douglasqian /// @notice This smart contract implements a simple staking protocol that /// plugs into Celo's L1 staking. On a high-level, the contract allows callers /// to stake with a designated validator group and unstake from it as well. /// The lockup period is the same as what's on the L1. /// /// Staking through this contract sends value directly to Celo's /// LockedGold contract so there should never be a large amount of /// value accrued in this contract's balance. From a security perspective /// it also means that we are leveraging the testing & auditing done on /// Celo's smart contracts to ensure funds are secured. /// /// Callers who staked through this contract can only redeem the original /// staking amount which means the rewards from staking are managed by the /// contract. /// /// @dev This contract simplifies the staking experience for Spirals users /// because it pushes the responsibility of activation & withdrawal to /// the contract admin. For activation, this means that it's up to us to /// activate the pending votes after the next epoch passes. Every call to /// "stake" resets the timer on behalf of this contract in Celo's Election /// smart contract. /// /// On the other side, users looking to unstake are able to after the /// same lockup period on the L1. This means that Spirals bears the /// responsibility of withdrawing on behalf of the protocol in a timely /// manner to ensure there's enough liquidity. Otherwise, users eligible to /// withdraw from Spirals will not be able to. We also address this by /// allowing deposits into a buffer pool. In the long-run though, building /// some automation around this would be ideal. /// contract SpiralsStaking { /* * Struct Definitions */ struct StakerInfo { uint256 stakedValue; uint256 withdrawalValue; uint256 withdrawalTimestamp; } /* * State Variables */ address public validatorGroup; address private ownerDeprecated; // don't remove this, will change slot assignments uint256 public bufferPool; uint256 public totalPendingWithdrawal; IRegistry constant c_celoRegistry = IRegistry(0x000000000000000000000000000000000000ce10); // TODO: change to nested mapping if we want to support multiple validator groups mapping(address => StakerInfo) stakers; /* * Events */ event Deposit( address indexed sender, uint256 indexed amount, bool isBuffer ); event UserCeloStaked( address indexed _address, address indexed _validatorGroup, uint256 indexed amount ); event ProtocolCeloActivated( address indexed _validatorGroup, uint256 indexed amount ); event UserCeloUnstaked( address indexed _address, address indexed _validatorGroup, uint256 indexed amount ); event UserCeloWithdrawn(address indexed _address, uint256 indexed amount); event ProtocolCeloWithdrawn( uint256 indexed totalAmount, uint256 indexed timestamp ); function initialize(address _validatorGroup) public virtual { validatorGroup = _validatorGroup; require(getAccounts().createAccount(), "CREATE_ACCOUNT_FAILED"); } receive() external payable { emit Deposit(msg.sender, msg.value, false); } /// @notice Allows deposits into the protocol's buffer pool to facilitate /// unstaking. function depositBP() public payable { bufferPool += msg.value; emit Deposit(msg.sender, msg.value, true); } /* * STAKING */ /// @notice Main function for staking with Spirals protocol. /// @dev Since contract call is atomic, staked Celo should never /// end up in this contract (goes straight to LockedGold). function stake() external payable virtual { require(msg.value > 0, "STAKING_ZERO"); lock(msg.value); vote(msg.value); stakers[msg.sender].stakedValue += msg.value; emit UserCeloStaked(msg.sender, validatorGroup, msg.value); } /// @dev Helper function for locking CELO function lock(uint256 _value) internal { require(_value > 0, "LOCKING_ZERO"); getLockedGold().lock{value: _value}(); } /// @dev Helper function for casting votes with a given validator group function vote(uint256 _value) internal { (address lesser, address greater) = getLesserGreater(); require( !(lesser == address(0) && greater == address(0)), "INVALID_LESSER_GREATER" ); // Can't both be null address require( getElection().vote(validatorGroup, _value, lesser, greater), "VOTE_FAILED" ); } /// @dev Helper function for getting the 2 validator groups that /// our target validator group is sandwiched between. function getLesserGreater() internal view returns (address, address) { (address[] memory validatorGroups, ) = getElection() .getTotalVotesForEligibleValidatorGroups(); // sorted by votes desc address lesser = address(0); address greater = address(0); for (uint256 i = 0; i < validatorGroups.length; i++) { if (validatorGroup == validatorGroups[i]) { if (i > 0) { greater = validatorGroups[i - 1]; } if (i < validatorGroups.length - 1) { lesser = validatorGroups[i + 1]; } break; } } return (lesser, greater); } /// @dev Helper function for finding the index of the validator /// group in a list of validator groups voted on by an account. function getGroupIndex(address _group) internal view returns (uint256, bool) { address[] memory votedValidatorGroups = getElection() .getGroupsVotedForByAccount(address(this)); for (uint256 i = 0; i < votedValidatorGroups.length; i++) { if (votedValidatorGroups[i] == _group) { return (i, true); } } return (0, false); } /* * UNSTAKING */ /// @notice Main function for unstaking from Spirals protocol /// @dev A particular user calling "unstake" adds a pending withdrawal /// for Spirals in the Celo smart contracts. After calling this function, /// a user officially unstakes but still needs to "withdraw" after /// the unlocking period is over. function unstake(uint256 _value) public virtual { require( stakers[msg.sender].stakedValue >= _value, "EXCEEDS_USER_STAKE" ); uint256 activeVotes = getActiveVotes(); (uint256 pendingVotes, ) = getPendingVotes(); require(activeVotes + pendingVotes >= _value, "EXCEEDS_PROTOCOL_STAKE"); // Can only support 1 outstanding unstake request at a time (without // rebuilding all of how Celo unstaking works) require( stakers[msg.sender].withdrawalValue == 0, "OUTSTANDING_PENDING_WITHDRAWAL" ); if (activeVotes >= _value) { revokeActive(_value); } else { revokePending(_value); } unlock(_value); StakerInfo memory newStaker = stakers[msg.sender]; newStaker.stakedValue -= _value; newStaker.withdrawalValue = _value; newStaker.withdrawalTimestamp = block.timestamp + getLockedGold().unlockingPeriod(); totalPendingWithdrawal += _value; stakers[msg.sender] = newStaker; emit UserCeloUnstaked(msg.sender, validatorGroup, _value); } /// @notice Helper function for revoking active votes CELO function revokeActive(uint256 _value) internal { (address lesser, address greater) = getLesserGreater(); (uint256 index, bool found) = getGroupIndex(validatorGroup); require(found, "UNSUPPORTED_VALIDATOR_GROUP"); require( getElection().revokeActive( validatorGroup, _value, lesser, greater, index ) ); } /// @notice Helper function for revoking pending votes CELO function revokePending(uint256 _value) internal { (address lesser, address greater) = getLesserGreater(); (uint256 index, bool found) = getGroupIndex(validatorGroup); require(found, "UNSUPPORTED_VALIDATOR_GROUP"); require( getElection().revokePending( validatorGroup, _value, lesser, greater, index ) ); } /// @notice Helper function for unlocking CELO function unlock(uint256 _value) internal { getLockedGold().unlock(_value); } /// @notice Allow user to withdraw their stake back to wallet. /// @dev Withdraws from this contracts balance directly. function withdraw() public virtual { StakerInfo memory s = stakers[msg.sender]; require(s.withdrawalValue > 0, "NO_PENDING_WITHDRAWALS"); require(userCanWithdraw(msg.sender), "WITHDRAWAL_NOT_READY"); payable(msg.sender).transfer(s.withdrawalValue); // should fail if protocol doesn't have enough emit UserCeloWithdrawn(msg.sender, s.withdrawalValue); totalPendingWithdrawal -= s.withdrawalValue; s.withdrawalValue = 0; s.withdrawalTimestamp = 0; stakers[msg.sender] = s; } /// @notice Helper function for checking whether protocol can support /// a user who wants to withdraw. function userCanWithdraw(address _address) public view returns (bool) { StakerInfo memory s = stakers[_address]; return address(this).balance >= s.withdrawalValue && s.withdrawalTimestamp <= block.timestamp; } /* * ADMIN */ /// @notice Activates pending votes (if ready) with a given validator group. /// @dev Onus is on the protocol owners to activate to make sure CELO /// staked with protocol is staked on CELO L1. function activateForProtocol() external { IElection c_election = getElection(); require( c_election.hasActivatablePendingVotes( address(this), validatorGroup ), "NOT_READY_TO_ACTIVATE" ); uint256 pendingVotes = getElection().getPendingVotesForGroupByAccount( validatorGroup, address(this) ); require(c_election.activate(validatorGroup), "ACTIVATE_FAILED"); // all pending -> active for this group emit ProtocolCeloActivated(validatorGroup, pendingVotes); } /// @notice Attemps to withdraw CELO for all pending withdrawals that are /// available for the proxy contract address. /// @dev Onus is on the protocol owners to withdraw CELO from LockedGold function withdrawForProtocol() external { (uint256[] memory values, uint256[] memory timestamps) = getLockedGold() .getPendingWithdrawals(address(this)); require(values.length > 0, "NO_PENDING_WITHDRAWALS"); // loop backwards so withdrawing at a single index doesn't shift indices uint256 withdrawnTotal; for (uint256 i = timestamps.length; i > 0; i--) { if (block.timestamp >= timestamps[i - 1]) { getLockedGold().withdraw(i - 1); withdrawnTotal += values[i - 1]; } } require(withdrawnTotal > 0, "NO_WITHDRAWALS_READY"); if (withdrawnTotal > 0) { emit ProtocolCeloWithdrawn(withdrawnTotal, block.timestamp); } } /* * OTHER */ /// @notice Returns all details relevant to an account staking with Spirals. function getAccount(address _address) public view returns ( uint256, uint256, uint256 ) { StakerInfo memory s = stakers[_address]; return (s.stakedValue, s.withdrawalValue, s.withdrawalTimestamp); } /// @notice For updating with validator group we stake with. Performs /// some simple checks to make sure address given is an eligible /// validator group (limited to 1 for now). function setValidatorGroup(address _newValidatorGroup) external virtual { require( getValidators().isValidatorGroup(_newValidatorGroup), "NOT_VALIDATOR_GROUP" ); require( getElection().getGroupEligibility(_newValidatorGroup), "NOT_ELIGIBLE_VALIDATOR_GROUP" ); validatorGroup = _newValidatorGroup; } /// @notice Get pending votes for this smart contract. function getPendingVotes() public view returns (uint256, bool) { return ( getElection().getPendingVotesForGroupByAccount( validatorGroup, address(this) ), getElection().hasActivatablePendingVotes( address(this), validatorGroup ) ); } /// @notice Get active votes (staked + rewards) for this smart contract. function getActiveVotes() public view returns (uint256) { return getElection().getActiveVotesForGroupByAccount( validatorGroup, address(this) ); } /* * CELO SMART CONTRACT HELPERS */ /// @dev Returns a Accounts.sol interface for interacting with the smart contract. function getAccounts() internal view returns (IAccounts) { address accountsAddr = c_celoRegistry.getAddressForStringOrDie( "Accounts" ); return IAccounts(accountsAddr); } /// @dev Returns an Election.sol interface for interacting with the smart contract. function getElection() internal view returns (IElection) { address electionAddr = c_celoRegistry.getAddressForStringOrDie( "Election" ); return IElection(electionAddr); } /// @dev Returns a LockedGold.sol interface for interacting with the smart contract. function getLockedGold() internal view returns (ILockedGold) { address lockedGoldAddr = c_celoRegistry.getAddressForStringOrDie( "LockedGold" ); return ILockedGold(lockedGoldAddr); } /// @dev Returns a Validators.sol interface for interacting with the smart contract. function getValidators() internal view returns (IValidators) { address validatorsAddr = c_celoRegistry.getAddressForStringOrDie( "Validators" ); return IValidators(validatorsAddr); } }
/src/staking/SpiralsStakingV2.sol
// SPDX-License-Identifier: Apache-2.0 // https://docs.soliditylang.org/en/v0.8.10/style-guide.html pragma solidity 0.8.11; import "src/staking/SpiralsStaking.sol"; import "src/interfaces/IManager.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; /// @title SpiralsStakingV2 /// @author @douglasqian /// @notice This is a 2nd iteration of SpiralsStaking that inherits some /// basic OpenZeppelin upgradeable contracts to enhance security on the /// core staking logic. /// /// @dev We inherit "SpiralsStaking" first so that existing state variables /// preserve their slot assignments. New state variables introduced on this /// smart contract occupy slots after all inherited contract variables /// are assigned. /// contract SpiralsStakingV2 is SpiralsStaking, OwnableUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable { uint256 public totalStaked; uint256 public numStakers; /// @notice Initializes the Spirals staking smart contract. Should only be /// called once (stored in state variable). function initialize(uint8 _version) public reinitializer(_version) { __Ownable_init(); __Pausable_init(); __ReentrancyGuard_init(); if (!getAccounts().isAccount(address(this))) { // Ensures "initialize" is idempotent. require(getAccounts().createAccount(), "CREATE_ACCOUNT_FAILED"); } } /// @notice Pauses the smart contract. This is useful if a critical /// issue or vulnerability is discovered that requires patching or if /// the contract function stop() external onlyOwner { _pause(); } /// @notice Resumes the smart contract. function resume() external onlyOwner { _unpause(); } /// @notice See "stake" in SpiralsStaking.sol /// @dev Same implementation as original with 2 new modifiers. function stake() external payable override nonReentrant whenNotPaused { require(msg.value > 0, "STAKING_ZERO"); lock(msg.value); vote(msg.value); if (stakers[msg.sender].stakedValue == 0) { // msg.sender is a new staker numStakers++; } stakers[msg.sender].stakedValue += msg.value; totalStaked += msg.value; emit UserCeloStaked(msg.sender, validatorGroup, msg.value); } /// @notice See "unstake" in SpiralsStaking.sol /// @dev Same implementation as original with 2 new modifiers. function unstake(uint256 _value) public override nonReentrant whenNotPaused { require( stakers[msg.sender].stakedValue >= _value, "EXCEEDS_USER_STAKE" ); uint256 activeVotes = getActiveVotes(); (uint256 pendingVotes, ) = getPendingVotes(); require(activeVotes + pendingVotes >= _value, "EXCEEDS_PROTOCOL_STAKE"); // Can only support 1 outstanding unstake request at a time (without // rebuilding all of how Celo unstaking works) require( stakers[msg.sender].withdrawalValue == 0, "OUTSTANDING_PENDING_WITHDRAWAL" ); if (_value <= pendingVotes) { // Prefer to revoke from pending so we don't have to activate votes again. revokePending(_value); } else { // Revoke as much from pending as we can, revoke the rest from active. revokePending(pendingVotes); revokeActive(_value - pendingVotes); } unlock(_value); StakerInfo memory newStaker = stakers[msg.sender]; newStaker.stakedValue -= _value; newStaker.withdrawalValue = _value; newStaker.withdrawalTimestamp = block.timestamp + getLockedGold().unlockingPeriod(); totalPendingWithdrawal += _value; totalStaked -= _value; if (newStaker.stakedValue == 0) { // msg.sender unstaked all CELO numStakers--; } stakers[msg.sender] = newStaker; emit UserCeloUnstaked(msg.sender, validatorGroup, _value); } /// @notice See "withdraw" in SpiralsStaking.sol /// @dev Same implementation as original with 2 new modifiers. function withdraw() public override nonReentrant whenNotPaused { StakerInfo memory s = stakers[msg.sender]; require(s.withdrawalValue > 0, "NO_PENDING_WITHDRAWALS"); require(userCanWithdraw(msg.sender), "WITHDRAWAL_NOT_READY"); payable(msg.sender).transfer(s.withdrawalValue); // should fail if protocol doesn't have enough emit UserCeloWithdrawn(msg.sender, s.withdrawalValue); totalPendingWithdrawal -= s.withdrawalValue; s.withdrawalValue = 0; s.withdrawalTimestamp = 0; stakers[msg.sender] = s; } /// @notice See "setValidatorGroup" in SpiralsStaking.sol /// @dev Same implementation as original with 2 new modifiers. function setValidatorGroup(address _newValidatorGroup) external override onlyOwner whenNotPaused { _setValidatorGroup(_newValidatorGroup); } /// @notice Implementation of "setValidatorGroup" function _setValidatorGroup(address _newValidatorGroup) internal onlyOwner whenNotPaused { require( getValidators().isValidatorGroup(_newValidatorGroup), "NOT_VALIDATOR_GROUP" ); require( getElection().getGroupEligibility(_newValidatorGroup), "NOT_ELIGIBLE_VALIDATOR_GROUP" ); validatorGroup = _newValidatorGroup; } }
/src/staking/migration/IMigrationToImpactVault.sol
// SPDX-License-Identifier: Apache-2.0 // https://docs.soliditylang.org/en/v0.8.10/style-guide.html pragma solidity 0.8.11; import "src/vaults/ImpactVault.sol"; interface IMigrationToImpactVault { event AssetsTransferredToImpactVault( address indexed _from, uint256 indexed _amountAssets, uint256 indexed _amountYield, address _vault ); function transferAssetsToImpactVault( address[] memory _addrs, ImpactVault _vault, uint256[] memory _yields ) external; function transferAssetsToImpactVaultForAddress( address _addr, ImpactVault _vault, uint256 _yield ) external; }
/src/vaults/ImpactVault.sol
// SPDX-License-Identifier: Apache-2.0 // https://docs.soliditylang.org/en/v0.8.10/style-guide.html pragma solidity 0.8.11; import {MathUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import {ImpactVaultManager} from "src/vaults/ImpactVaultManager.sol"; /** * @title ImpactVault * @author douglasqian * @notice This contract implements a new token vault standard inspired by * ERC-4626. Key difference is that ImpactVault ERC20 tokens do not * entitle depositors to a portion of the yield earned on the vault. * Instead, shares of yield is tracked to mint a proportional amount of * governance tokens to determine how the vault's yield will be deployed. * * Note: this vault should always be initialized with an ERC20 token * (ex: CELO) and a non-rebasing yield token (ex: stCELO). */ abstract contract ImpactVault is ERC20Upgradeable, PausableUpgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable { using MathUpgradeable for uint256; using SafeERC20Upgradeable for IERC20Upgradeable; error ZeroDeposit(); error ZeroWithdraw(); event Deposit(uint256 _amount, address _receiver); event DepositWithYield(uint256 _amount, address _receiver, uint256 _yield); event WithdrawAsset(uint256 _amount, address _owner, address _receiver); event WithdrawYieldAsset( uint256 _amount, address _owner, address _receiver ); event TransferYieldToManager( address _owner, uint256 _amountYieldAsset, uint256 _amountCUSD ); IERC20Upgradeable internal asset; IERC20Upgradeable internal yieldAsset; address public impactVaultManager; /** * @dev Data structure that allows us to keep track of how much yield * each depositor in the vault is generating. For every depositor, this * is updated on deposits & withdraws. * * yield{t, t-1} = total_value{t} - total_value{t-1} */ struct YieldIndex { // Tracks the amount of yield assets held at last update. // This is important to track because yield generated is calculated // based on how much this share of the vault has appreciated. uint256 amountYieldAssetAtLastUpdate; // Tracks the total value of yield assets associated with a depositor // in the vault at last update. Denominated in "asset" uint256 totalAssetValueAtLastUpdate; // Tracks the total amount of yield accumulated into vault. // Denominated in "asset". uint256 accumulatedYield; } mapping(address => YieldIndex) public yieldIndexMap; /** * @dev Set the underlying asset contracts. Checks invariant: * convertToAsset(convertToYieldAsset(asset)) == asset */ function __ImpactVault_init( IERC20Upgradeable _asset, IERC20Upgradeable _yieldAsset, address _impactVaultManager ) internal onlyInitializing { __ImpactVault_init_unchained(_asset, _yieldAsset, _impactVaultManager); } function __ImpactVault_init_unchained( IERC20Upgradeable _asset, IERC20Upgradeable _yieldAsset, address _impactVaultManager ) internal onlyInitializing { asset = _asset; yieldAsset = _yieldAsset; impactVaultManager = _impactVaultManager; } /** * @notice Returns total asset value of vault. */ function totalAssets() public view virtual returns (uint256) { return asset.balanceOf(address(this)) + convertToAsset(yieldAsset.balanceOf(address(this))); } /** * DEPOSIT */ /** * @notice After asset are deposited in the vault, we stake it in the * underlying staked asset and mint new vault tokens. */ function deposit(uint256 _amount, address _receiver) public virtual whenNotPaused nonReentrant { if (_amount == 0) { revert ZeroDeposit(); } // Using SafeERC20Upgradeable // slither-disable-next-line unchecked-transfer asset.transferFrom(_msgSender(), address(this), _amount); _stake(_amount); _mint(_receiver, _amount); _updateYieldIndexSinceLastUpdate(_receiver, _amount, true); emit Deposit(_amount, _receiver); } /** * @dev For initial migration from V0 staking vaults only. Mint tokens * proportional to principal but stake all of the underlying asset that * can be transferred. Can only be called by a V0 vault. */ function depositWithYield( uint256 _amount, address _receiver, uint256 _yield ) external virtual whenNotPaused nonReentrant onlyV0Vault(_msgSender()) { if (_amount + _yield == 0) { revert ZeroDeposit(); } // Using SafeERC20Upgradeable // slither-disable-next-line unchecked-transfer asset.transferFrom(_msgSender(), address(this), _amount + _yield); _stake(_amount + _yield); _mint(_receiver, _amount); _updateYieldIndexSinceLastUpdate(_receiver, _amount + _yield, true); yieldIndexMap[_receiver].accumulatedYield += _yield; emit DepositWithYield(_amount, _receiver, _yield); } modifier onlyV0Vault(address _vault) { require( ImpactVaultManager(payable(impactVaultManager)).isV0Vault(_vault), "NOT_V0_VAULT" ); _; } /** * WITHDRAW */ /** * @notice Withdraws underlying asset by converting equivalent value in * staked asset and transferring it to the receiver. * @dev Burn vault tokens before withdrawing. */ function withdraw( uint256 _amount, address _receiver, address _owner ) public virtual whenNotPaused nonReentrant { // Capture assets associated with owner before burn. _beforeWithdraw(_amount, _owner); _withdraw(_receiver, _amount); _updateYieldIndexSinceLastUpdate(_owner, _amount, false); emit WithdrawAsset(_amount, _owner, _receiver); } function withdrawAll(address _receiver, address _owner) external virtual { withdraw(balanceOf(_owner), _receiver, _owner); } /** * @notice Withdraws yield asset from owner balance to receiver. * @param _amountAsset Amount to withdraw, denominated in asset. */ function withdrawYieldAsset( uint256 _amountAsset, address _receiver, address _owner ) public virtual whenNotPaused nonReentrant { // Capture assets associated with owner before burn. _beforeWithdraw(_amountAsset, _owner); uint256 amountYieldAssetToWithdraw = convertToYieldAsset(_amountAsset); yieldAsset.transfer(_receiver, amountYieldAssetToWithdraw); _updateYieldIndexSinceLastUpdate(_owner, _amountAsset, false); emit WithdrawYieldAsset(amountYieldAssetToWithdraw, _owner, _receiver); } function withdrawAllYieldAsset(address _receiver, address _owner) external virtual { withdrawYieldAsset(balanceOf(_owner), _receiver, _owner); } /** * @notice Transfers yield associated with a given address to the * ImpactVaultManager and updates their yield index. This can only be * triggered on the vault manager by the owner of the underlying asset. * Returns the amount of yield assets withdrawn from the vault in cUSD. */ function transferYieldToManager(address _address) external virtual whenNotPaused nonReentrant onlyVaultManager returns (uint256 amountToTransferCUSD) { // Withdraw total yield value in cUSD to ImpactVaultManager uint256 amountToTransferYieldAsset = convertToYieldAsset( getYield(_address) ); yieldAsset.transfer(_msgSender(), amountToTransferYieldAsset); // Reset yield index YieldIndex memory yIndex = yieldIndexMap[_address]; yIndex.accumulatedYield = 0; yIndex.amountYieldAssetAtLastUpdate = 0; yIndex.totalAssetValueAtLastUpdate = balanceOf(_address); // just assets yieldIndexMap[_address] = yIndex; amountToTransferCUSD = convertToUSD( convertToAsset(amountToTransferYieldAsset) ); emit TransferYieldToManager( _address, amountToTransferYieldAsset, amountToTransferCUSD ); return amountToTransferCUSD; } modifier onlyVaultManager() { require(_msgSender() == impactVaultManager); _; } /** * @dev Common hook called before all withdrawal flows. */ function _beforeWithdraw(uint256 _amount, address _owner) internal virtual { if (_amount == 0) { revert ZeroWithdraw(); } address caller = _msgSender(); if (caller != _owner) { _spendAllowance(_owner, caller, _amount); } _burn(_owner, _amount); } /** * YIELD INDEX */ /** * @dev Updates the yield index for a given address. Yield values * should not change before & after this (invariant). * * @param _address Address of the depositor * @param _amount Amount of asset being deposited/withdrawn * @param _isDeposit True if deposit otherwise withdraw */ function _updateYieldIndexSinceLastUpdate( address _address, uint256 _amount, bool _isDeposit ) internal virtual { uint256 yieldBeforeUpdate = getYield(_address); // Adjust the yield asset balance associated with this address. YieldIndex memory yIndex = yieldIndexMap[_address]; if (_isDeposit) { yIndex.amountYieldAssetAtLastUpdate += convertToYieldAsset(_amount); } else { yIndex.amountYieldAssetAtLastUpdate -= convertToYieldAsset(_amount); } // Update total value of yield asset (denominated in asset). yIndex.totalAssetValueAtLastUpdate = convertToAsset( yIndex.amountYieldAssetAtLastUpdate ); yIndex.accumulatedYield += _yieldEarnedSinceLastUpdate(_address); yieldIndexMap[_address] = yIndex; uint256 yieldAfterUpdate = getYield(_address); require(yieldBeforeUpdate == yieldAfterUpdate, "YIELD_SHOULDNT_CHANGE"); } /** * @dev Computes the yield earned by yield assets since the last index update. */ function _yieldEarnedSinceLastUpdate(address _address) internal view returns (uint256) { uint256 assetValueNow = convertToAsset( yieldIndexMap[_address].amountYieldAssetAtLastUpdate ); uint256 assetValueAtLastUpdate = yieldIndexMap[_address] .totalAssetValueAtLastUpdate; // Capped at current value to prevent potential underflow from rounding errors. return assetValueNow - MathUpgradeable.min(assetValueNow, assetValueAtLastUpdate); } /** * @notice Returns total yield generated on vault in the underlying asset. */ function totalYield() public view virtual returns (uint256) { return totalAssets() - totalSupply(); } function totalYieldUSD() public view virtual returns (uint256) { return convertToUSD(totalYield()); } /** * @notice Returns yield in vault associated with a depositor in underlying asset. */ function getYield(address _address) public view virtual returns (uint256) { return yieldIndexMap[_address].accumulatedYield + _yieldEarnedSinceLastUpdate(_address); } /** * @notice Returns yield in vault associated with a depositor in cUSD. */ function getYieldUSD(address _address) public view virtual returns (uint256) { return convertToUSD(getYield(_address)); } function pause() external onlyOwner { _pause(); } function unpause() external onlyOwner { _unpause(); } /** * TO BE IMPLEMENTED */ /** * @notice Converts an amount of the underlying asset to its value in cUSD. */ function convertToUSD(uint256 _assetAmount) public view virtual returns (uint256); /** * @dev Converts amount of yield asset to asset. */ function convertToAsset(uint256 _amountYieldAsset) public view virtual returns (uint256); /** * @dev Converts amount of asset to yield asset. */ function convertToYieldAsset(uint256 _amountAsset) public view virtual returns (uint256); /** * @dev Post-deposit hook to stake assets deposited and store in vault. */ function _stake(uint256 _assets) internal virtual; /** * @dev Core logic for withdrawing from staked asset contract to * receive underlying asset that we send back to receiver. */ function _withdraw(address _receiver, uint256 _amount) internal virtual; }
/src/vaults/ImpactVaultManager.sol
// SPDX-License-Identifier: Apache-2.0 // https://docs.soliditylang.org/en/v0.8.10/style-guide.html pragma solidity 0.8.11; import {MathUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import {ImpactVault} from "src/vaults/ImpactVault.sol"; import {ERC20PresetMinterPauserUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/presets/ERC20PresetMinterPauserUpgradeable.sol"; /** * @title ImpactVaultManager * @author douglasqian * @notice This contract implements a new token vault standard inspired by * ERC-4626. Key difference is that ImpactVault ERC20 tokens do not * entitle depositors to a portion of the yield earned on the vault. * Instead, shares of yield is tracked to mint a proportional amount of * governance tokens to determine how the vault's yield will be deployed. * * Note: this vault should always be initialized with an ERC20 token * (ex: CELO) and a non-rebasing yield token (ex: stCELO). */ contract ImpactVaultManager is PausableUpgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable { event Receive(address indexed sender, uint256 indexed amount); event ImpactVaultRegistered(address indexed vault); event ImpactVaultDeregistered(address indexed vault); event V0VaultRegistered(address indexed vault); event V0VaultDeregistered(address indexed vault); event DependenciesUpdated( address indexed manager, address indexed registry ); // New vaults that implement the ImpactVault interface. address[] public impactVaults; ERC20PresetMinterPauserUpgradeable c_SPRL; // Original Spirals staking contracts. Not backward compatible with // ImpactVault interface so stored separately. address[] public v0Vaults; receive() external payable { emit Receive(msg.sender, msg.value); } function initialize(address _sprlTokenAddress) external initializer { __Ownable_init(); __Pausable_init(); __ReentrancyGuard_init(); // Ensures that `_owner` is set setDependencies(_sprlTokenAddress); } function setDependencies(address _sprlTokenAddress) public onlyOwner { c_SPRL = ERC20PresetMinterPauserUpgradeable(_sprlTokenAddress); } /** * @notice Add a new ImpactVault */ function registerVault(address _vaultToAdd) external onlyOwner whenNotPaused onlyNotRegisteredVault(impactVaults, _vaultToAdd) { impactVaults.push(_vaultToAdd); emit ImpactVaultRegistered(_vaultToAdd); } /** * @notice For migration purposes only. */ function registerV0Vault(address _vaultToAdd) external onlyOwner whenNotPaused onlyNotRegisteredVault(v0Vaults, _vaultToAdd) { v0Vaults.push(_vaultToAdd); emit V0VaultRegistered(_vaultToAdd); } /** * @notice Remove a registered ImpactVault */ function deregisterVault(address _vaultToRemove) external onlyOwner whenNotPaused onlyRegisteredVault(impactVaults, _vaultToRemove) { for (uint256 i = 0; i < impactVaults.length; i++) { if (impactVaults[i] == _vaultToRemove) { impactVaults[i] = impactVaults[impactVaults.length - 1]; impactVaults.pop(); break; } } emit ImpactVaultDeregistered(_vaultToRemove); } function deregisterV0Vault(address _vaultToRemove) external onlyOwner whenNotPaused onlyRegisteredVault(v0Vaults, _vaultToRemove) { for (uint256 i = 0; i < v0Vaults.length; i++) { if (v0Vaults[i] == _vaultToRemove) { v0Vaults[i] = v0Vaults[v0Vaults.length - 1]; v0Vaults.pop(); break; } } emit V0VaultDeregistered(_vaultToRemove); } modifier onlyRegisteredVault(address[] memory _vaults, address _vault) { require(isRegisteredVault(_vaults, _vault), "VAULT_NOT_REGISTERED"); _; } modifier onlyNotRegisteredVault(address[] memory _vaults, address _vault) { require( !isRegisteredVault(_vaults, _vault), "VAULT_ALREADY_REGISTERED" ); _; } function isImpactVault(address _vault) public view returns (bool) { return isRegisteredVault(impactVaults, _vault); } function isV0Vault(address _vault) public view returns (bool) { return isRegisteredVault(v0Vaults, _vault); } function isRegisteredVault(address[] memory _vaults, address _vault) internal pure returns (bool isRegistered) { for (uint256 i = 0; i < _vaults.length; i++) { if (_vaults[i] == _vault) { isRegistered = true; break; } } return isRegistered; } /** * @notice Claims SPRL governance tokens for a given address in proportion * to the yield associated with that address across all registered vaults. * * Withdraws underlying yield assets from vault into this contract. */ function claimGovernanceTokens() external whenNotPaused nonReentrant { uint256 totalYieldUSD; for (uint256 i = 0; i < impactVaults.length; i++) { totalYieldUSD += ImpactVault(impactVaults[i]) .transferYieldToManager(_msgSender()); } c_SPRL.mint(_msgSender(), totalYieldUSD); } /** * @dev Returns the total yield in cUSD associated with a given address * across all impact vaults. */ function getTotalYieldCUSD(address _address) public view returns (uint256 totalYieldUSD) { for (uint256 i = 0; i < impactVaults.length; i++) { uint256 y = ImpactVault(impactVaults[i]).getYieldUSD(_address); totalYieldUSD += y; } return totalYieldUSD; } function pause() external onlyOwner { _pause(); } function unpause() external onlyOwner { _unpause(); } }
/src/vaults/SpiralsCeloImpactVault.sol
// SPDX-License-Identifier: Apache-2.0 // https://docs.soliditylang.org/en/v0.8.10/style-guide.html pragma solidity 0.8.11; import {IManager} from "src/interfaces/IManager.sol"; import {IManaged} from "src/interfaces/IManaged.sol"; import {ILockedGold} from "src/interfaces/ILockedGold.sol"; import {IRegistry} from "src/interfaces/IRegistry.sol"; import {ISortedOracles} from "src/interfaces/ISortedOracles.sol"; import {ImpactVault} from "src/vaults/ImpactVault.sol"; import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import {MathUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; /** * @title SpiralsCeloImpactVault * @author @douglasqian * @notice Implementation of ImpactVault on the Celo Gold token (ERC20 * wrapping Celo chain-native currency). Celo deposited is staked in * the staked Celo (stCelo) liquid staking protocol. Withdrawing back * into Celo is subject to the chain's unlocking period (72 hours) * so this contract stages withdrawals until users come back to claim them. * For simplicity, each user can only have 1 outstanding withdrawal at * any given point in time. */ contract SpiralsCeloImpactVault is ImpactVault { using SafeERC20Upgradeable for IERC20Upgradeable; using MathUpgradeable for uint256; error WithdrawOutstanding( address receiver, uint256 value, uint256 timestamp ); error WithdrawNotReady(address receiver, uint256 timestamp); event Receive(address indexed sender, uint256 indexed amount); event Claim(address indexed receiver, uint256 indexed amount); event DependenciesUpdated( address indexed stCelo, address indexed manager, address indexed registry ); struct WithdrawalInfo { uint256 value; uint256 timestamp; } mapping(address => WithdrawalInfo) internal withdrawals; IManager internal c_stCeloManager; IRegistry internal c_celoRegistry; /** * Inititalize as ImpactVault. * asset -> CELO * yieldAsset -> stCELO */ function initialize( address _stCeloTokenAddress, address _stCeloManagerAddress, address _celoRegistryAddress, address _impactVaultManagerAddress ) external initializer { __Ownable_init(); __Pausable_init(); __ReentrancyGuard_init(); // Ensures that `_owner` is set. setDependencies( _stCeloTokenAddress, _stCeloManagerAddress, _celoRegistryAddress ); // Ensures that `_stCeloTokenAddress` has been sanitized. __ERC20_init("Spirals Celo Vault Token", "spCELO"); __ImpactVault_init( getGoldToken(), IERC20Upgradeable(_stCeloTokenAddress), _impactVaultManagerAddress ); } receive() external payable { emit Receive(msg.sender, msg.value); } /** * @notice Sets dependencies on contract (stCELO contract addresses). */ function setDependencies( address _stCeloTokenAddress, address _stCeloManagerAddress, address _celoRegistryAddress ) public onlyOwner { require( IManaged(_stCeloTokenAddress).manager() == _stCeloManagerAddress, "NON_MATCHING_STCELO_MANAGER" ); require( IRegistry(_celoRegistryAddress).getAddressForStringOrDie( "Validators" ) != address(0), "INVALID_REGISTRY_ADDRESS" ); c_stCeloManager = IManager(_stCeloManagerAddress); c_celoRegistry = IRegistry(_celoRegistryAddress); emit DependenciesUpdated( _stCeloTokenAddress, _stCeloManagerAddress, _celoRegistryAddress ); } /** * DEPOSIT */ /** * @dev Slight variant of ImpactVault.deposit that uses msg.value */ function depositCelo(address _receiver) external payable virtual whenNotPaused nonReentrant { if (msg.value == 0) { revert ZeroDeposit(); } // Using SafeERC20Upgradeable // slither-disable-next-line unchecked-transfer uint256 amount = msg.value; _stake(amount); _mint(_receiver, amount); _updateYieldIndexSinceLastUpdate(_receiver, amount, true); emit Deposit(amount, _receiver); } /** * @dev Deposit CELO into stCELO Manager. */ function _stake(uint256 _amount) internal virtual override { // Verifying "c_stCeloManager" when dependencies are set. // slither-disable-next-line arbitrary-send-eth c_stCeloManager.deposit{value: _amount}(); } /** * @dev Initiates CELO withdraw from stCELO Manager contract and * marks outstanding withdrawal (only 1 at a time). */ function _withdraw(address _receiver, uint256 _amount) internal virtual override { WithdrawalInfo memory withdrawInfo = withdrawals[_receiver]; if (hasOutstandingWithdrawal(_receiver)) { revert WithdrawOutstanding( _receiver, withdrawInfo.value, withdrawInfo.timestamp ); } // Initiate CELO withdraw by burning stCELO, will land in contract // automatically after 3 days. // // spCELO burned in "_beforeWithdraw" before initiating withdraw so reentrant call will fail. // slither-disable-next-line reentrancy-no-eth uint256 stCeloAmount = c_stCeloManager.toStakedCelo(_amount); c_stCeloManager.withdraw(stCeloAmount); withdrawInfo.value = _amount; withdrawInfo.timestamp = block.timestamp + getLockedGold().unlockingPeriod(); withdrawals[_receiver] = withdrawInfo; } /** * @dev Withdraws CELO from this contract into msg.sender's address. */ function claim() external virtual whenNotPaused nonReentrant { if (!hasWithdrawalReady(_msgSender())) { revert WithdrawNotReady( _msgSender(), withdrawals[_msgSender()].timestamp ); } WithdrawalInfo memory withdrawInfo = withdrawals[_msgSender()]; uint256 celoToWithdraw = withdrawInfo.value; // Reset these values transfer to protect against re-entrancy withdrawInfo.value = 0; withdrawInfo.timestamp = 0; withdrawals[_msgSender()] = withdrawInfo; // Using SafeERC20Upgradeable // slither-disable-next-line unchecked-transfer getGoldToken().transfer(_msgSender(), celoToWithdraw); emit Claim(_msgSender(), celoToWithdraw); } /** * @dev Returns true if the current user has an oustanding withdrawal. */ function hasOutstandingWithdrawal(address _address) public view returns (bool) { return withdrawals[_address].timestamp != 0; } /** * @dev Returns true if current user's pending withdrawal is ready. */ function hasWithdrawalReady(address _address) public view returns (bool) { uint256 ts = withdrawals[_address].timestamp; // This is ok because even if a validator messes with timestamp, // spCELO tokens are still being burned during withdraw to prevent // double-dipping on withdraws. Worst case is that someone taps // into the staged CELO on this contract earlier than they're supposed // to, but they shouldn't be able to withdraw more than their tokens // entitle them to. The limitation that there can only be 1 outstanding // withdrawal at a time and a significant unlocking period also means // that one would have to spoof the block time quite significantly // to the point where other validators would accept these blocks (~3 days). // // slither-disable-next-line timestamp return ts != 0 && block.timestamp >= ts; } /** * @dev CELO -> cUSD */ function convertToUSD(uint256 _amountAsset) public view virtual override returns (uint256 usdAmount) { ISortedOracles sortedOracles = ISortedOracles( c_celoRegistry.getAddressForStringOrDie("SortedOracles") ); // Returns the price of cUSD relative to Celo. (uint256 rateNumerator, uint256 rateDenominator) = sortedOracles .medianRate(address(getStableToken())); return _amountAsset.mulDiv(rateNumerator, rateDenominator); } /** * @dev stCELO -> CELO */ function convertToAsset(uint256 _amountYieldAsset) public view virtual override returns (uint256) { return c_stCeloManager.toCelo(_amountYieldAsset); } /** * @dev CELO -> stCELO */ function convertToYieldAsset(uint256 _amountAsset) public view virtual override returns (uint256) { return c_stCeloManager.toStakedCelo(_amountAsset); } /** * @dev Returns GoldToken contract (Celo). */ function getGoldToken() internal view returns (IERC20Upgradeable) { address goldTokenAddr = IRegistry(c_celoRegistry) .getAddressForStringOrDie("GoldToken"); return IERC20Upgradeable(goldTokenAddr); } /** * @dev Returns StableToken contract (cUSD). */ function getStableToken() internal view returns (IERC20Upgradeable) { address stableTokenAddr = IRegistry(c_celoRegistry) .getAddressForStringOrDie("StableToken"); return IERC20Upgradeable(stableTokenAddr); } /// @dev Returns LockedGold contract. function getLockedGold() internal view returns (ILockedGold) { address lockedGoldAddr = IRegistry(c_celoRegistry) .getAddressForStringOrDie("LockedGold"); return ILockedGold(lockedGoldAddr); } }
Contract ABI
[{"type":"event","name":"AssetsTransferredToImpactVault","inputs":[{"type":"address","name":"_from","internalType":"address","indexed":true},{"type":"uint256","name":"_amountAssets","internalType":"uint256","indexed":true},{"type":"uint256","name":"_amountYield","internalType":"uint256","indexed":true},{"type":"address","name":"_vault","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Deposit","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":true},{"type":"bool","name":"isBuffer","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"type":"uint8","name":"version","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Paused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"ProtocolCeloActivated","inputs":[{"type":"address","name":"_validatorGroup","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"ProtocolCeloWithdrawn","inputs":[{"type":"uint256","name":"totalAmount","internalType":"uint256","indexed":true},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"Unpaused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"UserCeloStaked","inputs":[{"type":"address","name":"_address","internalType":"address","indexed":true},{"type":"address","name":"_validatorGroup","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"UserCeloUnstaked","inputs":[{"type":"address","name":"_address","internalType":"address","indexed":true},{"type":"address","name":"_validatorGroup","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"UserCeloWithdrawn","inputs":[{"type":"address","name":"_address","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"activateForProtocol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"bufferPool","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"depositBP","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAccount","inputs":[{"type":"address","name":"_address","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getActiveVotes","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"bool","name":"","internalType":"bool"}],"name":"getPendingVotes","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"uint8","name":"_version","internalType":"uint8"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_validatorGroup","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"numStakers","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"resume","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setValidatorGroup","inputs":[{"type":"address","name":"_newValidatorGroup","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"stake","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stop","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalPendingWithdrawal","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalStaked","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferAssetsToImpactVault","inputs":[{"type":"address[]","name":"_addrs","internalType":"address[]"},{"type":"address","name":"_vault","internalType":"contract ImpactVault"},{"type":"uint256[]","name":"_yields","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferAssetsToImpactVaultForAddress","inputs":[{"type":"address","name":"_address","internalType":"address"},{"type":"address","name":"_vault","internalType":"contract ImpactVault"},{"type":"uint256","name":"_yield","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unstake","inputs":[{"type":"uint256","name":"_value","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"userCanWithdraw","inputs":[{"type":"address","name":"_address","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"validatorGroup","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawAllForMigration","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawForProtocol","inputs":[]},{"type":"receive","stateMutability":"payable"}]
Contract Creation Code
0x608060405234801561001057600080fd5b50612a59806100206000396000f3fe6080604052600436106101a05760003560e01c8063680104c5116100ec578063a798283f1161008a578063c4d66de811610064578063c4d66de81461045b578063d41e97201461047b578063f2fde38b14610491578063fbcbc0f1146104b157600080fd5b8063a798283f14610410578063aa0068cf14610426578063ac4603eb1461043b57600080fd5b8063715018a6116100c6578063715018a6146103bf578063817b1cd2146103d45780638c1a5d01146103ea5780638da5cb5b146103f257600080fd5b8063680104c5146103745780636c8b052a146103945780636e92462b146103aa57600080fd5b80633a4b66f11161015957806341e8ea281161013357806341e8ea28146102ec5780634351e6b61461030c578063486475991461032c5780635c975abb1461035c57600080fd5b80633a4b66f1146102975780633ccfd60b1461029f578063417c393d146102b457600080fd5b8063046f7da2146101e45780630617e1cf146101fb57806307da68f5146102105780631f604243146102255780631f8dfbd31461024d5780632e17de781461027757600080fd5b366101df5760405160008152349033907f693c1828300d1cab0919b948d714897f817e305af51c026ad14233b6a8939adb9060200160405180910390a3005b600080fd5b3480156101f057600080fd5b506101f961052b565b005b34801561020757600080fd5b506101f961053d565b34801561021c57600080fd5b506101f961076f565b34801561023157600080fd5b5061023a61077f565b6040519081526020015b60405180910390f35b34801561025957600080fd5b50610262610801565b60408051928352901515602083015201610244565b34801561028357600080fd5b506101f96102923660046124bb565b610902565b6101f9610c0f565b3480156102ab57600080fd5b506101f9610d39565b3480156102c057600080fd5b506000546102d4906001600160a01b031681565b6040516001600160a01b039091168152602001610244565b3480156102f857600080fd5b506101f96103073660046124f9565b610ee9565b34801561031857600080fd5b506101f961032736600461253a565b6110fa565b34801561033857600080fd5b5061034c61034736600461255d565b611314565b6040519015158152602001610244565b34801561036857600080fd5b50606a5460ff1661034c565b34801561038057600080fd5b506101f961038f36600461255d565b61136e565b3480156103a057600080fd5b5061023a60cf5481565b3480156103b657600080fd5b506101f961138a565b3480156103cb57600080fd5b506101f96115be565b3480156103e057600080fd5b5061023a60ce5481565b6101f96115d0565b3480156103fe57600080fd5b506038546001600160a01b03166102d4565b34801561041c57600080fd5b5061023a60025481565b34801561043257600080fd5b506101f9611621565b34801561044757600080fd5b506101f9610456366004612650565b61168c565b34801561046757600080fd5b506101f961047636600461255d565b6116fd565b34801561048757600080fd5b5061023a60035481565b34801561049d57600080fd5b506101f96104ac36600461255d565b6117c7565b3480156104bd57600080fd5b506105106104cc36600461255d565b6001600160a01b0316600090815260046020908152604091829020825160608101845281548082526001830154938201849052600290920154930183905292909190565b60408051938452602084019290925290820152606001610244565b61053361183d565b61053b611897565b565b60006105476118e9565b60005460405163098fb3dd60e21b81523060048201526001600160a01b03918216602482015291925082169063263ecf7490604401602060405180830381865afa158015610599573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bd9190612725565b6106065760405162461bcd60e51b81526020600482015260156024820152744e4f545f52454144595f544f5f414354495641544560581b60448201526064015b60405180910390fd5b60006106106118e9565b600054604051639b95975f60e01b81526001600160a01b039182166004820152306024820152911690639b95975f90604401602060405180830381865afa15801561065f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106839190612747565b600054604051630716a76760e21b81526001600160a01b039182166004820152919250831690631c5a9d9c906024016020604051808303816000875af11580156106d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f59190612725565b6107335760405162461bcd60e51b815260206004820152600f60248201526e1050d5125590551157d19052531151608a1b60448201526064016105fd565b6000805460405183926001600160a01b03909216917fca287ca3252932704109e3adbc2d726718b9c6b00d12049534d899bb8e19e7f091a35050565b61077761183d565b61053b61196f565b60006107896118e9565b6000546040516334f890a960e21b81526001600160a01b03918216600482015230602482015291169063d3e242a490604401602060405180830381865afa1580156107d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fc9190612747565b905090565b60008061080c6118e9565b600054604051639b95975f60e01b81526001600160a01b039182166004820152306024820152911690639b95975f90604401602060405180830381865afa15801561085b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087f9190612747565b6108876118e9565b60005460405163098fb3dd60e21b81523060048201526001600160a01b03918216602482015291169063263ecf7490604401602060405180830381865afa1580156108d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fa9190612725565b915091509091565b6002609c5414156109255760405162461bcd60e51b81526004016105fd90612760565b6002609c556109326119ac565b336000908152600460205260409020548111156109865760405162461bcd60e51b8152602060048201526012602482015271455843454544535f555345525f5354414b4560701b60448201526064016105fd565b600061099061077f565b9050600061099c610801565b509050826109aa82846127ad565b10156109f15760405162461bcd60e51b8152602060048201526016602482015275455843454544535f50524f544f434f4c5f5354414b4560501b60448201526064016105fd565b3360009081526004602052604090206001015415610a515760405162461bcd60e51b815260206004820152601e60248201527f4f55545354414e44494e475f50454e44494e475f5749544844524157414c000060448201526064016105fd565b808311610a6657610a61836119f2565b610a81565b610a6f816119f2565b610a81610a7c82856127c5565b611b13565b610a8a83611be5565b33600090815260046020908152604091829020825160608101845281548082526001830154938201939093526002909101549281019290925284908290610ad29083906127c5565b90525060208101849052610ae4611c48565b6001600160a01b03166320637d8e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b459190612747565b610b4f90426127ad565b604082015260038054859190600090610b699084906127ad565b925050819055508360ce6000828254610b8291906127c5565b90915550508051610ba35760cf8054906000610b9d836127dc565b91905055505b33600081815260046020908152604080832085518155918501516001830155848101516002909201919091558154905187936001600160a01b03909216927f1d9cacc586dec6c2956710b69efd1866c8621d4132f107ef3e49040bdb6df47191a450506001609c555050565b6002609c541415610c325760405162461bcd60e51b81526004016105fd90612760565b6002609c55610c3f6119ac565b60003411610c7e5760405162461bcd60e51b815260206004820152600c60248201526b5354414b494e475f5a45524f60a01b60448201526064016105fd565b610c8734611c8d565b610c9034611d2a565b33600090815260046020526040902054610cba5760cf8054906000610cb4836127f3565b91905055505b3360009081526004602052604081208054349290610cd99084906127ad565b925050819055503460ce6000828254610cf291906127ad565b90915550506000805460405134926001600160a01b039092169133917fd5f44d85e0d349356f32ca770a4f4947ed8a5542b66e733b90017cdf46f8f38e9190a46001609c55565b6002609c541415610d5c5760405162461bcd60e51b81526004016105fd90612760565b6002609c55610d696119ac565b33600090815260046020908152604091829020825160608101845281548152600182015492810183905260029091015492810192909252610de55760405162461bcd60e51b81526020600482015260166024820152754e4f5f50454e44494e475f5749544844524157414c5360501b60448201526064016105fd565b610dee33611314565b610e315760405162461bcd60e51b81526020600482015260146024820152735749544844524157414c5f4e4f545f524541445960601b60448201526064016105fd565b6020810151604051339180156108fc02916000818181858888f19350505050158015610e61573d6000803e3d6000fd5b50602081015160405133907fefff521bc5c8341dd70e7ab8fd1ef08957d49310c246915f1c7a72f3f3254ee590600090a3806020015160036000828254610ea891906127c5565b909155505060006020808301828152604080850184815233855260049093529092209251835590516001808401919091559051600290920191909155609c55565b610ef161183d565b610ef9611e66565b6001600160a01b038316600090815260046020908152604080832081516060810183528154808252600183015494820185905260029092015492810192909252909291610f45916127ad565b90506000610f5384836127ad565b905080610f6257505050505050565b6001600160a01b0386166000908152600460205260408120818155600181018290556002015584610f91611eaf565b60405163095ea7b360e01b81526001600160a01b03888116600483015260248201859052919091169063095ea7b3906044016020604051808303816000875af1158015610fe2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110069190612725565b5060405163cf69a64560e01b8152600481018490526001600160a01b0388811660248301526044820187905282169063cf69a64590606401600060405180830381600087803b15801561105857600080fd5b505af115801561106c573d6000803e3d6000fd5b50506040516001600160a01b0389811682528893508692508a16907fa0dac3293bb97df1e5a10f77f528f6f9366cac15d4da6c2f0cfad1a80487bb059060200160405180910390a46000805460405185926001600160a01b03928316928b16917f1d9cacc586dec6c2956710b69efd1866c8621d4132f107ef3e49040bdb6df4719190a4505050505b505050565b6005548190610100900460ff1615801561111b575060055460ff8083169116105b61117e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016105fd565b6005805461ffff191660ff83161761010017905561119a611ef3565b6111a2611f22565b6111aa611f51565b6111b2611f80565b604051630972932760e21b81523060048201526001600160a01b0391909116906325ca4c9c90602401602060405180830381865afa1580156111f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121c9190612725565b6112cf57611228611f80565b6001600160a01b0316639dca362f6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611267573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128b9190612725565b6112cf5760405162461bcd60e51b815260206004820152601560248201527410d49150551157d050d0d3d5539517d19052531151605a1b60448201526064016105fd565b6005805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b6001600160a01b0381166000908152600460209081526040808320815160608101835281548152600182015493810184905260029091015491810191909152904710801590611367575042816040015111155b9392505050565b61137661183d565b61137e6119ac565b61138781611fc3565b50565b600080611395611c48565b604051630f340c0d60e41b81523060048201526001600160a01b03919091169063f340c0d090602401600060405180830381865afa1580156113db573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114039190810190612869565b9150915060008251116114515760405162461bcd60e51b81526020600482015260166024820152754e4f5f50454e44494e475f5749544844524157414c5360501b60448201526064016105fd565b80516000905b801561153e57826114696001836127c5565b81518110611479576114796128cd565b6020026020010151421061152c5761148f611c48565b6001600160a01b0316632e1a7d4d6114a86001846127c5565b6040518263ffffffff1660e01b81526004016114c691815260200190565b600060405180830381600087803b1580156114e057600080fd5b505af11580156114f4573d6000803e3d6000fd5b505050508360018261150691906127c5565b81518110611516576115166128cd565b60200260200101518261152991906127ad565b91505b80611536816127dc565b915050611457565b50600081116115865760405162461bcd60e51b81526020600482015260146024820152734e4f5f5749544844524157414c535f524541445960601b60448201526064016105fd565b80156110f557604051429082907ff030c63e92fb40dbcb20e5212f35876093032724e26c4d422fbe42d94e7517a090600090a3505050565b6115c661183d565b61053b600061216b565b34600260008282546115e291906127ad565b909155505060405160018152349033907f693c1828300d1cab0919b948d714897f817e305af51c026ad14233b6a8939adb9060200160405180910390a3565b61162961183d565b611631611e66565b60008061163c61077f565b9050801561165a5761164d81611b13565b61165781836127ad565b91505b6000611664610801565b509050801561168357611676816119f2565b61168081846127ad565b92505b6110f583611be5565b61169461183d565b61169c611e66565b60005b83518110156116f7576116e58482815181106116bd576116bd6128cd565b6020026020010151848484815181106116d8576116d86128cd565b6020026020010151610ee9565b806116ef816127f3565b91505061169f565b50505050565b600080546001600160a01b0319166001600160a01b038316179055611720611f80565b6001600160a01b0316639dca362f6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561175f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117839190612725565b6113875760405162461bcd60e51b815260206004820152601560248201527410d49150551157d050d0d3d5539517d19052531151605a1b60448201526064016105fd565b6117cf61183d565b6001600160a01b0381166118345760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105fd565b6113878161216b565b6038546001600160a01b0316331461053b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105fd565b61189f611e66565b606a805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60405163224cb2fd60e21b815260206004820152600860248201526722b632b1ba34b7b760c11b6044820152600090819061ce1090638932cbf4906064015b602060405180830381865afa158015611945573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196991906128e3565b92915050565b6119776119ac565b606a805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586118cc3390565b606a5460ff161561053b5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016105fd565b6000806119fd6121bd565b60008054929450909250908190611a1c906001600160a01b03166122ff565b9150915080611a6d5760405162461bcd60e51b815260206004820152601b60248201527f554e535550504f525445445f56414c494441544f525f47524f5550000000000060448201526064016105fd565b611a756118e9565b600054604051639dfb608160e01b81526001600160a01b039182166004820152602481018890528682166044820152858216606482015260848101859052911690639dfb60819060a4015b6020604051808303816000875af1158015611adf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b039190612725565b611b0c57600080fd5b5050505050565b600080611b1e6121bd565b60008054929450909250908190611b3d906001600160a01b03166122ff565b9150915080611b8e5760405162461bcd60e51b815260206004820152601b60248201527f554e535550504f525445445f56414c494441544f525f47524f5550000000000060448201526064016105fd565b611b966118e9565b600054604051636e19847560e01b81526001600160a01b039182166004820152602481018890528682166044820152858216606482015260848101859052911690636e1984759060a401611ac0565b611bed611c48565b6001600160a01b0316636198e339826040518263ffffffff1660e01b8152600401611c1a91815260200190565b600060405180830381600087803b158015611c3457600080fd5b505af1158015611b0c573d6000803e3d6000fd5b60405163224cb2fd60e21b815260206004820152600a602482015269131bd8dad95911dbdb1960b21b6044820152600090819061ce1090638932cbf490606401611928565b60008111611ccc5760405162461bcd60e51b815260206004820152600c60248201526b4c4f434b494e475f5a45524f60a01b60448201526064016105fd565b611cd4611c48565b6001600160a01b031663f83d08ba826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611d0e57600080fd5b505af1158015611d22573d6000803e3d6000fd5b505050505050565b600080611d356121bd565b90925090506001600160a01b038216158015611d5857506001600160a01b038116155b15611d9e5760405162461bcd60e51b815260206004820152601660248201527524a72b20a624a22fa622a9a9a2a92fa3a922a0aa22a960511b60448201526064016105fd565b611da66118e9565b600054604051632c06ba3d60e11b81526001600160a01b039182166004820152602481018690528482166044820152838216606482015291169063580d747a906084016020604051808303816000875af1158015611e08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2c9190612725565b6110f55760405162461bcd60e51b815260206004820152600b60248201526a1593d51157d1905253115160aa1b60448201526064016105fd565b606a5460ff1661053b5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016105fd565b60405163224cb2fd60e21b815260206004820152600960248201526823b7b6322a37b5b2b760b91b6044820152600090819061ce1090638932cbf490606401611928565b600554610100900460ff16611f1a5760405162461bcd60e51b81526004016105fd90612900565b61053b6123e5565b600554610100900460ff16611f495760405162461bcd60e51b81526004016105fd90612900565b61053b612415565b600554610100900460ff16611f785760405162461bcd60e51b81526004016105fd90612900565b61053b612448565b60405163224cb2fd60e21b81526020600482015260086024820152674163636f756e747360c01b6044820152600090819061ce1090638932cbf490606401611928565b611fcb61183d565b611fd36119ac565b611fdb612476565b6040516329789d2760e11b81526001600160a01b03838116600483015291909116906352f13a4e90602401602060405180830381865afa158015612023573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120479190612725565b6120895760405162461bcd60e51b815260206004820152601360248201527204e4f545f56414c494441544f525f47524f555606c1b60448201526064016105fd565b6120916118e9565b604051638c66677560e01b81526001600160a01b0383811660048301529190911690638c66677590602401602060405180830381865afa1580156120d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fd9190612725565b6121495760405162461bcd60e51b815260206004820152601c60248201527f4e4f545f454c494749424c455f56414c494441544f525f47524f55500000000060448201526064016105fd565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b603880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008060006121ca6118e9565b6001600160a01b0316637046c96b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612207573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261222f91908101906129af565b50905060008060005b83518110156122f457838181518110612253576122536128cd565b60209081029190910101516000546001600160a01b03908116911614156122e25780156122a157836122866001836127c5565b81518110612296576122966128cd565b602002602001015191505b600184516122af91906127c5565b8110156122dd57836122c28260016127ad565b815181106122d2576122d26128cd565b602002602001015192505b6122f4565b806122ec816127f3565b915050612238565b509094909350915050565b600080600061230c6118e9565b60405163457578a360e01b81523060048201526001600160a01b03919091169063457578a390602401600060405180830381865afa158015612352573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261237a91908101906129e6565b905060005b81518110156123d857846001600160a01b03168282815181106123a4576123a46128cd565b60200260200101516001600160a01b031614156123c657946001945092505050565b806123d0816127f3565b91505061237f565b5060009485945092505050565b600554610100900460ff1661240c5760405162461bcd60e51b81526004016105fd90612900565b61053b3361216b565b600554610100900460ff1661243c5760405162461bcd60e51b81526004016105fd90612900565b606a805460ff19169055565b600554610100900460ff1661246f5760405162461bcd60e51b81526004016105fd90612900565b6001609c55565b60405163224cb2fd60e21b815260206004820152600a60248201526956616c696461746f727360b01b6044820152600090819061ce1090638932cbf490606401611928565b6000602082840312156124cd57600080fd5b5035919050565b6001600160a01b038116811461138757600080fd5b80356124f4816124d4565b919050565b60008060006060848603121561250e57600080fd5b8335612519816124d4565b92506020840135612529816124d4565b929592945050506040919091013590565b60006020828403121561254c57600080fd5b813560ff8116811461136757600080fd5b60006020828403121561256f57600080fd5b8135611367816124d4565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156125b9576125b961257a565b604052919050565b600067ffffffffffffffff8211156125db576125db61257a565b5060051b60200190565b600082601f8301126125f657600080fd5b8135602061260b612606836125c1565b612590565b82815260059290921b8401810191818101908684111561262a57600080fd5b8286015b84811015612645578035835291830191830161262e565b509695505050505050565b60008060006060848603121561266557600080fd5b833567ffffffffffffffff8082111561267d57600080fd5b818601915086601f83011261269157600080fd5b813560206126a1612606836125c1565b82815260059290921b8401810191818101908a8411156126c057600080fd5b948201945b838610156126e75785356126d8816124d4565b825294820194908201906126c5565b97506126f690508882016124e9565b95505050604086013591508082111561270e57600080fd5b5061271b868287016125e5565b9150509250925092565b60006020828403121561273757600080fd5b8151801515811461136757600080fd5b60006020828403121561275957600080fd5b5051919050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b634e487b7160e01b600052601160045260246000fd5b600082198211156127c0576127c0612797565b500190565b6000828210156127d7576127d7612797565b500390565b6000816127eb576127eb612797565b506000190190565b600060001982141561280757612807612797565b5060010190565b600082601f83011261281f57600080fd5b8151602061282f612606836125c1565b82815260059290921b8401810191818101908684111561284e57600080fd5b8286015b848110156126455780518352918301918301612852565b6000806040838503121561287c57600080fd5b825167ffffffffffffffff8082111561289457600080fd5b6128a08683870161280e565b935060208501519150808211156128b657600080fd5b506128c38582860161280e565b9150509250929050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156128f557600080fd5b8151611367816124d4565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600082601f83011261295c57600080fd5b8151602061296c612606836125c1565b82815260059290921b8401810191818101908684111561298b57600080fd5b8286015b848110156126455780516129a2816124d4565b835291830191830161298f565b600080604083850312156129c257600080fd5b825167ffffffffffffffff808211156129da57600080fd5b6128a08683870161294b565b6000602082840312156129f857600080fd5b815167ffffffffffffffff811115612a0f57600080fd5b612a1b8482850161294b565b94935050505056fea2646970667358221220e024215c63f20bcb31a8ca6e8c77fb1bbf66187359ac92a82d30796863745b3c64736f6c634300080b0033
Deployed ByteCode
0x6080604052600436106101a05760003560e01c8063680104c5116100ec578063a798283f1161008a578063c4d66de811610064578063c4d66de81461045b578063d41e97201461047b578063f2fde38b14610491578063fbcbc0f1146104b157600080fd5b8063a798283f14610410578063aa0068cf14610426578063ac4603eb1461043b57600080fd5b8063715018a6116100c6578063715018a6146103bf578063817b1cd2146103d45780638c1a5d01146103ea5780638da5cb5b146103f257600080fd5b8063680104c5146103745780636c8b052a146103945780636e92462b146103aa57600080fd5b80633a4b66f11161015957806341e8ea281161013357806341e8ea28146102ec5780634351e6b61461030c578063486475991461032c5780635c975abb1461035c57600080fd5b80633a4b66f1146102975780633ccfd60b1461029f578063417c393d146102b457600080fd5b8063046f7da2146101e45780630617e1cf146101fb57806307da68f5146102105780631f604243146102255780631f8dfbd31461024d5780632e17de781461027757600080fd5b366101df5760405160008152349033907f693c1828300d1cab0919b948d714897f817e305af51c026ad14233b6a8939adb9060200160405180910390a3005b600080fd5b3480156101f057600080fd5b506101f961052b565b005b34801561020757600080fd5b506101f961053d565b34801561021c57600080fd5b506101f961076f565b34801561023157600080fd5b5061023a61077f565b6040519081526020015b60405180910390f35b34801561025957600080fd5b50610262610801565b60408051928352901515602083015201610244565b34801561028357600080fd5b506101f96102923660046124bb565b610902565b6101f9610c0f565b3480156102ab57600080fd5b506101f9610d39565b3480156102c057600080fd5b506000546102d4906001600160a01b031681565b6040516001600160a01b039091168152602001610244565b3480156102f857600080fd5b506101f96103073660046124f9565b610ee9565b34801561031857600080fd5b506101f961032736600461253a565b6110fa565b34801561033857600080fd5b5061034c61034736600461255d565b611314565b6040519015158152602001610244565b34801561036857600080fd5b50606a5460ff1661034c565b34801561038057600080fd5b506101f961038f36600461255d565b61136e565b3480156103a057600080fd5b5061023a60cf5481565b3480156103b657600080fd5b506101f961138a565b3480156103cb57600080fd5b506101f96115be565b3480156103e057600080fd5b5061023a60ce5481565b6101f96115d0565b3480156103fe57600080fd5b506038546001600160a01b03166102d4565b34801561041c57600080fd5b5061023a60025481565b34801561043257600080fd5b506101f9611621565b34801561044757600080fd5b506101f9610456366004612650565b61168c565b34801561046757600080fd5b506101f961047636600461255d565b6116fd565b34801561048757600080fd5b5061023a60035481565b34801561049d57600080fd5b506101f96104ac36600461255d565b6117c7565b3480156104bd57600080fd5b506105106104cc36600461255d565b6001600160a01b0316600090815260046020908152604091829020825160608101845281548082526001830154938201849052600290920154930183905292909190565b60408051938452602084019290925290820152606001610244565b61053361183d565b61053b611897565b565b60006105476118e9565b60005460405163098fb3dd60e21b81523060048201526001600160a01b03918216602482015291925082169063263ecf7490604401602060405180830381865afa158015610599573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bd9190612725565b6106065760405162461bcd60e51b81526020600482015260156024820152744e4f545f52454144595f544f5f414354495641544560581b60448201526064015b60405180910390fd5b60006106106118e9565b600054604051639b95975f60e01b81526001600160a01b039182166004820152306024820152911690639b95975f90604401602060405180830381865afa15801561065f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106839190612747565b600054604051630716a76760e21b81526001600160a01b039182166004820152919250831690631c5a9d9c906024016020604051808303816000875af11580156106d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f59190612725565b6107335760405162461bcd60e51b815260206004820152600f60248201526e1050d5125590551157d19052531151608a1b60448201526064016105fd565b6000805460405183926001600160a01b03909216917fca287ca3252932704109e3adbc2d726718b9c6b00d12049534d899bb8e19e7f091a35050565b61077761183d565b61053b61196f565b60006107896118e9565b6000546040516334f890a960e21b81526001600160a01b03918216600482015230602482015291169063d3e242a490604401602060405180830381865afa1580156107d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fc9190612747565b905090565b60008061080c6118e9565b600054604051639b95975f60e01b81526001600160a01b039182166004820152306024820152911690639b95975f90604401602060405180830381865afa15801561085b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087f9190612747565b6108876118e9565b60005460405163098fb3dd60e21b81523060048201526001600160a01b03918216602482015291169063263ecf7490604401602060405180830381865afa1580156108d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fa9190612725565b915091509091565b6002609c5414156109255760405162461bcd60e51b81526004016105fd90612760565b6002609c556109326119ac565b336000908152600460205260409020548111156109865760405162461bcd60e51b8152602060048201526012602482015271455843454544535f555345525f5354414b4560701b60448201526064016105fd565b600061099061077f565b9050600061099c610801565b509050826109aa82846127ad565b10156109f15760405162461bcd60e51b8152602060048201526016602482015275455843454544535f50524f544f434f4c5f5354414b4560501b60448201526064016105fd565b3360009081526004602052604090206001015415610a515760405162461bcd60e51b815260206004820152601e60248201527f4f55545354414e44494e475f50454e44494e475f5749544844524157414c000060448201526064016105fd565b808311610a6657610a61836119f2565b610a81565b610a6f816119f2565b610a81610a7c82856127c5565b611b13565b610a8a83611be5565b33600090815260046020908152604091829020825160608101845281548082526001830154938201939093526002909101549281019290925284908290610ad29083906127c5565b90525060208101849052610ae4611c48565b6001600160a01b03166320637d8e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b459190612747565b610b4f90426127ad565b604082015260038054859190600090610b699084906127ad565b925050819055508360ce6000828254610b8291906127c5565b90915550508051610ba35760cf8054906000610b9d836127dc565b91905055505b33600081815260046020908152604080832085518155918501516001830155848101516002909201919091558154905187936001600160a01b03909216927f1d9cacc586dec6c2956710b69efd1866c8621d4132f107ef3e49040bdb6df47191a450506001609c555050565b6002609c541415610c325760405162461bcd60e51b81526004016105fd90612760565b6002609c55610c3f6119ac565b60003411610c7e5760405162461bcd60e51b815260206004820152600c60248201526b5354414b494e475f5a45524f60a01b60448201526064016105fd565b610c8734611c8d565b610c9034611d2a565b33600090815260046020526040902054610cba5760cf8054906000610cb4836127f3565b91905055505b3360009081526004602052604081208054349290610cd99084906127ad565b925050819055503460ce6000828254610cf291906127ad565b90915550506000805460405134926001600160a01b039092169133917fd5f44d85e0d349356f32ca770a4f4947ed8a5542b66e733b90017cdf46f8f38e9190a46001609c55565b6002609c541415610d5c5760405162461bcd60e51b81526004016105fd90612760565b6002609c55610d696119ac565b33600090815260046020908152604091829020825160608101845281548152600182015492810183905260029091015492810192909252610de55760405162461bcd60e51b81526020600482015260166024820152754e4f5f50454e44494e475f5749544844524157414c5360501b60448201526064016105fd565b610dee33611314565b610e315760405162461bcd60e51b81526020600482015260146024820152735749544844524157414c5f4e4f545f524541445960601b60448201526064016105fd565b6020810151604051339180156108fc02916000818181858888f19350505050158015610e61573d6000803e3d6000fd5b50602081015160405133907fefff521bc5c8341dd70e7ab8fd1ef08957d49310c246915f1c7a72f3f3254ee590600090a3806020015160036000828254610ea891906127c5565b909155505060006020808301828152604080850184815233855260049093529092209251835590516001808401919091559051600290920191909155609c55565b610ef161183d565b610ef9611e66565b6001600160a01b038316600090815260046020908152604080832081516060810183528154808252600183015494820185905260029092015492810192909252909291610f45916127ad565b90506000610f5384836127ad565b905080610f6257505050505050565b6001600160a01b0386166000908152600460205260408120818155600181018290556002015584610f91611eaf565b60405163095ea7b360e01b81526001600160a01b03888116600483015260248201859052919091169063095ea7b3906044016020604051808303816000875af1158015610fe2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110069190612725565b5060405163cf69a64560e01b8152600481018490526001600160a01b0388811660248301526044820187905282169063cf69a64590606401600060405180830381600087803b15801561105857600080fd5b505af115801561106c573d6000803e3d6000fd5b50506040516001600160a01b0389811682528893508692508a16907fa0dac3293bb97df1e5a10f77f528f6f9366cac15d4da6c2f0cfad1a80487bb059060200160405180910390a46000805460405185926001600160a01b03928316928b16917f1d9cacc586dec6c2956710b69efd1866c8621d4132f107ef3e49040bdb6df4719190a4505050505b505050565b6005548190610100900460ff1615801561111b575060055460ff8083169116105b61117e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016105fd565b6005805461ffff191660ff83161761010017905561119a611ef3565b6111a2611f22565b6111aa611f51565b6111b2611f80565b604051630972932760e21b81523060048201526001600160a01b0391909116906325ca4c9c90602401602060405180830381865afa1580156111f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121c9190612725565b6112cf57611228611f80565b6001600160a01b0316639dca362f6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611267573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128b9190612725565b6112cf5760405162461bcd60e51b815260206004820152601560248201527410d49150551157d050d0d3d5539517d19052531151605a1b60448201526064016105fd565b6005805461ff001916905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b6001600160a01b0381166000908152600460209081526040808320815160608101835281548152600182015493810184905260029091015491810191909152904710801590611367575042816040015111155b9392505050565b61137661183d565b61137e6119ac565b61138781611fc3565b50565b600080611395611c48565b604051630f340c0d60e41b81523060048201526001600160a01b03919091169063f340c0d090602401600060405180830381865afa1580156113db573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114039190810190612869565b9150915060008251116114515760405162461bcd60e51b81526020600482015260166024820152754e4f5f50454e44494e475f5749544844524157414c5360501b60448201526064016105fd565b80516000905b801561153e57826114696001836127c5565b81518110611479576114796128cd565b6020026020010151421061152c5761148f611c48565b6001600160a01b0316632e1a7d4d6114a86001846127c5565b6040518263ffffffff1660e01b81526004016114c691815260200190565b600060405180830381600087803b1580156114e057600080fd5b505af11580156114f4573d6000803e3d6000fd5b505050508360018261150691906127c5565b81518110611516576115166128cd565b60200260200101518261152991906127ad565b91505b80611536816127dc565b915050611457565b50600081116115865760405162461bcd60e51b81526020600482015260146024820152734e4f5f5749544844524157414c535f524541445960601b60448201526064016105fd565b80156110f557604051429082907ff030c63e92fb40dbcb20e5212f35876093032724e26c4d422fbe42d94e7517a090600090a3505050565b6115c661183d565b61053b600061216b565b34600260008282546115e291906127ad565b909155505060405160018152349033907f693c1828300d1cab0919b948d714897f817e305af51c026ad14233b6a8939adb9060200160405180910390a3565b61162961183d565b611631611e66565b60008061163c61077f565b9050801561165a5761164d81611b13565b61165781836127ad565b91505b6000611664610801565b509050801561168357611676816119f2565b61168081846127ad565b92505b6110f583611be5565b61169461183d565b61169c611e66565b60005b83518110156116f7576116e58482815181106116bd576116bd6128cd565b6020026020010151848484815181106116d8576116d86128cd565b6020026020010151610ee9565b806116ef816127f3565b91505061169f565b50505050565b600080546001600160a01b0319166001600160a01b038316179055611720611f80565b6001600160a01b0316639dca362f6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561175f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117839190612725565b6113875760405162461bcd60e51b815260206004820152601560248201527410d49150551157d050d0d3d5539517d19052531151605a1b60448201526064016105fd565b6117cf61183d565b6001600160a01b0381166118345760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105fd565b6113878161216b565b6038546001600160a01b0316331461053b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105fd565b61189f611e66565b606a805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60405163224cb2fd60e21b815260206004820152600860248201526722b632b1ba34b7b760c11b6044820152600090819061ce1090638932cbf4906064015b602060405180830381865afa158015611945573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196991906128e3565b92915050565b6119776119ac565b606a805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586118cc3390565b606a5460ff161561053b5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016105fd565b6000806119fd6121bd565b60008054929450909250908190611a1c906001600160a01b03166122ff565b9150915080611a6d5760405162461bcd60e51b815260206004820152601b60248201527f554e535550504f525445445f56414c494441544f525f47524f5550000000000060448201526064016105fd565b611a756118e9565b600054604051639dfb608160e01b81526001600160a01b039182166004820152602481018890528682166044820152858216606482015260848101859052911690639dfb60819060a4015b6020604051808303816000875af1158015611adf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b039190612725565b611b0c57600080fd5b5050505050565b600080611b1e6121bd565b60008054929450909250908190611b3d906001600160a01b03166122ff565b9150915080611b8e5760405162461bcd60e51b815260206004820152601b60248201527f554e535550504f525445445f56414c494441544f525f47524f5550000000000060448201526064016105fd565b611b966118e9565b600054604051636e19847560e01b81526001600160a01b039182166004820152602481018890528682166044820152858216606482015260848101859052911690636e1984759060a401611ac0565b611bed611c48565b6001600160a01b0316636198e339826040518263ffffffff1660e01b8152600401611c1a91815260200190565b600060405180830381600087803b158015611c3457600080fd5b505af1158015611b0c573d6000803e3d6000fd5b60405163224cb2fd60e21b815260206004820152600a602482015269131bd8dad95911dbdb1960b21b6044820152600090819061ce1090638932cbf490606401611928565b60008111611ccc5760405162461bcd60e51b815260206004820152600c60248201526b4c4f434b494e475f5a45524f60a01b60448201526064016105fd565b611cd4611c48565b6001600160a01b031663f83d08ba826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611d0e57600080fd5b505af1158015611d22573d6000803e3d6000fd5b505050505050565b600080611d356121bd565b90925090506001600160a01b038216158015611d5857506001600160a01b038116155b15611d9e5760405162461bcd60e51b815260206004820152601660248201527524a72b20a624a22fa622a9a9a2a92fa3a922a0aa22a960511b60448201526064016105fd565b611da66118e9565b600054604051632c06ba3d60e11b81526001600160a01b039182166004820152602481018690528482166044820152838216606482015291169063580d747a906084016020604051808303816000875af1158015611e08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2c9190612725565b6110f55760405162461bcd60e51b815260206004820152600b60248201526a1593d51157d1905253115160aa1b60448201526064016105fd565b606a5460ff1661053b5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016105fd565b60405163224cb2fd60e21b815260206004820152600960248201526823b7b6322a37b5b2b760b91b6044820152600090819061ce1090638932cbf490606401611928565b600554610100900460ff16611f1a5760405162461bcd60e51b81526004016105fd90612900565b61053b6123e5565b600554610100900460ff16611f495760405162461bcd60e51b81526004016105fd90612900565b61053b612415565b600554610100900460ff16611f785760405162461bcd60e51b81526004016105fd90612900565b61053b612448565b60405163224cb2fd60e21b81526020600482015260086024820152674163636f756e747360c01b6044820152600090819061ce1090638932cbf490606401611928565b611fcb61183d565b611fd36119ac565b611fdb612476565b6040516329789d2760e11b81526001600160a01b03838116600483015291909116906352f13a4e90602401602060405180830381865afa158015612023573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120479190612725565b6120895760405162461bcd60e51b815260206004820152601360248201527204e4f545f56414c494441544f525f47524f555606c1b60448201526064016105fd565b6120916118e9565b604051638c66677560e01b81526001600160a01b0383811660048301529190911690638c66677590602401602060405180830381865afa1580156120d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120fd9190612725565b6121495760405162461bcd60e51b815260206004820152601c60248201527f4e4f545f454c494749424c455f56414c494441544f525f47524f55500000000060448201526064016105fd565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b603880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008060006121ca6118e9565b6001600160a01b0316637046c96b6040518163ffffffff1660e01b8152600401600060405180830381865afa158015612207573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261222f91908101906129af565b50905060008060005b83518110156122f457838181518110612253576122536128cd565b60209081029190910101516000546001600160a01b03908116911614156122e25780156122a157836122866001836127c5565b81518110612296576122966128cd565b602002602001015191505b600184516122af91906127c5565b8110156122dd57836122c28260016127ad565b815181106122d2576122d26128cd565b602002602001015192505b6122f4565b806122ec816127f3565b915050612238565b509094909350915050565b600080600061230c6118e9565b60405163457578a360e01b81523060048201526001600160a01b03919091169063457578a390602401600060405180830381865afa158015612352573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261237a91908101906129e6565b905060005b81518110156123d857846001600160a01b03168282815181106123a4576123a46128cd565b60200260200101516001600160a01b031614156123c657946001945092505050565b806123d0816127f3565b91505061237f565b5060009485945092505050565b600554610100900460ff1661240c5760405162461bcd60e51b81526004016105fd90612900565b61053b3361216b565b600554610100900460ff1661243c5760405162461bcd60e51b81526004016105fd90612900565b606a805460ff19169055565b600554610100900460ff1661246f5760405162461bcd60e51b81526004016105fd90612900565b6001609c55565b60405163224cb2fd60e21b815260206004820152600a60248201526956616c696461746f727360b01b6044820152600090819061ce1090638932cbf490606401611928565b6000602082840312156124cd57600080fd5b5035919050565b6001600160a01b038116811461138757600080fd5b80356124f4816124d4565b919050565b60008060006060848603121561250e57600080fd5b8335612519816124d4565b92506020840135612529816124d4565b929592945050506040919091013590565b60006020828403121561254c57600080fd5b813560ff8116811461136757600080fd5b60006020828403121561256f57600080fd5b8135611367816124d4565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156125b9576125b961257a565b604052919050565b600067ffffffffffffffff8211156125db576125db61257a565b5060051b60200190565b600082601f8301126125f657600080fd5b8135602061260b612606836125c1565b612590565b82815260059290921b8401810191818101908684111561262a57600080fd5b8286015b84811015612645578035835291830191830161262e565b509695505050505050565b60008060006060848603121561266557600080fd5b833567ffffffffffffffff8082111561267d57600080fd5b818601915086601f83011261269157600080fd5b813560206126a1612606836125c1565b82815260059290921b8401810191818101908a8411156126c057600080fd5b948201945b838610156126e75785356126d8816124d4565b825294820194908201906126c5565b97506126f690508882016124e9565b95505050604086013591508082111561270e57600080fd5b5061271b868287016125e5565b9150509250925092565b60006020828403121561273757600080fd5b8151801515811461136757600080fd5b60006020828403121561275957600080fd5b5051919050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b634e487b7160e01b600052601160045260246000fd5b600082198211156127c0576127c0612797565b500190565b6000828210156127d7576127d7612797565b500390565b6000816127eb576127eb612797565b506000190190565b600060001982141561280757612807612797565b5060010190565b600082601f83011261281f57600080fd5b8151602061282f612606836125c1565b82815260059290921b8401810191818101908684111561284e57600080fd5b8286015b848110156126455780518352918301918301612852565b6000806040838503121561287c57600080fd5b825167ffffffffffffffff8082111561289457600080fd5b6128a08683870161280e565b935060208501519150808211156128b657600080fd5b506128c38582860161280e565b9150509250929050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156128f557600080fd5b8151611367816124d4565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600082601f83011261295c57600080fd5b8151602061296c612606836125c1565b82815260059290921b8401810191818101908684111561298b57600080fd5b8286015b848110156126455780516129a2816124d4565b835291830191830161298f565b600080604083850312156129c257600080fd5b825167ffffffffffffffff808211156129da57600080fd5b6128a08683870161294b565b6000602082840312156129f857600080fd5b815167ffffffffffffffff811115612a0f57600080fd5b612a1b8482850161294b565b94935050505056fea2646970667358221220e024215c63f20bcb31a8ca6e8c77fb1bbf66187359ac92a82d30796863745b3c64736f6c634300080b0033