├── .gitignore ├── remappings.txt ├── src └── Contract.sol ├── .gitmodules ├── misc ├── project_structure.png └── project_structure2.png ├── lib └── StakingV2 │ ├── contracts │ ├── interfaces │ │ ├── roles │ │ │ └── IGatekeeperable.sol │ │ ├── IAccessControlManager.sol │ │ ├── IStaking.sol │ │ ├── IYOPRewards.sol │ │ └── IVault.sol │ ├── security │ │ └── BasePauseableUpgradeable.sol │ ├── vaults │ │ └── roles │ │ │ ├── Gatekeeperable.sol │ │ │ └── Governable.sol │ └── staking │ │ ├── StakingV2.sol │ │ └── Staking.sol │ ├── settings.json │ └── @openzeppelin │ ├── contracts-upgradeable │ ├── proxy │ │ ├── beacon │ │ │ └── IBeaconUpgradeable.sol │ │ ├── utils │ │ │ ├── Initializable.sol │ │ │ └── UUPSUpgradeable.sol │ │ └── ERC1967 │ │ │ └── ERC1967UpgradeUpgradeable.sol │ ├── token │ │ ├── ERC1155 │ │ │ ├── extensions │ │ │ │ └── IERC1155MetadataURIUpgradeable.sol │ │ │ ├── IERC1155ReceiverUpgradeable.sol │ │ │ ├── IERC1155Upgradeable.sol │ │ │ └── ERC1155Upgradeable.sol │ │ └── ERC20 │ │ │ ├── IERC20Upgradeable.sol │ │ │ └── utils │ │ │ └── SafeERC20Upgradeable.sol │ ├── utils │ │ ├── introspection │ │ │ ├── IERC165Upgradeable.sol │ │ │ ├── ERC165Upgradeable.sol │ │ │ └── ERC165CheckerUpgradeable.sol │ │ ├── ContextUpgradeable.sol │ │ ├── StorageSlotUpgradeable.sol │ │ └── AddressUpgradeable.sol │ └── security │ │ ├── PausableUpgradeable.sol │ │ └── ReentrancyGuardUpgradeable.sol │ └── contracts │ ├── token │ └── ERC20 │ │ ├── extensions │ │ ├── IERC20Metadata.sol │ │ ├── draft-IERC20Permit.sol │ │ └── draft-ERC20Permit.sol │ │ ├── IERC20.sol │ │ └── ERC20.sol │ └── utils │ ├── Context.sol │ ├── Counters.sol │ ├── Strings.sol │ └── cryptography │ ├── draft-EIP712.sol │ └── ECDSA.sol ├── foundry.toml ├── script └── Contract.s.sol ├── .github └── workflows │ └── test.yml └── test └── Contract.t.sol /.gitignore: -------------------------------------------------------------------------------- 1 | cache/ 2 | out/ 3 | -------------------------------------------------------------------------------- /remappings.txt: -------------------------------------------------------------------------------- 1 | @openzeppelin=lib/StakingV2/@openzeppelin -------------------------------------------------------------------------------- /src/Contract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | contract Contract {} 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | -------------------------------------------------------------------------------- /misc/project_structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SergeKireev/foundry-immunefi-poc-tutorial/HEAD/misc/project_structure.png -------------------------------------------------------------------------------- /misc/project_structure2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SergeKireev/foundry-immunefi-poc-tutorial/HEAD/misc/project_structure2.png -------------------------------------------------------------------------------- /lib/StakingV2/contracts/interfaces/roles/IGatekeeperable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.8.9; 3 | 4 | interface IGatekeeperable { 5 | function gatekeeper() external view returns (address); 6 | } 7 | -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [default] 2 | src = 'src' 3 | out = 'out' 4 | libs = ['lib'] 5 | 6 | chain_id = 1 7 | eth_rpc_url = 'https://eth-mainnet.alchemyapi.io/v2/{alchemy_api_key}' 8 | fork_block_number = 14812830 9 | etherscan_api_key = '{etherscan_api_key}' -------------------------------------------------------------------------------- /lib/StakingV2/contracts/interfaces/IAccessControlManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.8.9; 3 | 4 | interface IAccessControlManager { 5 | function hasAccess(address _user, address _vault) external view returns (bool); 6 | } 7 | -------------------------------------------------------------------------------- /script/Contract.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import "forge-std/Script.sol"; 5 | 6 | contract ContractScript is Script { 7 | function setUp() public {} 8 | 9 | function run() public { 10 | vm.broadcast(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/StakingV2/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "optimizer": { 3 | "enabled": true, 4 | "runs": 10 5 | }, 6 | "outputSelection": { 7 | "*": { 8 | "*": [ 9 | "evm.bytecode", 10 | "evm.deployedBytecode", 11 | "devdoc", 12 | "userdoc", 13 | "metadata", 14 | "abi" 15 | ] 16 | } 17 | }, 18 | "libraries": {} 19 | } -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev This is the interface that {BeaconProxy} expects of its beacon. 8 | */ 9 | interface IBeaconUpgradeable { 10 | /** 11 | * @dev Must return an address that can be used as a delegate call target. 12 | * 13 | * {BeaconProxy} will check that this address is a contract. 14 | */ 15 | function implementation() external view returns (address); 16 | } 17 | -------------------------------------------------------------------------------- /lib/StakingV2/contracts/interfaces/IStaking.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.8.9; 3 | 4 | interface IStaking { 5 | function totalWorkingSupply() external view returns (uint256); 6 | 7 | function workingBalanceOf(address _user) external view returns (uint256); 8 | } 9 | 10 | interface IStakingV2 { 11 | function stakeForUser( 12 | uint248 _amount, 13 | uint8 _lockPeriod, 14 | address _to 15 | ) external returns (uint256); 16 | 17 | function stakeAndBoostForUser( 18 | uint248 _amount, 19 | uint8 _lockPeriod, 20 | address _to, 21 | address[] calldata _vaultsToBoost 22 | ) external returns (uint256); 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: workflow_dispatch 4 | 5 | env: 6 | FOUNDRY_PROFILE: ci 7 | 8 | jobs: 9 | check: 10 | strategy: 11 | fail-fast: true 12 | 13 | name: Foundry project 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | with: 18 | submodules: recursive 19 | 20 | - name: Install Foundry 21 | uses: foundry-rs/foundry-toolchain@v1 22 | with: 23 | version: nightly 24 | 25 | - name: Run Forge build 26 | run: | 27 | forge --version 28 | forge build --sizes 29 | id: build 30 | 31 | - name: Run Forge tests 32 | run: | 33 | forge test -vvv 34 | id: test 35 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "../IERC20.sol"; 7 | 8 | /** 9 | * @dev Interface for the optional metadata functions from the ERC20 standard. 10 | * 11 | * _Available since v4.1._ 12 | */ 13 | interface IERC20Metadata is IERC20 { 14 | /** 15 | * @dev Returns the name of the token. 16 | */ 17 | function name() external view returns (string memory); 18 | 19 | /** 20 | * @dev Returns the symbol of the token. 21 | */ 22 | function symbol() external view returns (string memory); 23 | 24 | /** 25 | * @dev Returns the decimals places of the token. 26 | */ 27 | function decimals() external view returns (uint8); 28 | } 29 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/IERC1155MetadataURIUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "../IERC1155Upgradeable.sol"; 7 | 8 | /** 9 | * @dev Interface of the optional ERC1155MetadataExtension interface, as defined 10 | * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP]. 11 | * 12 | * _Available since v3.1._ 13 | */ 14 | interface IERC1155MetadataURIUpgradeable is IERC1155Upgradeable { 15 | /** 16 | * @dev Returns the URI for token type `id`. 17 | * 18 | * If the `\{id\}` substring is present in the URI, it must be replaced by 19 | * clients with the actual token type ID. 20 | */ 21 | function uri(uint256 id) external view returns (string memory); 22 | } 23 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts/utils/Context.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev Provides information about the current execution context, including the 8 | * sender of the transaction and its data. While these are generally available 9 | * via msg.sender and msg.data, they should not be accessed in such a direct 10 | * manner, since when dealing with meta-transactions the account sending and 11 | * paying for execution may not be the actual sender (as far as an application 12 | * is concerned). 13 | * 14 | * This contract is only required for intermediate, library-like contracts. 15 | */ 16 | abstract contract Context { 17 | function _msgSender() internal view virtual returns (address) { 18 | return msg.sender; 19 | } 20 | 21 | function _msgData() internal view virtual returns (bytes calldata) { 22 | return msg.data; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev Interface of the ERC165 standard, as defined in the 8 | * https://eips.ethereum.org/EIPS/eip-165[EIP]. 9 | * 10 | * Implementers can declare support of contract interfaces, which can then be 11 | * queried by others ({ERC165Checker}). 12 | * 13 | * For an implementation, see {ERC165}. 14 | */ 15 | interface IERC165Upgradeable { 16 | /** 17 | * @dev Returns true if this contract implements the interface defined by 18 | * `interfaceId`. See the corresponding 19 | * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] 20 | * to learn more about how these ids are created. 21 | * 22 | * This function call must use less than 30 000 gas. 23 | */ 24 | function supportsInterface(bytes4 interfaceId) external view returns (bool); 25 | } 26 | -------------------------------------------------------------------------------- /test/Contract.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.9; 3 | 4 | import "forge-std/Test.sol"; 5 | import "StakingV2/contracts/staking/StakingV2.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 7 | 8 | contract ContractTest is Test { 9 | using stdStorage for StdStorage; 10 | 11 | IERC20 yopToken = IERC20(0xAE1eaAE3F627AAca434127644371b67B18444051); 12 | StakingV2 staking = StakingV2(0x5B705d7c6362A73fD56D5bCedF09f4E40C2d3670); 13 | address attacker = address(1); 14 | 15 | function writeTokenBalance( 16 | address who, 17 | IERC20 token, 18 | uint256 amt 19 | ) internal { 20 | stdstore 21 | .target(address(token)) 22 | .sig(token.balanceOf.selector) 23 | .with_key(who) 24 | .checked_write(amt); 25 | } 26 | 27 | function setUp() public { 28 | writeTokenBalance(attacker, yopToken, 500 ether); 29 | } 30 | 31 | function testExample() public { 32 | vm.startPrank(attacker); 33 | uint8 lock_duration_months = 1; 34 | yopToken.approve(address(staking), 500 ether); 35 | staking.stake(500 ether, lock_duration_months); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | import "../proxy/utils/Initializable.sol"; 6 | 7 | /** 8 | * @dev Provides information about the current execution context, including the 9 | * sender of the transaction and its data. While these are generally available 10 | * via msg.sender and msg.data, they should not be accessed in such a direct 11 | * manner, since when dealing with meta-transactions the account sending and 12 | * paying for execution may not be the actual sender (as far as an application 13 | * is concerned). 14 | * 15 | * This contract is only required for intermediate, library-like contracts. 16 | */ 17 | abstract contract ContextUpgradeable is Initializable { 18 | function __Context_init() internal onlyInitializing { 19 | __Context_init_unchained(); 20 | } 21 | 22 | function __Context_init_unchained() internal onlyInitializing { 23 | } 24 | function _msgSender() internal view virtual returns (address) { 25 | return msg.sender; 26 | } 27 | 28 | function _msgData() internal view virtual returns (bytes calldata) { 29 | return msg.data; 30 | } 31 | uint256[50] private __gap; 32 | } 33 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "./IERC165Upgradeable.sol"; 7 | import "../../proxy/utils/Initializable.sol"; 8 | 9 | /** 10 | * @dev Implementation of the {IERC165} interface. 11 | * 12 | * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check 13 | * for the additional interface id that will be supported. For example: 14 | * 15 | * ```solidity 16 | * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 17 | * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); 18 | * } 19 | * ``` 20 | * 21 | * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. 22 | */ 23 | abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable { 24 | function __ERC165_init() internal onlyInitializing { 25 | __ERC165_init_unchained(); 26 | } 27 | 28 | function __ERC165_init_unchained() internal onlyInitializing { 29 | } 30 | /** 31 | * @dev See {IERC165-supportsInterface}. 32 | */ 33 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 34 | return interfaceId == type(IERC165Upgradeable).interfaceId; 35 | } 36 | uint256[50] private __gap; 37 | } 38 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts/utils/Counters.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @title Counters 8 | * @author Matt Condon (@shrugs) 9 | * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number 10 | * of elements in a mapping, issuing ERC721 ids, or counting request ids. 11 | * 12 | * Include with `using Counters for Counters.Counter;` 13 | */ 14 | library Counters { 15 | struct Counter { 16 | // This variable should never be directly accessed by users of the library: interactions must be restricted to 17 | // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add 18 | // this feature: see https://github.com/ethereum/solidity/issues/4637 19 | uint256 _value; // default: 0 20 | } 21 | 22 | function current(Counter storage counter) internal view returns (uint256) { 23 | return counter._value; 24 | } 25 | 26 | function increment(Counter storage counter) internal { 27 | unchecked { 28 | counter._value += 1; 29 | } 30 | } 31 | 32 | function decrement(Counter storage counter) internal { 33 | uint256 value = counter._value; 34 | require(value > 0, "Counter: decrement overflow"); 35 | unchecked { 36 | counter._value = value - 1; 37 | } 38 | } 39 | 40 | function reset(Counter storage counter) internal { 41 | counter._value = 0; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/StakingV2/contracts/security/BasePauseableUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.8.9; 3 | import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; 4 | import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; 5 | import "../vaults/roles/Governable.sol"; 6 | import "../vaults/roles/Gatekeeperable.sol"; 7 | 8 | /// @dev Use this contract as the base for contracts that are going to be pauseable and upgradeable. 9 | /// It exposes the common functions used by all these contracts (like Pause, Unpause, setGatekeeper etc) and make sure the right permissions are set for all these methods. 10 | abstract contract BasePauseableUpgradeable is 11 | GovernableUpgradeable, 12 | Gatekeeperable, 13 | PausableUpgradeable, 14 | UUPSUpgradeable 15 | { 16 | // solhint-disable-next-line no-empty-blocks 17 | constructor() {} 18 | 19 | // solhint-disable-next-line func-name-mixedcase 20 | function __BasePauseableUpgradeable_init(address _governance, address _gatekeeper) internal onlyInitializing { 21 | __Governable_init(_governance); 22 | __Gatekeeperable_init_unchained(_gatekeeper); 23 | __Pausable_init_unchained(); 24 | __UUPSUpgradeable_init(); 25 | __BasePauseableUpgradeable_init_unchained(); 26 | } 27 | 28 | // solhint-disable-next-line func-name-mixedcase no-empty-blocks 29 | function __BasePauseableUpgradeable_init_unchained() internal onlyInitializing {} 30 | 31 | /// @notice Pause the contract. Can be called by either the governance or gatekeeper. 32 | function pause() external onlyGovernanceOrGatekeeper(governance) { 33 | _pause(); 34 | } 35 | 36 | // @notice Unpause the contract. Can only be called by the governance. 37 | function unpause() external onlyGovernance { 38 | _unpause(); 39 | } 40 | 41 | /// @notice Set the gatekeeper address of the contract 42 | function setGatekeeper(address _gatekeeper) external onlyGovernance { 43 | _updateGatekeeper(_gatekeeper); 44 | } 45 | 46 | // solhint-disable-next-line no-unused-vars no-empty-blocks 47 | function _authorizeUpgrade(address implementation) internal view override onlyGovernance {} 48 | } 49 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts/utils/Strings.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev String operations. 8 | */ 9 | library Strings { 10 | bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; 11 | 12 | /** 13 | * @dev Converts a `uint256` to its ASCII `string` decimal representation. 14 | */ 15 | function toString(uint256 value) internal pure returns (string memory) { 16 | // Inspired by OraclizeAPI's implementation - MIT licence 17 | // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol 18 | 19 | if (value == 0) { 20 | return "0"; 21 | } 22 | uint256 temp = value; 23 | uint256 digits; 24 | while (temp != 0) { 25 | digits++; 26 | temp /= 10; 27 | } 28 | bytes memory buffer = new bytes(digits); 29 | while (value != 0) { 30 | digits -= 1; 31 | buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); 32 | value /= 10; 33 | } 34 | return string(buffer); 35 | } 36 | 37 | /** 38 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. 39 | */ 40 | function toHexString(uint256 value) internal pure returns (string memory) { 41 | if (value == 0) { 42 | return "0x00"; 43 | } 44 | uint256 temp = value; 45 | uint256 length = 0; 46 | while (temp != 0) { 47 | length++; 48 | temp >>= 8; 49 | } 50 | return toHexString(value, length); 51 | } 52 | 53 | /** 54 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. 55 | */ 56 | function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { 57 | bytes memory buffer = new bytes(2 * length + 2); 58 | buffer[0] = "0"; 59 | buffer[1] = "x"; 60 | for (uint256 i = 2 * length + 1; i > 1; --i) { 61 | buffer[i] = _HEX_SYMBOLS[value & 0xf]; 62 | value >>= 4; 63 | } 64 | require(value == 0, "Strings: hex length insufficient"); 65 | return string(buffer); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/StakingV2/contracts/interfaces/IYOPRewards.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.8.9; 3 | 4 | interface IYOPRewards { 5 | /// @notice Returns the current emission rate (per epoch) for vault rewards and the current number of epoch (start from 1). 6 | function rate() external view returns (uint256 _rate, uint256 _epoch); 7 | 8 | /// @notice Returns the current ratio of community emissions for vault users 9 | function vaultsRewardsWeight() external view returns (uint256); 10 | 11 | /// @notice Returns the current ratio of community emissions for staking users 12 | function stakingRewardsWeight() external view returns (uint256); 13 | 14 | /// @notice Set the ratios of community emission for vaults and staking respectively. Governance only. Should emit an event. 15 | function setRewardsAllocationWeights(uint256 _weightForVaults, uint256 _weightForStaking) external; 16 | 17 | /// @notice Get the weight of a Vault 18 | function perVaultRewardsWeight(address vault) external view returns (uint256); 19 | 20 | /// @notice Set the weights for vaults. Governance only. Should emit events. 21 | function setPerVaultRewardsWeight(address[] calldata vaults, uint256[] calldata weights) external; 22 | 23 | /// @notice Calculate the rewards for the given user in the given vault. Vaults Only. 24 | /// This should be called by every Vault every time a user deposits or withdraws. 25 | function calculateVaultRewards(address _user) external; 26 | 27 | /// @notice Calculate the rewards for the given stake id in the staking contract. 28 | function calculateStakingRewards(uint256 _stakeId) external; 29 | 30 | /// @notice Allow a user to claim the accrued rewards from both vaults and staking, and transfer the YOP tokens to the given account. 31 | function claimAll(address _to) external; 32 | 33 | /// @notice Calculate the unclaimed rewards for the calling user 34 | function allUnclaimedRewards(address _user) 35 | external 36 | view 37 | returns ( 38 | uint256 totalRewards, 39 | uint256 vaultsRewards, 40 | uint256 stakingRewards 41 | ); 42 | } 43 | 44 | interface IYOPRewardsV2 { 45 | function claimRewardsForStakes(uint256[] calldata _stakeIds) external returns (uint256, uint256[] memory); 46 | 47 | function claimVaultRewardsForUsers(address[] calldata _users) external returns (uint256, uint256[] memory); 48 | } 49 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in 8 | * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. 9 | * 10 | * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by 11 | * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't 12 | * need to send a transaction, and thus is not required to hold Ether at all. 13 | */ 14 | interface IERC20Permit { 15 | /** 16 | * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, 17 | * given ``owner``'s signed approval. 18 | * 19 | * IMPORTANT: The same issues {IERC20-approve} has related to transaction 20 | * ordering also apply here. 21 | * 22 | * Emits an {Approval} event. 23 | * 24 | * Requirements: 25 | * 26 | * - `spender` cannot be the zero address. 27 | * - `deadline` must be a timestamp in the future. 28 | * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` 29 | * over the EIP712-formatted function arguments. 30 | * - the signature must use ``owner``'s current nonce (see {nonces}). 31 | * 32 | * For more information on the signature format, see the 33 | * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP 34 | * section]. 35 | */ 36 | function permit( 37 | address owner, 38 | address spender, 39 | uint256 value, 40 | uint256 deadline, 41 | uint8 v, 42 | bytes32 r, 43 | bytes32 s 44 | ) external; 45 | 46 | /** 47 | * @dev Returns the current nonce for `owner`. This value must be 48 | * included whenever a signature is generated for {permit}. 49 | * 50 | * Every successful call to {permit} increases ``owner``'s nonce by one. This 51 | * prevents a signature from being used multiple times. 52 | */ 53 | function nonces(address owner) external view returns (uint256); 54 | 55 | /** 56 | * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. 57 | */ 58 | // solhint-disable-next-line func-name-mixedcase 59 | function DOMAIN_SEPARATOR() external view returns (bytes32); 60 | } 61 | -------------------------------------------------------------------------------- /lib/StakingV2/contracts/vaults/roles/Gatekeeperable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.8.9; 3 | pragma abicoder v2; 4 | 5 | import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; 6 | import "../../interfaces/roles/IGatekeeperable.sol"; 7 | 8 | /// @dev Add the `Gatekeeper` role. 9 | /// Gatekeepers will help ensure the security of the vaults. They can set vault limits, pause deposits or withdraws. 10 | /// For vaults that defined restricted access, they will be able to control the access to these vaults as well. 11 | /// This contract also provides a `onlyGatekeeper` modifier to allow controlling access to functions of the contract. 12 | abstract contract Gatekeeperable is IGatekeeperable, ContextUpgradeable { 13 | event GatekeeperUpdated(address _guardian); 14 | 15 | /// @notice the address of the guardian for the vault 16 | /// @dev This contract is used as part of the Vault contract and it is upgradeable. 17 | /// which means any changes to the state variables could corrupt the data. Do not modify this at all. 18 | address public gatekeeper; 19 | 20 | /// @dev make sure msg.sender is the guardian or the governance 21 | modifier onlyGovernanceOrGatekeeper(address _governance) { 22 | _onlyGovernanceOrGatekeeper(_governance); 23 | _; 24 | } 25 | 26 | // solhint-disable-next-line no-empty-blocks 27 | constructor() {} 28 | 29 | /// @dev set the initial value for the gatekeeper. The deployer can not be the gatekeeper. 30 | /// @param _gatekeeper the default address of the guardian 31 | // solhint-disable-next-line func-name-mixedcase 32 | function __Gatekeeperable_init_unchained(address _gatekeeper) internal { 33 | require(_msgSender() != _gatekeeper, "invalid address"); 34 | _updateGatekeeper(_gatekeeper); 35 | } 36 | 37 | // solhint-disable-next-line func-name-mixedcase 38 | function __Gatekeeperable_init(address _gatekeeper) internal { 39 | __Context_init(); 40 | __Gatekeeperable_init_unchained(_gatekeeper); 41 | } 42 | 43 | ///@dev this can be used internally to update the gatekeep. If you want to expose it, create an external function in the implementation contract and call this. 44 | function _updateGatekeeper(address _gatekeeper) internal { 45 | require(_gatekeeper != address(0), "address is not valid"); 46 | require(_gatekeeper != gatekeeper, "already the gatekeeper"); 47 | gatekeeper = _gatekeeper; 48 | emit GatekeeperUpdated(_gatekeeper); 49 | } 50 | 51 | function _onlyGovernanceOrGatekeeper(address _governance) internal view { 52 | require((_msgSender() == _governance) || (gatekeeper != address(0) && gatekeeper == _msgSender()), "!authorised"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155ReceiverUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155Receiver.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "../../utils/introspection/IERC165Upgradeable.sol"; 7 | 8 | /** 9 | * @dev _Available since v3.1._ 10 | */ 11 | interface IERC1155ReceiverUpgradeable is IERC165Upgradeable { 12 | /** 13 | @dev Handles the receipt of a single ERC1155 token type. This function is 14 | called at the end of a `safeTransferFrom` after the balance has been updated. 15 | To accept the transfer, this must return 16 | `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` 17 | (i.e. 0xf23a6e61, or its own function selector). 18 | @param operator The address which initiated the transfer (i.e. msg.sender) 19 | @param from The address which previously owned the token 20 | @param id The ID of the token being transferred 21 | @param value The amount of tokens being transferred 22 | @param data Additional data with no specified format 23 | @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed 24 | */ 25 | function onERC1155Received( 26 | address operator, 27 | address from, 28 | uint256 id, 29 | uint256 value, 30 | bytes calldata data 31 | ) external returns (bytes4); 32 | 33 | /** 34 | @dev Handles the receipt of a multiple ERC1155 token types. This function 35 | is called at the end of a `safeBatchTransferFrom` after the balances have 36 | been updated. To accept the transfer(s), this must return 37 | `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` 38 | (i.e. 0xbc197c81, or its own function selector). 39 | @param operator The address which initiated the batch transfer (i.e. msg.sender) 40 | @param from The address which previously owned the token 41 | @param ids An array containing ids of each token being transferred (order and length must match values array) 42 | @param values An array containing amounts of each token being transferred (order and length must match ids array) 43 | @param data Additional data with no specified format 44 | @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed 45 | */ 46 | function onERC1155BatchReceived( 47 | address operator, 48 | address from, 49 | uint256[] calldata ids, 50 | uint256[] calldata values, 51 | bytes calldata data 52 | ) external returns (bytes4); 53 | } 54 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/utils/StorageSlotUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev Library for reading and writing primitive types to specific storage slots. 8 | * 9 | * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. 10 | * This library helps with reading and writing to such slots without the need for inline assembly. 11 | * 12 | * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. 13 | * 14 | * Example usage to set ERC1967 implementation slot: 15 | * ``` 16 | * contract ERC1967 { 17 | * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; 18 | * 19 | * function _getImplementation() internal view returns (address) { 20 | * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; 21 | * } 22 | * 23 | * function _setImplementation(address newImplementation) internal { 24 | * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); 25 | * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; 26 | * } 27 | * } 28 | * ``` 29 | * 30 | * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ 31 | */ 32 | library StorageSlotUpgradeable { 33 | struct AddressSlot { 34 | address value; 35 | } 36 | 37 | struct BooleanSlot { 38 | bool value; 39 | } 40 | 41 | struct Bytes32Slot { 42 | bytes32 value; 43 | } 44 | 45 | struct Uint256Slot { 46 | uint256 value; 47 | } 48 | 49 | /** 50 | * @dev Returns an `AddressSlot` with member `value` located at `slot`. 51 | */ 52 | function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { 53 | assembly { 54 | r.slot := slot 55 | } 56 | } 57 | 58 | /** 59 | * @dev Returns an `BooleanSlot` with member `value` located at `slot`. 60 | */ 61 | function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { 62 | assembly { 63 | r.slot := slot 64 | } 65 | } 66 | 67 | /** 68 | * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. 69 | */ 70 | function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { 71 | assembly { 72 | r.slot := slot 73 | } 74 | } 75 | 76 | /** 77 | * @dev Returns an `Uint256Slot` with member `value` located at `slot`. 78 | */ 79 | function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { 80 | assembly { 81 | r.slot := slot 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (security/Pausable.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "../utils/ContextUpgradeable.sol"; 7 | import "../proxy/utils/Initializable.sol"; 8 | 9 | /** 10 | * @dev Contract module which allows children to implement an emergency stop 11 | * mechanism that can be triggered by an authorized account. 12 | * 13 | * This module is used through inheritance. It will make available the 14 | * modifiers `whenNotPaused` and `whenPaused`, which can be applied to 15 | * the functions of your contract. Note that they will not be pausable by 16 | * simply including this module, only once the modifiers are put in place. 17 | */ 18 | abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { 19 | /** 20 | * @dev Emitted when the pause is triggered by `account`. 21 | */ 22 | event Paused(address account); 23 | 24 | /** 25 | * @dev Emitted when the pause is lifted by `account`. 26 | */ 27 | event Unpaused(address account); 28 | 29 | bool private _paused; 30 | 31 | /** 32 | * @dev Initializes the contract in unpaused state. 33 | */ 34 | function __Pausable_init() internal onlyInitializing { 35 | __Context_init_unchained(); 36 | __Pausable_init_unchained(); 37 | } 38 | 39 | function __Pausable_init_unchained() internal onlyInitializing { 40 | _paused = false; 41 | } 42 | 43 | /** 44 | * @dev Returns true if the contract is paused, and false otherwise. 45 | */ 46 | function paused() public view virtual returns (bool) { 47 | return _paused; 48 | } 49 | 50 | /** 51 | * @dev Modifier to make a function callable only when the contract is not paused. 52 | * 53 | * Requirements: 54 | * 55 | * - The contract must not be paused. 56 | */ 57 | modifier whenNotPaused() { 58 | require(!paused(), "Pausable: paused"); 59 | _; 60 | } 61 | 62 | /** 63 | * @dev Modifier to make a function callable only when the contract is paused. 64 | * 65 | * Requirements: 66 | * 67 | * - The contract must be paused. 68 | */ 69 | modifier whenPaused() { 70 | require(paused(), "Pausable: not paused"); 71 | _; 72 | } 73 | 74 | /** 75 | * @dev Triggers stopped state. 76 | * 77 | * Requirements: 78 | * 79 | * - The contract must not be paused. 80 | */ 81 | function _pause() internal virtual whenNotPaused { 82 | _paused = true; 83 | emit Paused(_msgSender()); 84 | } 85 | 86 | /** 87 | * @dev Returns to normal state. 88 | * 89 | * Requirements: 90 | * 91 | * - The contract must be paused. 92 | */ 93 | function _unpause() internal virtual whenPaused { 94 | _paused = false; 95 | emit Unpaused(_msgSender()); 96 | } 97 | uint256[49] private __gap; 98 | } 99 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts/token/ERC20/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev Interface of the ERC20 standard as defined in the EIP. 8 | */ 9 | interface IERC20 { 10 | /** 11 | * @dev Returns the amount of tokens in existence. 12 | */ 13 | function totalSupply() external view returns (uint256); 14 | 15 | /** 16 | * @dev Returns the amount of tokens owned by `account`. 17 | */ 18 | function balanceOf(address account) external view returns (uint256); 19 | 20 | /** 21 | * @dev Moves `amount` tokens from the caller's account to `recipient`. 22 | * 23 | * Returns a boolean value indicating whether the operation succeeded. 24 | * 25 | * Emits a {Transfer} event. 26 | */ 27 | function transfer(address recipient, uint256 amount) external returns (bool); 28 | 29 | /** 30 | * @dev Returns the remaining number of tokens that `spender` will be 31 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 32 | * zero by default. 33 | * 34 | * This value changes when {approve} or {transferFrom} are called. 35 | */ 36 | function allowance(address owner, address spender) external view returns (uint256); 37 | 38 | /** 39 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 40 | * 41 | * Returns a boolean value indicating whether the operation succeeded. 42 | * 43 | * IMPORTANT: Beware that changing an allowance with this method brings the risk 44 | * that someone may use both the old and the new allowance by unfortunate 45 | * transaction ordering. One possible solution to mitigate this race 46 | * condition is to first reduce the spender's allowance to 0 and set the 47 | * desired value afterwards: 48 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 49 | * 50 | * Emits an {Approval} event. 51 | */ 52 | function approve(address spender, uint256 amount) external returns (bool); 53 | 54 | /** 55 | * @dev Moves `amount` tokens from `sender` to `recipient` using the 56 | * allowance mechanism. `amount` is then deducted from the caller's 57 | * allowance. 58 | * 59 | * Returns a boolean value indicating whether the operation succeeded. 60 | * 61 | * Emits a {Transfer} event. 62 | */ 63 | function transferFrom( 64 | address sender, 65 | address recipient, 66 | uint256 amount 67 | ) external returns (bool); 68 | 69 | /** 70 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 71 | * another (`to`). 72 | * 73 | * Note that `value` may be zero. 74 | */ 75 | event Transfer(address indexed from, address indexed to, uint256 value); 76 | 77 | /** 78 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 79 | * a call to {approve}. `value` is the new allowance. 80 | */ 81 | event Approval(address indexed owner, address indexed spender, uint256 value); 82 | } 83 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev Interface of the ERC20 standard as defined in the EIP. 8 | */ 9 | interface IERC20Upgradeable { 10 | /** 11 | * @dev Returns the amount of tokens in existence. 12 | */ 13 | function totalSupply() external view returns (uint256); 14 | 15 | /** 16 | * @dev Returns the amount of tokens owned by `account`. 17 | */ 18 | function balanceOf(address account) external view returns (uint256); 19 | 20 | /** 21 | * @dev Moves `amount` tokens from the caller's account to `recipient`. 22 | * 23 | * Returns a boolean value indicating whether the operation succeeded. 24 | * 25 | * Emits a {Transfer} event. 26 | */ 27 | function transfer(address recipient, uint256 amount) external returns (bool); 28 | 29 | /** 30 | * @dev Returns the remaining number of tokens that `spender` will be 31 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 32 | * zero by default. 33 | * 34 | * This value changes when {approve} or {transferFrom} are called. 35 | */ 36 | function allowance(address owner, address spender) external view returns (uint256); 37 | 38 | /** 39 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 40 | * 41 | * Returns a boolean value indicating whether the operation succeeded. 42 | * 43 | * IMPORTANT: Beware that changing an allowance with this method brings the risk 44 | * that someone may use both the old and the new allowance by unfortunate 45 | * transaction ordering. One possible solution to mitigate this race 46 | * condition is to first reduce the spender's allowance to 0 and set the 47 | * desired value afterwards: 48 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 49 | * 50 | * Emits an {Approval} event. 51 | */ 52 | function approve(address spender, uint256 amount) external returns (bool); 53 | 54 | /** 55 | * @dev Moves `amount` tokens from `sender` to `recipient` using the 56 | * allowance mechanism. `amount` is then deducted from the caller's 57 | * allowance. 58 | * 59 | * Returns a boolean value indicating whether the operation succeeded. 60 | * 61 | * Emits a {Transfer} event. 62 | */ 63 | function transferFrom( 64 | address sender, 65 | address recipient, 66 | uint256 amount 67 | ) external returns (bool); 68 | 69 | /** 70 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 71 | * another (`to`). 72 | * 73 | * Note that `value` may be zero. 74 | */ 75 | event Transfer(address indexed from, address indexed to, uint256 value); 76 | 77 | /** 78 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 79 | * a call to {approve}. `value` is the new allowance. 80 | */ 81 | event Approval(address indexed owner, address indexed spender, uint256 value); 82 | } 83 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | import "../proxy/utils/Initializable.sol"; 6 | 7 | /** 8 | * @dev Contract module that helps prevent reentrant calls to a function. 9 | * 10 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier 11 | * available, which can be applied to functions to make sure there are no nested 12 | * (reentrant) calls to them. 13 | * 14 | * Note that because there is a single `nonReentrant` guard, functions marked as 15 | * `nonReentrant` may not call one another. This can be worked around by making 16 | * those functions `private`, and then adding `external` `nonReentrant` entry 17 | * points to them. 18 | * 19 | * TIP: If you would like to learn more about reentrancy and alternative ways 20 | * to protect against it, check out our blog post 21 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. 22 | */ 23 | abstract contract ReentrancyGuardUpgradeable is Initializable { 24 | // Booleans are more expensive than uint256 or any type that takes up a full 25 | // word because each write operation emits an extra SLOAD to first read the 26 | // slot's contents, replace the bits taken up by the boolean, and then write 27 | // back. This is the compiler's defense against contract upgrades and 28 | // pointer aliasing, and it cannot be disabled. 29 | 30 | // The values being non-zero value makes deployment a bit more expensive, 31 | // but in exchange the refund on every call to nonReentrant will be lower in 32 | // amount. Since refunds are capped to a percentage of the total 33 | // transaction's gas, it is best to keep them low in cases like this one, to 34 | // increase the likelihood of the full refund coming into effect. 35 | uint256 private constant _NOT_ENTERED = 1; 36 | uint256 private constant _ENTERED = 2; 37 | 38 | uint256 private _status; 39 | 40 | function __ReentrancyGuard_init() internal onlyInitializing { 41 | __ReentrancyGuard_init_unchained(); 42 | } 43 | 44 | function __ReentrancyGuard_init_unchained() internal onlyInitializing { 45 | _status = _NOT_ENTERED; 46 | } 47 | 48 | /** 49 | * @dev Prevents a contract from calling itself, directly or indirectly. 50 | * Calling a `nonReentrant` function from another `nonReentrant` 51 | * function is not supported. It is possible to prevent this from happening 52 | * by making the `nonReentrant` function external, and making it call a 53 | * `private` function that does the actual work. 54 | */ 55 | modifier nonReentrant() { 56 | // On the first call to nonReentrant, _notEntered will be true 57 | require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); 58 | 59 | // Any calls to nonReentrant after this point will fail 60 | _status = _ENTERED; 61 | 62 | _; 63 | 64 | // By storing the original value once again, a refund is triggered (see 65 | // https://eips.ethereum.org/EIPS/eip-2200) 66 | _status = _NOT_ENTERED; 67 | } 68 | uint256[49] private __gap; 69 | } 70 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-ERC20Permit.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "./draft-IERC20Permit.sol"; 7 | import "../ERC20.sol"; 8 | import "../../../utils/cryptography/draft-EIP712.sol"; 9 | import "../../../utils/cryptography/ECDSA.sol"; 10 | import "../../../utils/Counters.sol"; 11 | 12 | /** 13 | * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in 14 | * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. 15 | * 16 | * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by 17 | * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't 18 | * need to send a transaction, and thus is not required to hold Ether at all. 19 | * 20 | * _Available since v3.4._ 21 | */ 22 | abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 { 23 | using Counters for Counters.Counter; 24 | 25 | mapping(address => Counters.Counter) private _nonces; 26 | 27 | // solhint-disable-next-line var-name-mixedcase 28 | bytes32 private immutable _PERMIT_TYPEHASH = 29 | keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); 30 | 31 | /** 32 | * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. 33 | * 34 | * It's a good idea to use the same `name` that is defined as the ERC20 token name. 35 | */ 36 | constructor(string memory name) EIP712(name, "1") {} 37 | 38 | /** 39 | * @dev See {IERC20Permit-permit}. 40 | */ 41 | function permit( 42 | address owner, 43 | address spender, 44 | uint256 value, 45 | uint256 deadline, 46 | uint8 v, 47 | bytes32 r, 48 | bytes32 s 49 | ) public virtual override { 50 | require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); 51 | 52 | bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); 53 | 54 | bytes32 hash = _hashTypedDataV4(structHash); 55 | 56 | address signer = ECDSA.recover(hash, v, r, s); 57 | require(signer == owner, "ERC20Permit: invalid signature"); 58 | 59 | _approve(owner, spender, value); 60 | } 61 | 62 | /** 63 | * @dev See {IERC20Permit-nonces}. 64 | */ 65 | function nonces(address owner) public view virtual override returns (uint256) { 66 | return _nonces[owner].current(); 67 | } 68 | 69 | /** 70 | * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. 71 | */ 72 | // solhint-disable-next-line func-name-mixedcase 73 | function DOMAIN_SEPARATOR() external view override returns (bytes32) { 74 | return _domainSeparatorV4(); 75 | } 76 | 77 | /** 78 | * @dev "Consume a nonce": return the current value and increment. 79 | * 80 | * _Available since v4.1._ 81 | */ 82 | function _useNonce(address owner) internal virtual returns (uint256 current) { 83 | Counters.Counter storage nonce = _nonces[owner]; 84 | current = nonce.current(); 85 | nonce.increment(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (proxy/utils/Initializable.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "../../utils/AddressUpgradeable.sol"; 7 | 8 | /** 9 | * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed 10 | * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an 11 | * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer 12 | * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. 13 | * 14 | * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as 15 | * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. 16 | * 17 | * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure 18 | * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. 19 | * 20 | * [CAUTION] 21 | * ==== 22 | * Avoid leaving a contract uninitialized. 23 | * 24 | * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation 25 | * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the 26 | * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed: 27 | * 28 | * [.hljs-theme-light.nopadding] 29 | * ``` 30 | * /// @custom:oz-upgrades-unsafe-allow constructor 31 | * constructor() initializer {} 32 | * ``` 33 | * ==== 34 | */ 35 | abstract contract Initializable { 36 | /** 37 | * @dev Indicates that the contract has been initialized. 38 | */ 39 | bool private _initialized; 40 | 41 | /** 42 | * @dev Indicates that the contract is in the process of being initialized. 43 | */ 44 | bool private _initializing; 45 | 46 | /** 47 | * @dev Modifier to protect an initializer function from being invoked twice. 48 | */ 49 | modifier initializer() { 50 | // If the contract is initializing we ignore whether _initialized is set in order to support multiple 51 | // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the 52 | // contract may have been reentered. 53 | require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized"); 54 | 55 | bool isTopLevelCall = !_initializing; 56 | if (isTopLevelCall) { 57 | _initializing = true; 58 | _initialized = true; 59 | } 60 | 61 | _; 62 | 63 | if (isTopLevelCall) { 64 | _initializing = false; 65 | } 66 | } 67 | 68 | /** 69 | * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the 70 | * {initializer} modifier, directly or indirectly. 71 | */ 72 | modifier onlyInitializing() { 73 | require(_initializing, "Initializable: contract is not initializing"); 74 | _; 75 | } 76 | 77 | function _isConstructor() private view returns (bool) { 78 | return !AddressUpgradeable.isContract(address(this)); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (proxy/utils/UUPSUpgradeable.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "../ERC1967/ERC1967UpgradeUpgradeable.sol"; 7 | import "./Initializable.sol"; 8 | 9 | /** 10 | * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an 11 | * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. 12 | * 13 | * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is 14 | * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing 15 | * `UUPSUpgradeable` with a custom implementation of upgrades. 16 | * 17 | * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. 18 | * 19 | * _Available since v4.1._ 20 | */ 21 | abstract contract UUPSUpgradeable is Initializable, ERC1967UpgradeUpgradeable { 22 | function __UUPSUpgradeable_init() internal onlyInitializing { 23 | __ERC1967Upgrade_init_unchained(); 24 | __UUPSUpgradeable_init_unchained(); 25 | } 26 | 27 | function __UUPSUpgradeable_init_unchained() internal onlyInitializing { 28 | } 29 | /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment 30 | address private immutable __self = address(this); 31 | 32 | /** 33 | * @dev Check that the execution is being performed through a delegatecall call and that the execution context is 34 | * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case 35 | * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a 36 | * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to 37 | * fail. 38 | */ 39 | modifier onlyProxy() { 40 | require(address(this) != __self, "Function must be called through delegatecall"); 41 | require(_getImplementation() == __self, "Function must be called through active proxy"); 42 | _; 43 | } 44 | 45 | /** 46 | * @dev Upgrade the implementation of the proxy to `newImplementation`. 47 | * 48 | * Calls {_authorizeUpgrade}. 49 | * 50 | * Emits an {Upgraded} event. 51 | */ 52 | function upgradeTo(address newImplementation) external virtual onlyProxy { 53 | _authorizeUpgrade(newImplementation); 54 | _upgradeToAndCallSecure(newImplementation, new bytes(0), false); 55 | } 56 | 57 | /** 58 | * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call 59 | * encoded in `data`. 60 | * 61 | * Calls {_authorizeUpgrade}. 62 | * 63 | * Emits an {Upgraded} event. 64 | */ 65 | function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { 66 | _authorizeUpgrade(newImplementation); 67 | _upgradeToAndCallSecure(newImplementation, data, true); 68 | } 69 | 70 | /** 71 | * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by 72 | * {upgradeTo} and {upgradeToAndCall}. 73 | * 74 | * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. 75 | * 76 | * ```solidity 77 | * function _authorizeUpgrade(address) internal override onlyOwner {} 78 | * ``` 79 | */ 80 | function _authorizeUpgrade(address newImplementation) internal virtual; 81 | uint256[50] private __gap; 82 | } 83 | -------------------------------------------------------------------------------- /lib/StakingV2/contracts/vaults/roles/Governable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.8.9; 3 | pragma abicoder v2; 4 | 5 | import "@openzeppelin/contracts/utils/Context.sol"; 6 | import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; 7 | 8 | interface IGovernable { 9 | function proposeGovernance(address _pendingGovernance) external; 10 | 11 | function acceptGovernance() external; 12 | } 13 | 14 | abstract contract GovernableInternal { 15 | event GovenanceUpdated(address _govenance); 16 | event GovenanceProposed(address _pendingGovenance); 17 | 18 | /// @dev This contract is used as part of the Vault contract and it is upgradeable. 19 | /// which means any changes to the state variables could corrupt the data. Do not modify these at all. 20 | /// @notice the address of the current governance 21 | address public governance; 22 | /// @notice the address of the pending governance 23 | address public pendingGovernance; 24 | 25 | /// @dev ensure msg.send is the governanace 26 | modifier onlyGovernance() { 27 | require(_getMsgSender() == governance, "governance only"); 28 | _; 29 | } 30 | 31 | /// @dev ensure msg.send is the pendingGovernance 32 | modifier onlyPendingGovernance() { 33 | require(_getMsgSender() == pendingGovernance, "pending governance only"); 34 | _; 35 | } 36 | 37 | /// @dev the deployer of the contract will be set as the initial governance 38 | // solhint-disable-next-line func-name-mixedcase 39 | function __Governable_init_unchained(address _governance) internal { 40 | require(_getMsgSender() != _governance, "invalid address"); 41 | _updateGovernance(_governance); 42 | } 43 | 44 | ///@notice propose a new governance of the vault. Only can be called by the existing governance. 45 | ///@param _pendingGovernance the address of the pending governance 46 | function proposeGovernance(address _pendingGovernance) external onlyGovernance { 47 | require(_pendingGovernance != address(0), "invalid address"); 48 | require(_pendingGovernance != governance, "already the governance"); 49 | pendingGovernance = _pendingGovernance; 50 | emit GovenanceProposed(_pendingGovernance); 51 | } 52 | 53 | ///@notice accept the proposal to be the governance of the vault. Only can be called by the pending governance. 54 | function acceptGovernance() external onlyPendingGovernance { 55 | _updateGovernance(pendingGovernance); 56 | } 57 | 58 | function _updateGovernance(address _pendingGovernance) internal { 59 | governance = _pendingGovernance; 60 | emit GovenanceUpdated(governance); 61 | } 62 | 63 | /// @dev provides an internal function to allow reduce the contract size 64 | function _onlyGovernance() internal view { 65 | require(_getMsgSender() == governance, "governance only"); 66 | } 67 | 68 | function _getMsgSender() internal view virtual returns (address); 69 | } 70 | 71 | /// @dev Add a `governance` and a `pendingGovernance` role to the contract, and implements a 2-phased nominatiom process to change the governance. 72 | /// Also provides a modifier to allow controlling access to functions of the contract. 73 | contract Governable is Context, GovernableInternal { 74 | constructor(address _governance) GovernableInternal() { 75 | __Governable_init_unchained(_governance); 76 | } 77 | 78 | function _getMsgSender() internal view override returns (address) { 79 | return _msgSender(); 80 | } 81 | } 82 | 83 | /// @dev ungradeable version of the {Governable} contract. Can be used as part of an upgradeable contract. 84 | abstract contract GovernableUpgradeable is ContextUpgradeable, GovernableInternal { 85 | // solhint-disable-next-line no-empty-blocks 86 | constructor() {} 87 | 88 | // solhint-disable-next-line func-name-mixedcase 89 | function __Governable_init(address _governance) internal { 90 | __Context_init(); 91 | __Governable_init_unchained(_governance); 92 | } 93 | 94 | // solhint-disable-next-line func-name-mixedcase 95 | function _getMsgSender() internal view override returns (address) { 96 | return _msgSender(); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /lib/StakingV2/contracts/interfaces/IVault.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.8.9; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol"; 6 | 7 | struct StrategyInfo { 8 | uint256 activation; 9 | uint256 lastReport; 10 | uint256 totalDebt; 11 | uint256 totalGain; 12 | uint256 totalLoss; 13 | } 14 | 15 | interface IVault is IERC20, IERC20Permit { 16 | function name() external view returns (string memory); 17 | 18 | function symbol() external view returns (string memory); 19 | 20 | function decimals() external view returns (uint256); 21 | 22 | function activation() external view returns (uint256); 23 | 24 | function rewards() external view returns (address); 25 | 26 | function managementFee() external view returns (uint256); 27 | 28 | function gatekeeper() external view returns (address); 29 | 30 | function governance() external view returns (address); 31 | 32 | function creator() external view returns (address); 33 | 34 | function strategyDataStore() external view returns (address); 35 | 36 | function healthCheck() external view returns (address); 37 | 38 | function emergencyShutdown() external view returns (bool); 39 | 40 | function lockedProfitDegradation() external view returns (uint256); 41 | 42 | function depositLimit() external view returns (uint256); 43 | 44 | function lastReport() external view returns (uint256); 45 | 46 | function lockedProfit() external view returns (uint256); 47 | 48 | function totalDebt() external view returns (uint256); 49 | 50 | function token() external view returns (address); 51 | 52 | function totalAsset() external view returns (uint256); 53 | 54 | function availableDepositLimit() external view returns (uint256); 55 | 56 | function maxAvailableShares() external view returns (uint256); 57 | 58 | function pricePerShare() external view returns (uint256); 59 | 60 | function debtOutstanding(address _strategy) external view returns (uint256); 61 | 62 | function creditAvailable(address _strategy) external view returns (uint256); 63 | 64 | function expectedReturn(address _strategy) external view returns (uint256); 65 | 66 | function strategy(address _strategy) external view returns (StrategyInfo memory); 67 | 68 | function strategyDebtRatio(address _strategy) external view returns (uint256); 69 | 70 | function setRewards(address _rewards) external; 71 | 72 | function setManagementFee(uint256 _managementFee) external; 73 | 74 | function setGatekeeper(address _gatekeeper) external; 75 | 76 | function setStrategyDataStore(address _strategyDataStoreContract) external; 77 | 78 | function setHealthCheck(address _healthCheck) external; 79 | 80 | function setVaultEmergencyShutdown(bool _active) external; 81 | 82 | function setLockedProfileDegradation(uint256 _degradation) external; 83 | 84 | function setDepositLimit(uint256 _limit) external; 85 | 86 | function sweep(address _token, uint256 _amount) external; 87 | 88 | function addStrategy(address _strategy) external returns (bool); 89 | 90 | function migrateStrategy(address _oldVersion, address _newVersion) external returns (bool); 91 | 92 | function revokeStrategy() external; 93 | 94 | /// @notice deposit the given amount into the vault, and return the number of shares 95 | function deposit(uint256 _amount, address _recipient) external returns (uint256); 96 | 97 | /// @notice burn the given amount of shares from the vault, and return the number of underlying tokens recovered 98 | function withdraw( 99 | uint256 _shares, 100 | address _recipient, 101 | uint256 _maxLoss 102 | ) external returns (uint256); 103 | 104 | function report( 105 | uint256 _gain, 106 | uint256 _loss, 107 | uint256 _debtPayment 108 | ) external returns (uint256); 109 | } 110 | 111 | interface IBoostedVault { 112 | function totalBoostedSupply() external view returns (uint256); 113 | 114 | function boostedBalanceOf(address _user) external view returns (uint256); 115 | 116 | function updateBoostedBalancesForUsers(address[] calldata _users) external; 117 | } 118 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "../IERC20Upgradeable.sol"; 7 | import "../../../utils/AddressUpgradeable.sol"; 8 | 9 | /** 10 | * @title SafeERC20 11 | * @dev Wrappers around ERC20 operations that throw on failure (when the token 12 | * contract returns false). Tokens that return no value (and instead revert or 13 | * throw on failure) are also supported, non-reverting calls are assumed to be 14 | * successful. 15 | * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, 16 | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. 17 | */ 18 | library SafeERC20Upgradeable { 19 | using AddressUpgradeable for address; 20 | 21 | function safeTransfer( 22 | IERC20Upgradeable token, 23 | address to, 24 | uint256 value 25 | ) internal { 26 | _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 27 | } 28 | 29 | function safeTransferFrom( 30 | IERC20Upgradeable token, 31 | address from, 32 | address to, 33 | uint256 value 34 | ) internal { 35 | _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 36 | } 37 | 38 | /** 39 | * @dev Deprecated. This function has issues similar to the ones found in 40 | * {IERC20-approve}, and its usage is discouraged. 41 | * 42 | * Whenever possible, use {safeIncreaseAllowance} and 43 | * {safeDecreaseAllowance} instead. 44 | */ 45 | function safeApprove( 46 | IERC20Upgradeable token, 47 | address spender, 48 | uint256 value 49 | ) internal { 50 | // safeApprove should only be called when setting an initial allowance, 51 | // or when resetting it to zero. To increase and decrease it, use 52 | // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' 53 | require( 54 | (value == 0) || (token.allowance(address(this), spender) == 0), 55 | "SafeERC20: approve from non-zero to non-zero allowance" 56 | ); 57 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 58 | } 59 | 60 | function safeIncreaseAllowance( 61 | IERC20Upgradeable token, 62 | address spender, 63 | uint256 value 64 | ) internal { 65 | uint256 newAllowance = token.allowance(address(this), spender) + value; 66 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 67 | } 68 | 69 | function safeDecreaseAllowance( 70 | IERC20Upgradeable token, 71 | address spender, 72 | uint256 value 73 | ) internal { 74 | unchecked { 75 | uint256 oldAllowance = token.allowance(address(this), spender); 76 | require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); 77 | uint256 newAllowance = oldAllowance - value; 78 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 79 | } 80 | } 81 | 82 | /** 83 | * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement 84 | * on the return value: the return value is optional (but if data is returned, it must not be false). 85 | * @param token The token targeted by the call. 86 | * @param data The call data (encoded using abi.encode or one of its variants). 87 | */ 88 | function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { 89 | // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since 90 | // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that 91 | // the target address contains contract code and also asserts for success in the low-level call. 92 | 93 | bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); 94 | if (returndata.length > 0) { 95 | // Return data is optional 96 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "../../utils/introspection/IERC165Upgradeable.sol"; 7 | 8 | /** 9 | * @dev Required interface of an ERC1155 compliant contract, as defined in the 10 | * https://eips.ethereum.org/EIPS/eip-1155[EIP]. 11 | * 12 | * _Available since v3.1._ 13 | */ 14 | interface IERC1155Upgradeable is IERC165Upgradeable { 15 | /** 16 | * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. 17 | */ 18 | event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); 19 | 20 | /** 21 | * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all 22 | * transfers. 23 | */ 24 | event TransferBatch( 25 | address indexed operator, 26 | address indexed from, 27 | address indexed to, 28 | uint256[] ids, 29 | uint256[] values 30 | ); 31 | 32 | /** 33 | * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to 34 | * `approved`. 35 | */ 36 | event ApprovalForAll(address indexed account, address indexed operator, bool approved); 37 | 38 | /** 39 | * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. 40 | * 41 | * If an {URI} event was emitted for `id`, the standard 42 | * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value 43 | * returned by {IERC1155MetadataURI-uri}. 44 | */ 45 | event URI(string value, uint256 indexed id); 46 | 47 | /** 48 | * @dev Returns the amount of tokens of token type `id` owned by `account`. 49 | * 50 | * Requirements: 51 | * 52 | * - `account` cannot be the zero address. 53 | */ 54 | function balanceOf(address account, uint256 id) external view returns (uint256); 55 | 56 | /** 57 | * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. 58 | * 59 | * Requirements: 60 | * 61 | * - `accounts` and `ids` must have the same length. 62 | */ 63 | function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) 64 | external 65 | view 66 | returns (uint256[] memory); 67 | 68 | /** 69 | * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, 70 | * 71 | * Emits an {ApprovalForAll} event. 72 | * 73 | * Requirements: 74 | * 75 | * - `operator` cannot be the caller. 76 | */ 77 | function setApprovalForAll(address operator, bool approved) external; 78 | 79 | /** 80 | * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. 81 | * 82 | * See {setApprovalForAll}. 83 | */ 84 | function isApprovedForAll(address account, address operator) external view returns (bool); 85 | 86 | /** 87 | * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. 88 | * 89 | * Emits a {TransferSingle} event. 90 | * 91 | * Requirements: 92 | * 93 | * - `to` cannot be the zero address. 94 | * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}. 95 | * - `from` must have a balance of tokens of type `id` of at least `amount`. 96 | * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the 97 | * acceptance magic value. 98 | */ 99 | function safeTransferFrom( 100 | address from, 101 | address to, 102 | uint256 id, 103 | uint256 amount, 104 | bytes calldata data 105 | ) external; 106 | 107 | /** 108 | * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. 109 | * 110 | * Emits a {TransferBatch} event. 111 | * 112 | * Requirements: 113 | * 114 | * - `ids` and `amounts` must have the same length. 115 | * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the 116 | * acceptance magic value. 117 | */ 118 | function safeBatchTransferFrom( 119 | address from, 120 | address to, 121 | uint256[] calldata ids, 122 | uint256[] calldata amounts, 123 | bytes calldata data 124 | ) external; 125 | } 126 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "./ECDSA.sol"; 7 | 8 | /** 9 | * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. 10 | * 11 | * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, 12 | * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding 13 | * they need in their contracts using a combination of `abi.encode` and `keccak256`. 14 | * 15 | * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding 16 | * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA 17 | * ({_hashTypedDataV4}). 18 | * 19 | * The implementation of the domain separator was designed to be as efficient as possible while still properly updating 20 | * the chain id to protect against replay attacks on an eventual fork of the chain. 21 | * 22 | * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method 23 | * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. 24 | * 25 | * _Available since v3.4._ 26 | */ 27 | abstract contract EIP712 { 28 | /* solhint-disable var-name-mixedcase */ 29 | // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to 30 | // invalidate the cached domain separator if the chain id changes. 31 | bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; 32 | uint256 private immutable _CACHED_CHAIN_ID; 33 | address private immutable _CACHED_THIS; 34 | 35 | bytes32 private immutable _HASHED_NAME; 36 | bytes32 private immutable _HASHED_VERSION; 37 | bytes32 private immutable _TYPE_HASH; 38 | 39 | /* solhint-enable var-name-mixedcase */ 40 | 41 | /** 42 | * @dev Initializes the domain separator and parameter caches. 43 | * 44 | * The meaning of `name` and `version` is specified in 45 | * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: 46 | * 47 | * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. 48 | * - `version`: the current major version of the signing domain. 49 | * 50 | * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart 51 | * contract upgrade]. 52 | */ 53 | constructor(string memory name, string memory version) { 54 | bytes32 hashedName = keccak256(bytes(name)); 55 | bytes32 hashedVersion = keccak256(bytes(version)); 56 | bytes32 typeHash = keccak256( 57 | "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" 58 | ); 59 | _HASHED_NAME = hashedName; 60 | _HASHED_VERSION = hashedVersion; 61 | _CACHED_CHAIN_ID = block.chainid; 62 | _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion); 63 | _CACHED_THIS = address(this); 64 | _TYPE_HASH = typeHash; 65 | } 66 | 67 | /** 68 | * @dev Returns the domain separator for the current chain. 69 | */ 70 | function _domainSeparatorV4() internal view returns (bytes32) { 71 | if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) { 72 | return _CACHED_DOMAIN_SEPARATOR; 73 | } else { 74 | return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION); 75 | } 76 | } 77 | 78 | function _buildDomainSeparator( 79 | bytes32 typeHash, 80 | bytes32 nameHash, 81 | bytes32 versionHash 82 | ) private view returns (bytes32) { 83 | return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this))); 84 | } 85 | 86 | /** 87 | * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this 88 | * function returns the hash of the fully encoded EIP712 message for this domain. 89 | * 90 | * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: 91 | * 92 | * ```solidity 93 | * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( 94 | * keccak256("Mail(address to,string contents)"), 95 | * mailTo, 96 | * keccak256(bytes(mailContents)) 97 | * ))); 98 | * address signer = ECDSA.recover(digest, signature); 99 | * ``` 100 | */ 101 | function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { 102 | return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/utils/introspection/ERC165CheckerUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "./IERC165Upgradeable.sol"; 7 | 8 | /** 9 | * @dev Library used to query support of an interface declared via {IERC165}. 10 | * 11 | * Note that these functions return the actual result of the query: they do not 12 | * `revert` if an interface is not supported. It is up to the caller to decide 13 | * what to do in these cases. 14 | */ 15 | library ERC165CheckerUpgradeable { 16 | // As per the EIP-165 spec, no interface should ever match 0xffffffff 17 | bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; 18 | 19 | /** 20 | * @dev Returns true if `account` supports the {IERC165} interface, 21 | */ 22 | function supportsERC165(address account) internal view returns (bool) { 23 | // Any contract that implements ERC165 must explicitly indicate support of 24 | // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid 25 | return 26 | _supportsERC165Interface(account, type(IERC165Upgradeable).interfaceId) && 27 | !_supportsERC165Interface(account, _INTERFACE_ID_INVALID); 28 | } 29 | 30 | /** 31 | * @dev Returns true if `account` supports the interface defined by 32 | * `interfaceId`. Support for {IERC165} itself is queried automatically. 33 | * 34 | * See {IERC165-supportsInterface}. 35 | */ 36 | function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { 37 | // query support of both ERC165 as per the spec and support of _interfaceId 38 | return supportsERC165(account) && _supportsERC165Interface(account, interfaceId); 39 | } 40 | 41 | /** 42 | * @dev Returns a boolean array where each value corresponds to the 43 | * interfaces passed in and whether they're supported or not. This allows 44 | * you to batch check interfaces for a contract where your expectation 45 | * is that some interfaces may not be supported. 46 | * 47 | * See {IERC165-supportsInterface}. 48 | * 49 | * _Available since v3.4._ 50 | */ 51 | function getSupportedInterfaces(address account, bytes4[] memory interfaceIds) 52 | internal 53 | view 54 | returns (bool[] memory) 55 | { 56 | // an array of booleans corresponding to interfaceIds and whether they're supported or not 57 | bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); 58 | 59 | // query support of ERC165 itself 60 | if (supportsERC165(account)) { 61 | // query support of each interface in interfaceIds 62 | for (uint256 i = 0; i < interfaceIds.length; i++) { 63 | interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]); 64 | } 65 | } 66 | 67 | return interfaceIdsSupported; 68 | } 69 | 70 | /** 71 | * @dev Returns true if `account` supports all the interfaces defined in 72 | * `interfaceIds`. Support for {IERC165} itself is queried automatically. 73 | * 74 | * Batch-querying can lead to gas savings by skipping repeated checks for 75 | * {IERC165} support. 76 | * 77 | * See {IERC165-supportsInterface}. 78 | */ 79 | function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { 80 | // query support of ERC165 itself 81 | if (!supportsERC165(account)) { 82 | return false; 83 | } 84 | 85 | // query support of each interface in _interfaceIds 86 | for (uint256 i = 0; i < interfaceIds.length; i++) { 87 | if (!_supportsERC165Interface(account, interfaceIds[i])) { 88 | return false; 89 | } 90 | } 91 | 92 | // all interfaces supported 93 | return true; 94 | } 95 | 96 | /** 97 | * @notice Query if a contract implements an interface, does not check ERC165 support 98 | * @param account The address of the contract to query for support of an interface 99 | * @param interfaceId The interface identifier, as specified in ERC-165 100 | * @return true if the contract at account indicates support of the interface with 101 | * identifier interfaceId, false otherwise 102 | * @dev Assumes that account contains a contract that supports ERC165, otherwise 103 | * the behavior of this method is undefined. This precondition can be checked 104 | * with {supportsERC165}. 105 | * Interface identification is specified in ERC-165. 106 | */ 107 | function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) { 108 | bytes memory encodedParams = abi.encodeWithSelector(IERC165Upgradeable.supportsInterface.selector, interfaceId); 109 | (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams); 110 | if (result.length < 32) return false; 111 | return success && abi.decode(result, (bool)); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/Address.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev Collection of functions related to the address type 8 | */ 9 | library AddressUpgradeable { 10 | /** 11 | * @dev Returns true if `account` is a contract. 12 | * 13 | * [IMPORTANT] 14 | * ==== 15 | * It is unsafe to assume that an address for which this function returns 16 | * false is an externally-owned account (EOA) and not a contract. 17 | * 18 | * Among others, `isContract` will return false for the following 19 | * types of addresses: 20 | * 21 | * - an externally-owned account 22 | * - a contract in construction 23 | * - an address where a contract will be created 24 | * - an address where a contract lived, but was destroyed 25 | * ==== 26 | */ 27 | function isContract(address account) internal view returns (bool) { 28 | // This method relies on extcodesize, which returns 0 for contracts in 29 | // construction, since the code is only stored at the end of the 30 | // constructor execution. 31 | 32 | uint256 size; 33 | assembly { 34 | size := extcodesize(account) 35 | } 36 | return size > 0; 37 | } 38 | 39 | /** 40 | * @dev Replacement for Solidity's `transfer`: sends `amount` wei to 41 | * `recipient`, forwarding all available gas and reverting on errors. 42 | * 43 | * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost 44 | * of certain opcodes, possibly making contracts go over the 2300 gas limit 45 | * imposed by `transfer`, making them unable to receive funds via 46 | * `transfer`. {sendValue} removes this limitation. 47 | * 48 | * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. 49 | * 50 | * IMPORTANT: because control is transferred to `recipient`, care must be 51 | * taken to not create reentrancy vulnerabilities. Consider using 52 | * {ReentrancyGuard} or the 53 | * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. 54 | */ 55 | function sendValue(address payable recipient, uint256 amount) internal { 56 | require(address(this).balance >= amount, "Address: insufficient balance"); 57 | 58 | (bool success, ) = recipient.call{value: amount}(""); 59 | require(success, "Address: unable to send value, recipient may have reverted"); 60 | } 61 | 62 | /** 63 | * @dev Performs a Solidity function call using a low level `call`. A 64 | * plain `call` is an unsafe replacement for a function call: use this 65 | * function instead. 66 | * 67 | * If `target` reverts with a revert reason, it is bubbled up by this 68 | * function (like regular Solidity function calls). 69 | * 70 | * Returns the raw returned data. To convert to the expected return value, 71 | * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. 72 | * 73 | * Requirements: 74 | * 75 | * - `target` must be a contract. 76 | * - calling `target` with `data` must not revert. 77 | * 78 | * _Available since v3.1._ 79 | */ 80 | function functionCall(address target, bytes memory data) internal returns (bytes memory) { 81 | return functionCall(target, data, "Address: low-level call failed"); 82 | } 83 | 84 | /** 85 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with 86 | * `errorMessage` as a fallback revert reason when `target` reverts. 87 | * 88 | * _Available since v3.1._ 89 | */ 90 | function functionCall( 91 | address target, 92 | bytes memory data, 93 | string memory errorMessage 94 | ) internal returns (bytes memory) { 95 | return functionCallWithValue(target, data, 0, errorMessage); 96 | } 97 | 98 | /** 99 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 100 | * but also transferring `value` wei to `target`. 101 | * 102 | * Requirements: 103 | * 104 | * - the calling contract must have an ETH balance of at least `value`. 105 | * - the called Solidity function must be `payable`. 106 | * 107 | * _Available since v3.1._ 108 | */ 109 | function functionCallWithValue( 110 | address target, 111 | bytes memory data, 112 | uint256 value 113 | ) internal returns (bytes memory) { 114 | return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); 115 | } 116 | 117 | /** 118 | * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but 119 | * with `errorMessage` as a fallback revert reason when `target` reverts. 120 | * 121 | * _Available since v3.1._ 122 | */ 123 | function functionCallWithValue( 124 | address target, 125 | bytes memory data, 126 | uint256 value, 127 | string memory errorMessage 128 | ) internal returns (bytes memory) { 129 | require(address(this).balance >= value, "Address: insufficient balance for call"); 130 | require(isContract(target), "Address: call to non-contract"); 131 | 132 | (bool success, bytes memory returndata) = target.call{value: value}(data); 133 | return verifyCallResult(success, returndata, errorMessage); 134 | } 135 | 136 | /** 137 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 138 | * but performing a static call. 139 | * 140 | * _Available since v3.3._ 141 | */ 142 | function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { 143 | return functionStaticCall(target, data, "Address: low-level static call failed"); 144 | } 145 | 146 | /** 147 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 148 | * but performing a static call. 149 | * 150 | * _Available since v3.3._ 151 | */ 152 | function functionStaticCall( 153 | address target, 154 | bytes memory data, 155 | string memory errorMessage 156 | ) internal view returns (bytes memory) { 157 | require(isContract(target), "Address: static call to non-contract"); 158 | 159 | (bool success, bytes memory returndata) = target.staticcall(data); 160 | return verifyCallResult(success, returndata, errorMessage); 161 | } 162 | 163 | /** 164 | * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the 165 | * revert reason using the provided one. 166 | * 167 | * _Available since v4.3._ 168 | */ 169 | function verifyCallResult( 170 | bool success, 171 | bytes memory returndata, 172 | string memory errorMessage 173 | ) internal pure returns (bytes memory) { 174 | if (success) { 175 | return returndata; 176 | } else { 177 | // Look for revert reason and bubble it up if present 178 | if (returndata.length > 0) { 179 | // The easiest way to bubble the revert reason is using memory via assembly 180 | 181 | assembly { 182 | let returndata_size := mload(returndata) 183 | revert(add(32, returndata), returndata_size) 184 | } 185 | } else { 186 | revert(errorMessage); 187 | } 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Upgrade.sol) 3 | 4 | pragma solidity ^0.8.2; 5 | 6 | import "../beacon/IBeaconUpgradeable.sol"; 7 | import "../../utils/AddressUpgradeable.sol"; 8 | import "../../utils/StorageSlotUpgradeable.sol"; 9 | import "../utils/Initializable.sol"; 10 | 11 | /** 12 | * @dev This abstract contract provides getters and event emitting update functions for 13 | * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. 14 | * 15 | * _Available since v4.1._ 16 | * 17 | * @custom:oz-upgrades-unsafe-allow delegatecall 18 | */ 19 | abstract contract ERC1967UpgradeUpgradeable is Initializable { 20 | function __ERC1967Upgrade_init() internal onlyInitializing { 21 | __ERC1967Upgrade_init_unchained(); 22 | } 23 | 24 | function __ERC1967Upgrade_init_unchained() internal onlyInitializing { 25 | } 26 | // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 27 | bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; 28 | 29 | /** 30 | * @dev Storage slot with the address of the current implementation. 31 | * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is 32 | * validated in the constructor. 33 | */ 34 | bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; 35 | 36 | /** 37 | * @dev Emitted when the implementation is upgraded. 38 | */ 39 | event Upgraded(address indexed implementation); 40 | 41 | /** 42 | * @dev Returns the current implementation address. 43 | */ 44 | function _getImplementation() internal view returns (address) { 45 | return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value; 46 | } 47 | 48 | /** 49 | * @dev Stores a new address in the EIP1967 implementation slot. 50 | */ 51 | function _setImplementation(address newImplementation) private { 52 | require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract"); 53 | StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; 54 | } 55 | 56 | /** 57 | * @dev Perform implementation upgrade 58 | * 59 | * Emits an {Upgraded} event. 60 | */ 61 | function _upgradeTo(address newImplementation) internal { 62 | _setImplementation(newImplementation); 63 | emit Upgraded(newImplementation); 64 | } 65 | 66 | /** 67 | * @dev Perform implementation upgrade with additional setup call. 68 | * 69 | * Emits an {Upgraded} event. 70 | */ 71 | function _upgradeToAndCall( 72 | address newImplementation, 73 | bytes memory data, 74 | bool forceCall 75 | ) internal { 76 | _upgradeTo(newImplementation); 77 | if (data.length > 0 || forceCall) { 78 | _functionDelegateCall(newImplementation, data); 79 | } 80 | } 81 | 82 | /** 83 | * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. 84 | * 85 | * Emits an {Upgraded} event. 86 | */ 87 | function _upgradeToAndCallSecure( 88 | address newImplementation, 89 | bytes memory data, 90 | bool forceCall 91 | ) internal { 92 | address oldImplementation = _getImplementation(); 93 | 94 | // Initial upgrade and setup call 95 | _setImplementation(newImplementation); 96 | if (data.length > 0 || forceCall) { 97 | _functionDelegateCall(newImplementation, data); 98 | } 99 | 100 | // Perform rollback test if not already in progress 101 | StorageSlotUpgradeable.BooleanSlot storage rollbackTesting = StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT); 102 | if (!rollbackTesting.value) { 103 | // Trigger rollback using upgradeTo from the new implementation 104 | rollbackTesting.value = true; 105 | _functionDelegateCall( 106 | newImplementation, 107 | abi.encodeWithSignature("upgradeTo(address)", oldImplementation) 108 | ); 109 | rollbackTesting.value = false; 110 | // Check rollback was effective 111 | require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades"); 112 | // Finally reset to the new implementation and log the upgrade 113 | _upgradeTo(newImplementation); 114 | } 115 | } 116 | 117 | /** 118 | * @dev Storage slot with the admin of the contract. 119 | * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is 120 | * validated in the constructor. 121 | */ 122 | bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; 123 | 124 | /** 125 | * @dev Emitted when the admin account has changed. 126 | */ 127 | event AdminChanged(address previousAdmin, address newAdmin); 128 | 129 | /** 130 | * @dev Returns the current admin. 131 | */ 132 | function _getAdmin() internal view returns (address) { 133 | return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value; 134 | } 135 | 136 | /** 137 | * @dev Stores a new address in the EIP1967 admin slot. 138 | */ 139 | function _setAdmin(address newAdmin) private { 140 | require(newAdmin != address(0), "ERC1967: new admin is the zero address"); 141 | StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin; 142 | } 143 | 144 | /** 145 | * @dev Changes the admin of the proxy. 146 | * 147 | * Emits an {AdminChanged} event. 148 | */ 149 | function _changeAdmin(address newAdmin) internal { 150 | emit AdminChanged(_getAdmin(), newAdmin); 151 | _setAdmin(newAdmin); 152 | } 153 | 154 | /** 155 | * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. 156 | * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. 157 | */ 158 | bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; 159 | 160 | /** 161 | * @dev Emitted when the beacon is upgraded. 162 | */ 163 | event BeaconUpgraded(address indexed beacon); 164 | 165 | /** 166 | * @dev Returns the current beacon. 167 | */ 168 | function _getBeacon() internal view returns (address) { 169 | return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value; 170 | } 171 | 172 | /** 173 | * @dev Stores a new beacon in the EIP1967 beacon slot. 174 | */ 175 | function _setBeacon(address newBeacon) private { 176 | require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract"); 177 | require( 178 | AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()), 179 | "ERC1967: beacon implementation is not a contract" 180 | ); 181 | StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon; 182 | } 183 | 184 | /** 185 | * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does 186 | * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). 187 | * 188 | * Emits a {BeaconUpgraded} event. 189 | */ 190 | function _upgradeBeaconToAndCall( 191 | address newBeacon, 192 | bytes memory data, 193 | bool forceCall 194 | ) internal { 195 | _setBeacon(newBeacon); 196 | emit BeaconUpgraded(newBeacon); 197 | if (data.length > 0 || forceCall) { 198 | _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data); 199 | } 200 | } 201 | 202 | /** 203 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 204 | * but performing a delegate call. 205 | * 206 | * _Available since v3.4._ 207 | */ 208 | function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) { 209 | require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract"); 210 | 211 | // solhint-disable-next-line avoid-low-level-calls 212 | (bool success, bytes memory returndata) = target.delegatecall(data); 213 | return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed"); 214 | } 215 | uint256[50] private __gap; 216 | } 217 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts/utils/cryptography/ECDSA.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (utils/cryptography/ECDSA.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "../Strings.sol"; 7 | 8 | /** 9 | * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. 10 | * 11 | * These functions can be used to verify that a message was signed by the holder 12 | * of the private keys of a given address. 13 | */ 14 | library ECDSA { 15 | enum RecoverError { 16 | NoError, 17 | InvalidSignature, 18 | InvalidSignatureLength, 19 | InvalidSignatureS, 20 | InvalidSignatureV 21 | } 22 | 23 | function _throwError(RecoverError error) private pure { 24 | if (error == RecoverError.NoError) { 25 | return; // no error: do nothing 26 | } else if (error == RecoverError.InvalidSignature) { 27 | revert("ECDSA: invalid signature"); 28 | } else if (error == RecoverError.InvalidSignatureLength) { 29 | revert("ECDSA: invalid signature length"); 30 | } else if (error == RecoverError.InvalidSignatureS) { 31 | revert("ECDSA: invalid signature 's' value"); 32 | } else if (error == RecoverError.InvalidSignatureV) { 33 | revert("ECDSA: invalid signature 'v' value"); 34 | } 35 | } 36 | 37 | /** 38 | * @dev Returns the address that signed a hashed message (`hash`) with 39 | * `signature` or error string. This address can then be used for verification purposes. 40 | * 41 | * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: 42 | * this function rejects them by requiring the `s` value to be in the lower 43 | * half order, and the `v` value to be either 27 or 28. 44 | * 45 | * IMPORTANT: `hash` _must_ be the result of a hash operation for the 46 | * verification to be secure: it is possible to craft signatures that 47 | * recover to arbitrary addresses for non-hashed data. A safe way to ensure 48 | * this is by receiving a hash of the original message (which may otherwise 49 | * be too long), and then calling {toEthSignedMessageHash} on it. 50 | * 51 | * Documentation for signature generation: 52 | * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] 53 | * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] 54 | * 55 | * _Available since v4.3._ 56 | */ 57 | function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { 58 | // Check the signature length 59 | // - case 65: r,s,v signature (standard) 60 | // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ 61 | if (signature.length == 65) { 62 | bytes32 r; 63 | bytes32 s; 64 | uint8 v; 65 | // ecrecover takes the signature parameters, and the only way to get them 66 | // currently is to use assembly. 67 | assembly { 68 | r := mload(add(signature, 0x20)) 69 | s := mload(add(signature, 0x40)) 70 | v := byte(0, mload(add(signature, 0x60))) 71 | } 72 | return tryRecover(hash, v, r, s); 73 | } else if (signature.length == 64) { 74 | bytes32 r; 75 | bytes32 vs; 76 | // ecrecover takes the signature parameters, and the only way to get them 77 | // currently is to use assembly. 78 | assembly { 79 | r := mload(add(signature, 0x20)) 80 | vs := mload(add(signature, 0x40)) 81 | } 82 | return tryRecover(hash, r, vs); 83 | } else { 84 | return (address(0), RecoverError.InvalidSignatureLength); 85 | } 86 | } 87 | 88 | /** 89 | * @dev Returns the address that signed a hashed message (`hash`) with 90 | * `signature`. This address can then be used for verification purposes. 91 | * 92 | * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: 93 | * this function rejects them by requiring the `s` value to be in the lower 94 | * half order, and the `v` value to be either 27 or 28. 95 | * 96 | * IMPORTANT: `hash` _must_ be the result of a hash operation for the 97 | * verification to be secure: it is possible to craft signatures that 98 | * recover to arbitrary addresses for non-hashed data. A safe way to ensure 99 | * this is by receiving a hash of the original message (which may otherwise 100 | * be too long), and then calling {toEthSignedMessageHash} on it. 101 | */ 102 | function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { 103 | (address recovered, RecoverError error) = tryRecover(hash, signature); 104 | _throwError(error); 105 | return recovered; 106 | } 107 | 108 | /** 109 | * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. 110 | * 111 | * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] 112 | * 113 | * _Available since v4.3._ 114 | */ 115 | function tryRecover( 116 | bytes32 hash, 117 | bytes32 r, 118 | bytes32 vs 119 | ) internal pure returns (address, RecoverError) { 120 | bytes32 s; 121 | uint8 v; 122 | assembly { 123 | s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) 124 | v := add(shr(255, vs), 27) 125 | } 126 | return tryRecover(hash, v, r, s); 127 | } 128 | 129 | /** 130 | * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. 131 | * 132 | * _Available since v4.2._ 133 | */ 134 | function recover( 135 | bytes32 hash, 136 | bytes32 r, 137 | bytes32 vs 138 | ) internal pure returns (address) { 139 | (address recovered, RecoverError error) = tryRecover(hash, r, vs); 140 | _throwError(error); 141 | return recovered; 142 | } 143 | 144 | /** 145 | * @dev Overload of {ECDSA-tryRecover} that receives the `v`, 146 | * `r` and `s` signature fields separately. 147 | * 148 | * _Available since v4.3._ 149 | */ 150 | function tryRecover( 151 | bytes32 hash, 152 | uint8 v, 153 | bytes32 r, 154 | bytes32 s 155 | ) internal pure returns (address, RecoverError) { 156 | // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature 157 | // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines 158 | // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most 159 | // signatures from current libraries generate a unique signature with an s-value in the lower half order. 160 | // 161 | // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value 162 | // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or 163 | // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept 164 | // these malleable signatures as well. 165 | if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { 166 | return (address(0), RecoverError.InvalidSignatureS); 167 | } 168 | if (v != 27 && v != 28) { 169 | return (address(0), RecoverError.InvalidSignatureV); 170 | } 171 | 172 | // If the signature is valid (and not malleable), return the signer address 173 | address signer = ecrecover(hash, v, r, s); 174 | if (signer == address(0)) { 175 | return (address(0), RecoverError.InvalidSignature); 176 | } 177 | 178 | return (signer, RecoverError.NoError); 179 | } 180 | 181 | /** 182 | * @dev Overload of {ECDSA-recover} that receives the `v`, 183 | * `r` and `s` signature fields separately. 184 | */ 185 | function recover( 186 | bytes32 hash, 187 | uint8 v, 188 | bytes32 r, 189 | bytes32 s 190 | ) internal pure returns (address) { 191 | (address recovered, RecoverError error) = tryRecover(hash, v, r, s); 192 | _throwError(error); 193 | return recovered; 194 | } 195 | 196 | /** 197 | * @dev Returns an Ethereum Signed Message, created from a `hash`. This 198 | * produces hash corresponding to the one signed with the 199 | * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] 200 | * JSON-RPC method as part of EIP-191. 201 | * 202 | * See {recover}. 203 | */ 204 | function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { 205 | // 32 is the length in bytes of hash, 206 | // enforced by the type signature above 207 | return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); 208 | } 209 | 210 | /** 211 | * @dev Returns an Ethereum Signed Message, created from `s`. This 212 | * produces hash corresponding to the one signed with the 213 | * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] 214 | * JSON-RPC method as part of EIP-191. 215 | * 216 | * See {recover}. 217 | */ 218 | function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { 219 | return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); 220 | } 221 | 222 | /** 223 | * @dev Returns an Ethereum Signed Typed Data, created from a 224 | * `domainSeparator` and a `structHash`. This produces hash corresponding 225 | * to the one signed with the 226 | * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] 227 | * JSON-RPC method as part of EIP-712. 228 | * 229 | * See {recover}. 230 | */ 231 | function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { 232 | return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /lib/StakingV2/contracts/staking/StakingV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.8.9; 3 | 4 | import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165CheckerUpgradeable.sol"; 5 | import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; 6 | import "./Staking.sol"; 7 | import "../interfaces/IVault.sol"; 8 | 9 | /// @dev Add a new stake function that will update the user's boost balance in selected vaults immediately after staking 10 | contract StakingV2 is IStakingV2, Staking, ReentrancyGuardUpgradeable { 11 | using ERC165CheckerUpgradeable for address; 12 | using SafeERC20Upgradeable for IERC20Upgradeable; 13 | 14 | event StakeExtended(uint256 indexed _tokenId, uint248 indexed _newAmount, uint8 _newlockPeriod, address[] _vaults); 15 | 16 | /// @custom:oz-upgrades-unsafe-allow constructor 17 | constructor() initializer {} 18 | 19 | function initialize( 20 | string memory _name, 21 | string memory _symbol, 22 | address _governance, 23 | address _gatekeeper, 24 | address _yopRewards, 25 | string memory _uri, 26 | string memory _contractURI, 27 | address _owner, 28 | address _accessControlManager 29 | ) external virtual override initializer { 30 | __ReentrancyGuard_init(); 31 | __Staking_init( 32 | _name, 33 | _symbol, 34 | _governance, 35 | _gatekeeper, 36 | _yopRewards, 37 | _uri, 38 | _contractURI, 39 | _owner, 40 | _accessControlManager 41 | ); 42 | } 43 | 44 | /// @notice Return the total number of stakes created so far 45 | function totalSupply() external view returns (uint256) { 46 | return stakes.length; 47 | } 48 | 49 | /// @notice Same as `stake(uint248,uint8)`, but will take an array of vault addresses as extra parameter. 50 | /// If the vault addresses are provided, the user's boosted balance in these vaults will be updated immediately after staking to take into account their latest staking positions. 51 | /// @param _amount The amount of YOP tokens to stake 52 | /// @param _lockPeriod The locking period of the stake, in months 53 | /// @param _vaultsToBoost The vaults that the user's boosted balance should be updated after staking 54 | /// @return The id of the NFT token that is also the id of the stake 55 | function stakeAndBoost( 56 | uint248 _amount, 57 | uint8 _lockPeriod, 58 | address[] calldata _vaultsToBoost 59 | ) external nonReentrant returns (uint256) { 60 | _notPaused(); 61 | uint256 tokenId = _mintStake(_amount, _lockPeriod, _msgSender()); 62 | _updateVaults(_vaultsToBoost, _msgSender()); 63 | return tokenId; 64 | } 65 | 66 | /// @notice Stake the YOP tokens on behalf of another user. 67 | /// @param _amount The amount of YOP tokens to stake 68 | /// @param _lockPeriod The locking period of the stake, in months 69 | /// @param _to The user to send the NFT to 70 | /// @return The id of the NFT token that is also the id of the stake 71 | function stakeForUser( 72 | uint248 _amount, 73 | uint8 _lockPeriod, 74 | address _to 75 | ) external returns (uint256) { 76 | _notPaused(); 77 | return _mintStake(_amount, _lockPeriod, _to); 78 | } 79 | 80 | /// @notice Stake the YOP tokens on behalf of another user and boost the user's balance in the given vaults 81 | /// @param _amount The amount of YOP tokens to stake 82 | /// @param _lockPeriod The locking period of the stake, in months 83 | /// @param _to The user to send the NFT to 84 | /// @param _vaultsToBoost The vaults that the user's boosted balance should be updated after staking 85 | /// @return The id of the NFT token that is also the id of the stake 86 | function stakeAndBoostForUser( 87 | uint248 _amount, 88 | uint8 _lockPeriod, 89 | address _to, 90 | address[] calldata _vaultsToBoost 91 | ) external nonReentrant returns (uint256) { 92 | _notPaused(); 93 | uint256 tokenId = _mintStake(_amount, _lockPeriod, _to); 94 | _updateVaults(_vaultsToBoost, _to); 95 | return tokenId; 96 | } 97 | 98 | /// @notice Exit a single unlocked staking position, claim remaining rewards associated with the stake, and adjust the boost values in vaults 99 | /// @param _stakeId The id of the unlocked staking positon 100 | /// @param _to The recipient address that will receive the YOP tokens 101 | /// @param _vaultsToBoost The list of vaults that will have the boost updated 102 | function unstakeSingleAndBoost( 103 | uint256 _stakeId, 104 | address _to, 105 | address[] calldata _vaultsToBoost 106 | ) external nonReentrant { 107 | _notPaused(); 108 | _burnSingle(_stakeId, _to); 109 | _updateVaults(_vaultsToBoost, _msgSender()); 110 | } 111 | 112 | /// @notice Exit all unlocked staking position, claim all remaining rewards associated with the stakes, and adjust the boost values in vaults 113 | /// @param _to The recipient address that will receive the YOP tokens 114 | /// @param _vaultsToBoost The list of vaults that will have the boost updated 115 | function unstakeAllAndBoost(address _to, address[] calldata _vaultsToBoost) external nonReentrant { 116 | _notPaused(); 117 | _burnAll(_to); 118 | _updateVaults(_vaultsToBoost, _msgSender()); 119 | } 120 | 121 | /// @notice Increase the staking amount or lock period for a single stake position. Update the boosted balance in the list of vaults. 122 | /// @param _stakeId The id of the stake 123 | /// @param _additionalDuration The additional lockup months to add to the stake. New lockup months can not exceed maximum value. 124 | /// @param _additionalAmount Additional YOP amounts to add to the stake. 125 | /// @param _vaultsToUpdate The list of vaults that will have the boost updated for the owner of the stake 126 | function extendStake( 127 | uint256 _stakeId, 128 | uint8 _additionalDuration, 129 | uint248 _additionalAmount, 130 | address[] calldata _vaultsToUpdate 131 | ) external nonReentrant { 132 | _notPaused(); 133 | require(_additionalAmount > 0 || _additionalDuration > 0, "!parameters"); 134 | 135 | Stake storage stake = stakes[_stakeId]; 136 | require(owners[_stakeId] == _msgSender(), "!owner"); 137 | 138 | uint8 newLockPeriod = stake.lockPeriod; 139 | if (_additionalDuration > 0) { 140 | newLockPeriod = stake.lockPeriod + _additionalDuration; 141 | require(newLockPeriod <= MAX_LOCK_PERIOD, "!duration"); 142 | } 143 | 144 | uint248 newAmount = stake.amount; 145 | if (_additionalAmount > 0) { 146 | require(IERC20Upgradeable(_getYOPAddress()).balanceOf(_msgSender()) >= _additionalAmount, "!balance"); 147 | newAmount = stake.amount + _additionalAmount; 148 | require(newAmount >= minStakeAmount, "!amount"); 149 | } 150 | 151 | uint256 newTotalWorkingSupply = (totalWorkingSupply + 152 | (newAmount * newLockPeriod - stake.amount * stake.lockPeriod)); 153 | 154 | require(newTotalWorkingSupply <= stakingLimit, "limit"); 155 | 156 | IYOPRewards(yopRewards).calculateStakingRewards(_stakeId); 157 | 158 | if (_additionalDuration > 0) { 159 | stake.lockPeriod = newLockPeriod; 160 | } 161 | if (_additionalAmount > 0) { 162 | IERC20Upgradeable(_getYOPAddress()).safeTransferFrom(_msgSender(), address(this), _additionalAmount); 163 | stake.amount = newAmount; 164 | } 165 | totalWorkingSupply = newTotalWorkingSupply; 166 | _updateVaults(_vaultsToUpdate, _msgSender()); 167 | emit StakeExtended(_stakeId, newAmount, newLockPeriod, _vaultsToUpdate); 168 | } 169 | 170 | /// @notice Claim the rewards for all the given stakes, and extend each stake by the amount of rewards collected. 171 | /// @dev For each stake, this will basically claim the rewards for that stake, and add the rewards to the amount of that stake. No changes to the stake duration. 172 | /// This is built with automation in mind so that we can build an auto-compounding feature for users if we want. However, users can call this to claim & topup their existing stakes too. 173 | /// @param _stakeIds The ids of the stakes that will be compounded 174 | function compoundForStaking(uint256[] calldata _stakeIds) external { 175 | _notPaused(); 176 | uint256 totalIncreasedSupply = _compoundForStakes(_stakeIds); 177 | totalWorkingSupply += totalIncreasedSupply; 178 | } 179 | 180 | /// @notice Claim vault rewards for each user and top up a stake of that user. No changes to the duration of the stake. 181 | /// @dev This is built mainly for automation. 182 | /// @param _users List of user address to claim vault rewards from. 183 | /// @param _topupStakes The list of stakes to top up with the vault rewards. Each stake in the list should be owned by the address in the corresponding position in the `_users` list. 184 | /// E.g. `_users[0]` should own `_topupStakes[0]`, `_users[1]` should own `_topupStakes[1]` and so on. 185 | function compoundWithVaultRewards(address[] calldata _users, uint256[] calldata _topupStakes) external { 186 | _notPaused(); 187 | uint256 totalIncreasedSupply = _compoundWithVaultRewards(_users, _topupStakes); 188 | totalWorkingSupply += totalIncreasedSupply; 189 | } 190 | 191 | /// @notice Compound staking & vault rewards for the user in a single transaction, in a gas efficient way. 192 | /// Staking rewards will be claimed and added to each stake respectively. 193 | /// Vault rewards will be claimed and added to the given stake. 194 | /// @dev This is mainly to be called by the user, or a smart contract that will call this on a user's behalf. 195 | /// @param _user The user address 196 | /// @param _topupStakeId The stake id to add the vault rewards 197 | function compoundForUser(address _user, uint256 _topupStakeId) external { 198 | _notPaused(); 199 | require(owners[_topupStakeId] == _user, "!owner"); 200 | uint256[] memory stakeIds = stakesForAddress[_user]; 201 | uint256 totalIncreasedSupply = _compoundForStakes(stakeIds); 202 | address[] memory users = new address[](1); 203 | uint256[] memory topupStakes = new uint256[](1); 204 | users[0] = _user; 205 | topupStakes[0] = _topupStakeId; 206 | totalIncreasedSupply += _compoundWithVaultRewards(users, topupStakes); 207 | totalWorkingSupply += totalIncreasedSupply; 208 | } 209 | 210 | function _updateVaults(address[] calldata _vaultsToBoost, address _user) internal { 211 | for (uint256 i = 0; i < _vaultsToBoost.length; i++) { 212 | require(_vaultsToBoost[i].supportsInterface(type(IVault).interfaceId), "!vault interface"); 213 | if (IVault(_vaultsToBoost[i]).balanceOf(_user) > 0) { 214 | address[] memory users = new address[](1); 215 | users[0] = _user; 216 | IBoostedVault(_vaultsToBoost[i]).updateBoostedBalancesForUsers(users); 217 | } 218 | } 219 | } 220 | 221 | function _compoundForStakes(uint256[] memory _stakeIds) internal returns (uint256) { 222 | (, uint256[] memory rewardsAmount) = IYOPRewardsV2(yopRewards).claimRewardsForStakes(_stakeIds); 223 | uint256 totalIncreasedSupply; 224 | for (uint256 i = 0; i < _stakeIds.length; i++) { 225 | uint248 newAmount = uint248(stakes[_stakeIds[i]].amount + rewardsAmount[i]); 226 | stakes[_stakeIds[i]].amount = newAmount; 227 | totalIncreasedSupply += rewardsAmount[i] * stakes[_stakeIds[i]].lockPeriod; 228 | address[] memory vaults; 229 | emit StakeExtended(_stakeIds[i], newAmount, stakes[_stakeIds[i]].lockPeriod, vaults); 230 | } 231 | return totalIncreasedSupply; 232 | } 233 | 234 | function _compoundWithVaultRewards(address[] memory _users, uint256[] memory _topupStakes) 235 | internal 236 | returns (uint256) 237 | { 238 | (, uint256[] memory rewardsAmount) = IYOPRewardsV2(yopRewards).claimVaultRewardsForUsers(_users); 239 | uint256 totalIncreasedSupply; 240 | for (uint256 i = 0; i < _topupStakes.length; i++) { 241 | uint256 stakeId = _topupStakes[i]; 242 | uint248 newAmount = uint248(stakes[stakeId].amount + rewardsAmount[i]); 243 | require(owners[stakeId] == _users[i], "!owner"); 244 | stakes[stakeId].amount = newAmount; 245 | totalIncreasedSupply += rewardsAmount[i] * stakes[stakeId].lockPeriod; 246 | address[] memory vaults; 247 | emit StakeExtended(stakeId, newAmount, stakes[stakeId].lockPeriod, vaults); 248 | } 249 | return totalIncreasedSupply; 250 | } 251 | 252 | function _notPaused() internal view { 253 | require(!paused(), "Pausable: paused"); 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts/token/ERC20/ERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC20/ERC20.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "./IERC20.sol"; 7 | import "./extensions/IERC20Metadata.sol"; 8 | import "../../utils/Context.sol"; 9 | 10 | /** 11 | * @dev Implementation of the {IERC20} interface. 12 | * 13 | * This implementation is agnostic to the way tokens are created. This means 14 | * that a supply mechanism has to be added in a derived contract using {_mint}. 15 | * For a generic mechanism see {ERC20PresetMinterPauser}. 16 | * 17 | * TIP: For a detailed writeup see our guide 18 | * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How 19 | * to implement supply mechanisms]. 20 | * 21 | * We have followed general OpenZeppelin Contracts guidelines: functions revert 22 | * instead returning `false` on failure. This behavior is nonetheless 23 | * conventional and does not conflict with the expectations of ERC20 24 | * applications. 25 | * 26 | * Additionally, an {Approval} event is emitted on calls to {transferFrom}. 27 | * This allows applications to reconstruct the allowance for all accounts just 28 | * by listening to said events. Other implementations of the EIP may not emit 29 | * these events, as it isn't required by the specification. 30 | * 31 | * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} 32 | * functions have been added to mitigate the well-known issues around setting 33 | * allowances. See {IERC20-approve}. 34 | */ 35 | contract ERC20 is Context, IERC20, IERC20Metadata { 36 | mapping(address => uint256) private _balances; 37 | 38 | mapping(address => mapping(address => uint256)) private _allowances; 39 | 40 | uint256 private _totalSupply; 41 | 42 | string private _name; 43 | string private _symbol; 44 | 45 | /** 46 | * @dev Sets the values for {name} and {symbol}. 47 | * 48 | * The default value of {decimals} is 18. To select a different value for 49 | * {decimals} you should overload it. 50 | * 51 | * All two of these values are immutable: they can only be set once during 52 | * construction. 53 | */ 54 | constructor(string memory name_, string memory symbol_) { 55 | _name = name_; 56 | _symbol = symbol_; 57 | } 58 | 59 | /** 60 | * @dev Returns the name of the token. 61 | */ 62 | function name() public view virtual override returns (string memory) { 63 | return _name; 64 | } 65 | 66 | /** 67 | * @dev Returns the symbol of the token, usually a shorter version of the 68 | * name. 69 | */ 70 | function symbol() public view virtual override returns (string memory) { 71 | return _symbol; 72 | } 73 | 74 | /** 75 | * @dev Returns the number of decimals used to get its user representation. 76 | * For example, if `decimals` equals `2`, a balance of `505` tokens should 77 | * be displayed to a user as `5.05` (`505 / 10 ** 2`). 78 | * 79 | * Tokens usually opt for a value of 18, imitating the relationship between 80 | * Ether and Wei. This is the value {ERC20} uses, unless this function is 81 | * overridden; 82 | * 83 | * NOTE: This information is only used for _display_ purposes: it in 84 | * no way affects any of the arithmetic of the contract, including 85 | * {IERC20-balanceOf} and {IERC20-transfer}. 86 | */ 87 | function decimals() public view virtual override returns (uint8) { 88 | return 18; 89 | } 90 | 91 | /** 92 | * @dev See {IERC20-totalSupply}. 93 | */ 94 | function totalSupply() public view virtual override returns (uint256) { 95 | return _totalSupply; 96 | } 97 | 98 | /** 99 | * @dev See {IERC20-balanceOf}. 100 | */ 101 | function balanceOf(address account) public view virtual override returns (uint256) { 102 | return _balances[account]; 103 | } 104 | 105 | /** 106 | * @dev See {IERC20-transfer}. 107 | * 108 | * Requirements: 109 | * 110 | * - `recipient` cannot be the zero address. 111 | * - the caller must have a balance of at least `amount`. 112 | */ 113 | function transfer(address recipient, uint256 amount) public virtual override returns (bool) { 114 | _transfer(_msgSender(), recipient, amount); 115 | return true; 116 | } 117 | 118 | /** 119 | * @dev See {IERC20-allowance}. 120 | */ 121 | function allowance(address owner, address spender) public view virtual override returns (uint256) { 122 | return _allowances[owner][spender]; 123 | } 124 | 125 | /** 126 | * @dev See {IERC20-approve}. 127 | * 128 | * Requirements: 129 | * 130 | * - `spender` cannot be the zero address. 131 | */ 132 | function approve(address spender, uint256 amount) public virtual override returns (bool) { 133 | _approve(_msgSender(), spender, amount); 134 | return true; 135 | } 136 | 137 | /** 138 | * @dev See {IERC20-transferFrom}. 139 | * 140 | * Emits an {Approval} event indicating the updated allowance. This is not 141 | * required by the EIP. See the note at the beginning of {ERC20}. 142 | * 143 | * Requirements: 144 | * 145 | * - `sender` and `recipient` cannot be the zero address. 146 | * - `sender` must have a balance of at least `amount`. 147 | * - the caller must have allowance for ``sender``'s tokens of at least 148 | * `amount`. 149 | */ 150 | function transferFrom( 151 | address sender, 152 | address recipient, 153 | uint256 amount 154 | ) public virtual override returns (bool) { 155 | _transfer(sender, recipient, amount); 156 | 157 | uint256 currentAllowance = _allowances[sender][_msgSender()]; 158 | require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); 159 | unchecked { 160 | _approve(sender, _msgSender(), currentAllowance - amount); 161 | } 162 | 163 | return true; 164 | } 165 | 166 | /** 167 | * @dev Atomically increases the allowance granted to `spender` by the caller. 168 | * 169 | * This is an alternative to {approve} that can be used as a mitigation for 170 | * problems described in {IERC20-approve}. 171 | * 172 | * Emits an {Approval} event indicating the updated allowance. 173 | * 174 | * Requirements: 175 | * 176 | * - `spender` cannot be the zero address. 177 | */ 178 | function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { 179 | _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue); 180 | return true; 181 | } 182 | 183 | /** 184 | * @dev Atomically decreases the allowance granted to `spender` by the caller. 185 | * 186 | * This is an alternative to {approve} that can be used as a mitigation for 187 | * problems described in {IERC20-approve}. 188 | * 189 | * Emits an {Approval} event indicating the updated allowance. 190 | * 191 | * Requirements: 192 | * 193 | * - `spender` cannot be the zero address. 194 | * - `spender` must have allowance for the caller of at least 195 | * `subtractedValue`. 196 | */ 197 | function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { 198 | uint256 currentAllowance = _allowances[_msgSender()][spender]; 199 | require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); 200 | unchecked { 201 | _approve(_msgSender(), spender, currentAllowance - subtractedValue); 202 | } 203 | 204 | return true; 205 | } 206 | 207 | /** 208 | * @dev Moves `amount` of tokens from `sender` to `recipient`. 209 | * 210 | * This internal function is equivalent to {transfer}, and can be used to 211 | * e.g. implement automatic token fees, slashing mechanisms, etc. 212 | * 213 | * Emits a {Transfer} event. 214 | * 215 | * Requirements: 216 | * 217 | * - `sender` cannot be the zero address. 218 | * - `recipient` cannot be the zero address. 219 | * - `sender` must have a balance of at least `amount`. 220 | */ 221 | function _transfer( 222 | address sender, 223 | address recipient, 224 | uint256 amount 225 | ) internal virtual { 226 | require(sender != address(0), "ERC20: transfer from the zero address"); 227 | require(recipient != address(0), "ERC20: transfer to the zero address"); 228 | 229 | _beforeTokenTransfer(sender, recipient, amount); 230 | 231 | uint256 senderBalance = _balances[sender]; 232 | require(senderBalance >= amount, "ERC20: transfer amount exceeds balance"); 233 | unchecked { 234 | _balances[sender] = senderBalance - amount; 235 | } 236 | _balances[recipient] += amount; 237 | 238 | emit Transfer(sender, recipient, amount); 239 | 240 | _afterTokenTransfer(sender, recipient, amount); 241 | } 242 | 243 | /** @dev Creates `amount` tokens and assigns them to `account`, increasing 244 | * the total supply. 245 | * 246 | * Emits a {Transfer} event with `from` set to the zero address. 247 | * 248 | * Requirements: 249 | * 250 | * - `account` cannot be the zero address. 251 | */ 252 | function _mint(address account, uint256 amount) internal virtual { 253 | require(account != address(0), "ERC20: mint to the zero address"); 254 | 255 | _beforeTokenTransfer(address(0), account, amount); 256 | 257 | _totalSupply += amount; 258 | _balances[account] += amount; 259 | emit Transfer(address(0), account, amount); 260 | 261 | _afterTokenTransfer(address(0), account, amount); 262 | } 263 | 264 | /** 265 | * @dev Destroys `amount` tokens from `account`, reducing the 266 | * total supply. 267 | * 268 | * Emits a {Transfer} event with `to` set to the zero address. 269 | * 270 | * Requirements: 271 | * 272 | * - `account` cannot be the zero address. 273 | * - `account` must have at least `amount` tokens. 274 | */ 275 | function _burn(address account, uint256 amount) internal virtual { 276 | require(account != address(0), "ERC20: burn from the zero address"); 277 | 278 | _beforeTokenTransfer(account, address(0), amount); 279 | 280 | uint256 accountBalance = _balances[account]; 281 | require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); 282 | unchecked { 283 | _balances[account] = accountBalance - amount; 284 | } 285 | _totalSupply -= amount; 286 | 287 | emit Transfer(account, address(0), amount); 288 | 289 | _afterTokenTransfer(account, address(0), amount); 290 | } 291 | 292 | /** 293 | * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. 294 | * 295 | * This internal function is equivalent to `approve`, and can be used to 296 | * e.g. set automatic allowances for certain subsystems, etc. 297 | * 298 | * Emits an {Approval} event. 299 | * 300 | * Requirements: 301 | * 302 | * - `owner` cannot be the zero address. 303 | * - `spender` cannot be the zero address. 304 | */ 305 | function _approve( 306 | address owner, 307 | address spender, 308 | uint256 amount 309 | ) internal virtual { 310 | require(owner != address(0), "ERC20: approve from the zero address"); 311 | require(spender != address(0), "ERC20: approve to the zero address"); 312 | 313 | _allowances[owner][spender] = amount; 314 | emit Approval(owner, spender, amount); 315 | } 316 | 317 | /** 318 | * @dev Hook that is called before any transfer of tokens. This includes 319 | * minting and burning. 320 | * 321 | * Calling conditions: 322 | * 323 | * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens 324 | * will be transferred to `to`. 325 | * - when `from` is zero, `amount` tokens will be minted for `to`. 326 | * - when `to` is zero, `amount` of ``from``'s tokens will be burned. 327 | * - `from` and `to` are never both zero. 328 | * 329 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 330 | */ 331 | function _beforeTokenTransfer( 332 | address from, 333 | address to, 334 | uint256 amount 335 | ) internal virtual {} 336 | 337 | /** 338 | * @dev Hook that is called after any transfer of tokens. This includes 339 | * minting and burning. 340 | * 341 | * Calling conditions: 342 | * 343 | * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens 344 | * has been transferred to `to`. 345 | * - when `from` is zero, `amount` tokens have been minted for `to`. 346 | * - when `to` is zero, `amount` of ``from``'s tokens have been burned. 347 | * - `from` and `to` are never both zero. 348 | * 349 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 350 | */ 351 | function _afterTokenTransfer( 352 | address from, 353 | address to, 354 | uint256 amount 355 | ) internal virtual {} 356 | } 357 | -------------------------------------------------------------------------------- /lib/StakingV2/contracts/staking/Staking.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.8.9; 3 | 4 | import "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol"; 5 | import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; 6 | import "../security/BasePauseableUpgradeable.sol"; 7 | import "../interfaces/IYOPRewards.sol"; 8 | import "../interfaces/IAccessControlManager.sol"; 9 | import "../interfaces/IStaking.sol"; 10 | 11 | /// @notice This contract will stake (lock) YOP tokens for a period of time. While the tokens are locked in this contract, users will be able to claim additional YOP tokens (from the community emission as per YOP tokenomics). 12 | /// Users can stake as many times as they want, but each stake can't be modified/extended once it is created. 13 | /// For each stake, the user will recive an ERC1155 NFT token as the receipt. These NFT tokens can be transferred to other to still allow users to use the locked YOP tokens as a collateral. 14 | /// When the NFT tokens are transferred, all the remaining unclaimed rewards will be transferred to the new owner as well. 15 | contract Staking is IStaking, ERC1155Upgradeable, BasePauseableUpgradeable { 16 | using SafeERC20Upgradeable for IERC20Upgradeable; 17 | 18 | event Staked( 19 | address indexed _user, 20 | uint256 indexed _tokenId, 21 | uint248 indexed _amount, 22 | uint8 _lockPeriod, 23 | uint256 _startTime 24 | ); 25 | event Unstaked( 26 | address indexed _user, 27 | uint256 indexed _tokenId, 28 | uint248 indexed _amount, 29 | uint8 _lockPeriod, 30 | uint256 _startTime 31 | ); 32 | 33 | /// @notice Emitted when the contract URI is updated 34 | event StakingContractURIUpdated(string _contractURI); 35 | /// @notice Emitted when the access control manager is updated 36 | event AccessControlManagerUpdated(address indexed _accessControlManager); 37 | /// @notice Emitted when staking limit is updated 38 | event StakingLimitUpdated(uint256 indexed _newLimit); 39 | 40 | /// @dev represent each stake 41 | struct Stake { 42 | // the duration of the stake, in number of months 43 | uint8 lockPeriod; 44 | // amount of YOP tokens to stake 45 | uint248 amount; 46 | // when the stake is started 47 | uint256 startTime; 48 | // when the last time the NFT is transferred. This is useful to help us track how long an account has hold the token 49 | uint256 lastTransferTime; 50 | } 51 | 52 | uint8 public constant MAX_LOCK_PERIOD = 60; 53 | uint256 public constant SECONDS_PER_MONTH = 2629743; // 1 month/30.44 days 54 | address public constant YOP_ADDRESS = 0xAE1eaAE3F627AAca434127644371b67B18444051; 55 | /// @notice The name of the token 56 | string public name; 57 | /// @notice The symbol of the token 58 | string public symbol; 59 | /// @notice The URL for the storefront-level metadata 60 | string public contractURI; 61 | /// @notice Used by OpenSea for admin access of the collection 62 | address public owner; 63 | // the minimum amount for staking 64 | uint256 public minStakeAmount; 65 | // the total supply of "working balance". The "working balance" of each stake is calculated as amount * lockPeriod. 66 | uint256 public totalWorkingSupply; 67 | // all the stake positions 68 | Stake[] public stakes; 69 | // the address of the YOPRewards contract 70 | address public yopRewards; 71 | // the address of the AccessControlManager contract 72 | address public accessControlManager; 73 | // stakes for each account 74 | mapping(address => uint256[]) internal stakesForAddress; 75 | // ownership of the NFTs 76 | mapping(uint256 => address) public owners; 77 | // cap for staking 78 | uint256 public stakingLimit; 79 | 80 | // solhint-disable-next-line no-empty-blocks 81 | constructor() {} 82 | 83 | /// @notice Initialize the contract. 84 | /// @param _governance the governance address 85 | /// @param _gatekeeper the gatekeeper address 86 | /// @param _yopRewards the address of the yop rewards contract 87 | /// @param _uri the base URI for the token 88 | function initialize( 89 | string memory _name, 90 | string memory _symbol, 91 | address _governance, 92 | address _gatekeeper, 93 | address _yopRewards, 94 | string memory _uri, 95 | string memory _contractURI, 96 | address _owner, 97 | address _accessControlManager 98 | ) external virtual initializer { 99 | __Staking_init( 100 | _name, 101 | _symbol, 102 | _governance, 103 | _gatekeeper, 104 | _yopRewards, 105 | _uri, 106 | _contractURI, 107 | _owner, 108 | _accessControlManager 109 | ); 110 | } 111 | 112 | // solhint-disable-next-line func-name-mixedcase 113 | function __Staking_init( 114 | string memory _name, 115 | string memory _symbol, 116 | address _governance, 117 | address _gatekeeper, 118 | address _yopRewards, 119 | string memory _uri, 120 | string memory _contractURI, 121 | address _owner, 122 | address _accessControlManager 123 | ) internal onlyInitializing { 124 | __ERC1155_init(_uri); 125 | __BasePauseableUpgradeable_init(_governance, _gatekeeper); 126 | __Staking_init_unchained(_name, _symbol, _yopRewards, _contractURI, _owner, _accessControlManager); 127 | } 128 | 129 | // solhint-disable-next-line func-name-mixedcase 130 | function __Staking_init_unchained( 131 | string memory _name, 132 | string memory _symbol, 133 | address _yopRewards, 134 | string memory _contractURI, 135 | address _owner, 136 | address _accessControlManager 137 | ) internal onlyInitializing { 138 | require(_yopRewards != address(0), "!input"); 139 | require(_owner != address(0), "!input"); 140 | name = _name; 141 | symbol = _symbol; 142 | yopRewards = _yopRewards; 143 | owner = _owner; 144 | stakingLimit = type(uint256).max; 145 | _updateContractURI(_contractURI); 146 | _updateAccessControlManager(_accessControlManager); 147 | } 148 | 149 | /// @notice Set the minimum amount of tokens for staking 150 | /// @param _minAmount The minimum amount of tokens 151 | function setMinStakeAmount(uint256 _minAmount) external onlyGovernance { 152 | minStakeAmount = _minAmount; 153 | } 154 | 155 | /// @notice Set the limit of staking. 156 | /// @param _limit The limit value. It is the limit of the total working balance (combined value of number of tokens and stake duration) 157 | function setStakingLimit(uint256 _limit) external onlyGovernance { 158 | if (stakingLimit != _limit) { 159 | stakingLimit = _limit; 160 | emit StakingLimitUpdated(_limit); 161 | } 162 | } 163 | 164 | /// @dev Set the contractURI for store front metadata. Can only be called by governance. 165 | /// @param _contractURI URL of the metadata 166 | function setContractURI(string memory _contractURI) external onlyGovernance { 167 | _updateContractURI(_contractURI); 168 | } 169 | 170 | function setAccessControlManager(address _accessControlManager) external onlyGovernance { 171 | _updateAccessControlManager(_accessControlManager); 172 | } 173 | 174 | /// @notice Create a new staking position 175 | /// @param _amount The amount of YOP tokens to stake 176 | /// @param _lockPeriod The locking period of the stake, in months 177 | /// @return The id of the NFT token that is also the id of the stake 178 | function stake(uint248 _amount, uint8 _lockPeriod) external whenNotPaused returns (uint256) { 179 | return _mintStake(_amount, _lockPeriod, _msgSender()); 180 | } 181 | 182 | /// @notice Unstake a single staking position that is owned by the caller after it's unlocked, and transfer the unlocked tokens to the _to address 183 | /// @param _stakeId The id of the staking NFT token, and owned by the caller 184 | function unstakeSingle(uint256 _stakeId, address _to) external whenNotPaused { 185 | _burnSingle(_stakeId, _to); 186 | } 187 | 188 | /// @notice Unstake all the unlocked stakes the caller currently has and transfer all the tokens to _to address in a single transfer. 189 | /// This will be more gas efficient if the caller has multiple stakes that are unlocked. 190 | /// @param _to the address that will receive the tokens 191 | function unstakeAll(address _to) external whenNotPaused { 192 | _burnAll(_to); 193 | } 194 | 195 | /// @notice Lists the is of stakes for a user 196 | /// @param _user The user address 197 | /// @return the ids of stakes 198 | function stakesFor(address _user) external view returns (uint256[] memory) { 199 | return stakesForAddress[_user]; 200 | } 201 | 202 | /// @notice Check the working balance of an user address. 203 | /// @param _user The user address 204 | /// @return The value of working balance 205 | function workingBalanceOf(address _user) external view returns (uint256) { 206 | uint256 balance = 0; 207 | uint256[] memory stakeIds = stakesForAddress[_user]; 208 | for (uint256 i = 0; i < stakeIds.length; i++) { 209 | balance += _workingBalanceOfStake(stakes[stakeIds[i]]); 210 | } 211 | return balance; 212 | } 213 | 214 | /// @notice Get the working balance for the stake with the given stake id. 215 | /// @param _stakeId The id of the stake 216 | /// @return The working balance, calculated as stake.amount * stake.lockPeriod 217 | function workingBalanceOfStake(uint256 _stakeId) external view returns (uint256) { 218 | if (_stakeId < stakes.length) { 219 | Stake memory s = stakes[_stakeId]; 220 | return _workingBalanceOfStake(s); 221 | } 222 | return 0; 223 | } 224 | 225 | function _workingBalanceOfStake(Stake memory _stake) internal pure returns (uint256) { 226 | return _stake.amount * _stake.lockPeriod; 227 | } 228 | 229 | function _isUnlocked(Stake memory _stake) internal view returns (bool) { 230 | return _getBlockTimestamp() > (_stake.startTime + _stake.lockPeriod * SECONDS_PER_MONTH); 231 | } 232 | 233 | function _getUnlockedStakeIds(uint256[] memory _stakeIds) internal view returns (uint256[] memory) { 234 | // solidity doesn't allow changing the size of memory arrays dynamically, so have to use this function to build the array that only contains stake ids that are unlocked 235 | uint256[] memory temp = new uint256[](_stakeIds.length); 236 | uint256 counter; 237 | for (uint256 i = 0; i < _stakeIds.length; i++) { 238 | Stake memory s = stakes[_stakeIds[i]]; 239 | // find all the unlocked stakes first and store them in an array 240 | if (_isUnlocked(s)) { 241 | temp[counter] = _stakeIds[i]; 242 | counter++; 243 | } 244 | } 245 | // copy the array to change the size 246 | uint256[] memory unlocked; 247 | if (counter > 0) { 248 | unlocked = new uint256[](counter); 249 | for (uint256 j = 0; j < counter; j++) { 250 | unlocked[j] = temp[j]; 251 | } 252 | } 253 | return unlocked; 254 | } 255 | 256 | /// @dev This function is invoked by the ERC1155 implementation. It will be called everytime when tokens are minted, transferred and burned. 257 | /// We add implementation for this function to perform the common bookkeeping tasks, like update the working balance, update ownership mapping etc. 258 | function _beforeTokenTransfer( 259 | address, 260 | address _from, 261 | address _to, 262 | uint256[] memory _ids, 263 | uint256[] memory, 264 | bytes memory 265 | ) internal override { 266 | for (uint256 i = 0; i < _ids.length; i++) { 267 | uint256 tokenId = _ids[i]; 268 | Stake storage s = stakes[tokenId]; 269 | s.lastTransferTime = _getBlockTimestamp(); 270 | uint256 balance = _workingBalanceOfStake(s); 271 | if (_from != address(0)) { 272 | totalWorkingSupply -= balance; 273 | _removeValue(stakesForAddress[_from], tokenId); 274 | owners[tokenId] = address(0); 275 | } 276 | if (_to != address(0)) { 277 | totalWorkingSupply += balance; 278 | stakesForAddress[_to].push(tokenId); 279 | owners[tokenId] = _to; 280 | } else { 281 | // this is a burn, reset the fields of the stake record 282 | delete stakes[tokenId]; 283 | } 284 | } 285 | } 286 | 287 | /// @dev For testing 288 | function _getBlockTimestamp() internal view virtual returns (uint256) { 289 | // solhint-disable-next-line not-rely-on-time 290 | return block.timestamp; 291 | } 292 | 293 | /// @dev For testing 294 | function _getYOPAddress() internal view virtual returns (address) { 295 | return YOP_ADDRESS; 296 | } 297 | 298 | function _removeValue(uint256[] storage _values, uint256 _val) internal { 299 | uint256 i; 300 | for (i = 0; i < _values.length; i++) { 301 | if (_values[i] == _val) { 302 | break; 303 | } 304 | } 305 | for (; i < _values.length - 1; i++) { 306 | _values[i] = _values[i + 1]; 307 | } 308 | _values.pop(); 309 | } 310 | 311 | function _updateAccessControlManager(address _accessControlManager) internal { 312 | // no check on the parameter as it can be address(0) 313 | if (accessControlManager != _accessControlManager) { 314 | accessControlManager = _accessControlManager; 315 | emit AccessControlManagerUpdated(_accessControlManager); 316 | } 317 | } 318 | 319 | function _updateContractURI(string memory _contractURI) internal { 320 | contractURI = _contractURI; 321 | emit StakingContractURIUpdated(_contractURI); 322 | } 323 | 324 | function _mintStake( 325 | uint248 _amount, 326 | uint8 _lockPeriod, 327 | address _to 328 | ) internal returns (uint256) { 329 | require(_amount > minStakeAmount, "!amount"); 330 | require(_lockPeriod > 0 && _lockPeriod <= MAX_LOCK_PERIOD, "!lockPeriod"); 331 | require(IERC20Upgradeable(_getYOPAddress()).balanceOf(_msgSender()) >= _amount, "!balance"); 332 | require((totalWorkingSupply + _amount * _lockPeriod) <= stakingLimit, "limit reached"); 333 | if (accessControlManager != address(0)) { 334 | require(IAccessControlManager(accessControlManager).hasAccess(_to, address(this)), "!access"); 335 | } 336 | // issue token id 337 | uint256 tokenId = stakes.length; 338 | // calculate the rewards for the token. 339 | // This only needs to be called when NFT tokens are minted/burne. It doesn't need to be called again when NFTs are transferred as the balance of the token and the totalBalance are not changed when tokens are transferred 340 | // This needs to be called before the stakes array is updated as otherwise the workingBalanceOfStake will return a value. 341 | IYOPRewards(yopRewards).calculateStakingRewards(tokenId); 342 | // record the stake 343 | Stake memory s = Stake({ 344 | lockPeriod: _lockPeriod, 345 | amount: _amount, 346 | startTime: _getBlockTimestamp(), 347 | lastTransferTime: _getBlockTimestamp() 348 | }); 349 | stakes.push(s); 350 | // transfer the the tokens to this contract and mint an NFT token 351 | IERC20Upgradeable(_getYOPAddress()).safeTransferFrom(_msgSender(), address(this), _amount); 352 | bytes memory data; 353 | _mint(_to, tokenId, 1, data); 354 | emit Staked(_to, tokenId, _amount, _lockPeriod, _getBlockTimestamp()); 355 | return tokenId; 356 | } 357 | 358 | function _burnSingle(uint256 _stakeId, address _to) internal { 359 | require(_to != address(0), "!input"); 360 | require(balanceOf(_msgSender(), _stakeId) > 0, "!stake"); 361 | Stake memory s = stakes[_stakeId]; 362 | uint256 startTime = s.startTime; 363 | uint248 amount = s.amount; 364 | uint8 lockPeriod = s.lockPeriod; 365 | require(_isUnlocked(s), "locked"); 366 | // This only needs to be called when NFT tokens are minted/burne. It doesn't need to be called again when NFTs are transferred as the balance of the token and the totalBalance are not changed when tokens are transferred 367 | uint256[] memory stakeIds = new uint256[](1); 368 | stakeIds[0] = _stakeId; 369 | (uint256 rewardsAmount, ) = IYOPRewardsV2(yopRewards).claimRewardsForStakes(stakeIds); 370 | // burn the NFT 371 | _burn(_msgSender(), _stakeId, 1); 372 | // transfer the tokens to _to 373 | IERC20Upgradeable(_getYOPAddress()).safeTransfer(_to, amount + rewardsAmount); 374 | emit Unstaked(_msgSender(), _stakeId, amount, lockPeriod, startTime); 375 | } 376 | 377 | function _burnAll(address _to) internal { 378 | require(_to != address(0), "!input"); 379 | uint256[] memory stakeIds = stakesForAddress[_msgSender()]; 380 | uint256[] memory unlockedIds = _getUnlockedStakeIds(stakeIds); 381 | require(unlockedIds.length > 0, "!unlocked"); 382 | (uint256 toTransfer, ) = IYOPRewardsV2(yopRewards).claimRewardsForStakes(unlockedIds); 383 | uint256[] memory amounts = new uint256[](unlockedIds.length); 384 | for (uint256 i = 0; i < unlockedIds.length; i++) { 385 | amounts[i] = 1; 386 | Stake memory s = stakes[unlockedIds[i]]; 387 | uint256 startTime = s.startTime; 388 | uint248 amount = s.amount; 389 | uint8 lockPeriod = s.lockPeriod; 390 | toTransfer += amount; 391 | emit Unstaked(_msgSender(), unlockedIds[i], amount, lockPeriod, startTime); 392 | } 393 | // burn the NFTs 394 | _burnBatch(_msgSender(), unlockedIds, amounts); 395 | // transfer the tokens to _to 396 | IERC20Upgradeable(_getYOPAddress()).safeTransfer(_to, toTransfer); 397 | } 398 | } 399 | -------------------------------------------------------------------------------- /lib/StakingV2/@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts v4.4.1 (token/ERC1155/ERC1155.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "./IERC1155Upgradeable.sol"; 7 | import "./IERC1155ReceiverUpgradeable.sol"; 8 | import "./extensions/IERC1155MetadataURIUpgradeable.sol"; 9 | import "../../utils/AddressUpgradeable.sol"; 10 | import "../../utils/ContextUpgradeable.sol"; 11 | import "../../utils/introspection/ERC165Upgradeable.sol"; 12 | import "../../proxy/utils/Initializable.sol"; 13 | 14 | /** 15 | * @dev Implementation of the basic standard multi-token. 16 | * See https://eips.ethereum.org/EIPS/eip-1155 17 | * Originally based on code by Enjin: https://github.com/enjin/erc-1155 18 | * 19 | * _Available since v3.1._ 20 | */ 21 | contract ERC1155Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC1155Upgradeable, IERC1155MetadataURIUpgradeable { 22 | using AddressUpgradeable for address; 23 | 24 | // Mapping from token ID to account balances 25 | mapping(uint256 => mapping(address => uint256)) private _balances; 26 | 27 | // Mapping from account to operator approvals 28 | mapping(address => mapping(address => bool)) private _operatorApprovals; 29 | 30 | // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json 31 | string private _uri; 32 | 33 | /** 34 | * @dev See {_setURI}. 35 | */ 36 | function __ERC1155_init(string memory uri_) internal onlyInitializing { 37 | __Context_init_unchained(); 38 | __ERC165_init_unchained(); 39 | __ERC1155_init_unchained(uri_); 40 | } 41 | 42 | function __ERC1155_init_unchained(string memory uri_) internal onlyInitializing { 43 | _setURI(uri_); 44 | } 45 | 46 | /** 47 | * @dev See {IERC165-supportsInterface}. 48 | */ 49 | function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) { 50 | return 51 | interfaceId == type(IERC1155Upgradeable).interfaceId || 52 | interfaceId == type(IERC1155MetadataURIUpgradeable).interfaceId || 53 | super.supportsInterface(interfaceId); 54 | } 55 | 56 | /** 57 | * @dev See {IERC1155MetadataURI-uri}. 58 | * 59 | * This implementation returns the same URI for *all* token types. It relies 60 | * on the token type ID substitution mechanism 61 | * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. 62 | * 63 | * Clients calling this function must replace the `\{id\}` substring with the 64 | * actual token type ID. 65 | */ 66 | function uri(uint256) public view virtual override returns (string memory) { 67 | return _uri; 68 | } 69 | 70 | /** 71 | * @dev See {IERC1155-balanceOf}. 72 | * 73 | * Requirements: 74 | * 75 | * - `account` cannot be the zero address. 76 | */ 77 | function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { 78 | require(account != address(0), "ERC1155: balance query for the zero address"); 79 | return _balances[id][account]; 80 | } 81 | 82 | /** 83 | * @dev See {IERC1155-balanceOfBatch}. 84 | * 85 | * Requirements: 86 | * 87 | * - `accounts` and `ids` must have the same length. 88 | */ 89 | function balanceOfBatch(address[] memory accounts, uint256[] memory ids) 90 | public 91 | view 92 | virtual 93 | override 94 | returns (uint256[] memory) 95 | { 96 | require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); 97 | 98 | uint256[] memory batchBalances = new uint256[](accounts.length); 99 | 100 | for (uint256 i = 0; i < accounts.length; ++i) { 101 | batchBalances[i] = balanceOf(accounts[i], ids[i]); 102 | } 103 | 104 | return batchBalances; 105 | } 106 | 107 | /** 108 | * @dev See {IERC1155-setApprovalForAll}. 109 | */ 110 | function setApprovalForAll(address operator, bool approved) public virtual override { 111 | _setApprovalForAll(_msgSender(), operator, approved); 112 | } 113 | 114 | /** 115 | * @dev See {IERC1155-isApprovedForAll}. 116 | */ 117 | function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { 118 | return _operatorApprovals[account][operator]; 119 | } 120 | 121 | /** 122 | * @dev See {IERC1155-safeTransferFrom}. 123 | */ 124 | function safeTransferFrom( 125 | address from, 126 | address to, 127 | uint256 id, 128 | uint256 amount, 129 | bytes memory data 130 | ) public virtual override { 131 | require( 132 | from == _msgSender() || isApprovedForAll(from, _msgSender()), 133 | "ERC1155: caller is not owner nor approved" 134 | ); 135 | _safeTransferFrom(from, to, id, amount, data); 136 | } 137 | 138 | /** 139 | * @dev See {IERC1155-safeBatchTransferFrom}. 140 | */ 141 | function safeBatchTransferFrom( 142 | address from, 143 | address to, 144 | uint256[] memory ids, 145 | uint256[] memory amounts, 146 | bytes memory data 147 | ) public virtual override { 148 | require( 149 | from == _msgSender() || isApprovedForAll(from, _msgSender()), 150 | "ERC1155: transfer caller is not owner nor approved" 151 | ); 152 | _safeBatchTransferFrom(from, to, ids, amounts, data); 153 | } 154 | 155 | /** 156 | * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. 157 | * 158 | * Emits a {TransferSingle} event. 159 | * 160 | * Requirements: 161 | * 162 | * - `to` cannot be the zero address. 163 | * - `from` must have a balance of tokens of type `id` of at least `amount`. 164 | * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the 165 | * acceptance magic value. 166 | */ 167 | function _safeTransferFrom( 168 | address from, 169 | address to, 170 | uint256 id, 171 | uint256 amount, 172 | bytes memory data 173 | ) internal virtual { 174 | require(to != address(0), "ERC1155: transfer to the zero address"); 175 | 176 | address operator = _msgSender(); 177 | 178 | _beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data); 179 | 180 | uint256 fromBalance = _balances[id][from]; 181 | require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); 182 | unchecked { 183 | _balances[id][from] = fromBalance - amount; 184 | } 185 | _balances[id][to] += amount; 186 | 187 | emit TransferSingle(operator, from, to, id, amount); 188 | 189 | _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); 190 | } 191 | 192 | /** 193 | * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}. 194 | * 195 | * Emits a {TransferBatch} event. 196 | * 197 | * Requirements: 198 | * 199 | * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the 200 | * acceptance magic value. 201 | */ 202 | function _safeBatchTransferFrom( 203 | address from, 204 | address to, 205 | uint256[] memory ids, 206 | uint256[] memory amounts, 207 | bytes memory data 208 | ) internal virtual { 209 | require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); 210 | require(to != address(0), "ERC1155: transfer to the zero address"); 211 | 212 | address operator = _msgSender(); 213 | 214 | _beforeTokenTransfer(operator, from, to, ids, amounts, data); 215 | 216 | for (uint256 i = 0; i < ids.length; ++i) { 217 | uint256 id = ids[i]; 218 | uint256 amount = amounts[i]; 219 | 220 | uint256 fromBalance = _balances[id][from]; 221 | require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); 222 | unchecked { 223 | _balances[id][from] = fromBalance - amount; 224 | } 225 | _balances[id][to] += amount; 226 | } 227 | 228 | emit TransferBatch(operator, from, to, ids, amounts); 229 | 230 | _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); 231 | } 232 | 233 | /** 234 | * @dev Sets a new URI for all token types, by relying on the token type ID 235 | * substitution mechanism 236 | * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. 237 | * 238 | * By this mechanism, any occurrence of the `\{id\}` substring in either the 239 | * URI or any of the amounts in the JSON file at said URI will be replaced by 240 | * clients with the token type ID. 241 | * 242 | * For example, the `https://token-cdn-domain/\{id\}.json` URI would be 243 | * interpreted by clients as 244 | * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` 245 | * for token type ID 0x4cce0. 246 | * 247 | * See {uri}. 248 | * 249 | * Because these URIs cannot be meaningfully represented by the {URI} event, 250 | * this function emits no events. 251 | */ 252 | function _setURI(string memory newuri) internal virtual { 253 | _uri = newuri; 254 | } 255 | 256 | /** 257 | * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`. 258 | * 259 | * Emits a {TransferSingle} event. 260 | * 261 | * Requirements: 262 | * 263 | * - `to` cannot be the zero address. 264 | * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the 265 | * acceptance magic value. 266 | */ 267 | function _mint( 268 | address to, 269 | uint256 id, 270 | uint256 amount, 271 | bytes memory data 272 | ) internal virtual { 273 | require(to != address(0), "ERC1155: mint to the zero address"); 274 | 275 | address operator = _msgSender(); 276 | 277 | _beforeTokenTransfer(operator, address(0), to, _asSingletonArray(id), _asSingletonArray(amount), data); 278 | 279 | _balances[id][to] += amount; 280 | emit TransferSingle(operator, address(0), to, id, amount); 281 | 282 | _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); 283 | } 284 | 285 | /** 286 | * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. 287 | * 288 | * Requirements: 289 | * 290 | * - `ids` and `amounts` must have the same length. 291 | * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the 292 | * acceptance magic value. 293 | */ 294 | function _mintBatch( 295 | address to, 296 | uint256[] memory ids, 297 | uint256[] memory amounts, 298 | bytes memory data 299 | ) internal virtual { 300 | require(to != address(0), "ERC1155: mint to the zero address"); 301 | require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); 302 | 303 | address operator = _msgSender(); 304 | 305 | _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); 306 | 307 | for (uint256 i = 0; i < ids.length; i++) { 308 | _balances[ids[i]][to] += amounts[i]; 309 | } 310 | 311 | emit TransferBatch(operator, address(0), to, ids, amounts); 312 | 313 | _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); 314 | } 315 | 316 | /** 317 | * @dev Destroys `amount` tokens of token type `id` from `from` 318 | * 319 | * Requirements: 320 | * 321 | * - `from` cannot be the zero address. 322 | * - `from` must have at least `amount` tokens of token type `id`. 323 | */ 324 | function _burn( 325 | address from, 326 | uint256 id, 327 | uint256 amount 328 | ) internal virtual { 329 | require(from != address(0), "ERC1155: burn from the zero address"); 330 | 331 | address operator = _msgSender(); 332 | 333 | _beforeTokenTransfer(operator, from, address(0), _asSingletonArray(id), _asSingletonArray(amount), ""); 334 | 335 | uint256 fromBalance = _balances[id][from]; 336 | require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); 337 | unchecked { 338 | _balances[id][from] = fromBalance - amount; 339 | } 340 | 341 | emit TransferSingle(operator, from, address(0), id, amount); 342 | } 343 | 344 | /** 345 | * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. 346 | * 347 | * Requirements: 348 | * 349 | * - `ids` and `amounts` must have the same length. 350 | */ 351 | function _burnBatch( 352 | address from, 353 | uint256[] memory ids, 354 | uint256[] memory amounts 355 | ) internal virtual { 356 | require(from != address(0), "ERC1155: burn from the zero address"); 357 | require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); 358 | 359 | address operator = _msgSender(); 360 | 361 | _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); 362 | 363 | for (uint256 i = 0; i < ids.length; i++) { 364 | uint256 id = ids[i]; 365 | uint256 amount = amounts[i]; 366 | 367 | uint256 fromBalance = _balances[id][from]; 368 | require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); 369 | unchecked { 370 | _balances[id][from] = fromBalance - amount; 371 | } 372 | } 373 | 374 | emit TransferBatch(operator, from, address(0), ids, amounts); 375 | } 376 | 377 | /** 378 | * @dev Approve `operator` to operate on all of `owner` tokens 379 | * 380 | * Emits a {ApprovalForAll} event. 381 | */ 382 | function _setApprovalForAll( 383 | address owner, 384 | address operator, 385 | bool approved 386 | ) internal virtual { 387 | require(owner != operator, "ERC1155: setting approval status for self"); 388 | _operatorApprovals[owner][operator] = approved; 389 | emit ApprovalForAll(owner, operator, approved); 390 | } 391 | 392 | /** 393 | * @dev Hook that is called before any token transfer. This includes minting 394 | * and burning, as well as batched variants. 395 | * 396 | * The same hook is called on both single and batched variants. For single 397 | * transfers, the length of the `id` and `amount` arrays will be 1. 398 | * 399 | * Calling conditions (for each `id` and `amount` pair): 400 | * 401 | * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens 402 | * of token type `id` will be transferred to `to`. 403 | * - When `from` is zero, `amount` tokens of token type `id` will be minted 404 | * for `to`. 405 | * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` 406 | * will be burned. 407 | * - `from` and `to` are never both zero. 408 | * - `ids` and `amounts` have the same, non-zero length. 409 | * 410 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 411 | */ 412 | function _beforeTokenTransfer( 413 | address operator, 414 | address from, 415 | address to, 416 | uint256[] memory ids, 417 | uint256[] memory amounts, 418 | bytes memory data 419 | ) internal virtual {} 420 | 421 | function _doSafeTransferAcceptanceCheck( 422 | address operator, 423 | address from, 424 | address to, 425 | uint256 id, 426 | uint256 amount, 427 | bytes memory data 428 | ) private { 429 | if (to.isContract()) { 430 | try IERC1155ReceiverUpgradeable(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { 431 | if (response != IERC1155ReceiverUpgradeable.onERC1155Received.selector) { 432 | revert("ERC1155: ERC1155Receiver rejected tokens"); 433 | } 434 | } catch Error(string memory reason) { 435 | revert(reason); 436 | } catch { 437 | revert("ERC1155: transfer to non ERC1155Receiver implementer"); 438 | } 439 | } 440 | } 441 | 442 | function _doSafeBatchTransferAcceptanceCheck( 443 | address operator, 444 | address from, 445 | address to, 446 | uint256[] memory ids, 447 | uint256[] memory amounts, 448 | bytes memory data 449 | ) private { 450 | if (to.isContract()) { 451 | try IERC1155ReceiverUpgradeable(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns ( 452 | bytes4 response 453 | ) { 454 | if (response != IERC1155ReceiverUpgradeable.onERC1155BatchReceived.selector) { 455 | revert("ERC1155: ERC1155Receiver rejected tokens"); 456 | } 457 | } catch Error(string memory reason) { 458 | revert(reason); 459 | } catch { 460 | revert("ERC1155: transfer to non ERC1155Receiver implementer"); 461 | } 462 | } 463 | } 464 | 465 | function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { 466 | uint256[] memory array = new uint256[](1); 467 | array[0] = element; 468 | 469 | return array; 470 | } 471 | uint256[47] private __gap; 472 | } 473 | --------------------------------------------------------------------------------