├── .env-sample ├── .gitignore ├── README.md ├── addresses └── rinkeby.json ├── contracts └── solidity │ ├── NFTXEligibilityManager.sol │ ├── NFTXInventoryStaking.sol │ ├── NFTXLPStaking.sol │ ├── NFTXMarketplace0xZap.sol │ ├── NFTXMarketplaceZap.sol │ ├── NFTXSimpleFeeDistributor.sol │ ├── NFTXStakingZap.sol │ ├── NFTXUnstakingInventoryZap.sol │ ├── NFTXV1Buyout.sol │ ├── NFTXVaultFactoryUpgradeable.sol │ ├── NFTXVaultUpgradeable.sol │ ├── StakingTokenProvider.sol │ ├── eligibility │ ├── NFTXAvastarRank60Eligibility.sol │ ├── NFTXDeferEligibility.sol │ ├── NFTXDenyEligibility.sol │ ├── NFTXENSMerkleEligibility.sol │ ├── NFTXEligibility.sol │ ├── NFTXGen0Eligibility.sol │ ├── NFTXGen0FastEligibility.sol │ ├── NFTXListEligibility.sol │ ├── NFTXMerkleEligibility.sol │ ├── NFTXMintRequestEligibility.sol │ ├── NFTXOpenseaEligibility.sol │ ├── NFTXRangeEligibility.sol │ ├── NFTXRangeExtendedEligibility.sol │ ├── NFTXUglyEligibility.sol │ ├── NFTXUniqueEligibility.sol │ ├── UniqueEligibility.sol │ └── UniswapV3SparkleEligibility.sol │ ├── interface │ ├── IAdminUpgradeabilityProxy.sol │ ├── IERC165Upgradeable.sol │ ├── IERC3156Upgradeable.sol │ ├── INFTXEligibility.sol │ ├── INFTXEligibilityManager.sol │ ├── INFTXFeeDistributor.sol │ ├── INFTXInventoryStaking.sol │ ├── INFTXLPStaking.sol │ ├── INFTXSimpleFeeDistributor.sol │ ├── INFTXVault.sol │ ├── INFTXVaultFactory.sol │ ├── IPrevNftxContract.sol │ ├── IRewardDistributionToken.sol │ ├── ITimelockExcludeList.sol │ ├── ITimelockRewardDistributionToken.sol │ ├── IUniswapV2Pair.sol │ ├── IUniswapV2Router01.sol │ └── IVaultTokenUpgradeable.sol │ ├── other │ ├── PalmNFTXStakingZap.sol │ └── TimelockExcludeList.sol │ ├── proxy │ ├── BeaconProxy.sol │ ├── ClonesUpgradeable.sol │ ├── Create2BeaconProxy.sol │ ├── IBeacon.sol │ ├── Initializable.sol │ ├── MultiProxyController.sol │ ├── Proxy.sol │ ├── ProxyController.sol │ ├── ProxyControllerSimple.sol │ └── UpgradeableBeacon.sol │ ├── testing │ ├── Address.sol │ ├── Context.sol │ ├── CryptoPunks.sol │ ├── DummyToken.sol │ ├── DummyXToken.sol │ ├── ERC1155.sol │ ├── ERC1155Receiver.sol │ ├── ERC165.sol │ ├── ERC721.sol │ ├── EnumerableMap.sol │ ├── EnumerableSet.sol │ ├── FlashBorrower.sol │ ├── IERC1155.sol │ ├── IERC1155MetadataURI.sol │ ├── IERC1155Receiver.sol │ ├── IERC165.sol │ ├── IERC721.sol │ ├── IERC721Enumerable.sol │ ├── IERC721Metadata.sol │ ├── IERC721Receiver.sol │ ├── Mock0xProvider.sol │ ├── MockDistributor.sol │ ├── MockENSMerkleEligibility.sol │ ├── MockERC20.sol │ ├── MockStakingProvider.sol │ ├── MockVault.sol │ ├── NFTXEligibilityManager2.sol │ ├── NFTXLPStaking2.sol │ ├── NFTXVaultFactoryUpgradeable2.sol │ ├── SafeMath.sol │ ├── Strings.sol │ ├── TestUpgrade.sol │ ├── TestVaultUpgrade.sol │ └── WETH.sol │ ├── token │ ├── ERC1155HolderUpgradeable.sol │ ├── ERC1155ReceiverUpgradeable.sol │ ├── ERC1155SafeHolderUpgradeable.sol │ ├── ERC20FlashMintUpgradeable.sol │ ├── ERC20Upgradeable.sol │ ├── ERC721HolderUpgradeable.sol │ ├── ERC721SafeHolderUpgradeable.sol │ ├── IERC1155ReceiverUpgradeable.sol │ ├── IERC1155Upgradeable.sol │ ├── IERC20Metadata.sol │ ├── IERC20Upgradeable.sol │ ├── IERC721Enumerable.sol │ ├── IERC721ReceiverUpgradeable.sol │ ├── IERC721Upgradeable.sol │ ├── IWETH.sol │ ├── RewardDistributionTokenUpgradeable.sol │ ├── TimelockRewardDistributionTokenImpl.sol │ └── XTokenUpgradeable.sol │ ├── tools │ └── NFTXFlashSwipe.sol │ └── util │ ├── Address.sol │ ├── ContextUpgradeable.sol │ ├── Create2.sol │ ├── ERC165Upgradeable.sol │ ├── EnumerableMapUpgradeable.sol │ ├── EnumerableSetUpgradeable.sol │ ├── Ownable.sol │ ├── OwnableUpgradeable.sol │ ├── PausableUpgradeable.sol │ ├── ReentrancyGuard.sol │ ├── ReentrancyGuardUpgradeable.sol │ ├── SafeERC20Upgradeable.sol │ ├── SafeMathInt.sol │ └── SafeMathUpgradeable.sol ├── hardhat.config.js ├── package-lock.json ├── package.json ├── scripts ├── 2022-0-invstaking.js ├── 2022-1-proxycontroller.js ├── 2022-2-feedistro.js ├── 2022-3-lpstaking.js ├── 2022-4-vault.js ├── 2022-5-configure.js ├── 2022-6-stakingzap.js ├── 2022-7-mpzap.js ├── arbitrum-deploy.js ├── arbitrum │ └── 1-deploy.js ├── assign-default-features.js ├── deploy-lpstaking-impl.js ├── deploy-marketplace-zap.js ├── deploy-marketplace0x-zap.js ├── deploy-simpfeedist.js ├── deploy-simplefeedistro.js ├── deploy-staking-zap.js ├── deploy-test-sushi-provider.js ├── deploy-upgradeable.js ├── deploy-vault-impl.js ├── deploy.js ├── goerli │ ├── 1-deploy.js │ ├── 2-bootstrap.js │ ├── simple-script.js │ └── staker-fee-distrib-update.js ├── mainnet-deploy.js ├── mainnet-upgrade.js ├── palm-deploy.js ├── prepare-mainnet-fork.js ├── retrieve-tokens-upgrade.js ├── ropsten │ ├── 1-deploy.js │ └── 2-bootstrap.js ├── simple-script.js ├── timelock-exclusion-upgrade.js ├── upgrade-lpstaking-and-zap.js └── upgrade.js ├── test ├── eligibility-mint-request-test.js ├── eligibility-range-test.js ├── eligibility-unique-test.js ├── eligibility │ └── merkle-eligibility-test.js ├── inventorystaking-test.js ├── lpstaking-test-1.js ├── mainnet │ ├── mainnet-fee-distr-update.js │ ├── mainnet-inventorystaking.js │ ├── mainnet-kongz-approve-bug.js │ ├── mainnet-lpstaking-migrate-now.js │ ├── mainnet-marketplace-zap.js │ ├── mainnet-multiproxycontroller-test.js │ ├── mainnet-retrieve-tokens.js │ ├── mainnet-set-metadata.js │ ├── mainnet-timelock-exclusion.js │ ├── mainnet-unstaking-inventory-zap.js │ ├── mainnet-upgrade.js │ └── mainnet-vault-shutdown.js ├── marketplace-0x-zap.js ├── multiproxycontroller-test.js ├── nftx-test-0.js ├── nftxeligmanager-test-2.js ├── rinkeby │ └── rinkeby-unstaking-inventory-zap.js ├── stakingprovider-test.js └── v1-buyout.js ├── utils └── expectRevert.js └── yarn.lock /.env-sample: -------------------------------------------------------------------------------- 1 | ALCHEMY_MAINNET_API_KEY=secretGoesHere 2 | ALCHEMY_RINKEBY_API_KEY=secretGoesHere 3 | DEV_PRIVATE_KEY=secreteGoesHere -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .openzeppelin 3 | bin 4 | .env 5 | **/.DS_Store 6 | yarn-error.log 7 | flattened 8 | 9 | #Hardhat files 10 | cache 11 | artifacts 12 | hardhat.config.local.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NFTX Protocol v2 2 | The new and updated version of NFTX. 3 | 4 | ## Getting Started 5 | 6 | `yarn install` 7 | 8 | `npx hardhat compile` (optional) 9 | 10 | `npx hardhat test` 11 | 12 | ## Primary Contracts 13 | 14 | - StakingTokenProvider 15 | - NFTXLPStaking 16 | - NFTXVaultUpgradeable 17 | - NFTXFeeDistributor 18 | - NFTXVaultFactory 19 | - NFTXEligibilityManager 20 | - Eligibility Modules 21 | 22 | ## Mainnet Contract Addresses 23 | 24 | ### Protocol 25 | 26 | - StakingTokenProvider: 0x5fAD0e4cc9925365b9B0bbEc9e0C3536c0B1a5C7 27 | - Staking: 0x688c3E4658B5367da06fd629E41879beaB538E37 28 | - Vault template: 0xe8B6820b74533c27786E4724a578Bfca28D97BD1 29 | - FeeDistributor: 0x7AE9D7Ee8489cAD7aFc84111b8b185EE594Ae090 30 | - VaultFactory: 0xBE86f647b167567525cCAAfcd6f881F1Ee558216 31 | - EligibilityManager: 0x4086e98Cce041d286112d021612fD894cFed94D5 32 | - ProxyController address: 0x4333d66Ec59762D1626Ec102d7700E64610437Df 33 | 34 | ## Rinkeby Contract Addresses 35 | 36 | ### NFT contracts for testing (open permissions to call `mint()`) 37 | 38 | - Twerky (1155): 0xA04a0C462373aAB7db22A4EeEcDE3EDA3e5B7d27 39 | - CryptoPunks: 0xf8168585599b9997Db76C39e4edD27D63c307EaC 40 | - ArtBlocks: 0x7D76E9247f5C184d9E73212953A9258FCb6e7886 41 | 42 | -------------------------------------------------------------------------------- /addresses/rinkeby.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /contracts/solidity/NFTXEligibilityManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma experimental ABIEncoderV2; 4 | pragma solidity ^0.8.0; 5 | 6 | import "./interface/INFTXVaultFactory.sol"; 7 | import "./interface/INFTXEligibility.sol"; 8 | import "./util/OwnableUpgradeable.sol"; 9 | import "./proxy/ClonesUpgradeable.sol"; 10 | 11 | contract NFTXEligibilityManager is OwnableUpgradeable { 12 | struct EligibilityModule { 13 | address implementation; 14 | address targetAsset; 15 | string name; 16 | } 17 | EligibilityModule[] public modules; 18 | 19 | event ModuleAdded( 20 | address implementation, 21 | address targetAsset, 22 | string name, 23 | bool finalizedOnDeploy 24 | ); 25 | event ModuleUpdated( 26 | address implementation, 27 | string name, 28 | bool finalizedOnDeploy 29 | ); 30 | 31 | function __NFTXEligibilityManager_init() public initializer { 32 | __Ownable_init(); 33 | } 34 | 35 | function addModule(address implementation) external onlyOwner { 36 | require(implementation != address(0), "Impl != address(0)"); 37 | INFTXEligibility elig = INFTXEligibility(implementation); 38 | string memory name = elig.name(); 39 | EligibilityModule memory module = EligibilityModule( 40 | implementation, 41 | elig.targetAsset(), 42 | name 43 | ); 44 | modules.push(module); 45 | emit ModuleAdded( 46 | implementation, 47 | module.targetAsset, 48 | name, 49 | elig.finalized() 50 | ); 51 | } 52 | 53 | function updateModule(uint256 moduleIndex, address implementation) 54 | external 55 | onlyOwner 56 | { 57 | require(moduleIndex < modules.length, "Out of bounds"); 58 | require(implementation != address(0), "Impl != address(0)"); 59 | modules[moduleIndex].implementation = implementation; 60 | INFTXEligibility elig = INFTXEligibility(implementation); 61 | emit ModuleUpdated(implementation, elig.name(), elig.finalized()); 62 | } 63 | 64 | function deployEligibility(uint256 moduleIndex, bytes calldata configData) 65 | external 66 | virtual 67 | returns (address) 68 | { 69 | require(moduleIndex < modules.length, "Out of bounds"); 70 | address eligImpl = modules[moduleIndex].implementation; 71 | address eligibilityClone = ClonesUpgradeable.clone(eligImpl); 72 | INFTXEligibility(eligibilityClone).__NFTXEligibility_init_bytes( 73 | configData 74 | ); 75 | return eligibilityClone; 76 | } 77 | 78 | function allModules() external view returns (EligibilityModule[] memory) { 79 | return modules; 80 | } 81 | 82 | function allModuleNames() external view returns (string[] memory) { 83 | EligibilityModule[] memory modulesCopy = modules; 84 | string[] memory names = new string[](modulesCopy.length); 85 | for (uint256 i = 0; i < modulesCopy.length; i++) { 86 | names[i] = modulesCopy[i].name; 87 | } 88 | return names; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /contracts/solidity/NFTXV1Buyout.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./token/IERC20Upgradeable.sol"; 6 | import "./util/ReentrancyGuardUpgradeable.sol"; 7 | import "./util/PausableUpgradeable.sol"; 8 | 9 | interface IV1Token is IERC20Upgradeable { 10 | function burnFrom(address account, uint256 amount) external; 11 | } 12 | 13 | contract NFTXV1Buyout is PausableUpgradeable, ReentrancyGuardUpgradeable { 14 | uint256 constant BASE = 10*18; 15 | mapping(address => uint256) public ethAvailiable; 16 | 17 | event TokenBuyout(address tokenAddress, uint256 totalEth); 18 | event BuyoutComplete(address tokenAddress); 19 | 20 | function __NFTXV1Buyout_init() external initializer { 21 | __Pausable_init(); 22 | __ReentrancyGuard_init(); 23 | } 24 | 25 | // Emergency functions. 26 | function emergencyWithdraw() external onlyOwner { 27 | payable(msg.sender).transfer(address(this).balance); 28 | } 29 | 30 | function clearBuyout(address v1TokenAddr) external onlyOwner { 31 | ethAvailiable[v1TokenAddr] = 0; 32 | emit BuyoutComplete(v1TokenAddr); 33 | } 34 | 35 | function addBuyout(address v1TokenAddr) external payable onlyOwner { 36 | require(msg.value > 0, "Cannot pair with 0 ETH"); 37 | ethAvailiable[v1TokenAddr] += msg.value; 38 | 39 | emit TokenBuyout(v1TokenAddr, msg.value); 40 | } 41 | 42 | function removeBuyout(address v1TokenAddr) external onlyOwner { 43 | uint256 amount = ethAvailiable[v1TokenAddr]; 44 | require(amount > 0, "Cannot remove 0"); 45 | ethAvailiable[v1TokenAddr] = 0; 46 | sendValue(payable(msg.sender), amount); 47 | emit BuyoutComplete(v1TokenAddr); 48 | } 49 | 50 | function claimETH(address v1TokenAddr) external nonReentrant { 51 | onlyOwnerIfPaused(0); 52 | uint256 ethAvail = ethAvailiable[v1TokenAddr]; 53 | require(ethAvail > 0, "Not a valid buyout token"); 54 | 55 | uint256 userBal = IV1Token(v1TokenAddr).balanceOf(msg.sender); 56 | require(userBal > 0, "cant be zero"); 57 | uint256 totalSupply = IV1Token(v1TokenAddr).totalSupply(); 58 | IV1Token(v1TokenAddr).burnFrom(msg.sender, userBal); 59 | uint256 ethToSend = (ethAvail * userBal)/totalSupply; 60 | ethToSend = ethToSend > ethAvail ? ethAvail : ethToSend; 61 | ethAvailiable[v1TokenAddr] -= ethToSend; 62 | (bool success, ) = msg.sender.call{ value: ethToSend }(""); 63 | require(success, "Address: unable to send value, recipient may have reverted"); 64 | 65 | if (ethAvailiable[v1TokenAddr] == 0) { 66 | emit BuyoutComplete(v1TokenAddr); 67 | } 68 | } 69 | 70 | function sendValue(address payable recipient, uint256 amount) internal { 71 | require(address(this).balance >= amount, "Address: insufficient balance"); 72 | 73 | // solhint-disable-next-line avoid-low-level-calls, avoid-call-value 74 | (bool success, ) = recipient.call{ value: amount }(""); 75 | require(success, "Address: unable to send value, recipient may have reverted"); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/NFTXAvastarRank60Eligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./NFTXEligibility.sol"; 6 | 7 | interface Avastar { 8 | enum Generation {ONE, TWO, THREE, FOUR, FIVE} 9 | enum Series {PROMO, ONE, TWO, THREE, FOUR, FIVE} 10 | enum Gender {ANY, MALE, FEMALE} 11 | 12 | function getPrimeByTokenId(uint256 _tokenId) external view returns ( 13 | uint256 tokenId, 14 | uint256 serial, 15 | uint256 traits, 16 | Generation generation, 17 | Series series, 18 | Gender gender, 19 | uint8 ranking 20 | ); 21 | } 22 | 23 | contract NFTXAvastarRank60Eligibility is NFTXEligibility { 24 | 25 | function name() public pure override virtual returns (string memory) { 26 | return "AvastarRank60"; 27 | } 28 | 29 | function finalized() public view override virtual returns (bool) { 30 | return true; 31 | } 32 | 33 | function targetAsset() public pure override virtual returns (address) { 34 | return 0xF3E778F839934fC819cFA1040AabaCeCBA01e049; 35 | } 36 | 37 | event NFTXEligibilityInit(); 38 | 39 | function __NFTXEligibility_init_bytes( 40 | bytes memory /* configData */ 41 | ) public override virtual initializer { 42 | __NFTXEligibility_init(); 43 | } 44 | 45 | // Parameters here should mirror the config struct. 46 | function __NFTXEligibility_init() public initializer { 47 | emit NFTXEligibilityInit(); 48 | } 49 | 50 | function _checkIfEligible( 51 | uint256 _tokenId 52 | ) internal view override virtual returns (bool) { 53 | (,,,,,,uint8 ranking) = Avastar(targetAsset()).getPrimeByTokenId(_tokenId); 54 | return ranking > 60; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/NFTXDeferEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./NFTXEligibility.sol"; 6 | import "../interface/IPrevNftxContract.sol"; 7 | 8 | contract NFTXDeferEligibility is NFTXEligibility { 9 | 10 | function name() public pure override virtual returns (string memory) { 11 | return "Defer"; 12 | } 13 | 14 | function finalized() public view override virtual returns (bool) { 15 | return true; 16 | } 17 | 18 | function targetAsset() public pure override virtual returns (address) { 19 | return address(0); 20 | } 21 | 22 | address public deferAddress; 23 | uint256 public deferVaultId; 24 | 25 | event NFTXEligibilityInit(address deferAddress, uint256 deferralVaultId); 26 | 27 | struct Config { 28 | address deferAddress; 29 | uint256 deferVaultId; 30 | } 31 | 32 | function __NFTXEligibility_init_bytes( 33 | bytes memory configData 34 | ) public override virtual initializer { 35 | (address _deferAddress, uint256 _deferId) = abi.decode(configData, (address, uint256)); 36 | __NFTXEligibility_init(_deferAddress, _deferId); 37 | } 38 | 39 | // Parameters here should mirror the config struct. 40 | function __NFTXEligibility_init( 41 | address _deferAddress, 42 | uint256 _deferVaultId 43 | ) public initializer { 44 | require(_deferAddress != address(0), "deferAddress != address(0)"); 45 | deferAddress = _deferAddress; 46 | deferVaultId = _deferVaultId; 47 | emit NFTXEligibilityInit(_deferAddress, _deferVaultId); 48 | } 49 | 50 | function _checkIfEligible( 51 | uint256 _tokenId 52 | ) internal view override virtual returns (bool) { 53 | return IPrevNftxContract(deferAddress).isEligible(deferVaultId, _tokenId); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/NFTXDenyEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./NFTXUniqueEligibility.sol"; 6 | 7 | contract NFTXDenyEligibility is NFTXUniqueEligibility { 8 | 9 | function name() public pure override virtual returns (string memory) { 10 | return "Deny"; 11 | } 12 | 13 | function _checkIfEligible( 14 | uint256 _tokenId 15 | ) internal view override virtual returns (bool) { 16 | return !isUniqueEligible(_tokenId); 17 | } 18 | 19 | function afterRedeemHook(uint256[] calldata tokenIds) external override virtual { 20 | require(msg.sender == vault); 21 | if (negateEligOnRedeem) { 22 | // Reversing eligibility to true here so they're added to the deny list. 23 | _setUniqueEligibilities(tokenIds, true); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/NFTXENSMerkleEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./NFTXMerkleEligibility.sol"; 6 | 7 | 8 | abstract contract ENS { 9 | function nameExpires(uint256 id) public virtual view returns (uint256); 10 | } 11 | 12 | 13 | /** 14 | * @title NFTX ENS Merkle Eligibility 15 | * @author Twade 16 | * 17 | * @notice Allows vaults to be allow eligibility based ENS domains, allowing for minimum 18 | * expiration times to be set. 19 | */ 20 | 21 | contract NFTXENSMerkleEligibility is NFTXMerkleEligibility { 22 | 23 | /// @notice Minimum expiration time for ENS domains in seconds 24 | uint public minExpirationTime; 25 | 26 | 27 | /** 28 | * @notice The name of our Eligibility Module. 29 | * 30 | * @return string 31 | */ 32 | 33 | function name() public pure override virtual returns (string memory) { 34 | return 'ENSMerkleEligibility'; 35 | } 36 | 37 | 38 | /** 39 | * @notice The address of our token asset contract. 40 | * 41 | * @return address 42 | */ 43 | 44 | function targetAsset() public pure override virtual returns (address) { 45 | return 0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85; 46 | } 47 | 48 | 49 | /** 50 | * @notice Allow our eligibility module to be initialised with optional 51 | * config data. 52 | * 53 | * @param configData Encoded config data 54 | */ 55 | 56 | function __NFTXEligibility_init_bytes(bytes memory configData) public override virtual initializer { 57 | ( 58 | bytes32 _merkleRoot, 59 | string memory _merkleReference, 60 | string memory _merkleLeavesURI, 61 | uint _minExpirationTime 62 | ) = abi.decode(configData, (bytes32, string, string, uint)); 63 | 64 | __NFTXEligibility_init(_merkleRoot, _merkleReference, _merkleLeavesURI, _minExpirationTime); 65 | } 66 | 67 | 68 | /** 69 | * @notice Parameters here should mirror the config struct. 70 | * 71 | * @param _merkleRoot The root of our merkle tree 72 | * @param _merkleReference Public name of the merkle eligibility implementation 73 | * @param _merkleLeavesURI API endpoint providing unencoded JSON array 74 | * @param _minExpirationTime Minimum number of seconds until ENS expiration 75 | */ 76 | 77 | function __NFTXEligibility_init( 78 | bytes32 _merkleRoot, 79 | string memory _merkleReference, 80 | string memory _merkleLeavesURI, 81 | uint _minExpirationTime 82 | ) public initializer { 83 | super.__NFTXEligibility_init(_merkleRoot, _merkleReference, _merkleLeavesURI); 84 | 85 | minExpirationTime = _minExpirationTime; 86 | } 87 | 88 | 89 | /** 90 | * @notice Checks if a supplied token is eligible; in addition to our core merkle 91 | * eligibility checks we also need to confirm that the ENS domain won't expire within 92 | * a year. 93 | * 94 | * @dev This check requires the token to have already been passed to `processToken`. 95 | * 96 | * @return bool If the tokenId is eligible 97 | */ 98 | 99 | function _checkIfEligible(uint tokenId) internal view override virtual returns (bool) { 100 | // Get the expiry time of the token ID provided and ensure it has at least 101 | // 365 days left until it expires. 102 | if (block.timestamp + minExpirationTime > ENS(targetAsset()).nameExpires(tokenId)) { 103 | return false; 104 | } 105 | 106 | return super._checkIfEligible(tokenId); 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/NFTXEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../proxy/Initializable.sol"; 6 | import "../interface/INFTXEligibility.sol"; 7 | 8 | // This is a contract meant to be inherited and overriden to implement eligibility modules. 9 | abstract contract NFTXEligibility is INFTXEligibility, Initializable { 10 | function name() public pure override virtual returns (string memory); 11 | function finalized() public view override virtual returns (bool); 12 | function targetAsset() public pure override virtual returns (address); 13 | 14 | function __NFTXEligibility_init_bytes(bytes memory initData) public override virtual; 15 | 16 | function checkIsEligible(uint256 tokenId) external view override virtual returns (bool) { 17 | return _checkIfEligible(tokenId); 18 | } 19 | 20 | function checkEligible(uint256[] calldata tokenIds) external override virtual view returns (bool[] memory) { 21 | uint256 length = tokenIds.length; 22 | bool[] memory eligibile = new bool[](length); 23 | for (uint256 i; i < length; i++) { 24 | eligibile[i] = _checkIfEligible(tokenIds[i]); 25 | } 26 | return eligibile; 27 | } 28 | 29 | function checkAllEligible(uint256[] calldata tokenIds) external override virtual view returns (bool) { 30 | uint256 length = tokenIds.length; 31 | for (uint256 i; i < length; i++) { 32 | // If any are not eligible, end the loop and return false. 33 | if (!_checkIfEligible(tokenIds[i])) { 34 | return false; 35 | } 36 | } 37 | return true; 38 | } 39 | 40 | // Checks if all provided NFTs are NOT eligible. This is needed for mint requesting where all NFTs 41 | // provided must be ineligible. 42 | function checkAllIneligible(uint256[] calldata tokenIds) external override virtual view returns (bool) { 43 | uint256 length = tokenIds.length; 44 | for (uint256 i; i < length; i++) { 45 | // If any are eligible, end the loop and return false. 46 | if (_checkIfEligible(tokenIds[i])) { 47 | return false; 48 | } 49 | } 50 | return true; 51 | } 52 | 53 | function beforeMintHook(uint256[] calldata tokenIds) external override virtual {} 54 | function afterMintHook(uint256[] calldata tokenIds) external override virtual {} 55 | function beforeRedeemHook(uint256[] calldata tokenIds) external override virtual {} 56 | function afterRedeemHook(uint256[] calldata tokenIds) external override virtual {} 57 | 58 | // Override this to implement your module! 59 | function _checkIfEligible(uint256 _tokenId) internal view virtual returns (bool); 60 | } 61 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/NFTXGen0Eligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./NFTXEligibility.sol"; 6 | 7 | interface KittyCore { 8 | function ownerOf(uint256 _tokenId) external view returns (address owner); 9 | function getKitty(uint256 _id) 10 | external 11 | view 12 | returns ( 13 | bool, 14 | bool, 15 | uint256, 16 | uint256, 17 | uint256, 18 | uint256, 19 | uint256, 20 | uint256, 21 | uint256 _generation, 22 | uint256 23 | ); 24 | } 25 | 26 | contract NFTXGen0KittyEligibility is NFTXEligibility { 27 | function name() public pure override virtual returns (string memory) { 28 | return "Gen0Kitty"; 29 | } 30 | 31 | function finalized() public view override virtual returns (bool) { 32 | return true; 33 | } 34 | 35 | function targetAsset() public pure override virtual returns (address) { 36 | return 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d; 37 | } 38 | 39 | event NFTXEligibilityInit(); 40 | 41 | function __NFTXEligibility_init_bytes( 42 | bytes memory /* configData */ 43 | ) public override virtual initializer { 44 | __NFTXEligibility_init(); 45 | } 46 | 47 | // Parameters here should mirror the config struct. 48 | function __NFTXEligibility_init() public initializer { 49 | emit NFTXEligibilityInit(); 50 | } 51 | 52 | function _checkIfEligible(uint256 _tokenId) 53 | internal 54 | view 55 | override 56 | virtual 57 | returns (bool) 58 | { 59 | (, , , , , , , , uint256 _generation, ) = KittyCore(targetAsset()) 60 | .getKitty(_tokenId); 61 | return _generation == 0; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/NFTXGen0FastEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./NFTXEligibility.sol"; 6 | 7 | interface KittyCore { 8 | function ownerOf(uint256 _tokenId) external view returns (address owner); 9 | function getKitty(uint256 _id) external view returns (bool,bool,uint256 _cooldownIndex,uint256,uint256,uint256,uint256,uint256,uint256 _generation,uint256); 10 | } 11 | 12 | contract NFTXGen0FastKittyEligibility is NFTXEligibility { 13 | 14 | function name() public pure override virtual returns (string memory) { 15 | return "Gen0FastKitty"; 16 | } 17 | 18 | function finalized() public view override virtual returns (bool) { 19 | return true; 20 | } 21 | 22 | function targetAsset() public pure override virtual returns (address) { 23 | return 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d; 24 | } 25 | 26 | event NFTXEligibilityInit(); 27 | 28 | function __NFTXEligibility_init_bytes( 29 | bytes memory /* configData */ 30 | ) public override virtual initializer { 31 | __NFTXEligibility_init(); 32 | } 33 | 34 | // Parameters here should mirror the config struct. 35 | function __NFTXEligibility_init() public initializer { 36 | emit NFTXEligibilityInit(); 37 | } 38 | 39 | function _checkIfEligible( 40 | uint256 _tokenId 41 | ) internal view override virtual returns (bool) { 42 | (,,uint256 _cooldownIndex,,,,,,uint256 _generation,) = KittyCore(targetAsset()).getKitty(_tokenId); 43 | return _cooldownIndex == 0 && _generation == 0; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/NFTXListEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./UniqueEligibility.sol"; 6 | import "./NFTXEligibility.sol"; 7 | 8 | contract NFTXListEligibility is NFTXEligibility, UniqueEligibility { 9 | function name() public pure override virtual returns (string memory) { 10 | return "List"; 11 | } 12 | 13 | function finalized() public view override virtual returns (bool) { 14 | return true; 15 | } 16 | 17 | function targetAsset() public pure override virtual returns (address) { 18 | return address(0); 19 | } 20 | 21 | struct Config { 22 | uint256[] tokenIds; 23 | } 24 | 25 | event NFTXEligibilityInit(uint256[] tokenIds); 26 | 27 | function __NFTXEligibility_init_bytes( 28 | bytes memory _configData 29 | ) public override virtual initializer { 30 | (uint256[] memory _ids) = abi.decode(_configData, (uint256[])); 31 | __NFTXEligibility_init(_ids); 32 | } 33 | 34 | function __NFTXEligibility_init( 35 | uint256[] memory tokenIds 36 | ) public initializer { 37 | _setUniqueEligibilities(tokenIds, true); 38 | emit NFTXEligibilityInit(tokenIds); 39 | } 40 | 41 | function _checkIfEligible( 42 | uint256 _tokenId 43 | ) internal view override virtual returns (bool) { 44 | return isUniqueEligible(_tokenId); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/NFTXOpenseaEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./NFTXEligibility.sol"; 6 | 7 | contract NFTXOpenseaEligibility is NFTXEligibility { 8 | 9 | function name() public pure override virtual returns (string memory) { 10 | return "Opensea"; 11 | } 12 | 13 | function finalized() public view override virtual returns (bool) { 14 | return true; 15 | } 16 | 17 | function targetAsset() public pure override virtual returns (address) { 18 | return 0x495f947276749Ce646f68AC8c248420045cb7b5e; 19 | } 20 | 21 | uint256 public collectionId; 22 | 23 | event NFTXEligibilityInit(uint256 collectionId); 24 | 25 | struct Config { 26 | uint256 collectionId; 27 | } 28 | 29 | function __NFTXEligibility_init_bytes( 30 | bytes memory configData 31 | ) public override virtual initializer { 32 | (uint256 _collectionId) = abi.decode(configData, (uint256)); 33 | __NFTXEligibility_init(_collectionId); 34 | } 35 | 36 | // Parameters here should mirror the config struct. 37 | function __NFTXEligibility_init( 38 | uint256 _collectionId 39 | ) public initializer { 40 | require(_collectionId != 0, "Can't be 0"); 41 | collectionId = _collectionId; 42 | emit NFTXEligibilityInit(_collectionId); 43 | } 44 | 45 | function _checkIfEligible( 46 | uint256 _tokenId 47 | ) internal view override virtual returns (bool) { 48 | uint256 _tokenCollectionId = uint160(_tokenId >> 96); 49 | return _tokenCollectionId == collectionId; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/NFTXRangeEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./NFTXEligibility.sol"; 6 | 7 | // Maybe use guardian here? 8 | contract NFTXRangeEligibility is NFTXEligibility { 9 | function name() public pure override virtual returns (string memory) { 10 | return "Range"; 11 | } 12 | 13 | function finalized() public view override virtual returns (bool) { 14 | return true; 15 | } 16 | 17 | function targetAsset() public pure override virtual returns (address) { 18 | return address(0); 19 | } 20 | 21 | uint256 public rangeStart; 22 | uint256 public rangeEnd; 23 | 24 | struct Config { 25 | uint256 rangeStart; 26 | uint256 rangeEnd; 27 | } 28 | event RangeSet(uint256 rangeStart, uint256 rangeEnd); 29 | event NFTXEligibilityInit( 30 | uint256 rangeStart, 31 | uint256 rangeEnd 32 | ); 33 | 34 | function __NFTXEligibility_init_bytes(bytes memory _configData) 35 | public 36 | override 37 | virtual 38 | initializer 39 | { 40 | (uint256 _rangeStart, uint256 _rangeEnd) = abi.decode(_configData, (uint256, uint256)); 41 | __NFTXEligibility_init(_rangeStart, _rangeEnd); 42 | } 43 | 44 | function __NFTXEligibility_init( 45 | uint256 _rangeStart, 46 | uint256 _rangeEnd 47 | ) public initializer { 48 | require(_rangeStart <= _rangeEnd, "start > end"); 49 | rangeStart = _rangeStart; 50 | rangeEnd = _rangeEnd; 51 | emit RangeSet(_rangeStart, _rangeEnd); 52 | emit NFTXEligibilityInit(_rangeStart, _rangeEnd); 53 | } 54 | 55 | function _checkIfEligible(uint256 _tokenId) 56 | internal 57 | view 58 | override 59 | virtual 60 | returns (bool) 61 | { 62 | return _tokenId >= rangeStart && _tokenId <= rangeEnd; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/NFTXRangeExtendedEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../util/OwnableUpgradeable.sol"; 6 | import "./UniqueEligibility.sol"; 7 | import "./NFTXEligibility.sol"; 8 | 9 | contract NFTXRangeExtendedEligibility is 10 | OwnableUpgradeable, 11 | NFTXEligibility, 12 | UniqueEligibility 13 | { 14 | 15 | function name() public pure override virtual returns (string memory) { 16 | return "RangeExtended"; 17 | } 18 | 19 | function finalized() public view override virtual returns (bool) { 20 | return isInitialized && owner() == address(0); 21 | } 22 | 23 | function targetAsset() public pure override virtual returns (address) { 24 | return address(0); 25 | } 26 | 27 | bool public isInitialized; 28 | uint256 public rangeStart; 29 | uint256 public rangeEnd; 30 | 31 | struct Config { 32 | address owner; 33 | uint256 rangeStart; 34 | uint256 rangeEnd; 35 | } 36 | event RangeSet(uint256 rangeStart, uint256 rangeEnd); 37 | event NFTXEligibilityInit( 38 | address owner, 39 | uint256 rangeStart, 40 | uint256 rangeEnd 41 | ); 42 | 43 | function __NFTXEligibility_init_bytes(bytes memory _configData) 44 | public 45 | override 46 | virtual 47 | initializer 48 | { 49 | (address _owner, uint256 _rangeStart, uint256 _rangeEnd) = abi 50 | .decode(_configData, (address, uint256, uint256)); 51 | __NFTXEligibility_init(_owner, _rangeStart, _rangeEnd); 52 | } 53 | 54 | function __NFTXEligibility_init( 55 | address _owner, 56 | uint256 _rangeStart, 57 | uint256 _rangeEnd 58 | ) public initializer { 59 | __Ownable_init(); 60 | isInitialized = true; 61 | require(_rangeStart <= _rangeEnd, "Not valid"); 62 | rangeStart = _rangeStart; 63 | rangeEnd = _rangeEnd; 64 | emit RangeSet(_rangeStart, _rangeEnd); 65 | emit NFTXEligibilityInit(_owner, _rangeStart, _rangeEnd); 66 | 67 | transferOwnership(_owner); 68 | } 69 | 70 | function setEligibilityPreferences(uint256 _rangeStart, uint256 _rangeEnd) 71 | external 72 | virtual 73 | onlyOwner 74 | { 75 | require(_rangeStart <= _rangeEnd, "Not valid"); 76 | rangeStart = _rangeStart; 77 | rangeEnd = _rangeEnd; 78 | emit RangeSet(_rangeStart, _rangeEnd); 79 | } 80 | 81 | function setUniqueEligibilities( 82 | uint256[] calldata tokenIds, 83 | bool _isEligible 84 | ) external virtual onlyOwner { 85 | _setUniqueEligibilities(tokenIds, _isEligible); 86 | } 87 | 88 | function _checkIfEligible(uint256 _tokenId) 89 | internal 90 | view 91 | override 92 | virtual 93 | returns (bool) 94 | { 95 | bool isElig; 96 | if (rangeEnd > 0) { 97 | isElig = _tokenId >= rangeStart && _tokenId <= rangeEnd; 98 | } 99 | // Good to leave this here because if its a branch where it isn't eligibile via range or eligibility, 100 | // the tx will fail anyways and not have a cost to the user. 101 | // i.e. This is only a cost to users if unique eligibilty is used in conjunction with range and its a valid NFT. 102 | if (!isElig) { 103 | isElig = isUniqueEligible(_tokenId); 104 | } 105 | return isElig; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/NFTXUglyEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./NFTXEligibility.sol"; 6 | 7 | interface IPolymorph { 8 | function geneOf(uint256 tokenId) external view returns (uint256 gene); 9 | function lastTokenId() external view returns (uint256 tokenId); 10 | } 11 | 12 | contract NFTXUglyEligibility is NFTXEligibility { 13 | function name() public pure override virtual returns (string memory) { 14 | return "Ugly"; 15 | } 16 | 17 | function finalized() public view override virtual returns (bool) { 18 | return true; 19 | } 20 | 21 | function targetAsset() public pure override virtual returns (address) { 22 | return 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d; 23 | } 24 | 25 | event NFTXEligibilityInit(); 26 | 27 | function __NFTXEligibility_init_bytes( 28 | bytes memory /* configData */ 29 | ) public override virtual initializer { 30 | __NFTXEligibility_init(); 31 | } 32 | 33 | // Parameters here should mirror the config struct. 34 | function __NFTXEligibility_init() public initializer { 35 | emit NFTXEligibilityInit(); 36 | } 37 | 38 | function _checkIfEligible(uint256 _tokenId) 39 | internal 40 | view 41 | override 42 | virtual 43 | returns (bool) 44 | { 45 | uint256 gene = IPolymorph(targetAsset()) 46 | .geneOf(_tokenId); 47 | return gene == 0; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/NFTXUniqueEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../util/OwnableUpgradeable.sol"; 6 | import "./UniqueEligibility.sol"; 7 | import "./NFTXEligibility.sol"; 8 | 9 | // Maybe use guardian here? 10 | contract NFTXUniqueEligibility is 11 | OwnableUpgradeable, 12 | NFTXEligibility, 13 | UniqueEligibility 14 | { 15 | function name() public pure override virtual returns (string memory) { 16 | return "Unique"; 17 | } 18 | 19 | function finalized() public view override virtual returns (bool) { 20 | return isInitialized && owner() == address(0); 21 | } 22 | 23 | function targetAsset() public pure override virtual returns (address) { 24 | return address(0); 25 | } 26 | 27 | address vault; 28 | bool public isInitialized; 29 | bool public negateEligOnRedeem; 30 | 31 | struct Config { 32 | address owner; 33 | address vault; 34 | bool negateElig; 35 | bool finalize; 36 | uint256[] tokenIds; 37 | } 38 | 39 | event NFTXEligibilityInit( 40 | address owner, 41 | address vault, 42 | bool negateElig, 43 | bool finalize, 44 | uint256[] tokenIds 45 | ); 46 | event negateEligilityOnRedeemSet(bool negateElig); 47 | 48 | function __NFTXEligibility_init_bytes(bytes memory _configData) 49 | public 50 | override 51 | virtual 52 | initializer 53 | { 54 | __Ownable_init(); 55 | (address _owner, address _vault, bool finalize, bool negateElig, uint256[] memory _ids) = abi 56 | .decode(_configData, (address, address, bool, bool, uint256[])); 57 | __NFTXEligibility_init(_owner, _vault, negateElig, finalize, _ids); 58 | } 59 | 60 | function __NFTXEligibility_init( 61 | address _owner, 62 | address _vault, 63 | bool negateElig, 64 | bool finalize, 65 | uint256[] memory tokenIds 66 | ) public initializer { 67 | __Ownable_init(); 68 | require(_owner != address(0), "Owner != address(0)"); 69 | require(_vault != address(0), "Vault != address(0)"); 70 | isInitialized = true; 71 | vault = _vault; 72 | negateEligOnRedeem = negateElig; 73 | _setUniqueEligibilities(tokenIds, true); 74 | emit NFTXEligibilityInit( 75 | _owner, 76 | _vault, 77 | negateElig, 78 | finalize, 79 | tokenIds 80 | ); 81 | 82 | if (finalize) { 83 | renounceOwnership(); 84 | } else { 85 | transferOwnership(_owner); 86 | } 87 | } 88 | 89 | function setEligibilityPreferences(bool _negateEligOnRedeem) 90 | external 91 | onlyOwner 92 | { 93 | negateEligOnRedeem = _negateEligOnRedeem; 94 | emit negateEligilityOnRedeemSet(_negateEligOnRedeem); 95 | } 96 | 97 | function setUniqueEligibilities(uint256[] memory tokenIds, bool _isEligible) 98 | external 99 | virtual 100 | onlyOwner 101 | { 102 | _setUniqueEligibilities(tokenIds, _isEligible); 103 | } 104 | 105 | function afterRedeemHook(uint256[] calldata tokenIds) 106 | external 107 | override 108 | virtual 109 | { 110 | require(msg.sender == vault); 111 | if (negateEligOnRedeem) { 112 | _setUniqueEligibilities(tokenIds, false); 113 | } 114 | } 115 | 116 | function _checkIfEligible(uint256 _tokenId) 117 | internal 118 | view 119 | override 120 | virtual 121 | returns (bool) 122 | { 123 | return isUniqueEligible(_tokenId); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /contracts/solidity/eligibility/UniqueEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | contract UniqueEligibility { 6 | mapping(uint256 => uint256) eligibleBitMap; 7 | 8 | event UniqueEligibilitiesSet(uint256[] tokenIds, bool isEligible); 9 | 10 | function isUniqueEligible(uint256 tokenId) 11 | public 12 | view 13 | virtual 14 | returns (bool) 15 | { 16 | uint256 wordIndex = tokenId / 256; 17 | uint256 bitMap = eligibleBitMap[wordIndex]; 18 | return _getBit(bitMap, tokenId); 19 | } 20 | 21 | function _setUniqueEligibilities( 22 | uint256[] memory tokenIds, 23 | bool _isEligible 24 | ) internal virtual { 25 | uint256 cachedWord = eligibleBitMap[0]; 26 | uint256 cachedIndex = 0; 27 | for (uint256 i; i < tokenIds.length; i++) { 28 | uint256 tokenId = tokenIds[i]; 29 | uint256 eligibilityWordIndex = tokenId / 256; 30 | if (eligibilityWordIndex != cachedIndex) { 31 | // Save the cached word. 32 | eligibleBitMap[cachedIndex] = cachedWord; 33 | // Cache the new one. 34 | cachedWord = eligibleBitMap[eligibilityWordIndex]; 35 | cachedIndex = eligibilityWordIndex; 36 | } 37 | // Modify the cached word. 38 | cachedWord = _setBit(cachedWord, tokenId, _isEligible); 39 | } 40 | // Assign the last word since the loop is done. 41 | eligibleBitMap[cachedIndex] = cachedWord; 42 | emit UniqueEligibilitiesSet(tokenIds, _isEligible); 43 | } 44 | 45 | function _setBit(uint256 bitMap, uint256 index, bool eligible) 46 | internal 47 | pure 48 | returns (uint256) 49 | { 50 | uint256 claimedBitIndex = index % 256; 51 | if (eligible) { 52 | return bitMap | (1 << claimedBitIndex); 53 | } else { 54 | return bitMap & ~(1 << claimedBitIndex); 55 | } 56 | } 57 | 58 | function _getBit(uint256 bitMap, uint256 index) 59 | internal 60 | pure 61 | returns (bool) 62 | { 63 | uint256 claimedBitIndex = index % 256; 64 | return uint8((bitMap >> claimedBitIndex) & 1) == 1; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /contracts/solidity/interface/IAdminUpgradeabilityProxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface IAdminUpgradeabilityProxy { 6 | // Read functions. 7 | function admin() external view returns (address); 8 | function implementation() external view returns (address); 9 | 10 | // Write functions. 11 | function changeAdmin(address newAdmin) external; 12 | function upgradeTo(address newImplementation) external; 13 | } 14 | -------------------------------------------------------------------------------- /contracts/solidity/interface/IERC165Upgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev Interface of the ERC165 standard, as defined in the 7 | * https://eips.ethereum.org/EIPS/eip-165[EIP]. 8 | * 9 | * Implementers can declare support of contract interfaces, which can then be 10 | * queried by others ({ERC165Checker}). 11 | * 12 | * For an implementation, see {ERC165}. 13 | */ 14 | interface IERC165Upgradeable { 15 | /** 16 | * @dev Returns true if this contract implements the interface defined by 17 | * `interfaceId`. See the corresponding 18 | * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] 19 | * to learn more about how these ids are created. 20 | * 21 | * This function call must use less than 30 000 gas. 22 | */ 23 | function supportsInterface(bytes4 interfaceId) external view returns (bool); 24 | } 25 | -------------------------------------------------------------------------------- /contracts/solidity/interface/IERC3156Upgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev Interface of the ERC3156 FlashBorrower, as defined in 7 | * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. 8 | */ 9 | interface IERC3156FlashBorrowerUpgradeable { 10 | /** 11 | * @dev Receive a flash loan. 12 | * @param initiator The initiator of the loan. 13 | * @param token The loan currency. 14 | * @param amount The amount of tokens lent. 15 | * @param fee The additional amount of tokens to repay. 16 | * @param data Arbitrary data structure, intended to contain user-defined parameters. 17 | * @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan" 18 | */ 19 | function onFlashLoan( 20 | address initiator, 21 | address token, 22 | uint256 amount, 23 | uint256 fee, 24 | bytes calldata data 25 | ) external returns (bytes32); 26 | } 27 | 28 | /** 29 | * @dev Interface of the ERC3156 FlashLender, as defined in 30 | * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. 31 | */ 32 | interface IERC3156FlashLenderUpgradeable { 33 | /** 34 | * @dev The amount of currency available to be lended. 35 | * @param token The loan currency. 36 | * @return The amount of `token` that can be borrowed. 37 | */ 38 | function maxFlashLoan( 39 | address token 40 | ) external view returns (uint256); 41 | 42 | /** 43 | * @dev The fee to be charged for a given loan. 44 | * @param token The loan currency. 45 | * @param amount The amount of tokens lent. 46 | * @return The amount of `token` to be charged for the loan, on top of the returned principal. 47 | */ 48 | function flashFee( 49 | address token, 50 | uint256 amount 51 | ) external view returns (uint256); 52 | 53 | /** 54 | * @dev Initiate a flash loan. 55 | * @param receiver The receiver of the tokens in the loan, and the receiver of the callback. 56 | * @param token The loan currency. 57 | * @param amount The amount of tokens lent. 58 | * @param data Arbitrary data structure, intended to contain user-defined parameters. 59 | */ 60 | function flashLoan( 61 | IERC3156FlashBorrowerUpgradeable receiver, 62 | address token, 63 | uint256 amount, 64 | bytes calldata data 65 | ) external returns (bool); 66 | } -------------------------------------------------------------------------------- /contracts/solidity/interface/INFTXEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface INFTXEligibility { 6 | // Read functions. 7 | function name() external pure returns (string memory); 8 | function finalized() external view returns (bool); 9 | function targetAsset() external pure returns (address); 10 | function checkAllEligible(uint256[] calldata tokenIds) 11 | external 12 | view 13 | returns (bool); 14 | function checkEligible(uint256[] calldata tokenIds) 15 | external 16 | view 17 | returns (bool[] memory); 18 | function checkAllIneligible(uint256[] calldata tokenIds) 19 | external 20 | view 21 | returns (bool); 22 | function checkIsEligible(uint256 tokenId) external view returns (bool); 23 | 24 | // Write functions. 25 | function __NFTXEligibility_init_bytes(bytes calldata configData) external; 26 | function beforeMintHook(uint256[] calldata tokenIds) external; 27 | function afterMintHook(uint256[] calldata tokenIds) external; 28 | function beforeRedeemHook(uint256[] calldata tokenIds) external; 29 | function afterRedeemHook(uint256[] calldata tokenIds) external; 30 | } 31 | -------------------------------------------------------------------------------- /contracts/solidity/interface/INFTXEligibilityManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface INFTXEligibilityManager { 6 | function nftxVaultFactory() external returns (address); 7 | function eligibilityImpl() external returns (address); 8 | 9 | function deployEligibility(uint256 vaultId, bytes calldata initData) 10 | external 11 | returns (address); 12 | } 13 | -------------------------------------------------------------------------------- /contracts/solidity/interface/INFTXFeeDistributor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface INFTXFeeDistributor { 6 | 7 | struct FeeReceiver { 8 | uint256 allocPoint; 9 | address receiver; 10 | bool isContract; 11 | } 12 | 13 | function nftxVaultFactory() external returns (address); 14 | function lpStaking() external returns (address); 15 | function treasury() external returns (address); 16 | function defaultTreasuryAlloc() external returns (uint256); 17 | function defaultLPAlloc() external returns (uint256); 18 | function allocTotal(uint256 vaultId) external returns (uint256); 19 | function specificTreasuryAlloc(uint256 vaultId) external returns (uint256); 20 | 21 | // Write functions. 22 | function __FeeDistributor__init__(address _lpStaking, address _treasury) external; 23 | function rescueTokens(address token) external; 24 | function distribute(uint256 vaultId) external; 25 | function addReceiver(uint256 _vaultId, uint256 _allocPoint, address _receiver, bool _isContract) external; 26 | function initializeVaultReceivers(uint256 _vaultId) external; 27 | function changeMultipleReceiverAlloc( 28 | uint256[] memory _vaultIds, 29 | uint256[] memory _receiverIdxs, 30 | uint256[] memory allocPoints 31 | ) external; 32 | 33 | function changeMultipleReceiverAddress( 34 | uint256[] memory _vaultIds, 35 | uint256[] memory _receiverIdxs, 36 | address[] memory addresses, 37 | bool[] memory isContracts 38 | ) external; 39 | function changeReceiverAlloc(uint256 _vaultId, uint256 _idx, uint256 _allocPoint) external; 40 | function changeReceiverAddress(uint256 _vaultId, uint256 _idx, address _address, bool _isContract) external; 41 | function removeReceiver(uint256 _vaultId, uint256 _receiverIdx) external; 42 | 43 | // Configuration functions. 44 | function setTreasuryAddress(address _treasury) external; 45 | function setDefaultTreasuryAlloc(uint256 _allocPoint) external; 46 | function setSpecificTreasuryAlloc(uint256 _vaultId, uint256 _allocPoint) external; 47 | function setLPStakingAddress(address _lpStaking) external; 48 | function setNFTXVaultFactory(address _factory) external; 49 | function setDefaultLPAlloc(uint256 _allocPoint) external; 50 | } -------------------------------------------------------------------------------- /contracts/solidity/interface/INFTXInventoryStaking.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./INFTXVaultFactory.sol"; 6 | 7 | interface INFTXInventoryStaking { 8 | function nftxVaultFactory() external view returns (INFTXVaultFactory); 9 | function vaultXToken(uint256 vaultId) external view returns (address); 10 | function xTokenAddr(address baseToken) external view returns (address); 11 | function xTokenShareValue(uint256 vaultId) external view returns (uint256); 12 | 13 | function __NFTXInventoryStaking_init(address nftxFactory) external; 14 | 15 | function deployXTokenForVault(uint256 vaultId) external; 16 | function receiveRewards(uint256 vaultId, uint256 amount) external returns (bool); 17 | function timelockMintFor(uint256 vaultId, uint256 amount, address to, uint256 timelockLength) external returns (uint256); 18 | function deposit(uint256 vaultId, uint256 _amount) external; 19 | function withdraw(uint256 vaultId, uint256 _share) external; 20 | } -------------------------------------------------------------------------------- /contracts/solidity/interface/INFTXLPStaking.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface INFTXLPStaking { 6 | function nftxVaultFactory() external view returns (address); 7 | function rewardDistTokenImpl() external view returns (address); 8 | function stakingTokenProvider() external view returns (address); 9 | function vaultToken(address _stakingToken) external view returns (address); 10 | function stakingToken(address _vaultToken) external view returns (address); 11 | function rewardDistributionToken(uint256 vaultId) external view returns (address); 12 | function newRewardDistributionToken(uint256 vaultId) external view returns (address); 13 | function oldRewardDistributionToken(uint256 vaultId) external view returns (address); 14 | function unusedRewardDistributionToken(uint256 vaultId) external view returns (address); 15 | function rewardDistributionTokenAddr(address stakedToken, address rewardToken) external view returns (address); 16 | 17 | // Write functions. 18 | function __NFTXLPStaking__init(address _stakingTokenProvider) external; 19 | function setNFTXVaultFactory(address newFactory) external; 20 | function setStakingTokenProvider(address newProvider) external; 21 | function addPoolForVault(uint256 vaultId) external; 22 | function updatePoolForVault(uint256 vaultId) external; 23 | function updatePoolForVaults(uint256[] calldata vaultId) external; 24 | function receiveRewards(uint256 vaultId, uint256 amount) external returns (bool); 25 | function deposit(uint256 vaultId, uint256 amount) external; 26 | function timelockDepositFor(uint256 vaultId, address account, uint256 amount, uint256 timelockLength) external; 27 | function exit(uint256 vaultId, uint256 amount) external; 28 | function rescue(uint256 vaultId) external; 29 | function withdraw(uint256 vaultId, uint256 amount) external; 30 | function claimRewards(uint256 vaultId) external; 31 | } -------------------------------------------------------------------------------- /contracts/solidity/interface/INFTXSimpleFeeDistributor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface INFTXSimpleFeeDistributor { 6 | 7 | struct FeeReceiver { 8 | uint256 allocPoint; 9 | address receiver; 10 | bool isContract; 11 | } 12 | 13 | function nftxVaultFactory() external view returns (address); 14 | function lpStaking() external view returns (address); 15 | function inventoryStaking() external view returns (address); 16 | function treasury() external view returns (address); 17 | function allocTotal() external view returns (uint256); 18 | function feeReceiverInfo(uint256 index) external view returns (address, uint256); 19 | // function feeReceiverAddr(uint256 index) external view returns (address); 20 | // function feeReceiverAlloc(uint256 index) external view returns (uint256); 21 | 22 | // Write functions. 23 | function __SimpleFeeDistributor__init__(address _lpStaking, address _treasury) external; 24 | function rescueTokens(address token) external; 25 | function distribute(uint256 vaultId) external; 26 | function addReceiver(uint256 _allocPoint, address _receiver, bool _isContract) external; 27 | function initializeVaultReceivers(uint256 _vaultId) external; 28 | 29 | function changeReceiverAlloc(uint256 _idx, uint256 _allocPoint) external; 30 | function changeReceiverAddress(uint256 _idx, address _address, bool _isContract) external; 31 | function removeReceiver(uint256 _receiverIdx) external; 32 | 33 | // Configuration functions. 34 | function setTreasuryAddress(address _treasury) external; 35 | function setLPStakingAddress(address _lpStaking) external; 36 | function setInventoryStakingAddress(address _inventoryStaking) external; 37 | function setNFTXVaultFactory(address _factory) external; 38 | } -------------------------------------------------------------------------------- /contracts/solidity/interface/INFTXVaultFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../proxy/IBeacon.sol"; 6 | 7 | interface INFTXVaultFactory is IBeacon { 8 | // Read functions. 9 | function numVaults() external view returns (uint256); 10 | function zapContract() external view returns (address); 11 | function feeDistributor() external view returns (address); 12 | function eligibilityManager() external view returns (address); 13 | function vault(uint256 vaultId) external view returns (address); 14 | function allVaults() external view returns (address[] memory); 15 | function vaultsForAsset(address asset) external view returns (address[] memory); 16 | function isLocked(uint256 id) external view returns (bool); 17 | function excludedFromFees(address addr) external view returns (bool); 18 | function factoryMintFee() external view returns (uint64); 19 | function factoryRandomRedeemFee() external view returns (uint64); 20 | function factoryTargetRedeemFee() external view returns (uint64); 21 | function factoryRandomSwapFee() external view returns (uint64); 22 | function factoryTargetSwapFee() external view returns (uint64); 23 | function vaultFees(uint256 vaultId) external view returns (uint256, uint256, uint256, uint256, uint256); 24 | 25 | event NewFeeDistributor(address oldDistributor, address newDistributor); 26 | event NewZapContract(address oldZap, address newZap); 27 | event FeeExclusion(address feeExcluded, bool excluded); 28 | event NewEligibilityManager(address oldEligManager, address newEligManager); 29 | event NewVault(uint256 indexed vaultId, address vaultAddress, address assetAddress); 30 | event UpdateVaultFees(uint256 vaultId, uint256 mintFee, uint256 randomRedeemFee, uint256 targetRedeemFee, uint256 randomSwapFee, uint256 targetSwapFee); 31 | event DisableVaultFees(uint256 vaultId); 32 | event UpdateFactoryFees(uint256 mintFee, uint256 randomRedeemFee, uint256 targetRedeemFee, uint256 randomSwapFee, uint256 targetSwapFee); 33 | 34 | // Write functions. 35 | function __NFTXVaultFactory_init(address _vaultImpl, address _feeDistributor) external; 36 | function createVault( 37 | string calldata name, 38 | string calldata symbol, 39 | address _assetAddress, 40 | bool is1155, 41 | bool allowAllItems 42 | ) external returns (uint256); 43 | function setFeeDistributor(address _feeDistributor) external; 44 | function setEligibilityManager(address _eligibilityManager) external; 45 | function setZapContract(address _zapContract) external; 46 | function setFeeExclusion(address _excludedAddr, bool excluded) external; 47 | 48 | function setFactoryFees( 49 | uint256 mintFee, 50 | uint256 randomRedeemFee, 51 | uint256 targetRedeemFee, 52 | uint256 randomSwapFee, 53 | uint256 targetSwapFee 54 | ) external; 55 | function setVaultFees( 56 | uint256 vaultId, 57 | uint256 mintFee, 58 | uint256 randomRedeemFee, 59 | uint256 targetRedeemFee, 60 | uint256 randomSwapFee, 61 | uint256 targetSwapFee 62 | ) external; 63 | function disableVaultFees(uint256 vaultId) external; 64 | } 65 | -------------------------------------------------------------------------------- /contracts/solidity/interface/IPrevNftxContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC165Upgradeable.sol"; 6 | 7 | interface IPrevNftxContract { 8 | function isEligible(uint256 vaultId, uint256 nftId) external view returns (bool); 9 | } -------------------------------------------------------------------------------- /contracts/solidity/interface/IRewardDistributionToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../token/IERC20Upgradeable.sol"; 6 | 7 | interface IRewardDistributionToken is IERC20Upgradeable { 8 | function distributeRewards(uint amount) external; 9 | function __RewardDistributionToken_init(IERC20Upgradeable _target, string memory _name, string memory _symbol) external; 10 | function mint(address account, address to, uint256 amount) external; 11 | function burnFrom(address account, uint256 amount) external; 12 | function withdrawReward(address user) external; 13 | function dividendOf(address _owner) external view returns(uint256); 14 | function withdrawnRewardOf(address _owner) external view returns(uint256); 15 | function accumulativeRewardOf(address _owner) external view returns(uint256); 16 | } -------------------------------------------------------------------------------- /contracts/solidity/interface/ITimelockExcludeList.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface ITimelockExcludeList { 6 | function isExcluded(address addr, uint256 vaultId) external view returns (bool); 7 | } -------------------------------------------------------------------------------- /contracts/solidity/interface/ITimelockRewardDistributionToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../token/IERC20Upgradeable.sol"; 6 | 7 | interface ITimelockRewardDistributionToken is IERC20Upgradeable { 8 | function distributeRewards(uint amount) external; 9 | function __TimelockRewardDistributionToken_init(IERC20Upgradeable _target, string memory _name, string memory _symbol) external; 10 | function mint(address account, address to, uint256 amount) external; 11 | function timelockMint(address account, uint256 amount, uint256 timelockLength) external; 12 | function burnFrom(address account, uint256 amount) external; 13 | function withdrawReward(address user) external; 14 | function dividendOf(address _owner) external view returns(uint256); 15 | function withdrawnRewardOf(address _owner) external view returns(uint256); 16 | function accumulativeRewardOf(address _owner) external view returns(uint256); 17 | function timelockUntil(address account) external view returns (uint256); 18 | } -------------------------------------------------------------------------------- /contracts/solidity/interface/IUniswapV2Pair.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | interface IUniswapV2Pair { 4 | event Approval(address indexed owner, address indexed spender, uint value); 5 | event Transfer(address indexed from, address indexed to, uint value); 6 | 7 | function name() external pure returns (string memory); 8 | function symbol() external pure returns (string memory); 9 | function decimals() external pure returns (uint8); 10 | function totalSupply() external view returns (uint); 11 | function balanceOf(address owner) external view returns (uint); 12 | function allowance(address owner, address spender) external view returns (uint); 13 | 14 | function approve(address spender, uint value) external returns (bool); 15 | function transfer(address to, uint value) external returns (bool); 16 | function transferFrom(address from, address to, uint value) external returns (bool); 17 | 18 | function DOMAIN_SEPARATOR() external view returns (bytes32); 19 | function PERMIT_TYPEHASH() external pure returns (bytes32); 20 | function nonces(address owner) external view returns (uint); 21 | 22 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 23 | 24 | event Mint(address indexed sender, uint amount0, uint amount1); 25 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 26 | event Swap( 27 | address indexed sender, 28 | uint amount0In, 29 | uint amount1In, 30 | uint amount0Out, 31 | uint amount1Out, 32 | address indexed to 33 | ); 34 | event Sync(uint112 reserve0, uint112 reserve1); 35 | 36 | function MINIMUM_LIQUIDITY() external pure returns (uint); 37 | function factory() external view returns (address); 38 | function token0() external view returns (address); 39 | function token1() external view returns (address); 40 | function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); 41 | function price0CumulativeLast() external view returns (uint); 42 | function price1CumulativeLast() external view returns (uint); 43 | function kLast() external view returns (uint); 44 | 45 | function mint(address to) external returns (uint liquidity); 46 | function burn(address to) external returns (uint amount0, uint amount1); 47 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; 48 | function skim(address to) external; 49 | function sync() external; 50 | 51 | function initialize(address, address) external; 52 | } -------------------------------------------------------------------------------- /contracts/solidity/interface/IVaultTokenUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../token/IERC20Upgradeable.sol"; 6 | 7 | interface IVaultTokenUpgradeable is IERC20Upgradeable { 8 | function mint(address to, uint256 amount) external; 9 | 10 | function burnFrom(address account, uint256 amount) external; 11 | } 12 | -------------------------------------------------------------------------------- /contracts/solidity/other/TimelockExcludeList.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../util/Ownable.sol"; 6 | 7 | contract TimelockExcludeList is Ownable { 8 | mapping(address => bool) public excludeFromAll; 9 | mapping(address => mapping(uint256 => bool)) public excludeFromVault; 10 | 11 | event ExcludeFromAllSet(address, bool); 12 | event ExcludeFromVaultSet(address, uint256, bool); 13 | 14 | function isExcludedFromAll(address addr) public view returns (bool) { 15 | return excludeFromAll[addr]; 16 | } 17 | 18 | function isExcludedFromVault(address addr, uint256 vaultId) 19 | public 20 | view 21 | returns (bool) 22 | { 23 | return excludeFromVault[addr][vaultId]; 24 | } 25 | 26 | function isExcluded(address addr, uint256 vaultId) 27 | external 28 | view 29 | returns (bool) 30 | { 31 | return isExcludedFromAll(addr) || isExcludedFromVault(addr, vaultId); 32 | } 33 | 34 | function setExcludeFromAll(address addr, bool setting) external onlyOwner { 35 | excludeFromAll[addr] = setting; 36 | emit ExcludeFromAllSet(addr, setting); 37 | } 38 | 39 | function setExcludeFromVault( 40 | address addr, 41 | uint256 vaultId, 42 | bool setting 43 | ) external onlyOwner { 44 | excludeFromVault[addr][vaultId] = setting; 45 | emit ExcludeFromVaultSet(addr, vaultId, setting); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/solidity/proxy/BeaconProxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IBeacon.sol"; 6 | import "./Proxy.sol"; 7 | import "../util/Address.sol"; 8 | 9 | /** 10 | * @dev This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}. 11 | * 12 | * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't 13 | * conflict with the storage layout of the implementation behind the proxy. 14 | * 15 | * _Available since v3.4._ 16 | */ 17 | contract BeaconProxy is Proxy { 18 | /** 19 | * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. 20 | * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. 21 | */ 22 | bytes32 private constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; 23 | 24 | /** 25 | * @dev Initializes the proxy with `beacon`. 26 | * 27 | * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This 28 | * will typically be an encoded function call, and allows initializating the storage of the proxy like a Solidity 29 | * constructor. 30 | * 31 | * Requirements: 32 | * 33 | * - `beacon` must be a contract with the interface {IBeacon}. 34 | */ 35 | constructor(address beacon, bytes memory data) payable { 36 | assert(_BEACON_SLOT == bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1)); 37 | _setBeacon(beacon, data); 38 | } 39 | 40 | /** 41 | * @dev Returns the current beacon address. 42 | */ 43 | function _beacon() internal view virtual returns (address beacon) { 44 | bytes32 slot = _BEACON_SLOT; 45 | // solhint-disable-next-line no-inline-assembly 46 | assembly { 47 | beacon := sload(slot) 48 | } 49 | } 50 | 51 | /** 52 | * @dev Returns the current implementation address of the associated beacon. 53 | */ 54 | function _implementation() internal view virtual override returns (address) { 55 | return IBeacon(_beacon()).childImplementation(); 56 | } 57 | 58 | /** 59 | * @dev Changes the proxy to use a new beacon. 60 | * 61 | * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. 62 | * 63 | * Requirements: 64 | * 65 | * - `beacon` must be a contract. 66 | * - The implementation returned by `beacon` must be a contract. 67 | */ 68 | function _setBeacon(address beacon, bytes memory data) internal virtual { 69 | require( 70 | Address.isContract(beacon), 71 | "BeaconProxy: beacon is not a contract" 72 | ); 73 | require( 74 | Address.isContract(IBeacon(beacon).childImplementation()), 75 | "BeaconProxy: beacon implementation is not a contract" 76 | ); 77 | bytes32 slot = _BEACON_SLOT; 78 | 79 | // solhint-disable-next-line no-inline-assembly 80 | assembly { 81 | sstore(slot, beacon) 82 | } 83 | 84 | if (data.length > 0) { 85 | Address.functionDelegateCall(_implementation(), data, "BeaconProxy: function call failed"); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /contracts/solidity/proxy/ClonesUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for 7 | * deploying minimal proxy contracts, also known as "clones". 8 | * 9 | * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies 10 | * > a minimal bytecode implementation that delegates all calls to a known, fixed address. 11 | * 12 | * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` 13 | * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the 14 | * deterministic method. 15 | * 16 | * _Available since v3.4._ 17 | */ 18 | library ClonesUpgradeable { 19 | /** 20 | * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. 21 | * 22 | * This function uses the create opcode, which should never revert. 23 | */ 24 | function clone(address implementation) internal returns (address instance) { 25 | // solhint-disable-next-line no-inline-assembly 26 | assembly { 27 | let ptr := mload(0x40) 28 | mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) 29 | mstore(add(ptr, 0x14), shl(0x60, implementation)) 30 | mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) 31 | instance := create(0, ptr, 0x37) 32 | } 33 | require(instance != address(0), "ERC1167: create failed"); 34 | } 35 | 36 | /** 37 | * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. 38 | * 39 | * This function uses the create2 opcode and a `salt` to deterministically deploy 40 | * the clone. Using the same `implementation` and `salt` multiple time will revert, since 41 | * the clones cannot be deployed twice at the same address. 42 | */ 43 | function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { 44 | // solhint-disable-next-line no-inline-assembly 45 | assembly { 46 | let ptr := mload(0x40) 47 | mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) 48 | mstore(add(ptr, 0x14), shl(0x60, implementation)) 49 | mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) 50 | instance := create2(0, ptr, 0x37, salt) 51 | } 52 | require(instance != address(0), "ERC1167: create2 failed"); 53 | } 54 | 55 | /** 56 | * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. 57 | */ 58 | function predictDeterministicAddress(address implementation, bytes32 salt, address deployer) internal pure returns (address predicted) { 59 | // solhint-disable-next-line no-inline-assembly 60 | assembly { 61 | let ptr := mload(0x40) 62 | mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) 63 | mstore(add(ptr, 0x14), shl(0x60, implementation)) 64 | mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000) 65 | mstore(add(ptr, 0x38), shl(0x60, deployer)) 66 | mstore(add(ptr, 0x4c), salt) 67 | mstore(add(ptr, 0x6c), keccak256(ptr, 0x37)) 68 | predicted := keccak256(add(ptr, 0x37), 0x55) 69 | } 70 | } 71 | 72 | /** 73 | * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. 74 | */ 75 | function predictDeterministicAddress(address implementation, bytes32 salt) internal view returns (address predicted) { 76 | return predictDeterministicAddress(implementation, salt, address(this)); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /contracts/solidity/proxy/Create2BeaconProxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IBeacon.sol"; 6 | import "./Proxy.sol"; 7 | import "../util/Address.sol"; 8 | 9 | /** 10 | * @dev This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}. 11 | * Slightly modified to allow using beacon proxies with Create2. 12 | * 13 | * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't 14 | * conflict with the storage layout of the implementation behind the proxy. 15 | * 16 | * _Available since v3.4._ 17 | */ 18 | contract Create2BeaconProxy is Proxy { 19 | /** 20 | * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. 21 | * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. 22 | */ 23 | bytes32 private constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; 24 | 25 | /** 26 | * @dev Initializes the proxy with `beacon`. 27 | * 28 | * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This 29 | * will typically be an encoded function call, and allows initializating the storage of the proxy like a Solidity 30 | * constructor. 31 | * 32 | * Requirements: 33 | * 34 | * - `beacon` must be a contract with the interface {IBeacon}. 35 | */ 36 | constructor() payable { 37 | assert(_BEACON_SLOT == bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1)); 38 | _setBeacon(msg.sender, ""); 39 | } 40 | 41 | /** 42 | * @dev Returns the current beacon address. 43 | */ 44 | function _beacon() internal view virtual returns (address beacon) { 45 | bytes32 slot = _BEACON_SLOT; 46 | // solhint-disable-next-line no-inline-assembly 47 | assembly { 48 | beacon := sload(slot) 49 | } 50 | } 51 | 52 | /** 53 | * @dev Returns the current implementation address of the associated beacon. 54 | */ 55 | function _implementation() internal view virtual override returns (address) { 56 | return IBeacon(_beacon()).childImplementation(); 57 | } 58 | 59 | /** 60 | * @dev Changes the proxy to use a new beacon. 61 | * 62 | * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. 63 | * 64 | * Requirements: 65 | * 66 | * - `beacon` must be a contract. 67 | * - The implementation returned by `beacon` must be a contract. 68 | */ 69 | function _setBeacon(address beacon, bytes memory data) internal virtual { 70 | require( 71 | Address.isContract(beacon), 72 | "BeaconProxy: beacon is not a contract" 73 | ); 74 | require( 75 | Address.isContract(IBeacon(beacon).childImplementation()), 76 | "BeaconProxy: beacon implementation is not a contract" 77 | ); 78 | bytes32 slot = _BEACON_SLOT; 79 | 80 | // solhint-disable-next-line no-inline-assembly 81 | assembly { 82 | sstore(slot, beacon) 83 | } 84 | 85 | if (data.length > 0) { 86 | Address.functionDelegateCall(_implementation(), data, "BeaconProxy: function call failed"); 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /contracts/solidity/proxy/IBeacon.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev This is the interface that {BeaconProxy} expects of its beacon. 7 | */ 8 | interface IBeacon { 9 | /** 10 | * @dev Must return an address that can be used as a delegate call target. 11 | * 12 | * {BeaconProxy} will check that this address is a contract. 13 | */ 14 | function childImplementation() external view returns (address); 15 | function upgradeChildTo(address newImplementation) external; 16 | } -------------------------------------------------------------------------------- /contracts/solidity/proxy/Initializable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | // solhint-disable-next-line compiler-version 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed 8 | * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an 9 | * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer 10 | * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. 11 | * 12 | * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as 13 | * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. 14 | * 15 | * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure 16 | * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. 17 | */ 18 | abstract contract Initializable { 19 | 20 | /** 21 | * @dev Indicates that the contract has been initialized. 22 | */ 23 | bool private _initialized; 24 | 25 | /** 26 | * @dev Indicates that the contract is in the process of being initialized. 27 | */ 28 | bool private _initializing; 29 | 30 | /** 31 | * @dev Modifier to protect an initializer function from being invoked twice. 32 | */ 33 | modifier initializer() { 34 | require(_initializing || !_initialized, "Initializable: contract is already initialized"); 35 | 36 | bool isTopLevelCall = !_initializing; 37 | if (isTopLevelCall) { 38 | _initializing = true; 39 | _initialized = true; 40 | } 41 | 42 | _; 43 | 44 | if (isTopLevelCall) { 45 | _initializing = false; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /contracts/solidity/proxy/Proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM 7 | * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to 8 | * be specified by overriding the virtual {_implementation} function. 9 | * 10 | * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a 11 | * different contract through the {_delegate} function. 12 | * 13 | * The success and return data of the delegated call will be returned back to the caller of the proxy. 14 | */ 15 | abstract contract Proxy { 16 | /** 17 | * @dev Delegates the current call to `implementation`. 18 | * 19 | * This function does not return to its internall call site, it will return directly to the external caller. 20 | */ 21 | function _delegate(address implementation) internal virtual { 22 | // solhint-disable-next-line no-inline-assembly 23 | assembly { 24 | // Copy msg.data. We take full control of memory in this inline assembly 25 | // block because it will not return to Solidity code. We overwrite the 26 | // Solidity scratch pad at memory position 0. 27 | calldatacopy(0, 0, calldatasize()) 28 | 29 | // Call the implementation. 30 | // out and outsize are 0 because we don't know the size yet. 31 | let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) 32 | 33 | // Copy the returned data. 34 | returndatacopy(0, 0, returndatasize()) 35 | 36 | switch result 37 | // delegatecall returns 0 on error. 38 | case 0 { revert(0, returndatasize()) } 39 | default { return(0, returndatasize()) } 40 | } 41 | } 42 | 43 | /** 44 | * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function 45 | * and {_fallback} should delegate. 46 | */ 47 | function _implementation() internal view virtual returns (address); 48 | 49 | /** 50 | * @dev Delegates the current call to the address returned by `_implementation()`. 51 | * 52 | * This function does not return to its internall call site, it will return directly to the external caller. 53 | */ 54 | function _fallback() internal virtual { 55 | _beforeFallback(); 56 | _delegate(_implementation()); 57 | } 58 | 59 | /** 60 | * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other 61 | * function in the contract matches the call data. 62 | */ 63 | fallback () external payable virtual { 64 | _fallback(); 65 | } 66 | 67 | /** 68 | * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data 69 | * is empty. 70 | */ 71 | receive () external payable virtual { 72 | _fallback(); 73 | } 74 | 75 | /** 76 | * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` 77 | * call, or as part of the Solidity `fallback` or `receive` functions. 78 | * 79 | * If overriden should call `super._beforeFallback()`. 80 | */ 81 | function _beforeFallback() internal virtual { 82 | } 83 | } -------------------------------------------------------------------------------- /contracts/solidity/proxy/ProxyControllerSimple.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../util/Ownable.sol"; 6 | import "../interface/IAdminUpgradeabilityProxy.sol"; 7 | 8 | contract ProxyControllerSimple is Ownable { 9 | address public impl; 10 | 11 | IAdminUpgradeabilityProxy private proxy; 12 | 13 | event ImplAddressSet(address impl); 14 | event ProxyAdminChanged(address newAdmin); 15 | 16 | constructor(address _proxy) { 17 | proxy = IAdminUpgradeabilityProxy(_proxy); 18 | } 19 | 20 | function getAdmin() public view returns (address admin) { 21 | return proxy.admin(); 22 | } 23 | 24 | function fetchImplAddress() public { 25 | impl = proxy.implementation(); 26 | emit ImplAddressSet(impl); 27 | } 28 | 29 | function changeProxyAdmin(address newAdmin) public onlyOwner { 30 | proxy.changeAdmin(newAdmin); 31 | emit ProxyAdminChanged(newAdmin); 32 | } 33 | 34 | function upgradeProxyTo(address newImpl) public onlyOwner { 35 | proxy.upgradeTo(newImpl); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/solidity/proxy/UpgradeableBeacon.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IBeacon.sol"; 6 | import "../util/OwnableUpgradeable.sol"; 7 | import "../util/Address.sol"; 8 | 9 | /** 10 | * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their 11 | * implementation contract, which is where they will delegate all function calls. 12 | * 13 | * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon. 14 | */ 15 | contract UpgradeableBeacon is IBeacon, OwnableUpgradeable { 16 | address private _childImplementation; 17 | 18 | /** 19 | * @dev Emitted when the child implementation returned by the beacon is changed. 20 | */ 21 | event Upgraded(address indexed childImplementation); 22 | 23 | /** 24 | * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the 25 | * beacon. 26 | */ 27 | function __UpgradeableBeacon__init(address childImplementation_) public initializer { 28 | _setChildImplementation(childImplementation_); 29 | } 30 | 31 | /** 32 | * @dev Returns the current child implementation address. 33 | */ 34 | function childImplementation() public view virtual override returns (address) { 35 | return _childImplementation; 36 | } 37 | 38 | /** 39 | * @dev Upgrades the beacon to a new implementation. 40 | * 41 | * Emits an {Upgraded} event. 42 | * 43 | * Requirements: 44 | * 45 | * - msg.sender must be the owner of the contract. 46 | * - `newChildImplementation` must be a contract. 47 | */ 48 | function upgradeChildTo(address newChildImplementation) public virtual override onlyOwner { 49 | _setChildImplementation(newChildImplementation); 50 | } 51 | 52 | /** 53 | * @dev Sets the implementation contract address for this beacon 54 | * 55 | * Requirements: 56 | * 57 | * - `newChildImplementation` must be a contract. 58 | */ 59 | function _setChildImplementation(address newChildImplementation) private { 60 | require(Address.isContract(newChildImplementation), "UpgradeableBeacon: child implementation is not a contract"); 61 | _childImplementation = newChildImplementation; 62 | emit Upgraded(newChildImplementation); 63 | } 64 | } -------------------------------------------------------------------------------- /contracts/solidity/testing/Context.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /* 6 | * @dev Provides information about the current execution context, including the 7 | * sender of the transaction and its data. While these are generally available 8 | * via msg.sender and msg.data, they should not be accessed in such a direct 9 | * manner, since when dealing with meta-transactions the account sending and 10 | * paying for execution may not be the actual sender (as far as an application 11 | * is concerned). 12 | * 13 | * This contract is only required for intermediate, library-like contracts. 14 | */ 15 | abstract contract Context { 16 | function _msgSender() internal view virtual returns (address) { 17 | return msg.sender; 18 | } 19 | 20 | function _msgData() internal view virtual returns (bytes calldata) { 21 | this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 22 | return msg.data; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/solidity/testing/DummyToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | contract DummyToken { 6 | string public name; 7 | string public symbol; 8 | uint8 public decimals = 18; 9 | 10 | constructor(string memory _name, string memory _symbol) { 11 | name = _name; 12 | symbol = _symbol; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /contracts/solidity/testing/DummyXToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../token/ERC20Upgradeable.sol"; 6 | 7 | // Author: @0xKiwi_ 8 | 9 | contract DummyXToken is ERC20Upgradeable { 10 | constructor() { 11 | __ERC20_init("AMOGUS", "AMOGUS"); 12 | } 13 | 14 | function burnFrom(address account, uint256 amount) public virtual { 15 | uint256 _allowance = allowance(account, msg.sender); 16 | require(amount<=_allowance, "No allowance for burn"); 17 | uint256 decreasedAllowance = _allowance - amount; 18 | 19 | _approve(account, _msgSender(), decreasedAllowance); 20 | _burn(account, amount); 21 | } 22 | 23 | function mint(address account, uint256 amount) external { 24 | _mint(account, amount); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/solidity/testing/ERC1155Receiver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC1155Receiver.sol"; 6 | import "./ERC165.sol"; 7 | 8 | /** 9 | * @dev _Available since v3.1._ 10 | */ 11 | abstract contract ERC1155Receiver is ERC165, IERC1155Receiver { 12 | /** 13 | * @dev See {IERC165-supportsInterface}. 14 | */ 15 | function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { 16 | return interfaceId == type(IERC1155Receiver).interfaceId 17 | || super.supportsInterface(interfaceId); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/solidity/testing/ERC165.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC165.sol"; 6 | 7 | /** 8 | * @dev Implementation of the {IERC165} interface. 9 | * 10 | * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check 11 | * for the additional interface id that will be supported. For example: 12 | * 13 | * ```solidity 14 | * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 15 | * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); 16 | * } 17 | * ``` 18 | * 19 | * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. 20 | */ 21 | abstract contract ERC165 is IERC165 { 22 | /** 23 | * @dev See {IERC165-supportsInterface}. 24 | */ 25 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 26 | return interfaceId == type(IERC165).interfaceId; 27 | } 28 | } -------------------------------------------------------------------------------- /contracts/solidity/testing/FlashBorrower.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.0; 3 | 4 | import "../token/IERC20Upgradeable.sol"; 5 | import "../interface/IERC3156Upgradeable.sol"; 6 | 7 | contract FlashBorrower is IERC3156FlashBorrowerUpgradeable { 8 | enum Action {NORMAL, STEAL, REENTER} 9 | 10 | uint256 public flashBalance; 11 | address public flashUser; 12 | address public flashToken; 13 | uint256 public flashValue; 14 | uint256 public flashFee; 15 | 16 | /// @dev ERC-3156 Flash loan callback 17 | function onFlashLoan(address user, address token, uint256 value, uint256 fee, bytes calldata data) external override returns (bytes32) { 18 | (Action action) = abi.decode(data, (Action)); // Use this to unpack arbitrary data 19 | flashUser = user; 20 | flashToken = token; 21 | flashValue = value; 22 | flashFee = fee; 23 | if (action == Action.NORMAL) { 24 | flashBalance = IERC20Upgradeable(token).balanceOf(address(this)); 25 | IERC20Upgradeable(token).approve(msg.sender, value + fee); // Resolve the flash loan 26 | } else if (action == Action.STEAL) { 27 | // Do nothing 28 | } else if (action == Action.REENTER) { 29 | flashBorrow(msg.sender, token, value * 2); 30 | IERC20Upgradeable(token).approve(msg.sender, value + fee); 31 | } 32 | return keccak256("ERC3156FlashBorrower.onFlashLoan"); 33 | } 34 | 35 | function flashBorrow(address lender, address token, uint256 value) public { 36 | // Use this to pack arbitrary data to `onFlashLoan` 37 | bytes memory data = abi.encode(Action.NORMAL); 38 | IERC3156FlashLenderUpgradeable(lender).flashLoan(IERC3156FlashBorrowerUpgradeable(address(this)), token, value, data); 39 | } 40 | 41 | function flashBorrowAndSteal(address lender, address token, uint256 value) public { 42 | // Use this to pack arbitrary data to `onFlashLoan` 43 | bytes memory data = abi.encode(Action.STEAL); 44 | IERC3156FlashLenderUpgradeable(lender).flashLoan(IERC3156FlashBorrowerUpgradeable(address(this)), token, value, data); 45 | } 46 | 47 | function flashBorrowAndReenter(address lender, address token, uint256 value) public { 48 | // Use this to pack arbitrary data to `onFlashLoan` 49 | bytes memory data = abi.encode(Action.REENTER); 50 | IERC3156FlashLenderUpgradeable(lender).flashLoan(IERC3156FlashBorrowerUpgradeable(address(this)), token, value, data); 51 | } 52 | } -------------------------------------------------------------------------------- /contracts/solidity/testing/IERC1155MetadataURI.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC1155.sol"; 6 | 7 | /** 8 | * @dev Interface of the optional ERC1155MetadataExtension interface, as defined 9 | * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP]. 10 | * 11 | * _Available since v3.1._ 12 | */ 13 | interface IERC1155MetadataURI is IERC1155 { 14 | /** 15 | * @dev Returns the URI for token type `id`. 16 | * 17 | * If the `\{id\}` substring is present in the URI, it must be replaced by 18 | * clients with the actual token type ID. 19 | */ 20 | function uri(uint256 id) external view returns (string memory); 21 | } 22 | -------------------------------------------------------------------------------- /contracts/solidity/testing/IERC1155Receiver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC165.sol"; 6 | 7 | /** 8 | * _Available since v3.1._ 9 | */ 10 | interface IERC1155Receiver is IERC165 { 11 | /** 12 | @dev Handles the receipt of a single ERC1155 token type. This function is 13 | called at the end of a `safeTransferFrom` after the balance has been updated. 14 | To accept the transfer, this must return 15 | `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` 16 | (i.e. 0xf23a6e61, or its own function selector). 17 | @param operator The address which initiated the transfer (i.e. msg.sender) 18 | @param from The address which previously owned the token 19 | @param id The ID of the token being transferred 20 | @param value The amount of tokens being transferred 21 | @param data Additional data with no specified format 22 | @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed 23 | */ 24 | function onERC1155Received( 25 | address operator, 26 | address from, 27 | uint256 id, 28 | uint256 value, 29 | bytes calldata data 30 | ) external returns (bytes4); 31 | 32 | /** 33 | @dev Handles the receipt of a multiple ERC1155 token types. This function 34 | is called at the end of a `safeBatchTransferFrom` after the balances have 35 | been updated. To accept the transfer(s), this must return 36 | `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` 37 | (i.e. 0xbc197c81, or its own function selector). 38 | @param operator The address which initiated the batch transfer (i.e. msg.sender) 39 | @param from The address which previously owned the token 40 | @param ids An array containing ids of each token being transferred (order and length must match values array) 41 | @param values An array containing amounts of each token being transferred (order and length must match ids array) 42 | @param data Additional data with no specified format 43 | @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed 44 | */ 45 | function onERC1155BatchReceived( 46 | address operator, 47 | address from, 48 | uint256[] calldata ids, 49 | uint256[] calldata values, 50 | bytes calldata data 51 | ) external returns (bytes4); 52 | } 53 | -------------------------------------------------------------------------------- /contracts/solidity/testing/IERC165.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev Interface of the ERC165 standard, as defined in the 7 | * https://eips.ethereum.org/EIPS/eip-165[EIP]. 8 | * 9 | * Implementers can declare support of contract interfaces, which can then be 10 | * queried by others ({ERC165Checker}). 11 | * 12 | * For an implementation, see {ERC165}. 13 | */ 14 | interface IERC165 { 15 | /** 16 | * @dev Returns true if this contract implements the interface defined by 17 | * `interfaceId`. See the corresponding 18 | * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] 19 | * to learn more about how these ids are created. 20 | * 21 | * This function call must use less than 30 000 gas. 22 | */ 23 | function supportsInterface(bytes4 interfaceId) external view returns (bool); 24 | } 25 | -------------------------------------------------------------------------------- /contracts/solidity/testing/IERC721Enumerable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC721.sol"; 6 | 7 | /** 8 | * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension 9 | * @dev See https://eips.ethereum.org/EIPS/eip-721 10 | */ 11 | interface IERC721Enumerable is IERC721 { 12 | 13 | /** 14 | * @dev Returns the total amount of tokens stored by the contract. 15 | */ 16 | function totalSupply() external view returns (uint256); 17 | 18 | /** 19 | * @dev Returns a token ID owned by `owner` at a given `index` of its token list. 20 | * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. 21 | */ 22 | function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); 23 | 24 | /** 25 | * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. 26 | * Use along with {totalSupply} to enumerate all tokens. 27 | */ 28 | function tokenByIndex(uint256 index) external view returns (uint256); 29 | } 30 | -------------------------------------------------------------------------------- /contracts/solidity/testing/IERC721Metadata.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC721.sol"; 6 | 7 | /** 8 | * @title ERC-721 Non-Fungible Token Standard, optional metadata extension 9 | * @dev See https://eips.ethereum.org/EIPS/eip-721 10 | */ 11 | interface IERC721Metadata is IERC721 { 12 | 13 | /** 14 | * @dev Returns the token collection name. 15 | */ 16 | function name() external view returns (string memory); 17 | 18 | /** 19 | * @dev Returns the token collection symbol. 20 | */ 21 | function symbol() external view returns (string memory); 22 | 23 | /** 24 | * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. 25 | */ 26 | function tokenURI(uint256 tokenId) external view returns (string memory); 27 | } 28 | -------------------------------------------------------------------------------- /contracts/solidity/testing/IERC721Receiver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @title ERC721 token receiver interface 7 | * @dev Interface for any contract that wants to support safeTransfers 8 | * from ERC721 asset contracts. 9 | */ 10 | interface IERC721Receiver { 11 | /** 12 | * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} 13 | * by `operator` from `from`, this function is called. 14 | * 15 | * It must return its Solidity selector to confirm the token transfer. 16 | * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. 17 | * 18 | * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. 19 | */ 20 | function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4); 21 | } 22 | -------------------------------------------------------------------------------- /contracts/solidity/testing/Mock0xProvider.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../token/IERC20Upgradeable.sol"; 6 | 7 | import "hardhat/console.sol"; 8 | 9 | 10 | contract Mock0xProvider { 11 | 12 | uint256 private payInAmount; 13 | uint256 private payOutAmount; 14 | 15 | constructor() {} 16 | 17 | function setPayInAmount(uint256 _amount) external { 18 | payInAmount = _amount; 19 | } 20 | 21 | function setPayOutAmount(uint256 _amount) external { 22 | payOutAmount = _amount; 23 | } 24 | 25 | function transfer(address spender, address tokenIn, address tokenOut) external payable returns (bool, bytes memory) { 26 | // Transfer the input token in 27 | IERC20Upgradeable(tokenIn).transferFrom(msg.sender, address(this), payInAmount); 28 | 29 | // Transfer the payment token out 30 | IERC20Upgradeable(tokenOut).transfer(spender, payOutAmount); 31 | 32 | // Return success and empty bytes data 33 | return (true, hex''); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /contracts/solidity/testing/MockDistributor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | // Author: 0xKiwi. 6 | 7 | import "../token/IERC20Upgradeable.sol"; 8 | import "../util/OwnableUpgradeable.sol"; 9 | 10 | contract MockDistributor is OwnableUpgradeable { 11 | 12 | function __MockDistributor_init() external { 13 | __Ownable_init(); 14 | } 15 | 16 | function distribute(uint256 vaultId) external { 17 | } 18 | 19 | function initializeVaultReceivers(uint256 vaultId) external { 20 | 21 | } 22 | 23 | function withdrawTokens(address token) external onlyOwner { 24 | uint256 bal = IERC20Upgradeable(token).balanceOf(address(this)); 25 | IERC20Upgradeable(token).transfer(msg.sender, bal); 26 | } 27 | } -------------------------------------------------------------------------------- /contracts/solidity/testing/MockENSMerkleEligibility.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../eligibility/NFTXMerkleEligibility.sol"; 6 | 7 | 8 | contract MockNFTXENSMerkleEligibility is NFTXMerkleEligibility { 9 | 10 | /// @notice Minimum expiration time for ENS domains in seconds 11 | uint public minExpirationTime; 12 | 13 | 14 | /** 15 | * @notice The name of our Eligibility Module. 16 | * 17 | * @return string 18 | */ 19 | 20 | function name() public pure override virtual returns (string memory) { 21 | return 'ENSMerkleEligibility'; 22 | } 23 | 24 | 25 | /** 26 | * @notice The address of our token asset contract. 27 | * 28 | * @return address 29 | */ 30 | 31 | function targetAsset() public pure override virtual returns (address) { 32 | return 0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85; 33 | } 34 | 35 | 36 | /** 37 | * @notice Allow our eligibility module to be initialised with optional 38 | * config data. 39 | * 40 | * @param configData Encoded config data 41 | */ 42 | 43 | function __NFTXEligibility_init_bytes(bytes memory configData) public override virtual initializer { 44 | ( 45 | bytes32 _merkleRoot, 46 | string memory _merkleReference, 47 | string memory _merkleLeavesURI, 48 | uint _minExpirationTime 49 | ) = abi.decode(configData, (bytes32, string, string, uint)); 50 | 51 | __NFTXEligibility_init(_merkleRoot, _merkleReference, _merkleLeavesURI, _minExpirationTime); 52 | } 53 | 54 | 55 | /** 56 | * @notice Parameters here should mirror the config struct. 57 | * 58 | * @param _merkleRoot The root of our merkle tree 59 | * @param _merkleReference Public name of the merkle eligibility implementation 60 | * @param _merkleLeavesURI API endpoint providing unencoded JSON array 61 | * @param _minExpirationTime Minimum number of seconds until ENS expiration 62 | */ 63 | 64 | function __NFTXEligibility_init( 65 | bytes32 _merkleRoot, 66 | string memory _merkleReference, 67 | string memory _merkleLeavesURI, 68 | uint _minExpirationTime 69 | ) public initializer { 70 | super.__NFTXEligibility_init(_merkleRoot, _merkleReference, _merkleLeavesURI); 71 | 72 | minExpirationTime = _minExpirationTime; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /contracts/solidity/testing/MockERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../token/ERC20Upgradeable.sol"; 6 | 7 | 8 | contract MockERC20 is ERC20Upgradeable { 9 | 10 | /** 11 | * @dev See {IERC165-supportsInterface}. 12 | */ 13 | 14 | function mint(address account, uint256 amount) external { 15 | _mint(account, amount); 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /contracts/solidity/testing/MockStakingProvider.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | // Author: 0xKiwi. 6 | 7 | import "../token/IERC20Metadata.sol"; 8 | import "../util/OwnableUpgradeable.sol"; 9 | 10 | contract MockStakingProvider is OwnableUpgradeable{ 11 | 12 | bool changed; 13 | 14 | constructor() { 15 | __Ownable_init(); 16 | } 17 | 18 | function stakingTokenForVaultToken(address _vaultToken) external view returns (address) { 19 | return changed ? address(1) :_vaultToken; 20 | } 21 | 22 | function setChanged(bool _changed) external onlyOwner { 23 | changed = _changed; 24 | } 25 | 26 | function nameForStakingToken(address _vaultToken) external view returns (string memory) { 27 | string memory symbol = IERC20Metadata(_vaultToken).symbol(); 28 | return string(abi.encodePacked("based", symbol)); 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /contracts/solidity/testing/MockVault.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../token/ERC721HolderUpgradeable.sol"; 6 | 7 | contract MockVault is ERC721HolderUpgradeable { 8 | address public assetAddress; 9 | bool public is1155; 10 | 11 | constructor(address _assetAddress, bool _is1155) { 12 | assetAddress = _assetAddress; 13 | is1155 = _is1155; 14 | } 15 | 16 | function mintTo( 17 | uint256[] memory tokenIds, 18 | uint256[] memory amounts, 19 | address to 20 | ) public returns (uint256) { 21 | // TODO 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /contracts/solidity/testing/NFTXEligibilityManager2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../NFTXEligibilityManager.sol"; 6 | 7 | contract NFTXEligibilityManager2 is NFTXEligibilityManager { 8 | function sum(uint256 a, uint256 b) public pure returns (uint256) { 9 | return a + b; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /contracts/solidity/testing/NFTXLPStaking2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../NFTXLPStaking.sol"; 6 | 7 | contract NFTXLPStaking2 is NFTXLPStaking { 8 | function sum(uint256 a, uint256 b) public pure returns (uint256) { 9 | return a + b; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /contracts/solidity/testing/NFTXVaultFactoryUpgradeable2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../NFTXVaultFactoryUpgradeable.sol"; 6 | 7 | // Authors: @0xKiwi_ and @alexgausman. 8 | 9 | contract NFTXVaultFactoryUpgradeable2 is NFTXVaultFactoryUpgradeable { 10 | function twiceNumVaults() public view returns (uint256) { 11 | return vaults.length * 2; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /contracts/solidity/testing/Strings.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev String operations. 7 | */ 8 | library Strings { 9 | /** 10 | * @dev Converts a `uint256` to its ASCII `string` representation. 11 | */ 12 | function toString(uint256 value) internal pure returns (string memory) { 13 | // Inspired by OraclizeAPI's implementation - MIT licence 14 | // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol 15 | 16 | if (value == 0) { 17 | return "0"; 18 | } 19 | uint256 temp = value; 20 | uint256 digits; 21 | while (temp != 0) { 22 | digits++; 23 | temp /= 10; 24 | } 25 | bytes memory buffer = new bytes(digits); 26 | uint256 index = digits - 1; 27 | temp = value; 28 | while (temp != 0) { 29 | buffer[index--] = bytes1(uint8(48 + temp % 10)); 30 | temp /= 10; 31 | } 32 | return string(buffer); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /contracts/solidity/testing/TestUpgrade.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../NFTXVaultFactoryUpgradeable.sol"; 6 | 7 | contract TestFactoryUpgrade is NFTXVaultFactoryUpgradeable { 8 | function isUpgraded() public pure returns (bool) { 9 | return true; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /contracts/solidity/testing/TestVaultUpgrade.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | // SPDX-License-Identifier: MIT 4 | 5 | import "../NFTXVaultUpgradeable.sol"; 6 | 7 | contract TestVaultUpgrade is NFTXVaultUpgradeable { 8 | function isUpgraded() public pure returns (bool) { 9 | return true; 10 | } 11 | } -------------------------------------------------------------------------------- /contracts/solidity/testing/WETH.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.0; 2 | 3 | contract WETH { 4 | string public name = "Wrapped Ether"; 5 | string public symbol = "WETH"; 6 | uint8 public decimals = 18; 7 | 8 | event Approval(address indexed src, address indexed guy, uint wad); 9 | event Transfer(address indexed src, address indexed dst, uint wad); 10 | event Deposit(address indexed dst, uint wad); 11 | event Withdrawal(address indexed src, uint wad); 12 | 13 | mapping (address => uint) public balanceOf; 14 | mapping (address => mapping (address => uint)) public allowance; 15 | 16 | receive() external payable { 17 | deposit(); 18 | } 19 | 20 | function mint(address to, uint256 amount) public { 21 | balanceOf[to] += amount; 22 | } 23 | 24 | function deposit() public payable { 25 | balanceOf[msg.sender] += msg.value; 26 | emit Deposit(msg.sender, msg.value); 27 | } 28 | 29 | function withdraw(uint wad) public payable { 30 | require(balanceOf[msg.sender] >= wad); 31 | balanceOf[msg.sender] -= wad; 32 | payable(msg.sender).transfer(wad); 33 | emit Withdrawal(msg.sender, wad); 34 | } 35 | 36 | function totalSupply() public view returns (uint) { 37 | return address(this).balance; 38 | } 39 | 40 | function approve(address guy, uint wad) public returns (bool) { 41 | allowance[msg.sender][guy] = wad; 42 | emit Approval(msg.sender, guy, wad); 43 | return true; 44 | } 45 | 46 | function transfer(address dst, uint wad) public returns (bool) { 47 | return transferFrom(msg.sender, dst, wad); 48 | } 49 | 50 | function transferFrom(address src, address dst, uint wad) 51 | public 52 | returns (bool) 53 | { 54 | require(balanceOf[src] >= wad); 55 | 56 | if (src != msg.sender && allowance[src][msg.sender] >= 0) { 57 | require(allowance[src][msg.sender] >= wad); 58 | allowance[src][msg.sender] -= wad; 59 | } 60 | 61 | balanceOf[src] -= wad; 62 | balanceOf[dst] += wad; 63 | 64 | emit Transfer(src, dst, wad); 65 | 66 | return true; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /contracts/solidity/token/ERC1155HolderUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./ERC1155ReceiverUpgradeable.sol"; 6 | 7 | /** 8 | * @dev _Available since v3.1._ 9 | */ 10 | abstract contract ERC1155HolderUpgradeable is ERC1155ReceiverUpgradeable { 11 | function onERC1155Received(address, address, uint256, uint256, bytes memory) public virtual override returns (bytes4) { 12 | return this.onERC1155Received.selector; 13 | } 14 | 15 | function onERC1155BatchReceived(address, address, uint256[] memory, uint256[] memory, bytes memory) public virtual override returns (bytes4) { 16 | return this.onERC1155BatchReceived.selector; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/solidity/token/ERC1155ReceiverUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC1155ReceiverUpgradeable.sol"; 6 | import "../util/ERC165Upgradeable.sol"; 7 | 8 | /** 9 | * @dev _Available since v3.1._ 10 | */ 11 | abstract contract ERC1155ReceiverUpgradeable is ERC165Upgradeable, IERC1155ReceiverUpgradeable { 12 | /** 13 | * @dev See {IERC165-supportsInterface}. 14 | */ 15 | function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) { 16 | return interfaceId == type(IERC1155ReceiverUpgradeable).interfaceId 17 | || super.supportsInterface(interfaceId); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/solidity/token/ERC1155SafeHolderUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./ERC1155ReceiverUpgradeable.sol"; 6 | 7 | /** 8 | * @dev _Available since v3.1._ 9 | */ 10 | abstract contract ERC1155SafeHolderUpgradeable is ERC1155ReceiverUpgradeable { 11 | function onERC1155Received(address operator, address, uint256, uint256, bytes memory) public virtual override returns (bytes4) { 12 | return this.onERC1155Received.selector; 13 | } 14 | 15 | function onERC1155BatchReceived(address operator, address, uint256[] memory, uint256[] memory, bytes memory) public virtual override returns (bytes4) { 16 | return this.onERC1155BatchReceived.selector; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/solidity/token/ERC20FlashMintUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../interface/IERC3156Upgradeable.sol"; 6 | import "./ERC20Upgradeable.sol"; 7 | import "../proxy/Initializable.sol"; 8 | 9 | /** 10 | * @dev Implementation of the ERC3156 Flash loans extension, as defined in 11 | * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. 12 | * 13 | * Adds the {flashLoan} method, which provides flash loan support at the token 14 | * level. By default there is no fee, but this can be changed by overriding {flashFee}. 15 | */ 16 | abstract contract ERC20FlashMintUpgradeable is Initializable, ERC20Upgradeable, IERC3156FlashLenderUpgradeable { 17 | function __ERC20FlashMint_init() internal initializer { 18 | __Context_init_unchained(); 19 | __ERC20FlashMint_init_unchained(); 20 | } 21 | 22 | function __ERC20FlashMint_init_unchained() internal initializer { 23 | } 24 | bytes32 constant private RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); 25 | 26 | /** 27 | * @dev Returns the maximum amount of tokens available for loan. 28 | * @param token The address of the token that is requested. 29 | * @return The amont of token that can be loaned. 30 | */ 31 | function maxFlashLoan(address token) public view override returns (uint256) { 32 | return token == address(this) ? type(uint256).max - totalSupply() : 0; 33 | } 34 | 35 | /** 36 | * @dev Returns the fee applied when doing flash loans. By default this 37 | * implementation has 0 fees. This function can be overloaded to make 38 | * the flash loan mechanism deflationary. 39 | * @param token The token to be flash loaned. 40 | * @param amount The amount of tokens to be loaned. 41 | * @return The fees applied to the corresponding flash loan. 42 | */ 43 | function flashFee(address token, uint256 amount) public view virtual override returns (uint256) { 44 | require(token == address(this), "ERC20FlashMint: wrong token"); 45 | // silence warning about unused variable without the addition of bytecode. 46 | amount; 47 | return 0; 48 | } 49 | 50 | /** 51 | * @dev Performs a flash loan. New tokens are minted and sent to the 52 | * `receiver`, who is required to implement the {IERC3156FlashBorrower} 53 | * interface. By the end of the flash loan, the receiver is expected to own 54 | * amount + fee tokens and have them approved back to the token contract itself so 55 | * they can be burned. 56 | * @param receiver The receiver of the flash loan. Should implement the 57 | * {IERC3156FlashBorrower.onFlashLoan} interface. 58 | * @param token The token to be flash loaned. Only `address(this)` is 59 | * supported. 60 | * @param amount The amount of tokens to be loaned. 61 | * @param data An arbitrary datafield that is passed to the receiver. 62 | * @return `true` is the flash loan was successfull. 63 | */ 64 | function flashLoan( 65 | IERC3156FlashBorrowerUpgradeable receiver, 66 | address token, 67 | uint256 amount, 68 | bytes memory data 69 | ) 70 | public virtual override returns (bool) 71 | { 72 | uint256 fee = flashFee(token, amount); 73 | _mint(address(receiver), amount); 74 | require(receiver.onFlashLoan(msg.sender, token, amount, fee, data) == RETURN_VALUE, "ERC20FlashMint: invalid return value"); 75 | uint256 currentAllowance = allowance(address(receiver), address(this)); 76 | require(currentAllowance >= amount + fee, "ERC20FlashMint: allowance does not allow refund"); 77 | _approve(address(receiver), address(this), currentAllowance - amount - fee); 78 | _burn(address(receiver), amount + fee); 79 | return true; 80 | } 81 | uint256[50] private __gap; 82 | } -------------------------------------------------------------------------------- /contracts/solidity/token/ERC721HolderUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC721ReceiverUpgradeable.sol"; 6 | 7 | /** 8 | * @dev Implementation of the {IERC721Receiver} interface. 9 | * 10 | * Accepts all token transfers. 11 | * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. 12 | */ 13 | contract ERC721HolderUpgradeable is IERC721ReceiverUpgradeable { 14 | /** 15 | * @dev See {IERC721Receiver-onERC721Received}. 16 | * 17 | * Always returns `IERC721Receiver.onERC721Received.selector`. 18 | */ 19 | function onERC721Received( 20 | address, 21 | address, 22 | uint256, 23 | bytes memory 24 | ) public virtual override returns (bytes4) { 25 | return this.onERC721Received.selector; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contracts/solidity/token/ERC721SafeHolderUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC721ReceiverUpgradeable.sol"; 6 | 7 | /** 8 | * @dev Implementation of the {IERC721Receiver} interface. 9 | * 10 | * Accepts all token transfers. 11 | * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. 12 | */ 13 | contract ERC721SafeHolderUpgradeable is IERC721ReceiverUpgradeable { 14 | /** 15 | * @dev See {IERC721Receiver-onERC721Received}. 16 | * 17 | * Always returns `IERC721Receiver.onERC721Received.selector`. 18 | */ 19 | function onERC721Received( 20 | address operator, 21 | address, 22 | uint256, 23 | bytes memory 24 | ) public virtual override returns (bytes4) { 25 | return this.onERC721Received.selector; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contracts/solidity/token/IERC1155ReceiverUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../interface/IERC165Upgradeable.sol"; 6 | 7 | /** 8 | * @dev _Available since v3.1._ 9 | */ 10 | interface IERC1155ReceiverUpgradeable is IERC165Upgradeable { 11 | 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 | ) 32 | external 33 | returns(bytes4); 34 | 35 | /** 36 | @dev Handles the receipt of a multiple ERC1155 token types. This function 37 | is called at the end of a `safeBatchTransferFrom` after the balances have 38 | been updated. To accept the transfer(s), this must return 39 | `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` 40 | (i.e. 0xbc197c81, or its own function selector). 41 | @param operator The address which initiated the batch transfer (i.e. msg.sender) 42 | @param from The address which previously owned the token 43 | @param ids An array containing ids of each token being transferred (order and length must match values array) 44 | @param values An array containing amounts of each token being transferred (order and length must match ids array) 45 | @param data Additional data with no specified format 46 | @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed 47 | */ 48 | function onERC1155BatchReceived( 49 | address operator, 50 | address from, 51 | uint256[] calldata ids, 52 | uint256[] calldata values, 53 | bytes calldata data 54 | ) 55 | external 56 | returns(bytes4); 57 | } 58 | -------------------------------------------------------------------------------- /contracts/solidity/token/IERC20Metadata.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC20Upgradeable.sol"; 6 | 7 | /** 8 | * @dev Interface for the optional metadata functions from the ERC20 standard. 9 | * 10 | * _Available since v4.1._ 11 | */ 12 | interface IERC20Metadata is IERC20Upgradeable { 13 | /** 14 | * @dev Returns the name of the token. 15 | */ 16 | function name() external view returns (string memory); 17 | 18 | /** 19 | * @dev Returns the symbol of the token. 20 | */ 21 | function symbol() external view returns (string memory); 22 | 23 | /** 24 | * @dev Returns the decimals places of the token. 25 | */ 26 | function decimals() external view returns (uint8); 27 | } 28 | -------------------------------------------------------------------------------- /contracts/solidity/token/IERC20Upgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev Interface of the ERC20 standard as defined in the EIP. 7 | */ 8 | interface IERC20Upgradeable { 9 | /** 10 | * @dev Returns the amount of tokens in existence. 11 | */ 12 | function totalSupply() external view returns (uint256); 13 | 14 | /** 15 | * @dev Returns the amount of tokens owned by `account`. 16 | */ 17 | function balanceOf(address account) external view returns (uint256); 18 | 19 | /** 20 | * @dev Moves `amount` tokens from the caller's account to `recipient`. 21 | * 22 | * Returns a boolean value indicating whether the operation succeeded. 23 | * 24 | * Emits a {Transfer} event. 25 | */ 26 | function transfer(address recipient, uint256 amount) external returns (bool); 27 | 28 | /** 29 | * @dev Returns the remaining number of tokens that `spender` will be 30 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 31 | * zero by default. 32 | * 33 | * This value changes when {approve} or {transferFrom} are called. 34 | */ 35 | function allowance(address owner, address spender) external view returns (uint256); 36 | 37 | /** 38 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 39 | * 40 | * Returns a boolean value indicating whether the operation succeeded. 41 | * 42 | * IMPORTANT: Beware that changing an allowance with this method brings the risk 43 | * that someone may use both the old and the new allowance by unfortunate 44 | * transaction ordering. One possible solution to mitigate this race 45 | * condition is to first reduce the spender's allowance to 0 and set the 46 | * desired value afterwards: 47 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 48 | * 49 | * Emits an {Approval} event. 50 | */ 51 | function approve(address spender, uint256 amount) external returns (bool); 52 | 53 | /** 54 | * @dev Moves `amount` tokens from `sender` to `recipient` using the 55 | * allowance mechanism. `amount` is then deducted from the caller's 56 | * allowance. 57 | * 58 | * Returns a boolean value indicating whether the operation succeeded. 59 | * 60 | * Emits a {Transfer} event. 61 | */ 62 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 63 | 64 | /** 65 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 66 | * another (`to`). 67 | * 68 | * Note that `value` may be zero. 69 | */ 70 | event Transfer(address indexed from, address indexed to, uint256 value); 71 | 72 | /** 73 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 74 | * a call to {approve}. `value` is the new allowance. 75 | */ 76 | event Approval(address indexed owner, address indexed spender, uint256 value); 77 | } 78 | -------------------------------------------------------------------------------- /contracts/solidity/token/IERC721Enumerable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC721Upgradeable.sol"; 6 | 7 | /** 8 | * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension 9 | * @dev See https://eips.ethereum.org/EIPS/eip-721 10 | */ 11 | interface IERC721Enumerable is IERC721Upgradeable { 12 | 13 | /** 14 | * @dev Returns the total amount of tokens stored by the contract. 15 | */ 16 | function totalSupply() external view returns (uint256); 17 | 18 | /** 19 | * @dev Returns a token ID owned by `owner` at a given `index` of its token list. 20 | * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. 21 | */ 22 | function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); 23 | 24 | /** 25 | * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. 26 | * Use along with {totalSupply} to enumerate all tokens. 27 | */ 28 | function tokenByIndex(uint256 index) external view returns (uint256); 29 | } -------------------------------------------------------------------------------- /contracts/solidity/token/IERC721ReceiverUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @title ERC721 token receiver interface 7 | * @dev Interface for any contract that wants to support safeTransfers 8 | * from ERC721 asset contracts. 9 | */ 10 | interface IERC721ReceiverUpgradeable { 11 | /** 12 | * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} 13 | * by `operator` from `from`, this function is called. 14 | * 15 | * It must return its Solidity selector to confirm the token transfer. 16 | * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. 17 | * 18 | * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. 19 | */ 20 | function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4); 21 | } 22 | -------------------------------------------------------------------------------- /contracts/solidity/token/IWETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface IWETH { 6 | function balanceOf(address account) external view returns (uint256); 7 | function deposit() external payable; 8 | function transfer(address to, uint value) external returns (bool); 9 | function withdraw(uint) external; 10 | } -------------------------------------------------------------------------------- /contracts/solidity/token/XTokenUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./IERC20Upgradeable.sol"; 6 | import "./ERC20Upgradeable.sol"; 7 | import "../util/OwnableUpgradeable.sol"; 8 | import "../util/SafeERC20Upgradeable.sol"; 9 | 10 | // XTokens let uou come in with some vault tokens, and leave with more! The longer you stay, the more vault tokens you get. 11 | // 12 | // This contract handles swapping to and from xSushi, SushiSwap's staking token. 13 | contract XTokenUpgradeable is OwnableUpgradeable, ERC20Upgradeable { 14 | using SafeERC20Upgradeable for IERC20Upgradeable; 15 | 16 | uint256 internal constant MAX_TIMELOCK = 2592000; 17 | IERC20Upgradeable public baseToken; 18 | 19 | mapping(address => uint256) internal timelock; 20 | 21 | event Timelocked(address user, uint256 until); 22 | 23 | function __XToken_init(address _baseToken, string memory name, string memory symbol) public initializer { 24 | __Ownable_init(); 25 | // string memory _name = INFTXInventoryStaking(msg.sender).nftxVaultFactory().vault(); 26 | __ERC20_init(name, symbol); 27 | baseToken = IERC20Upgradeable(_baseToken); 28 | } 29 | 30 | // Needs to be called BEFORE new base tokens are deposited. 31 | function mintXTokens(address account, uint256 _amount, uint256 timelockLength) external onlyOwner returns (uint256) { 32 | // Gets the amount of Base Token locked in the contract 33 | uint256 totalBaseToken = baseToken.balanceOf(address(this)); 34 | // Gets the amount of xTokens in existence 35 | uint256 totalShares = totalSupply(); 36 | // If no xTokens exist, mint it 1:1 to the amount put in 37 | if (totalShares == 0 || totalBaseToken == 0) { 38 | _timelockMint(account, _amount, timelockLength); 39 | return _amount; 40 | } 41 | // Calculate and mint the amount of xTokens the base tokens are worth. The ratio will change overtime, as xTokens are burned/minted and base tokens deposited + gained from fees / withdrawn. 42 | else { 43 | uint256 what = (_amount * totalShares) / totalBaseToken; 44 | _timelockMint(account, what, timelockLength); 45 | return what; 46 | } 47 | } 48 | 49 | function burnXTokens(address who, uint256 _share) external onlyOwner returns (uint256) { 50 | // Gets the amount of xToken in existence 51 | uint256 totalShares = totalSupply(); 52 | // Calculates the amount of base tokens the xToken is worth 53 | uint256 what = (_share * baseToken.balanceOf(address(this))) / totalShares; 54 | _burn(who, _share); 55 | baseToken.safeTransfer(who, what); 56 | return what; 57 | } 58 | 59 | function timelockAccount(address account, uint256 timelockLength) public onlyOwner virtual { 60 | require(timelockLength < MAX_TIMELOCK, "Too long lock"); 61 | uint256 timelockFinish = block.timestamp + timelockLength; 62 | if(timelockFinish > timelock[account]){ 63 | timelock[account] = timelockFinish; 64 | emit Timelocked(account, timelockFinish); 65 | } 66 | } 67 | 68 | function _burn(address who, uint256 amount) internal override { 69 | require(block.timestamp > timelock[who], "User locked"); 70 | super._burn(who, amount); 71 | } 72 | 73 | function timelockUntil(address account) public view returns (uint256) { 74 | return timelock[account]; 75 | } 76 | 77 | function _timelockMint(address account, uint256 amount, uint256 timelockLength) internal virtual { 78 | timelockAccount(account, timelockLength); 79 | _mint(account, amount); 80 | } 81 | 82 | function _transfer(address from, address to, uint256 value) internal override { 83 | require(block.timestamp > timelock[from], "User locked"); 84 | super._transfer(from, to, value); 85 | } 86 | } -------------------------------------------------------------------------------- /contracts/solidity/util/ContextUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | import "../proxy/Initializable.sol"; 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 ContextUpgradeable is Initializable { 17 | function __Context_init() internal initializer { 18 | __Context_init_unchained(); 19 | } 20 | 21 | function __Context_init_unchained() internal initializer { 22 | } 23 | function _msgSender() internal view virtual returns (address) { 24 | return msg.sender; 25 | } 26 | 27 | function _msgData() internal view virtual returns (bytes calldata) { 28 | this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 29 | return msg.data; 30 | } 31 | uint256[50] private __gap; 32 | } 33 | -------------------------------------------------------------------------------- /contracts/solidity/util/Create2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer. 7 | * `CREATE2` can be used to compute in advance the address where a smart 8 | * contract will be deployed, which allows for interesting new mechanisms known 9 | * as 'counterfactual interactions'. 10 | * 11 | * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more 12 | * information. 13 | */ 14 | library Create2 { 15 | /** 16 | * @dev Deploys a contract using `CREATE2`. The address where the contract 17 | * will be deployed can be known in advance via {computeAddress}. 18 | * 19 | * The bytecode for a contract can be obtained from Solidity with 20 | * `type(contractName).creationCode`. 21 | * 22 | * Requirements: 23 | * 24 | * - `bytecode` must not be empty. 25 | * - `salt` must have not been used for `bytecode` already. 26 | * - the factory must have a balance of at least `amount`. 27 | * - if `amount` is non-zero, `bytecode` must have a `payable` constructor. 28 | */ 29 | function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address) { 30 | address addr; 31 | require(address(this).balance >= amount, "Create2: insufficient balance"); 32 | require(bytecode.length != 0, "Create2: bytecode length is zero"); 33 | // solhint-disable-next-line no-inline-assembly 34 | assembly { 35 | addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) 36 | } 37 | require(addr != address(0), "Create2: Failed on deploy"); 38 | return addr; 39 | } 40 | 41 | /** 42 | * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the 43 | * `bytecodeHash` or `salt` will result in a new destination address. 44 | */ 45 | function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) { 46 | return computeAddress(salt, bytecodeHash, address(this)); 47 | } 48 | 49 | /** 50 | * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at 51 | * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}. 52 | */ 53 | function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address) { 54 | bytes32 _data = keccak256( 55 | abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHash) 56 | ); 57 | return address(uint160(uint256(_data))); 58 | } 59 | } -------------------------------------------------------------------------------- /contracts/solidity/util/ERC165Upgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../interface/IERC165Upgradeable.sol"; 6 | 7 | /** 8 | * @dev Implementation of the {IERC165} interface. 9 | * 10 | * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check 11 | * for the additional interface id that will be supported. For example: 12 | * 13 | * ```solidity 14 | * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 15 | * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); 16 | * } 17 | * ``` 18 | * 19 | * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. 20 | */ 21 | abstract contract ERC165Upgradeable is IERC165Upgradeable { 22 | /** 23 | * @dev See {IERC165-supportsInterface}. 24 | */ 25 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 26 | return interfaceId == type(IERC165Upgradeable).interfaceId; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /contracts/solidity/util/Ownable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../testing/Context.sol"; 6 | 7 | /** 8 | * @dev Contract module which provides a basic access control mechanism, where 9 | * there is an account (an owner) that can be granted exclusive access to 10 | * specific functions. 11 | * 12 | * By default, the owner account will be the one that deploys the contract. This 13 | * can later be changed with {transferOwnership}. 14 | * 15 | * This module is used through inheritance. It will make available the modifier 16 | * `onlyOwner`, which can be applied to your functions to restrict their use to 17 | * the owner. 18 | */ 19 | abstract contract Ownable is Context { 20 | address private _owner; 21 | 22 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 23 | 24 | /** 25 | * @dev Initializes the contract setting the deployer as the initial owner. 26 | */ 27 | constructor() { 28 | address msgSender = _msgSender(); 29 | _owner = msgSender; 30 | emit OwnershipTransferred(address(0), msgSender); 31 | } 32 | 33 | /** 34 | * @dev Returns the address of the current owner. 35 | */ 36 | function owner() public view virtual returns (address) { 37 | return _owner; 38 | } 39 | 40 | /** 41 | * @dev Throws if called by any account other than the owner. 42 | */ 43 | modifier onlyOwner() { 44 | require(owner() == _msgSender(), "Ownable: caller is not the owner"); 45 | _; 46 | } 47 | 48 | /** 49 | * @dev Leaves the contract without owner. It will not be possible to call 50 | * `onlyOwner` functions anymore. Can only be called by the current owner. 51 | * 52 | * NOTE: Renouncing ownership will leave the contract without an owner, 53 | * thereby removing any functionality that is only available to the owner. 54 | */ 55 | function renounceOwnership() public virtual onlyOwner { 56 | emit OwnershipTransferred(_owner, address(0)); 57 | _owner = address(0); 58 | } 59 | 60 | /** 61 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 62 | * Can only be called by the current owner. 63 | */ 64 | function transferOwnership(address newOwner) public virtual onlyOwner { 65 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 66 | emit OwnershipTransferred(_owner, newOwner); 67 | _owner = newOwner; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /contracts/solidity/util/OwnableUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./ContextUpgradeable.sol"; 6 | import "../proxy/Initializable.sol"; 7 | /** 8 | * @dev Contract module which provides a basic access control mechanism, where 9 | * there is an account (an owner) that can be granted exclusive access to 10 | * specific functions. 11 | * 12 | * By default, the owner account will be the one that deploys the contract. This 13 | * can later be changed with {transferOwnership}. 14 | * 15 | * This module is used through inheritance. It will make available the modifier 16 | * `onlyOwner`, which can be applied to your functions to restrict their use to 17 | * the owner. 18 | */ 19 | abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { 20 | address private _owner; 21 | 22 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 23 | 24 | /** 25 | * @dev Initializes the contract setting the deployer as the initial owner. 26 | */ 27 | function __Ownable_init() internal initializer { 28 | __Context_init_unchained(); 29 | __Ownable_init_unchained(); 30 | } 31 | 32 | function __Ownable_init_unchained() internal initializer { 33 | address msgSender = _msgSender(); 34 | _owner = msgSender; 35 | emit OwnershipTransferred(address(0), msgSender); 36 | } 37 | 38 | /** 39 | * @dev Returns the address of the current owner. 40 | */ 41 | function owner() public view virtual returns (address) { 42 | return _owner; 43 | } 44 | 45 | /** 46 | * @dev Throws if called by any account other than the owner. 47 | */ 48 | modifier onlyOwner() { 49 | require(owner() == _msgSender(), "Ownable: caller is not the owner"); 50 | _; 51 | } 52 | 53 | /** 54 | * @dev Leaves the contract without owner. It will not be possible to call 55 | * `onlyOwner` functions anymore. Can only be called by the current owner. 56 | * 57 | * NOTE: Renouncing ownership will leave the contract without an owner, 58 | * thereby removing any functionality that is only available to the owner. 59 | */ 60 | function renounceOwnership() public virtual onlyOwner { 61 | emit OwnershipTransferred(_owner, address(0)); 62 | _owner = address(0); 63 | } 64 | 65 | /** 66 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 67 | * Can only be called by the current owner. 68 | */ 69 | function transferOwnership(address newOwner) public virtual onlyOwner { 70 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 71 | emit OwnershipTransferred(_owner, newOwner); 72 | _owner = newOwner; 73 | } 74 | uint256[49] private __gap; 75 | } 76 | -------------------------------------------------------------------------------- /contracts/solidity/util/PausableUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "./OwnableUpgradeable.sol"; 6 | 7 | contract PausableUpgradeable is OwnableUpgradeable { 8 | 9 | function __Pausable_init() internal initializer { 10 | __Ownable_init(); 11 | } 12 | 13 | event SetPaused(uint256 lockId, bool paused); 14 | event SetIsGuardian(address addr, bool isGuardian); 15 | 16 | mapping(address => bool) public isGuardian; 17 | mapping(uint256 => bool) public isPaused; 18 | // 0 : createVault 19 | // 1 : mint 20 | // 2 : redeem 21 | // 3 : swap 22 | // 4 : flashloan 23 | 24 | function onlyOwnerIfPaused(uint256 lockId) public view virtual { 25 | require(!isPaused[lockId] || msg.sender == owner(), "Paused"); 26 | } 27 | 28 | function unpause(uint256 lockId) 29 | public 30 | virtual 31 | onlyOwner 32 | { 33 | isPaused[lockId] = false; 34 | emit SetPaused(lockId, false); 35 | } 36 | 37 | function pause(uint256 lockId) public virtual { 38 | require(isGuardian[msg.sender], "Can't pause"); 39 | isPaused[lockId] = true; 40 | emit SetPaused(lockId, true); 41 | } 42 | 43 | function setIsGuardian(address addr, bool _isGuardian) public virtual onlyOwner { 44 | isGuardian[addr] = _isGuardian; 45 | emit SetIsGuardian(addr, _isGuardian); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/solidity/util/ReentrancyGuard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | abstract contract ReentrancyGuard { 6 | // Booleans are more expensive than uint256 or any type that takes up a full 7 | // word because each write operation emits an extra SLOAD to first read the 8 | // slot's contents, replace the bits taken up by the boolean, and then write 9 | // back. This is the compiler's defense against contract upgrades and 10 | // pointer aliasing, and it cannot be disabled. 11 | 12 | // The values being non-zero value makes deployment a bit more expensive, 13 | // but in exchange the refund on every call to nonReentrant will be lower in 14 | // amount. Since refunds are capped to a percentage of the total 15 | // transaction's gas, it is best to keep them low in cases like this one, to 16 | // increase the likelihood of the full refund coming into effect. 17 | uint256 private constant _NOT_ENTERED = 1; 18 | uint256 private constant _ENTERED = 2; 19 | 20 | uint256 private _status; 21 | 22 | constructor() { 23 | _status = _NOT_ENTERED; 24 | } 25 | 26 | /** 27 | * @dev Prevents a contract from calling itself, directly or indirectly. 28 | * Calling a `nonReentrant` function from another `nonReentrant` 29 | * function is not supported. It is possible to prevent this from happening 30 | * by making the `nonReentrant` function external, and make it call a 31 | * `private` function that does the actual work. 32 | */ 33 | modifier nonReentrant() { 34 | // On the first call to nonReentrant, _notEntered will be true 35 | require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); 36 | 37 | // Any calls to nonReentrant after this point will fail 38 | _status = _ENTERED; 39 | 40 | _; 41 | 42 | // By storing the original value once again, a refund is triggered (see 43 | // https://eips.ethereum.org/EIPS/eip-2200) 44 | _status = _NOT_ENTERED; 45 | } 46 | } -------------------------------------------------------------------------------- /contracts/solidity/util/ReentrancyGuardUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | import "../proxy/Initializable.sol"; 5 | 6 | /** 7 | * @dev Contract module that helps prevent reentrant calls to a function. 8 | * 9 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier 10 | * available, which can be applied to functions to make sure there are no nested 11 | * (reentrant) calls to them. 12 | * 13 | * Note that because there is a single `nonReentrant` guard, functions marked as 14 | * `nonReentrant` may not call one another. This can be worked around by making 15 | * those functions `private`, and then adding `external` `nonReentrant` entry 16 | * points to them. 17 | * 18 | * TIP: If you would like to learn more about reentrancy and alternative ways 19 | * to protect against it, check out our blog post 20 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. 21 | */ 22 | abstract contract ReentrancyGuardUpgradeable is Initializable { 23 | // Booleans are more expensive than uint256 or any type that takes up a full 24 | // word because each write operation emits an extra SLOAD to first read the 25 | // slot's contents, replace the bits taken up by the boolean, and then write 26 | // back. This is the compiler's defense against contract upgrades and 27 | // pointer aliasing, and it cannot be disabled. 28 | 29 | // The values being non-zero value makes deployment a bit more expensive, 30 | // but in exchange the refund on every call to nonReentrant will be lower in 31 | // amount. Since refunds are capped to a percentage of the total 32 | // transaction's gas, it is best to keep them low in cases like this one, to 33 | // increase the likelihood of the full refund coming into effect. 34 | uint256 private constant _NOT_ENTERED = 1; 35 | uint256 private constant _ENTERED = 2; 36 | 37 | uint256 private _status; 38 | 39 | function __ReentrancyGuard_init() internal initializer { 40 | __ReentrancyGuard_init_unchained(); 41 | } 42 | 43 | function __ReentrancyGuard_init_unchained() internal initializer { 44 | _status = _NOT_ENTERED; 45 | } 46 | 47 | /** 48 | * @dev Prevents a contract from calling itself, directly or indirectly. 49 | * Calling a `nonReentrant` function from another `nonReentrant` 50 | * function is not supported. It is possible to prevent this from happening 51 | * by making the `nonReentrant` function external, and make it call a 52 | * `private` function that does the actual work. 53 | */ 54 | modifier nonReentrant() { 55 | // On the first call to nonReentrant, _notEntered will be true 56 | require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); 57 | 58 | // Any calls to nonReentrant after this point will fail 59 | _status = _ENTERED; 60 | 61 | _; 62 | 63 | // By storing the original value once again, a refund is triggered (see 64 | // https://eips.ethereum.org/EIPS/eip-2200) 65 | _status = _NOT_ENTERED; 66 | } 67 | uint256[49] private __gap; 68 | } 69 | -------------------------------------------------------------------------------- /contracts/solidity/util/SafeERC20Upgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "../token/IERC20Upgradeable.sol"; 6 | import "./Address.sol"; 7 | 8 | /** 9 | * @title SafeERC20 10 | * @dev Wrappers around ERC20 operations that throw on failure (when the token 11 | * contract returns false). Tokens that return no value (and instead revert or 12 | * throw on failure) are also supported, non-reverting calls are assumed to be 13 | * successful. 14 | * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, 15 | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. 16 | */ 17 | library SafeERC20Upgradeable { 18 | using Address for address; 19 | 20 | function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal { 21 | _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 22 | } 23 | 24 | function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal { 25 | _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 26 | } 27 | 28 | /** 29 | * @dev Deprecated. This function has issues similar to the ones found in 30 | * {IERC20-approve}, and its usage is discouraged. 31 | * 32 | * Whenever possible, use {safeIncreaseAllowance} and 33 | * {safeDecreaseAllowance} instead. 34 | */ 35 | function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal { 36 | // safeApprove should only be called when setting an initial allowance, 37 | // or when resetting it to zero. To increase and decrease it, use 38 | // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' 39 | // solhint-disable-next-line max-line-length 40 | require((value == 0) || (token.allowance(address(this), spender) == 0), 41 | "SafeERC20: approve from non-zero to non-zero allowance" 42 | ); 43 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 44 | } 45 | 46 | function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { 47 | uint256 newAllowance = token.allowance(address(this), spender) + value; 48 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 49 | } 50 | 51 | function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { 52 | unchecked { 53 | uint256 oldAllowance = token.allowance(address(this), spender); 54 | require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); 55 | uint256 newAllowance = oldAllowance - value; 56 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 57 | } 58 | } 59 | 60 | /** 61 | * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement 62 | * on the return value: the return value is optional (but if data is returned, it must not be false). 63 | * @param token The token targeted by the call. 64 | * @param data The call data (encoded using abi.encode or one of its variants). 65 | */ 66 | function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { 67 | // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since 68 | // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that 69 | // the target address contains contract code and also asserts for success in the low-level call. 70 | 71 | bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); 72 | if (returndata.length > 0) { // Return data is optional 73 | // solhint-disable-next-line max-line-length 74 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /contracts/solidity/util/SafeMathInt.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @title SafeMathInt 7 | * @dev Math operations with safety checks that revert on error 8 | * @dev SafeMath adapted for int256 9 | * Based on code of https://github.com/RequestNetwork/requestNetwork/blob/master/packages/requestNetworkSmartContracts/contracts/base/math/SafeMathInt.sol 10 | */ 11 | library SafeMathInt { 12 | function mul(int256 a, int256 b) internal pure returns (int256) { 13 | // Prevent overflow when multiplying INT256_MIN with -1 14 | // https://github.com/RequestNetwork/requestNetwork/issues/43 15 | require(!(a == - 2**255 && b == -1) && !(b == - 2**255 && a == -1)); 16 | 17 | int256 c = a * b; 18 | require((b == 0) || (c / b == a)); 19 | return c; 20 | } 21 | 22 | function div(int256 a, int256 b) internal pure returns (int256) { 23 | // Prevent overflow when dividing INT256_MIN by -1 24 | // https://github.com/RequestNetwork/requestNetwork/issues/43 25 | require(!(a == - 2**255 && b == -1) && (b > 0)); 26 | 27 | return a / b; 28 | } 29 | 30 | function sub(int256 a, int256 b) internal pure returns (int256) { 31 | require((b >= 0 && a - b <= a) || (b < 0 && a - b > a)); 32 | 33 | return a - b; 34 | } 35 | 36 | function add(int256 a, int256 b) internal pure returns (int256) { 37 | int256 c = a + b; 38 | require((b >= 0 && c >= a) || (b < 0 && c < a)); 39 | return c; 40 | } 41 | 42 | function toUint256Safe(int256 a) internal pure returns (uint256) { 43 | require(a >= 0); 44 | return uint256(a); 45 | } 46 | } -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | require("@nomiclabs/hardhat-waffle"); 3 | require("@openzeppelin/hardhat-upgrades"); 4 | require("hardhat-gas-reporter"); 5 | require("@nomiclabs/hardhat-etherscan"); 6 | require('hardhat-docgen'); 7 | 8 | /** 9 | * @type import('hardhat/config').HardhatUserConfig 10 | */ 11 | module.exports = { 12 | networks: { 13 | rinkeby: { 14 | url: `https://eth-rinkeby.alchemyapi.io/v2/${process.env.ALCHEMY_RINKEBY_API_KEY}`, 15 | accounts: [`0x${process.env.DEV_PRIVATE_KEY}`], 16 | }, 17 | ropsten: { 18 | url: `https://eth-ropsten.alchemyapi.io/v2/${process.env.ALCHEMY_ROPSTEN_API_KEY}`, 19 | accounts: [`0x${process.env.DEV_PRIVATE_KEY}`], 20 | timeout: 600000, 21 | }, 22 | goerli: { 23 | url: `https://eth-goerli.alchemyapi.io/v2/${process.env.ALCHEMY_GOERLI_API_KEY}`, 24 | accounts: [`0x${process.env.DEV_PRIVATE_KEY}`], 25 | gasPrice: 2500000000, 26 | }, 27 | mainnet: { 28 | url: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_MAINNET_API_KEY}`, 29 | accounts: [`0x${process.env.DEV_PRIVATE_KEY}`], 30 | timeout: 60000, 31 | // gasPrice: 75000000000, 32 | }, 33 | palm: { 34 | url: `https://palm-mainnet.infura.io/v3/${process.env.PALM_API_KEY}`, 35 | accounts: [`0x${process.env.DEV_PRIVATE_KEY}`], 36 | }, 37 | arbitrum: { 38 | url: "https://arb1.arbitrum.io/rpc", 39 | accounts: [`0x${process.env.DEV_PRIVATE_KEY}`], 40 | timeout: 600000, 41 | }, 42 | frame: { 43 | url: "http://127.0.0.1:1248", 44 | }, 45 | hardhat: { 46 | mining: { 47 | auto: true, 48 | }, 49 | forking: { 50 | url: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_MAINNET_API_KEY}`, 51 | blockNumber: 12772572, 52 | }, 53 | }, 54 | }, 55 | solidity: { 56 | version: "0.8.4", 57 | settings: { 58 | optimizer: { 59 | enabled: true, 60 | runs: 1000, 61 | }, 62 | }, 63 | }, 64 | mocha: { 65 | timeout: 100000, 66 | }, 67 | etherscan: { 68 | apiKey: process.env.ETHERSCAN_API_KEY 69 | }, 70 | }; 71 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@nomiclabs/hardhat-ethers": "^2.0.2", 5 | "@nomiclabs/hardhat-etherscan": "^3.1.0", 6 | "@nomiclabs/hardhat-vyper": "^2.0.1", 7 | "@nomiclabs/hardhat-waffle": "^2.0.1", 8 | "chai": "^4.3.4", 9 | "ethereum-waffle": "^3.4.0", 10 | "ethers": "^5.4.7", 11 | "hardhat": "^2.6.5" 12 | }, 13 | "dependencies": { 14 | "@ethersproject/bignumber": "^5.4.2", 15 | "@openzeppelin/contracts": "^3.4.1", 16 | "@openzeppelin/contracts-upgradeable": "^3.4.2", 17 | "@openzeppelin/hardhat-upgrades": "^1.10.0", 18 | "dotenv": "^10.0.0", 19 | "hardhat-gas-reporter": "^1.0.4", 20 | "keccak256": "^1.0.6", 21 | "merkletreejs": "^0.2.32" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /scripts/2022-0-invstaking.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const rinkebyVaultFactoryAddr = "0xbbc53022Af15Bb973AD906577c84784c47C14371"; 15 | 16 | const InventoryStaking = await ethers.getContractFactory( 17 | "NFTXInventoryStaking" 18 | ); 19 | const inventoryStaking = await upgrades.deployProxy( 20 | InventoryStaking, 21 | [rinkebyVaultFactoryAddr], 22 | { 23 | initializer: "__NFTXInventoryStaking_init", 24 | unsafeAllow: "delegatecall", 25 | } 26 | ); 27 | await inventoryStaking.deployed(); 28 | 29 | console.log("InventoryStaking:", inventoryStaking.address); 30 | } 31 | 32 | main() 33 | .then(() => { 34 | console.log("\nDeployment completed successfully ✓"); 35 | process.exit(0); 36 | }) 37 | .catch((error) => { 38 | console.log("\nDeployment failed ✗"); 39 | console.error(error); 40 | process.exit(1); 41 | }); 42 | -------------------------------------------------------------------------------- /scripts/2022-1-proxycontroller.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const rinkebyVaultFactory = "0xbbc53022Af15Bb973AD906577c84784c47C14371"; 15 | const rinkebyFeeDistributor = "0x29F52f4Df3Ae7bd736305c035d45EBa563CD7A2f"; 16 | const rinkebyLPStaking = "0xcd0dfb870A60C30D957b0DF1D180a236a55b5740"; 17 | const rinkebyStakingTokenProv = "0x262FEeCBac8Ee97200F060aeFd89BD41b961e526"; 18 | const rinkebyInventoryStaking = "0x05aD54B40e3be8252CB257f77d9301E9CB1A9470"; 19 | const rinkebyEligManager = "0x0256B5E9bE57D8e14BAdfF94fD79760cC44A33c2"; 20 | 21 | const ProxyController = await ethers.getContractFactory( 22 | "MultiProxyController" 23 | ); 24 | const proxyController = await ProxyController.deploy( 25 | [ 26 | "NFTX Factory", 27 | "Fee Distributor", 28 | "LP Staking", 29 | "StakingTokenProvider", 30 | "Eligibility Manager", 31 | "Inventory Staking", 32 | ], 33 | [ 34 | rinkebyVaultFactory, 35 | rinkebyFeeDistributor, 36 | rinkebyLPStaking, 37 | rinkebyStakingTokenProv, 38 | rinkebyEligManager, 39 | rinkebyInventoryStaking, 40 | ] 41 | ); 42 | await proxyController.deployed(); 43 | console.log("ProxyController:", proxyController.address); 44 | 45 | const rinkebyMultiProxyController = proxyController.address; 46 | 47 | const existingProxyController = await ethers.getContractAt( 48 | "ProxyController", 49 | "0xD6f0Dd9400E89A7062a20f8E06bf8C083b184508" 50 | ); 51 | 52 | console.log("Chaging vault factory proxy admin..."); 53 | await existingProxyController.changeProxyAdmin( 54 | 0, 55 | rinkebyMultiProxyController, 56 | { 57 | gasLimit: "300000", 58 | } 59 | ); 60 | console.log("Chaging fee distributor proxy admin..."); 61 | await existingProxyController.changeProxyAdmin( 62 | 4, 63 | rinkebyMultiProxyController, 64 | { 65 | gasLimit: "300000", 66 | } 67 | ); 68 | console.log("Chaging LP staking proxy admin..."); 69 | await existingProxyController.changeProxyAdmin( 70 | 3, 71 | rinkebyMultiProxyController, 72 | { 73 | gasLimit: "300000", 74 | } 75 | ); 76 | console.log("Chaging staking token provider proxy admin..."); 77 | await existingProxyController.changeProxyAdmin( 78 | 2, 79 | rinkebyMultiProxyController, 80 | { 81 | gasLimit: "300000", 82 | } 83 | ); 84 | console.log("Chaging eligibility manager proxy admin..."); 85 | await existingProxyController.changeProxyAdmin( 86 | 1, 87 | rinkebyMultiProxyController, 88 | { 89 | gasLimit: "300000", 90 | } 91 | ); 92 | console.log("Chaging inventory staking proxy admin..."); 93 | await upgrades.admin.changeProxyAdmin( 94 | rinkebyInventoryStaking, 95 | rinkebyMultiProxyController 96 | ); 97 | } 98 | 99 | main() 100 | .then(() => { 101 | console.log("\nDeployment completed successfully ✓"); 102 | process.exit(0); 103 | }) 104 | .catch((error) => { 105 | console.log("\nDeployment failed ✗"); 106 | console.error(error); 107 | process.exit(1); 108 | }); 109 | -------------------------------------------------------------------------------- /scripts/2022-2-feedistro.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const FeeDistributor = await ethers.getContractFactory( 15 | "NFTXSimpleFeeDistributor" 16 | ); 17 | const feeDistributorImpl = await FeeDistributor.deploy(); 18 | await feeDistributorImpl.deployed(); 19 | console.log("NFTXSimpleFeeDistributor impl:", feeDistributorImpl.address); 20 | 21 | const rinkebyMultiProxyContr = "0xFc542C7fEA1da20E1195b2476ae35db50925515C"; 22 | 23 | const proxyController = await ethers.getContractAt( 24 | "MultiProxyController", 25 | rinkebyMultiProxyContr 26 | ); 27 | 28 | console.log("Upgrading simple fee distributor contract..."); 29 | 30 | await proxyController.upgradeProxyTo(1, feeDistributorImpl.address, { 31 | gasLimit: "300000", 32 | }); 33 | } 34 | 35 | main() 36 | .then(() => { 37 | console.log("\nDeployment completed successfully ✓"); 38 | process.exit(0); 39 | }) 40 | .catch((error) => { 41 | console.log("\nDeployment failed ✗"); 42 | console.error(error); 43 | process.exit(1); 44 | }); 45 | -------------------------------------------------------------------------------- /scripts/2022-3-lpstaking.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const LPStaking = await ethers.getContractFactory("NFTXLPStaking"); 15 | const lpStakingImpl = await LPStaking.deploy(); 16 | await lpStakingImpl.deployed(); 17 | console.log("NFTXLPStaking impl:", lpStakingImpl.address); 18 | 19 | const rinkebyMultiProxyContr = "0xFc542C7fEA1da20E1195b2476ae35db50925515C"; 20 | 21 | const proxyController = await ethers.getContractAt( 22 | "MultiProxyController", 23 | rinkebyMultiProxyContr 24 | ); 25 | 26 | console.log("Upgrading lp staking contract..."); 27 | 28 | await proxyController.upgradeProxyTo(2, lpStakingImpl.address, { 29 | gasLimit: "300000", 30 | }); 31 | } 32 | 33 | main() 34 | .then(() => { 35 | console.log("\nDeployment completed successfully ✓"); 36 | process.exit(0); 37 | }) 38 | .catch((error) => { 39 | console.log("\nDeployment failed ✗"); 40 | console.error(error); 41 | process.exit(1); 42 | }); 43 | -------------------------------------------------------------------------------- /scripts/2022-4-vault.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const VaultTemplate = await ethers.getContractFactory("NFTXVaultUpgradeable"); 15 | const vaultTemplateImpl = await VaultTemplate.deploy(); 16 | await vaultTemplateImpl.deployed(); 17 | console.log("NFTXVaultUpgradeable impl:", vaultTemplateImpl.address); 18 | 19 | const rinkebyVaultFactory = "0xbbc53022Af15Bb973AD906577c84784c47C14371"; 20 | 21 | const vaultFactory = await ethers.getContractAt( 22 | "NFTXVaultFactoryUpgradeable", 23 | rinkebyVaultFactory 24 | ); 25 | 26 | console.log("Upgrading vault template contract..."); 27 | 28 | await vaultFactory.upgradeChildTo(vaultTemplateImpl.address, { 29 | gasLimit: "300000", 30 | }); 31 | } 32 | 33 | main() 34 | .then(() => { 35 | console.log("\nDeployment completed successfully ✓"); 36 | process.exit(0); 37 | }) 38 | .catch((error) => { 39 | console.log("\nDeployment failed ✗"); 40 | console.error(error); 41 | process.exit(1); 42 | }); 43 | -------------------------------------------------------------------------------- /scripts/2022-5-configure.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const rinkebyFeeDistributor = "0x29F52f4Df3Ae7bd736305c035d45EBa563CD7A2f"; 15 | const rinkebyInvStaking = "0x05aD54B40e3be8252CB257f77d9301E9CB1A9470"; 16 | 17 | const feeDistributor = await ethers.getContractAt( 18 | "NFTXSimpleFeeDistributor", 19 | rinkebyFeeDistributor 20 | ); 21 | 22 | console.log("Upgrading inventory staking address..."); 23 | 24 | await feeDistributor.setInventoryStakingAddress(rinkebyInvStaking, { 25 | gasLimit: 100000, 26 | }); 27 | 28 | console.log("Updating inventory staking fee receiver address..."); 29 | 30 | await feeDistributor.changeReceiverAddress(1, rinkebyInvStaking, true, { 31 | gasLimit: 100000, 32 | }); 33 | } 34 | 35 | main() 36 | .then(() => { 37 | console.log("\nDeployment completed successfully ✓"); 38 | process.exit(0); 39 | }) 40 | .catch((error) => { 41 | console.log("\nDeployment failed ✗"); 42 | console.error(error); 43 | process.exit(1); 44 | }); 45 | -------------------------------------------------------------------------------- /scripts/2022-6-stakingzap.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const rinkebyVaultFactory = "0xbbc53022Af15Bb973AD906577c84784c47C14371"; 15 | const rinkebySushiRouter = "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506"; 16 | 17 | const StakingZap = await ethers.getContractFactory("NFTXStakingZap"); 18 | const stakingZap = await StakingZap.deploy( 19 | rinkebyVaultFactory, 20 | rinkebySushiRouter 21 | ); 22 | await stakingZap.deployed(); 23 | console.log("Staking Zap: ", stakingZap.address); 24 | 25 | console.log("Setting lp lock time..."); 26 | await stakingZap.setLPLockTime(600); 27 | 28 | console.log("Setting inventory lock time..."); 29 | await stakingZap.setInventoryLockTime(800); 30 | 31 | const vaultFactory = await ethers.getContractAt( 32 | "NFTXVaultFactoryUpgradeable", 33 | rinkebyVaultFactory 34 | ); 35 | 36 | console.log("Setting fee exclusion..."); 37 | await vaultFactory.setFeeExclusion(stakingZap.address, true, { 38 | gasLimit: 100000, 39 | }); 40 | } 41 | 42 | main() 43 | .then(() => { 44 | console.log("\nDeployment completed successfully ✓"); 45 | process.exit(0); 46 | }) 47 | .catch((error) => { 48 | console.log("\nDeployment failed ✗"); 49 | console.error(error); 50 | process.exit(1); 51 | }); 52 | -------------------------------------------------------------------------------- /scripts/2022-7-mpzap.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const rinkebyVaultFactory = "0xbbc53022Af15Bb973AD906577c84784c47C14371"; 15 | const rinkebySushiRouter = "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506"; 16 | 17 | const MarketplaceZap = await ethers.getContractFactory("NFTXMarketplaceZap"); 18 | const marketplaceZap = await MarketplaceZap.deploy( 19 | rinkebyVaultFactory, 20 | rinkebySushiRouter 21 | ); 22 | await marketplaceZap.deployed(); 23 | console.log("MarketplaceZap: ", marketplaceZap.address); 24 | } 25 | 26 | main() 27 | .then(() => { 28 | console.log("\nDeployment completed successfully ✓"); 29 | process.exit(0); 30 | }) 31 | .catch((error) => { 32 | console.log("\nDeployment failed ✗"); 33 | console.error(error); 34 | process.exit(1); 35 | }); 36 | -------------------------------------------------------------------------------- /scripts/assign-default-features.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | const notZeroAddr = "0x000000000000000000000000000000000000dead"; 5 | 6 | async function main() { 7 | const [deployer] = await ethers.getSigners(); 8 | 9 | console.log("Deploying account:", await deployer.getAddress()); 10 | console.log( 11 | "Deploying account balance:", 12 | (await deployer.getBalance()).toString(), 13 | "\n" 14 | ); 15 | 16 | const factory = await ethers.getContractAt("NFTXVaultFactoryUpgradeable", "0xBE86f647b167567525cCAAfcd6f881F1Ee558216") 17 | const vaults = await factory.allVaults(); 18 | 19 | for (let i = 0; i < vaults.length; i++) { 20 | const vault = await ethers.getContractAt("NFTXVaultUpgradeable", vaults[i]) 21 | const randomRedeem = await vault.enableRandomRedeem() 22 | const randomSwap = await vault.enableRandomSwap(); 23 | if (randomRedeem != randomSwap) { 24 | console.log(i, await vault.symbol(), vaults[i]) 25 | let tx = await vault.assignDefaultFeatures(); 26 | await tx.wait(); 27 | } 28 | } 29 | } 30 | 31 | main() 32 | .then(() => { 33 | console.log("\nDeployment completed successfully ✓"); 34 | process.exit(0); 35 | }) 36 | .catch((error) => { 37 | console.log("\nDeployment failed ✗"); 38 | console.error(error); 39 | process.exit(1); 40 | }); 41 | -------------------------------------------------------------------------------- /scripts/deploy-lpstaking-impl.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const NFTXLPStaking = await ethers.getContractFactory("NFTXLPStaking"); 15 | const lpStaking = await NFTXLPStaking.deploy(); 16 | await lpStaking.deployed(); 17 | console.log("NFTXLPStaking impl:", lpStaking.address); 18 | } 19 | 20 | main() 21 | .then(() => { 22 | console.log("\nDeployment completed successfully ✓"); 23 | process.exit(0); 24 | }) 25 | .catch((error) => { 26 | console.log("\nDeployment failed ✗"); 27 | console.error(error); 28 | process.exit(1); 29 | }); 30 | -------------------------------------------------------------------------------- /scripts/deploy-marketplace-zap.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | const notZeroAddr = "0x000000000000000000000000000000000000dead"; 5 | 6 | async function main() { 7 | const [deployer] = await ethers.getSigners(); 8 | 9 | console.log("Deploying account:", await deployer.getAddress()); 10 | console.log( 11 | "Deploying account balance:", 12 | (await deployer.getBalance()).toString(), 13 | "\n" 14 | ); 15 | 16 | const MarketZap = await ethers.getContractFactory( 17 | "NFTXMarketplaceZap" 18 | ); 19 | const zap = await MarketZap.deploy("0x8c9ECD518C7805e82cd6DC148e1c8902cb5d3655", "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506"); 20 | await zap.deployed(); 21 | console.log("Marketplace Zap:", zap.address); 22 | } 23 | 24 | main() 25 | .then(() => { 26 | console.log("\nDeployment completed successfully ✓"); 27 | process.exit(0); 28 | }) 29 | .catch((error) => { 30 | console.log("\nDeployment failed ✗"); 31 | console.error(error); 32 | process.exit(1); 33 | }); 34 | -------------------------------------------------------------------------------- /scripts/deploy-marketplace0x-zap.js: -------------------------------------------------------------------------------- 1 | const {BigNumber} = require("@ethersproject/bignumber"); 2 | const {ethers, upgrades} = require("hardhat"); 3 | 4 | const notZeroAddr = "0x000000000000000000000000000000000000dead"; 5 | 6 | async function main() { 7 | const [deployer] = await ethers.getSigners(); 8 | 9 | console.log("Deploying account:", await deployer.getAddress()); 10 | console.log( 11 | "Deploying account balance:", 12 | (await deployer.getBalance()).toString(), 13 | "\n" 14 | ); 15 | 16 | const MarketZap = await ethers.getContractFactory( 17 | "NFTXMarketplace0xZap" 18 | ); 19 | const zap = await MarketZap.deploy("0xe01Cf5099e700c282A56E815ABd0C4948298Afae", "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6"); 20 | await zap.deployed(); 21 | console.log("Marketplace Zap:", zap.address); 22 | } 23 | 24 | main() 25 | .then(() => { 26 | console.log("\nDeployment completed successfully ✓"); 27 | process.exit(0); 28 | }) 29 | .catch((error) => { 30 | console.log("\nDeployment failed ✗"); 31 | console.error(error); 32 | process.exit(1); 33 | }); 34 | -------------------------------------------------------------------------------- /scripts/deploy-simpfeedist.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const lpStaking = "0x73D2ff81fceA9832FC9Ee90521ABde1150F6b52a"; 15 | const controller = "0xDEA9196Dcdd2173D6E369c2AcC0faCc83fD9346a"; 16 | 17 | const Sfd = await ethers.getContractFactory("NFTXSimpleFeeDistributor"); 18 | const sfd = await upgrades.deployProxy(Sfd, [lpStaking, controller], { 19 | initializer: "__SimpleFeeDistributor__init__", 20 | }); 21 | await sfd.deployed(); 22 | console.log("SimpleFeeDistributor:", sfd.address); 23 | } 24 | 25 | main() 26 | .then(() => { 27 | console.log("\nDeployment completed successfully ✓"); 28 | process.exit(0); 29 | }) 30 | .catch((error) => { 31 | console.log("\nDeployment failed ✗"); 32 | console.error(error); 33 | process.exit(1); 34 | }); 35 | -------------------------------------------------------------------------------- /scripts/deploy-simplefeedistro.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | 15 | const SimpleFeeDistributor = await ethers.getContractFactory("NFTXSimpleFeeDistributor"); 16 | const simpleFeeDistrib = await upgrades.deployProxy( 17 | SimpleFeeDistributor, 18 | ["0x688c3E4658B5367da06fd629E41879beaB538E37", "0x40d73df4f99bae688ce3c23a01022224fe16c7b2"], 19 | { 20 | initializer: "__SimpleFeeDistributor__init__", 21 | } 22 | ); 23 | await simpleFeeDistrib.deployed(); 24 | 25 | await simpleFeeDistrib.setNFTXVaultFactory("0xBE86f647b167567525cCAAfcd6f881F1Ee558216"); 26 | console.log("SimpleFeeDistributor:", simpleFeeDistrib.address); 27 | } 28 | 29 | main() 30 | .then(() => { 31 | console.log("\nDeployment completed successfully ✓"); 32 | process.exit(0); 33 | }) 34 | .catch((error) => { 35 | console.log("\nDeployment failed ✗"); 36 | console.error(error); 37 | process.exit(1); 38 | }); 39 | -------------------------------------------------------------------------------- /scripts/deploy-staking-zap.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | const notZeroAddr = "0x000000000000000000000000000000000000dead"; 5 | 6 | async function main() { 7 | const [deployer] = await ethers.getSigners(); 8 | 9 | console.log("Deploying account:", await deployer.getAddress()); 10 | console.log( 11 | "Deploying account balance:", 12 | (await deployer.getBalance()).toString(), 13 | "\n" 14 | ); 15 | 16 | const StakingZap = await ethers.getContractFactory( 17 | "NFTXStakingZap" 18 | ); 19 | const zap = await StakingZap.deploy("0x8c9ECD518C7805e82cd6DC148e1c8902cb5d3655", "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506"); 20 | await zap.deployed(); 21 | console.log("Staking Zap:", zap.address); 22 | } 23 | 24 | main() 25 | .then(() => { 26 | console.log("\nDeployment completed successfully ✓"); 27 | process.exit(0); 28 | }) 29 | .catch((error) => { 30 | console.log("\nDeployment failed ✗"); 31 | console.error(error); 32 | process.exit(1); 33 | }); 34 | -------------------------------------------------------------------------------- /scripts/deploy-test-sushi-provider.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const StakingProvider = await ethers.getContractFactory( 15 | "StakingTokenProvider" 16 | ); 17 | const provider = await upgrades.deployProxy( 18 | StakingProvider, 19 | [ 20 | "0xc35DADB65012eC5796536bD9864eD8773aBc74C4" /*Sushiswap*/, 21 | "0xc778417e063141139fce010982780140aa0cd5ab" /*WETH*/, 22 | "x", 23 | ], 24 | { 25 | initializer: "__StakingTokenProvider_init", 26 | } 27 | ); 28 | await provider.deployed(); 29 | console.log("StakingTokenProvider:", provider.address); 30 | } 31 | 32 | main() 33 | .then(() => { 34 | console.log("\nDeployment completed successfully ✓"); 35 | process.exit(0); 36 | }) 37 | .catch((error) => { 38 | console.log("\nDeployment failed ✗"); 39 | console.error(error); 40 | process.exit(1); 41 | }); 42 | -------------------------------------------------------------------------------- /scripts/deploy-upgradeable.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | const treasuryAddr = "0x40d73df4f99bae688ce3c23a01022224fe16c7b2"; 5 | 6 | const daoAddress = treasuryAddr; 7 | 8 | const founderAddress = "0x8F217D5cCCd08fD9dCe24D6d42AbA2BB4fF4785B"; 9 | 10 | // const teamAddresses = [ 11 | // "0x701f373Df763308D96d8537822e8f9B2bAe4E847", // gaus1 12 | // "0x4586554a30148B8F4F3AB17E57C430eE193698Ec", // gaus2 13 | // "0x08D816526BdC9d077DD685Bd9FA49F58A5Ab8e48", // kiwi 14 | // "0x3FCe5449C7449983e263227c5AAEACB4A80B87C9", // quag 15 | // "0x4eAc46c2472b32dc7158110825A7443D35a90168", // javery 16 | // "0x45d28aA363fF215B4c6b6a212DC610f004272bb5", // chop 17 | // ]; 18 | 19 | async function main() { 20 | const [deployer] = await ethers.getSigners(); 21 | 22 | console.log("Deploying account:", await deployer.getAddress()); 23 | console.log( 24 | "Deploying account balance:", 25 | (await deployer.getBalance()).toString(), 26 | "\n" 27 | ); 28 | 29 | const NFTXV1Buyout = await ethers.getContractFactory("NFTXV1Buyout"); 30 | const v1Buyout = await upgrades.deployProxy(NFTXV1Buyout, [], { 31 | initializer: "__NFTXV1Buyout_init", 32 | }); 33 | await v1Buyout.deployed(); 34 | 35 | console.log("NFTXV1Buyout:", v1Buyout.address); 36 | 37 | const ProxyController = await ethers.getContractFactory( 38 | "ProxyControllerSimple" 39 | ); 40 | 41 | const proxyController = await ProxyController.deploy(v1Buyout.address); 42 | await proxyController.deployed(); 43 | console.log("ProxyController address:", proxyController.address); 44 | 45 | console.log("\nUpdating proxy admin..."); 46 | 47 | await upgrades.admin.changeProxyAdmin( 48 | v1Buyout.address, 49 | proxyController.address 50 | ); 51 | 52 | console.log("Fetching implementation addresses..."); 53 | 54 | await proxyController.fetchImplAddress({ 55 | gasLimit: "150000", 56 | }); 57 | 58 | console.log("Implementation address:", await proxyController.impl()); 59 | 60 | console.log("Transfering ownerships..."); 61 | await v1Buyout.transferOwnership(founderAddress); 62 | await proxyController.transferOwnership(founderAddress); 63 | 64 | console.log(""); 65 | } 66 | 67 | main() 68 | .then(() => { 69 | console.log("\nDeployment completed successfully ✓"); 70 | process.exit(0); 71 | }) 72 | .catch((error) => { 73 | console.log("\nDeployment failed ✗"); 74 | console.error(error); 75 | process.exit(1); 76 | }); 77 | -------------------------------------------------------------------------------- /scripts/deploy-vault-impl.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const Vault = await ethers.getContractFactory("NFTXVaultUpgradeable"); 15 | const vaultImpl = await Vault.deploy(); 16 | await vaultImpl.deployed(); 17 | console.log("Vault Impl:", vaultImpl.address); 18 | } 19 | 20 | main() 21 | .then(() => { 22 | console.log("\nDeployment completed successfully ✓"); 23 | process.exit(0); 24 | }) 25 | .catch((error) => { 26 | console.log("\nDeployment failed ✗"); 27 | console.error(error); 28 | process.exit(1); 29 | }); 30 | -------------------------------------------------------------------------------- /scripts/goerli/2-bootstrap.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | const { utils } = ethers; 4 | const { formatEther, parseEther } = utils; 5 | 6 | // const treasury = "0x40d73df4f99bae688ce3c23a01022224fe16c7b2"; 7 | 8 | const devAddress = "0xDEA9196Dcdd2173D6E369c2AcC0faCc83fD9346a"; 9 | const notZeroAddr = "0x000000000000000000000000000000000000dead"; 10 | 11 | let sushiRouterAddr = "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506"; 12 | let sushiFactoryAddr = "0xc35DADB65012eC5796536bD9864eD8773aBc74C4"; 13 | let wethAddress = "0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6"; 14 | 15 | const daoAddress = devAddress; 16 | 17 | async function main() { 18 | const [deployer] = await ethers.getSigners(); 19 | 20 | const myAddress = await deployer.getAddress(); 21 | 22 | console.log("Deploying account:", myAddress); 23 | console.log("Deploying account balance:", (await deployer.getBalance()).toString(), "\n"); 24 | 25 | const vaultFactory = await ethers.getContractAt( 26 | "NFTXVaultFactoryUpgradeable", 27 | "0xe01Cf5099e700c282A56E815ABd0C4948298Afae" 28 | ); 29 | const stakingZap = await ethers.getContractAt("NFTXStakingZap", "0xd9A60945DD4b3a5Ea91480e82dA20D3AceC5D857"); 30 | 31 | // const nft = await ethers.getContractAt("ERC721", "0x2D77756C139ed3c25472Daf233F332E8F605Dd8E"); 32 | 33 | const Erc721 = await ethers.getContractFactory("ERC721"); 34 | const nft = await Erc721.deploy("CryptoSloths", "CS"); 35 | await nft.deployed(); 36 | console.log("CryptoSloths NFT:", nft.address); 37 | 38 | const numMints = 10; 39 | for (let tokenId = 0; tokenId < numMints; tokenId++) { 40 | await nft.publicMint(myAddress, tokenId, { gasLimit: 100000 }); 41 | console.log("next.."); 42 | } 43 | console.log("-- minted " + numMints + " CryptoSloths"); 44 | 45 | await vaultFactory.createVault("CryptoSloths", "SLOTH", nft.address, false, true); 46 | console.log("-- created vault"); 47 | 48 | const numVaults = await vaultFactory.numVaults(); 49 | const vaultId = numVaults.sub(1); 50 | const vaultAddr = await vaultFactory.vault(vaultId); 51 | console.log("Vault address:", vaultAddr); 52 | const vault = await ethers.getContractAt("NFTXVaultUpgradeable", vaultAddr); 53 | await vault.finalizeVault(); 54 | console.log("-- finalized vault"); 55 | 56 | await nft.setApprovalForAll(stakingZap.address, true); 57 | console.log("-- approved NFTs to stakingzap"); 58 | await stakingZap.provideInventory721(vaultId, [0, 1], { gasLimit: "1000000" }); 59 | console.log("-- inventory staked NFTs"); 60 | await stakingZap.addLiquidity721ETH(vaultId, [2, 3, 4, 5, 6, 7], 0, { 61 | value: parseEther("0.18"), 62 | gasLimit: "1000000", 63 | }); 64 | console.log("-- liquidity staked NFTs"); 65 | } 66 | 67 | main() 68 | .then(() => { 69 | console.log("\nDeployment completed successfully ✓"); 70 | process.exit(0); 71 | }) 72 | .catch((error) => { 73 | console.log("\nDeployment failed ✗"); 74 | console.error(error); 75 | process.exit(1); 76 | }); 77 | -------------------------------------------------------------------------------- /scripts/goerli/simple-script.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | const { utils } = ethers; 4 | const { formatEther, parseEther } = utils; 5 | 6 | async function main() { 7 | const [deployer] = await ethers.getSigners(); 8 | 9 | const myAddress = await deployer.getAddress(); 10 | 11 | console.log("Deploying account:", myAddress); 12 | console.log("Deploying account balance:", (await deployer.getBalance()).toString(), "\n"); 13 | 14 | let factory = await ethers.getContractAt( 15 | "NFTXVaultFactoryUpgradeable", 16 | "0xe01Cf5099e700c282A56E815ABd0C4948298Afae" 17 | ); 18 | 19 | let proxyController = await ethers.getContractAt( 20 | "MultiProxyController", 21 | "0xbde65406B20ADb4ba9D88908187Bc9460fF24da9" 22 | ); 23 | 24 | 25 | } 26 | 27 | main() 28 | .then(() => { 29 | console.log("\nDeployment completed successfully ✓"); 30 | process.exit(0); 31 | }) 32 | .catch((error) => { 33 | console.log("\nDeployment failed ✗"); 34 | console.error(error); 35 | process.exit(1); 36 | }); 37 | -------------------------------------------------------------------------------- /scripts/goerli/staker-fee-distrib-update.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | const { utils } = ethers; 4 | const { formatEther, parseEther } = utils; 5 | 6 | let factory, proxyController; 7 | 8 | async function main() { 9 | const [deployer] = await ethers.getSigners(); 10 | 11 | const myAddress = await deployer.getAddress(); 12 | 13 | console.log("Deploying account:", myAddress); 14 | console.log("Deploying account balance:", (await deployer.getBalance()).toString(), "\n"); 15 | 16 | factory = await ethers.getContractAt( 17 | "NFTXVaultFactoryUpgradeable", 18 | "0xe01Cf5099e700c282A56E815ABd0C4948298Afae" 19 | ); 20 | 21 | proxyController = await ethers.getContractAt( 22 | "MultiProxyController", 23 | "0xbde65406B20ADb4ba9D88908187Bc9460fF24da9" 24 | ); 25 | 26 | // Upgrade fee distributor 27 | const FeeDistrImpl = await ethers.getContractFactory("NFTXSimpleFeeDistributor"); 28 | const feeDistrImpl = await FeeDistrImpl.deploy(); 29 | await feeDistrImpl.deployed(); 30 | console.log("\nfeeDistrImpl:", feeDistrImpl.address); 31 | 32 | await proxyController.upgradeProxyTo(1, feeDistrImpl.address, {gasLimit: 650000}); 33 | console.log("feeDistr upgraded"); 34 | 35 | // Upgrade LP staking 36 | const LPStakingImpl = await ethers.getContractFactory("NFTXLPStaking"); 37 | const lpStakingImpl = await LPStakingImpl.deploy(); 38 | await lpStakingImpl.deployed(); 39 | console.log("\nlpStakingImpl:", lpStakingImpl.address); 40 | 41 | await proxyController.upgradeProxyTo(2, lpStakingImpl.address, {gasLimit: 650000}); 42 | console.log("lpStaking upgraded"); 43 | 44 | // Upgrade inventory staking 45 | const InvStakingImpl = await ethers.getContractFactory("NFTXInventoryStaking"); 46 | const invStakingImpl = await InvStakingImpl.deploy(); 47 | await invStakingImpl.deployed(); 48 | console.log("\ninvStakingImpl:", invStakingImpl.address); 49 | 50 | await proxyController.upgradeProxyTo(5, invStakingImpl.address, {gasLimit: 650000}); 51 | console.log("invStaking upgraded"); 52 | 53 | // Upgrade vault template 54 | const VaultImpl = await ethers.getContractFactory("NFTXVaultUpgradeable"); 55 | const vaultImpl = await VaultImpl.deploy(); 56 | await vaultImpl.deployed(); 57 | console.log("\nvaultImpl:", vaultImpl.address); 58 | 59 | await factory.upgradeChildTo(vaultImpl.address, {gasLimit: 650000}); 60 | console.log("vaultImpl upgraded"); 61 | } 62 | 63 | main() 64 | .then(() => { 65 | console.log("\nDeployment completed successfully ✓"); 66 | process.exit(0); 67 | }) 68 | .catch((error) => { 69 | console.log("\nDeployment failed ✗"); 70 | console.error(error); 71 | process.exit(1); 72 | }); 73 | -------------------------------------------------------------------------------- /scripts/mainnet-upgrade.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | const treasuryAddr = "0x40d73df4f99bae688ce3c23a01022224fe16c7b2"; 5 | 6 | const daoAddress = treasuryAddr; 7 | 8 | async function main() { 9 | const [deployer] = await ethers.getSigners(); 10 | 11 | console.log("Deploying account:", await deployer.getAddress()); 12 | console.log( 13 | "Deploying account balance:", 14 | (await deployer.getBalance()).toString(), 15 | "\n" 16 | ); 17 | 18 | const StakingProvider = await ethers.getContractFactory( 19 | "StakingTokenProvider" 20 | ); 21 | const provider = await upgrades.deployProxy( 22 | StakingProvider, 23 | [ 24 | "0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac" /*Sushiswap*/, 25 | "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" /*WETH*/, 26 | "x", 27 | ], 28 | { 29 | initializer: "__StakingTokenProvider_init", 30 | } 31 | ); 32 | await provider.deployed(); 33 | console.log("StakingTokenProvider:", provider.address); 34 | 35 | const ProxyController = await ethers.getContractFactory("ProxyController"); 36 | const proxyController = await ProxyController.deploy( 37 | "0xBE86f647b167567525cCAAfcd6f881F1Ee558216", // factory 38 | "0x4086e98Cce041d286112d021612fD894cFed94D5", // eligmanager 39 | provider.address, 40 | "0x688c3E4658B5367da06fd629E41879beaB538E37", // staking 41 | "0x7AE9D7Ee8489cAD7aFc84111b8b185EE594Ae090" // feedistributor 42 | ); 43 | await proxyController.deployed(); 44 | console.log("ProxyController address:", proxyController.address); 45 | 46 | console.log("\nUpdating proxy admin..."); 47 | await upgrades.admin.changeProxyAdmin( 48 | provider.address, 49 | proxyController.address 50 | ); 51 | 52 | console.log("Fetching implementation address..."); 53 | await proxyController.fetchImplAddress(2, { 54 | gasLimit: "150000", 55 | }); 56 | 57 | console.log("Transfering ownership..."); 58 | await provider.transferOwnership(daoAddress); 59 | } 60 | 61 | main() 62 | .then(() => { 63 | console.log("\nDeployment completed successfully ✓"); 64 | process.exit(0); 65 | }) 66 | .catch((error) => { 67 | console.log("\nDeployment failed ✗"); 68 | console.error(error); 69 | process.exit(1); 70 | }); 71 | -------------------------------------------------------------------------------- /scripts/retrieve-tokens-upgrade.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const VaultImpl = await ethers.getContractFactory("NFTXVaultUpgradeable"); 15 | const vaultImpl = await VaultImpl.deploy(); 16 | await vaultImpl.deployed(); 17 | 18 | console.log('vault implementation deployed at:', vaultImpl.address); 19 | 20 | const LPStaking = await ethers.getContractFactory("NFTXLPStaking"); 21 | const lpStaking = await LPStaking.deploy(); 22 | await lpStaking.deployed(); 23 | 24 | console.log('lpstaking deployed at:', lpStaking.address ,'\n'); 25 | 26 | console.log('1) set child implementation on vault factory') 27 | console.log('2) set lpstaking impl on proxycontroller') 28 | 29 | } 30 | 31 | main() 32 | .then(() => { 33 | console.log("\nDeployment completed successfully ✓"); 34 | process.exit(0); 35 | }) 36 | .catch((error) => { 37 | console.log("\nDeployment failed ✗"); 38 | console.error(error); 39 | process.exit(1); 40 | }); 41 | ` -------------------------------------------------------------------------------- /scripts/ropsten/2-bootstrap.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | const { utils } = ethers; 4 | const { formatEther, parseEther } = utils; 5 | 6 | // const treasury = "0x40d73df4f99bae688ce3c23a01022224fe16c7b2"; 7 | 8 | const devAddress = "0xDEA9196Dcdd2173D6E369c2AcC0faCc83fD9346a"; 9 | const notZeroAddr = "0x000000000000000000000000000000000000dead"; 10 | 11 | let sushiRouterAddr = "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506"; 12 | let sushiFactoryAddr = "0xc35DADB65012eC5796536bD9864eD8773aBc74C4"; 13 | let wethAddress = "0xc778417E063141139Fce010982780140Aa0cD5Ab"; 14 | 15 | const daoAddress = devAddress; 16 | 17 | async function main() { 18 | const [deployer] = await ethers.getSigners(); 19 | 20 | const myAddress = await deployer.getAddress(); 21 | 22 | console.log("Deploying account:", myAddress); 23 | console.log("Deploying account balance:", (await deployer.getBalance()).toString(), "\n"); 24 | 25 | const vaultFactory = await ethers.getContractAt( 26 | "NFTXVaultFactoryUpgradeable", 27 | "0xfaB3a8739E9ED9D5aa3a43F4A8442610746b57E5" 28 | ); 29 | const stakingZap = await ethers.getContractAt( 30 | "NFTXStakingZap", 31 | "0xcA523fBAf06a157F3D96735b6fC0626323a65BAa" 32 | ); 33 | 34 | 35 | const Erc721 = await ethers.getContractFactory("ERC721"); 36 | nft = await Erc721.deploy("CryptoSloths", "CS"); 37 | await nft.deployed(); 38 | console.log("CryptoSloths NFT:", nft.address); 39 | 40 | const numMints = 10; 41 | for (let tokenId = 0; tokenId < numMints; tokenId++) { 42 | await nft.publicMint(myAddress, tokenId); 43 | } 44 | console.log("-- minted " + numMints + " CryptoSloths"); 45 | 46 | await vaultFactory.createVault("CryptoSloths", "SLOTH", nft.address, false, true); 47 | console.log("-- created vault"); 48 | 49 | const numVaults = await vaultFactory.numVaults(); 50 | const vaultId = numVaults.sub(1); 51 | const vaultAddr = await vaultFactory.vault(vaultId); 52 | const vault = await ethers.getContractAt("NFTXVaultUpgradeable", vaultAddr); 53 | await vault.finalizeVault(); 54 | console.log("-- finalized vault"); 55 | 56 | await nft.setApprovalForAll(stakingZap.address, true); 57 | console.log("-- approved NFTs to stakingzap"); 58 | await stakingZap.provideInventory721(vaultId, [0, 1], { gasLimit: "1000000" }); 59 | console.log('-- inventory staked NFTs') 60 | await stakingZap.addLiquidity721ETH(vaultId, [2, 3, 4, 5, 6, 7], 0, { value: parseEther("0.6"), gasLimit: "1000000" }); 61 | console.log('-- liquidity staked NFTs') 62 | } 63 | 64 | main() 65 | .then(() => { 66 | console.log("\nDeployment completed successfully ✓"); 67 | process.exit(0); 68 | }) 69 | .catch((error) => { 70 | console.log("\nDeployment failed ✗"); 71 | console.error(error); 72 | process.exit(1); 73 | }); 74 | -------------------------------------------------------------------------------- /scripts/simple-script.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | const vault = await ethers.getContractAt("NFTXVaultUpgradeable", "0x13edcC775f8895961B81Db5C0205889B3Afb3A16"); 15 | 16 | await vault.setVaultMetadata("Ringers (VOID)", "RINGER-VOID"); 17 | 18 | } 19 | 20 | main() 21 | .then(() => { 22 | console.log("\nDeployment completed successfully ✓"); 23 | process.exit(0); 24 | }) 25 | .catch((error) => { 26 | console.log("\nDeployment failed ✗"); 27 | console.error(error); 28 | process.exit(1); 29 | }); 30 | -------------------------------------------------------------------------------- /scripts/timelock-exclusion-upgrade.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log("Deploying account balance:", (await deployer.getBalance()).toString(), "\n"); 9 | 10 | const mainnet = { 11 | factory: "0xBE86f647b167567525cCAAfcd6f881F1Ee558216", 12 | sushiRouter: "0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F", 13 | dao: "0x40d73df4f99bae688ce3c23a01022224fe16c7b2", 14 | }; 15 | const rinkeby = { 16 | factory: "0xbbc53022Af15Bb973AD906577c84784c47C14371", 17 | sushiRouter: "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506", 18 | }; 19 | const arbitrum = { 20 | factory: "0xe01Cf5099e700c282A56E815ABd0C4948298Afae", 21 | sushiRouter: "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506", 22 | }; 23 | 24 | const TimelockExcludeList = await ethers.getContractFactory("TimelockExcludeList"); 25 | timelockExcludeList = await TimelockExcludeList.deploy(); 26 | await timelockExcludeList.deployed(); 27 | console.log("TimelockExcludeList:", timelockExcludeList.address); 28 | 29 | const StakingZap = await ethers.getContractFactory("NFTXStakingZap"); 30 | const stakingZap = await StakingZap.deploy(mainnet.factory, mainnet.sushiRouter); 31 | await stakingZap.deployed(); 32 | console.log("StakingZap: ", stakingZap.address); 33 | 34 | const InventoryStaking = await ethers.getContractFactory("NFTXInventoryStaking"); 35 | const inventoryStakingImpl = await InventoryStaking.deploy(); 36 | await inventoryStakingImpl.deployed(); 37 | console.log("InventoryStaking Impl:", inventoryStakingImpl.address, "\n"); 38 | 39 | console.log("Setting TimelockExclusionList on StakingZap..."); 40 | await stakingZap.setTimelockExcludeList(timelockExcludeList.address); 41 | console.log("Set TimelockExclusionList on StakingZap ✓\n "); 42 | 43 | // Mainnet only 44 | console.log("Transfering ownership of StakingZap to dao..."); 45 | await stakingZap.transferOwnership(mainnet.dao); 46 | console.log("Transferred ownership of StakingZap to dao ✓\n"); 47 | console.log("Transfering ownership of TimelockExcludeList to dao..."); 48 | await timelockExcludeList.transferOwnership(mainnet.dao); 49 | console.log("Transferred ownership of TimelockExcludeList to dao ✓\n"); 50 | 51 | // Remaining 52 | console.log("- Upgrade InventoryStaking proxy (5) on MultiProxyController to " + inventoryStakingImpl.address); 53 | console.log("- Set feeExclusion on factory for new StakingZap at " + stakingZap.address); 54 | console.log("- Set zapContract on factory to " + stakingZap.address + "\n"); 55 | console.log("NOTE:"); 56 | console.log( 57 | "zapContract setting on factory must get enacted at same time as frontend updates stakingZap address\n" 58 | ); 59 | console.log("- After inventory staking proxy update is enacted then.."); 60 | console.log(" 1) set timelockExcludeList on InventoryStaking to " + timelockExcludeList.address); 61 | console.log(" 2) set inventoryLockTimeErc20 on InventoryStaking to 604800"); 62 | } 63 | 64 | main() 65 | .then(() => { 66 | console.log("\nDeployment completed successfully ✓"); 67 | process.exit(0); 68 | }) 69 | .catch((error) => { 70 | console.log("\nDeployment failed ✗"); 71 | console.error(error); 72 | process.exit(1); 73 | }); 74 | -------------------------------------------------------------------------------- /scripts/upgrade-lpstaking-and-zap.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | async function main() { 5 | const [deployer] = await ethers.getSigners(); 6 | 7 | console.log("Deploying account:", await deployer.getAddress()); 8 | console.log( 9 | "Deploying account balance:", 10 | (await deployer.getBalance()).toString(), 11 | "\n" 12 | ); 13 | 14 | // const proxyController = await ethers.getContractAt("ProxyController", "0xD6f0Dd9400E89A7062a20f8E06bf8C083b184508"); 15 | // const NFTXLPStaking = await ethers.getContractFactory("NFTXLPStaking"); 16 | // const lpStaking = await NFTXLPStaking.deploy() 17 | // await lpStaking.deployed() 18 | // await proxyController.upgradeProxyTo(3, lpStaking.address) 19 | // console.log("Upgraded") 20 | 21 | 22 | const StakingZap = await ethers.getContractFactory("NFTXStakingZap"); 23 | const stakingZap = await StakingZap.deploy("0xbbc53022Af15Bb973AD906577c84784c47C14371", "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506") 24 | await stakingZap.deployed() 25 | console.log("Staking Zap: ", stakingZap.address) 26 | 27 | const factory = await ethers.getContractAt("NFTXVaultFactoryUpgradeable", "0xbbc53022Af15Bb973AD906577c84784c47C14371") 28 | await factory.setFeeExclusion(stakingZap.address, true); 29 | } 30 | 31 | main() 32 | .then(() => { 33 | console.log("\nDeployment completed successfully ✓"); 34 | process.exit(0); 35 | }) 36 | .catch((error) => { 37 | console.log("\nDeployment failed ✗"); 38 | console.error(error); 39 | process.exit(1); 40 | }); 41 | -------------------------------------------------------------------------------- /scripts/upgrade.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require("@ethersproject/bignumber"); 2 | const { ethers, upgrades } = require("hardhat"); 3 | 4 | const notZeroAddr = "0x000000000000000000000000000000000000dead"; 5 | 6 | async function main() { 7 | const [deployer] = await ethers.getSigners(); 8 | 9 | console.log("Deploying account:", await deployer.getAddress()); 10 | console.log( 11 | "Deploying account balance:", 12 | (await deployer.getBalance()).toString(), 13 | "\n" 14 | ); 15 | 16 | const VaultFactory2 = await ethers.getContractFactory( 17 | "NFTXVaultFactoryUpgradeable2" 18 | ); 19 | const vaultFactory2 = await VaultFactory2.deploy(); 20 | await vaultFactory2.deployed(); 21 | console.log("VaultFactory2:", vaultFactory2.address); 22 | 23 | main() 24 | .then(() => { 25 | console.log("\nDeployment completed successfully ✓"); 26 | process.exit(0); 27 | }) 28 | .catch((error) => { 29 | console.log("\nDeployment failed ✗"); 30 | console.error(error); 31 | process.exit(1); 32 | }); 33 | -------------------------------------------------------------------------------- /test/eligibility-mint-request-test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { expectRevert } = require("../utils/expectRevert"); 3 | 4 | const { BigNumber } = require("@ethersproject/bignumber"); 5 | const { ethers, upgrades } = require("hardhat"); 6 | 7 | const addresses = require("../addresses/rinkeby.json"); 8 | 9 | const BASE = BigNumber.from(10).pow(18); 10 | const zeroAddr = "0x0000000000000000000000000000000000000000"; 11 | const notZeroAddr = "0x000000000000000000000000000000000000dead"; 12 | 13 | let primary, alice; 14 | const vaults = []; 15 | 16 | describe("Main", function () { 17 | before("Setup", async () => { 18 | signers = await ethers.getSigners(); 19 | primary = signers[0]; 20 | alice = signers[1]; 21 | 22 | const Erc721 = await ethers.getContractFactory("ERC721"); 23 | erc721 = await Erc721.deploy(`CryptoPandas`, `CRYPTOPANDAS`); 24 | await erc721.deployed(); 25 | 26 | const Vault = await ethers.getContractFactory("MockVault"); 27 | const vault = await Vault.deploy(erc721.address, false); 28 | await vault.deployed(); 29 | vaults.push(vault); 30 | 31 | const RequestEligibility = await ethers.getContractFactory( 32 | "NFTXMintRequestEligibility" 33 | ); 34 | reqElig = await upgrades.deployProxy( 35 | RequestEligibility, 36 | [primary.address, vault.address, false, []], 37 | { 38 | initializer: "__NFTXEligibility_init", 39 | } 40 | ); 41 | await reqElig.deployed(); 42 | 43 | for (let i = 0; i <= 10; i++) { 44 | await erc721.publicMint(alice.address, i); 45 | } 46 | }); 47 | 48 | it("Should not be eligible before", async () => { 49 | expect(await reqElig.checkAllIneligible([0, 1, 2, 3])).to.equal(true) 50 | }) 51 | 52 | it("Should allow mint requests", async () => { 53 | await erc721.connect(alice).approve(reqElig.address, 0); 54 | await reqElig.connect(alice).requestMint([0], [1]); 55 | await erc721.connect(alice).approve(reqElig.address, 1); 56 | await erc721.connect(alice).approve(reqElig.address, 2); 57 | await erc721.connect(alice).approve(reqElig.address, 3); 58 | await reqElig.connect(alice).requestMint([1, 2, 3], [1, 1, 1]); 59 | }); 60 | 61 | it("Should allow approving mint request", async () => { 62 | await reqElig.approveMintRequests([0], [alice.address], false); 63 | await reqElig.approveMintRequests([1, 2, 3], [alice.address, alice.address, alice.address], true); 64 | await reqElig.connect(alice).claimUnminted([0], [alice.address]); 65 | }); 66 | 67 | it("Should be eligible after", async () => { 68 | expect(await reqElig.checkAllEligible([0, 1, 2, 3])).to.equal(true) 69 | }) 70 | }); 71 | -------------------------------------------------------------------------------- /test/eligibility-range-test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { expectRevert } = require("../utils/expectRevert"); 3 | 4 | const { BigNumber } = require("@ethersproject/bignumber"); 5 | const { ethers, upgrades } = require("hardhat"); 6 | 7 | const addresses = require("../addresses/rinkeby.json"); 8 | 9 | const BASE = BigNumber.from(10).pow(18); 10 | const zeroAddr = "0x0000000000000000000000000000000000000000"; 11 | const notZeroAddr = "0x000000000000000000000000000000000000dead"; 12 | 13 | let primary, alice; 14 | 15 | describe("Eligibility Range", function () { 16 | before("Setup", async () => { 17 | signers = await ethers.getSigners(); 18 | primary = signers[0]; 19 | alice = signers[1]; 20 | 21 | const RangeEligibility = await ethers.getContractFactory( 22 | "NFTXRangeExtendedEligibility" 23 | ); 24 | rangeElig = await upgrades.deployProxy( 25 | RangeEligibility, 26 | [primary.address, 0, 0], 27 | { 28 | initializer: "__NFTXEligibility_init", 29 | } 30 | ); 31 | await rangeElig.deployed(); 32 | }); 33 | it("Should return ineligible when no range set", async () => { 34 | expect(await rangeElig.checkIsEligible(0)).to.equal(false); 35 | expect(await rangeElig.checkIsEligible(42)).to.equal(false); 36 | expect(await rangeElig.checkAllEligible([0])).to.equal(false); 37 | expect(await rangeElig.checkAllEligible([42])).to.equal(false); 38 | expect(await rangeElig.checkAllEligible([0, 42])).to.equal(false); 39 | expect(await rangeElig.checkAllIneligible([0])).to.equal(true); 40 | expect(await rangeElig.checkAllIneligible([42])).to.equal(true); 41 | expect(await rangeElig.checkAllIneligible([0, 42])).to.equal(true); 42 | }); 43 | 44 | it("Should disallow range to be set by user", async () => { 45 | await expectRevert( 46 | rangeElig.connect(alice).setEligibilityPreferences(0, 10) 47 | ); 48 | }); 49 | 50 | it("Should allow range to be set by owner", async () => { 51 | await rangeElig.setEligibilityPreferences(0, 10); 52 | }); 53 | 54 | it("Should return correct boolean", async () => { 55 | const arr = []; 56 | for (let i = 0; i <= 10; i++) { 57 | arr.push(i); 58 | expect(await rangeElig.checkIsEligible(i)).to.equal(true); 59 | } 60 | expect(await rangeElig.checkIsEligible(11)).to.equal(false); 61 | expect(await rangeElig.checkIsEligible(42)).to.equal(false); 62 | expect(await rangeElig.checkAllEligible([0])).to.equal(true); 63 | expect(await rangeElig.checkAllEligible([0, 1])).to.equal(true); 64 | expect(await rangeElig.checkAllEligible(arr)).to.equal(true); 65 | arr.push(11); 66 | expect(await rangeElig.checkAllEligible(arr)).to.equal(false); 67 | expect(await rangeElig.checkAllEligible([0, 42])).to.equal(false); 68 | expect(await rangeElig.checkAllIneligible([42])).to.equal(true); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /test/eligibility-unique-test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { expectRevert } = require("../utils/expectRevert"); 3 | 4 | const { BigNumber } = require("@ethersproject/bignumber"); 5 | const { ethers, upgrades } = require("hardhat"); 6 | 7 | const addresses = require("../addresses/rinkeby.json"); 8 | 9 | const BASE = BigNumber.from(10).pow(18); 10 | const zeroAddr = "0x0000000000000000000000000000000000000000"; 11 | const notZeroAddr = "0x000000000000000000000000000000000000dead"; 12 | 13 | let primary, alice; 14 | const vaults = []; 15 | 16 | let arr = []; 17 | for (let i = 0; i <= 10; i++) { 18 | arr.push(i); 19 | } 20 | 21 | describe("Main", function () { 22 | before("Setup", async () => { 23 | signers = await ethers.getSigners(); 24 | primary = signers[0]; 25 | alice = signers[1]; 26 | 27 | const Erc721 = await ethers.getContractFactory("ERC721"); 28 | erc721 = await Erc721.deploy(`CryptoPandas`, `CRYPTOPANDAS`); 29 | await erc721.deployed(); 30 | 31 | const Vault = await ethers.getContractFactory("MockVault"); 32 | const vault = await Vault.deploy(erc721.address, false); 33 | await vault.deployed(); 34 | vaults.push(vault); 35 | 36 | const UniqueEligibility = await ethers.getContractFactory( 37 | "NFTXUniqueEligibility" 38 | ); 39 | uniqueElig = await upgrades.deployProxy( 40 | UniqueEligibility, 41 | [primary.address, vault.address, false, false, []], 42 | { 43 | initializer: "__NFTXEligibility_init", 44 | } 45 | ); 46 | await uniqueElig.deployed(); 47 | }); 48 | 49 | it("Should return false when no eligibilities are set", async () => { 50 | expect(await uniqueElig.checkIsEligible(0)).to.equal(false); 51 | expect(await uniqueElig.checkIsEligible(42)).to.equal(false); 52 | expect(await uniqueElig.checkAllEligible([0])).to.equal(false); 53 | expect(await uniqueElig.checkAllEligible([42])).to.equal(false); 54 | expect(await uniqueElig.checkAllEligible([0, 42])).to.equal(false); 55 | expect(await uniqueElig.checkAllIneligible([0])).to.equal(true); 56 | expect(await uniqueElig.checkAllIneligible([42])).to.equal(true); 57 | expect(await uniqueElig.checkAllIneligible([0, 42])).to.equal(true); 58 | }); 59 | 60 | it("Should disallow eligibilities to be set by user", async () => { 61 | await expectRevert( 62 | uniqueElig.connect(alice).setUniqueEligibilities(arr, true) 63 | ); 64 | }); 65 | 66 | it("Should allow eligibilities to be set by owner", async () => { 67 | await uniqueElig.setUniqueEligibilities(arr, true); 68 | }); 69 | 70 | it("Should return correct boolean", async () => { 71 | for (let i = 0; i < arr.length; i++) { 72 | const index = arr[i]; 73 | expect(await uniqueElig.checkIsEligible(index)).to.equal(true); 74 | } 75 | expect(await uniqueElig.checkIsEligible(11)).to.equal(false); 76 | expect(await uniqueElig.checkIsEligible(42)).to.equal(false); 77 | expect(await uniqueElig.checkAllEligible([0])).to.equal(true); 78 | expect(await uniqueElig.checkAllEligible([0, 1])).to.equal(true); 79 | expect(await uniqueElig.checkAllEligible(arr)).to.equal(true); 80 | arr.push(11); 81 | expect(await uniqueElig.checkAllEligible(arr)).to.equal(false); 82 | expect(await uniqueElig.checkAllEligible([0, 42])).to.equal(false); 83 | expect(await uniqueElig.checkAllIneligible([42])).to.equal(true); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /test/mainnet/mainnet-set-metadata.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { expectRevert, expectException } = require("../../utils/expectRevert"); 3 | 4 | const { BigNumber } = require("@ethersproject/bignumber"); 5 | const { ethers, network } = require("hardhat"); 6 | const { utils } = ethers; 7 | const { formatEther, parseEther } = utils; 8 | 9 | const BASE = BigNumber.from(10).pow(18); 10 | 11 | let zetsu; 12 | let dao; 13 | let factory; 14 | 15 | const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); 16 | 17 | describe("Mainnet unstaking test ERC721", function () { 18 | before("Setup", async () => { 19 | await network.provider.request({ 20 | method: "hardhat_reset", 21 | params: [ 22 | { 23 | forking: { 24 | jsonRpcUrl: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_MAINNET_API_KEY}`, 25 | blockNumber: 14928953, 26 | }, 27 | }, 28 | ], 29 | }); 30 | 31 | await hre.network.provider.request({ 32 | method: "hardhat_impersonateAccount", 33 | params: ["0xc6c2d5ee69745a1e9f2d1a06e0ef0788bd924302"], 34 | }); 35 | await hre.network.provider.request({ 36 | method: "hardhat_impersonateAccount", 37 | params: ["0x40d73df4f99bae688ce3c23a01022224fe16c7b2"], 38 | }); 39 | 40 | zetsu = await ethers.provider.getSigner("0xc6c2d5ee69745a1e9f2d1a06e0ef0788bd924302"); 41 | dao = await ethers.provider.getSigner("0x40d73df4f99bae688ce3c23a01022224fe16c7b2"); 42 | 43 | factory = await ethers.getContractAt( 44 | "NFTXVaultFactoryUpgradeable", 45 | "0xBE86f647b167567525cCAAfcd6f881F1Ee558216" 46 | ); 47 | }); 48 | 49 | it("Should upgrade vault contract", async () => { 50 | const VaultImpl = await ethers.getContractFactory("NFTXVaultUpgradeable"); 51 | const vaultImpl = await VaultImpl.deploy(); 52 | await vaultImpl.deployed(); 53 | 54 | await factory.connect(dao).upgradeChildTo(vaultImpl.address); 55 | }); 56 | 57 | it("Should update PUNK vault metadata", async () => { 58 | let punkVault = await ethers.getContractAt("NFTXVaultUpgradeable", "0x269616D549D7e8Eaa82DFb17028d0B212D11232A"); 59 | 60 | console.log("original name", await punkVault.name()); 61 | console.log("original symbol", await punkVault.symbol()); 62 | 63 | await punkVault.connect(dao).setVaultMetadata("new", "NEW"); 64 | 65 | console.log("new name", await punkVault.name()); 66 | console.log("new symbol", await punkVault.symbol()); 67 | }); 68 | 69 | 70 | }); 71 | -------------------------------------------------------------------------------- /test/mainnet/mainnet-vault-shutdown.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | const { expectRevert, expectException } = require("../../utils/expectRevert"); 3 | 4 | const { BigNumber } = require("@ethersproject/bignumber"); 5 | const { ethers, network } = require("hardhat"); 6 | const { utils } = ethers; 7 | const { formatEther, parseEther } = utils; 8 | 9 | const BASE = BigNumber.from(10).pow(18); 10 | 11 | let zetsu; 12 | let dao; 13 | let factory; 14 | 15 | const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); 16 | 17 | describe("Mainnet unstaking test ERC721", function () { 18 | before("Setup", async () => { 19 | await network.provider.request({ 20 | method: "hardhat_reset", 21 | params: [ 22 | { 23 | forking: { 24 | jsonRpcUrl: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_MAINNET_API_KEY}`, 25 | blockNumber: 14714200, 26 | }, 27 | }, 28 | ], 29 | }); 30 | 31 | await hre.network.provider.request({ 32 | method: "hardhat_impersonateAccount", 33 | params: ["0xc6c2d5ee69745a1e9f2d1a06e0ef0788bd924302"], 34 | }); 35 | await hre.network.provider.request({ 36 | method: "hardhat_impersonateAccount", 37 | params: ["0x40d73df4f99bae688ce3c23a01022224fe16c7b2"], 38 | }); 39 | 40 | zetsu = await ethers.provider.getSigner("0xc6c2d5ee69745a1e9f2d1a06e0ef0788bd924302"); 41 | dao = await ethers.provider.getSigner("0x40d73df4f99bae688ce3c23a01022224fe16c7b2"); 42 | 43 | factory = await ethers.getContractAt( 44 | "NFTXVaultFactoryUpgradeable", 45 | "0xBE86f647b167567525cCAAfcd6f881F1Ee558216" 46 | ); 47 | }); 48 | 49 | it("Should upgrade vault contract", async () => { 50 | const VaultImpl = await ethers.getContractFactory("NFTXVaultUpgradeable"); 51 | const vaultImpl = await VaultImpl.deploy(); 52 | await vaultImpl.deployed(); 53 | 54 | await factory.connect(dao).upgradeChildTo(vaultImpl.address); 55 | }); 56 | 57 | it("Should test shutdown", async () => { 58 | let nounVault = await ethers.getContractAt("NFTXVaultUpgradeable", "0x270B157A6bb0290484866383E14c1ef9375C6Fe8"); // holdings = 1, 721 59 | let nounNft = await ethers.getContractAt("ERC721", "0x9C8fF314C9Bc7F6e59A9d9225Fb22946427eDC03"); 60 | 61 | await expectRevert(nounVault.connect(zetsu).shutdown(zetsu._address)); 62 | 63 | console.log("nounNFT balance (start):", (await nounNft.balanceOf(zetsu._address)).toString()); 64 | await nounVault.connect(dao).shutdown(zetsu._address); 65 | console.log("nounNFT balance (end):", (await nounNft.balanceOf(zetsu._address)).toString(), '\n'); 66 | 67 | let mekaVault = await ethers.getContractAt("NFTXVaultUpgradeable", "0x0a776842783488E2b4E1277e98C05923874bfA7d"); // holdings = 3, 721 68 | let mekaNft = await ethers.getContractAt("ERC721", "0x9A534628B4062E123cE7Ee2222ec20B86e16Ca8F"); 69 | 70 | console.log("mekaNft balance (start):", (await mekaNft.balanceOf(zetsu._address)).toString()); 71 | await mekaVault.connect(dao).shutdown(zetsu._address); 72 | console.log("mekaNft balance (end):", (await mekaNft.balanceOf(zetsu._address)).toString(), '\n'); 73 | 74 | let miniVault = await ethers.getContractAt("NFTXVaultUpgradeable", "0x167C0A0B9AEB4febe50E965db6293bD886C91322"); // holdings = 4, 721 75 | 76 | await expectRevert(miniVault.connect(dao).shutdown(zetsu._address)); 77 | 78 | await mekaNft.connect(zetsu).approve(mekaVault.address, 1974); 79 | await expectRevert(mekaVault.connect(zetsu).mint([1974], [1])); 80 | 81 | 82 | }); 83 | 84 | }); 85 | -------------------------------------------------------------------------------- /test/stakingprovider-test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | 3 | const { ethers, upgrades } = require("hardhat"); 4 | 5 | let primary, alice, bob; 6 | let provider; 7 | let dummyWETH, dummyPUNK; 8 | 9 | describe("Staking provider", function () { 10 | before("Setup", async () => { 11 | signers = await ethers.getSigners(); 12 | primary = signers[0]; 13 | alice = signers[1]; 14 | bob = signers[2]; 15 | 16 | const DummyToken = await ethers.getContractFactory( 17 | "DummyToken" 18 | ); 19 | dummyPUNK = await DummyToken.deploy("PUNK", "PUNK"); 20 | await dummyPUNK.deployed(); 21 | dummyWETH = await DummyToken.deploy("WETH", "WETH"); 22 | await dummyWETH.deployed(); 23 | 24 | const StakingProvider = await ethers.getContractFactory( 25 | "StakingTokenProvider" 26 | ); 27 | provider = await upgrades.deployProxy( 28 | StakingProvider, 29 | [ 30 | "0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac" /*Sushiswap*/, 31 | dummyWETH.address /*WETH*/, 32 | "x", 33 | ], 34 | { 35 | initializer: "__StakingTokenProvider_init", 36 | } 37 | ); 38 | await provider.deployed(); 39 | }); 40 | 41 | it("Staking provider staked token address is correct", async () => { 42 | const stakedTokenName = await provider.nameForStakingToken(dummyPUNK.address); 43 | console.log(stakedTokenName); 44 | expect(stakedTokenName).to.equal("xPUNKWETH"); 45 | }) 46 | 47 | let stakedTokenAddr; 48 | it("Staking provider provides the corrent name", async () => { 49 | stakedTokenAddr = await provider.stakingTokenForVaultToken(dummyPUNK.address); 50 | console.log(stakedTokenAddr); 51 | }) 52 | 53 | it("Should allow changing paired token by owner", async () => { 54 | const DummyToken = await ethers.getContractFactory( 55 | "DummyToken" 56 | ); 57 | let dummyNFTX = await DummyToken.deploy("NFTX", "NFTX"); 58 | await dummyNFTX.deployed(); 59 | await provider.setPairedTokenForVaultToken(dummyPUNK.address, dummyNFTX.address, "nftx"); 60 | }); 61 | 62 | it("Staking provider provides the updated name", async () => { 63 | const stakedTokenName = await provider.nameForStakingToken(dummyPUNK.address); 64 | console.log(stakedTokenName); 65 | expect(stakedTokenName).to.equal("nftxPUNKNFTX"); 66 | }) 67 | 68 | it("Staking provider changed staking token for updated pair", async () => { 69 | const newStakedTokenAddr = await provider.stakingTokenForVaultToken(dummyPUNK.address); 70 | expect(newStakedTokenAddr).to.not.equal(stakedTokenAddr); 71 | }) 72 | 73 | it("Staking provider DAI/WETH should be accurate with sushi", async () => { 74 | await provider.setDefaultPairedToken("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" /* mainnet weth */, "x"); 75 | const newStakedTokenAddr = await provider.stakingTokenForVaultToken("0x6B175474E89094C44Da98b954EedeAC495271d0F" /* mainnet DAI */); 76 | expect(newStakedTokenAddr).to.equal("0xC3D03e4F041Fd4cD388c549Ee2A29a9E5075882f" /* mainnet sushi dai/eth */); 77 | }) 78 | 79 | it("Staking provider NFTX/WETH should be accurate with sushi", async () => { 80 | const newStakedTokenAddr = await provider.stakingTokenForVaultToken("0x87d73E916D7057945c9BcD8cdd94e42A6F47f776" /* mainnet NFTX */); 81 | expect(newStakedTokenAddr).to.equal("0x31d64f9403E82243e71C2af9D8F56C7DBe10C178" /* mainnet sushi nftx/eth */); 82 | }) 83 | }); 84 | -------------------------------------------------------------------------------- /utils/expectRevert.js: -------------------------------------------------------------------------------- 1 | const { fail } = require("assert"); 2 | 3 | const expectException = async (promise, expectedError) => { 4 | try { 5 | await promise; 6 | } catch (error) { 7 | if (error.message.indexOf(expectedError) === -1) { 8 | const actualError = error.message.replace( 9 | "Returned error: VM Exception while processing transaction: ", 10 | "" 11 | ); 12 | fail(actualError); // , expectedError, 'Wrong kind of exception received'); 13 | } 14 | return; 15 | } 16 | 17 | fail("Expected an exception but none was received"); 18 | }; 19 | 20 | const expectRevert = async (promise) => { 21 | await expectException(promise, "revert"); 22 | }; 23 | 24 | expectRevert.assertion = (promise) => 25 | expectException(promise, "invalid opcode"); 26 | expectRevert.outOfGas = (promise) => expectException(promise, "out of gas"); 27 | expectRevert.unspecified = (promise) => expectException(promise, "revert"); 28 | 29 | exports.expectException = expectException; 30 | exports.expectRevert = expectRevert; 31 | --------------------------------------------------------------------------------