├── README.md ├── brownie-config.yaml ├── contracts ├── DreamAccessControls.sol ├── DreamAuction.sol ├── DreamGenesisNFT.sol ├── DreamGenesisStaking.sol ├── DreamLPStaking.sol ├── DreamNFTStaking.sol ├── DreamRewards.sol ├── DreamToken.sol ├── ERC1155 │ ├── ERC1155.sol │ └── ERC1155Burnable.sol ├── ERC721 │ └── ERC721WithSameTokenURIForAllTokens.sol ├── ERC998 │ └── IERC998ERC1155TopDown.sol ├── Utils │ ├── ABDKMathQuad.sol │ ├── BokkyPooBahsDateTimeLibrary.sol │ ├── CloneFactory.sol │ ├── RealMath.sol │ ├── UniswapV2Library.sol │ ├── UniswapZAP.sol │ └── WETH9.sol ├── clothing │ ├── DreamClothingFactory.sol │ ├── DreamClothingNFT.sol │ ├── DreamMaterials.sol │ └── IDreamClothingNFT.sol └── mock │ ├── AlwaysRevertingEthReceiver.sol │ ├── BiddingContractMock.sol │ ├── DigitalaxGenesisNFTMock.sol │ ├── DreamAuctionMock.sol │ ├── ERC1155Mock.sol │ ├── ERC1155ReceiverMock.sol │ ├── ERC165Mock.sol │ ├── ERC721ReceiverMock.sol │ ├── MockERC20.sol │ ├── MockStaking.sol │ └── MockVault.sol ├── interfaces ├── IDigitalaxAuction.sol ├── IDigitalaxGenesisNFT.sol ├── IDigitalaxNFT.sol ├── IDigitalaxRewards.sol ├── IERC20.sol ├── IUniswapV2Factory.sol ├── IUniswapV2Pair.sol └── IWETH9.sol ├── outputs ├── SetContributions.csv ├── bonusPerWeek.csv └── tokensAllocationPerWeek.csv ├── scripts ├── __pycache__ │ ├── contract_addresses.cpython-38.pyc │ ├── contracts.cpython-38.pyc │ ├── deploy_AdminBuyGenesis.cpython-38.pyc │ ├── deploy_DigitalaxStaking.cpython-38.pyc │ ├── deploy_MONA.cpython-38.pyc │ ├── deploy_StakingDev.cpython-38.pyc │ ├── deploy_StakingMainnet.cpython-38.pyc │ ├── deploy_UniswapAddLiquidity.cpython-38.pyc │ ├── deploy_UniswapPool.cpython-38.pyc │ ├── deploy_setContributions.cpython-38.pyc │ ├── deploy_setRewards.cpython-38.pyc │ ├── deploy_setTokensClaimable.cpython-38.pyc │ ├── rewardsWeekly.cpython-38.pyc │ └── settings.cpython-38.pyc ├── check_contributions.py ├── contract_addresses.py ├── contracts.py ├── deploy_AdminBuyGenesis.py ├── deploy_AdminMintParent.py ├── deploy_MONA.py ├── deploy_StakingDev.py ├── deploy_StakingMainnet.py ├── deploy_UniswapAddLiquidity.py ├── deploy_UniswapPool.py ├── deploy_setAdminContributions.py ├── deploy_setBonus.py ├── deploy_setContributions.py ├── deploy_setRewards.py ├── deploy_setTokensClaimable.py ├── deploy_updateParentStaking.py ├── deploy_updateRewards.py ├── get_UniswapPair.py ├── get_token_indexes.py ├── rewards.py ├── rewardsWeekly.py └── settings.py └── tests ├── __pycache__ ├── conftest.cpython-38-pytest-6.0.1.pyc ├── settings.cpython-38.pyc ├── test_genesis_nft.cpython-38-pytest-6.0.1.pyc ├── test_rewards.cpython-38-pytest-6.0.1.pyc ├── test_staking.cpython-38-pytest-6.0.1.pyc ├── test_staking_genesis.cpython-38-pytest-6.0.1.pyc ├── test_staking_lp.cpython-38-pytest-6.0.1.pyc ├── test_staking_nft.cpython-38-pytest-6.0.1.pyc └── test_staking_parent.cpython-38-pytest-6.0.1.pyc ├── conftest.py ├── settings.py ├── test_genesis_nft.py ├── test_rewards.py ├── test_staking_genesis.py ├── test_staking_lp.py └── test_staking_parent.py /README.md: -------------------------------------------------------------------------------- 1 | ## Developer Setup 2 | 3 | Install Brownie: `pip3 install eth-brownie` 4 | 5 | 6 | ## Compiling the contracts 7 | 8 | Compile updated contracts: `brownie compile` 9 | 10 | Compile all contracts (even not changed ones): `brownie compile --all` 11 | 12 | ## Running tests 13 | 14 | Run tests: `brownie test` 15 | 16 | Run tests in verbose mode: `brownie test -v` 17 | 18 | Check available fixtures: `brownie --fixtures .` 19 | 20 | ## Brownie commands 21 | 22 | Run script: `brownie run ` 23 | 24 | Run console (very useful for debugging): `brownie console` 25 | -------------------------------------------------------------------------------- /brownie-config.yaml: -------------------------------------------------------------------------------- 1 | # Brownie configuration file 2 | # https://eth-brownie.readthedocs.io/en/stable/config.html 3 | networks: 4 | default: development # the default network that brownie connects to 5 | settings: 6 | gas_limit: "auto" 7 | gas_price: "auto" 8 | persist: true 9 | reverting_tx_gas_limit: false # if false, reverting tx's will raise without broadcasting 10 | pytest: 11 | # these settings replace the defaults when running pytest 12 | gas_limit: 6721975 13 | default_contract_owner: true 14 | reverting_tx_gas_limit: 6721975 15 | revert_traceback: true 16 | compiler: 17 | evm_version: null 18 | minify_source: false 19 | solc: 20 | version: 0.6.12 21 | optimize: true 22 | runs: 200 23 | remappings: 24 | - "@openzeppelin=OpenZeppelin/openzeppelin-contracts@3.2.0" 25 | dependencies: 26 | - OpenZeppelin/openzeppelin-contracts@3.2.0 27 | colors: 28 | key: 29 | value: bright blue 30 | callable: bright cyan 31 | module: bright blue 32 | contract: bright magenta 33 | contract_method: bright magenta 34 | string: bright magenta 35 | dull: dark white 36 | error: bright red 37 | success: bright green 38 | pending: bright yellow 39 | -------------------------------------------------------------------------------- /contracts/DreamAccessControls.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.6.12; 2 | 3 | import "@openzeppelin/contracts/access/AccessControl.sol"; 4 | 5 | /** 6 | * @notice Access Controls contract for the Dream clothing Platform 7 | * @author BlockRocket.tech 8 | */ 9 | contract DreamAccessControls is AccessControl { 10 | /// @notice Role definitions 11 | bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); 12 | bytes32 public constant SMART_CONTRACT_ROLE = 13 | keccak256("SMART_CONTRACT_ROLE"); 14 | 15 | /// @notice Events for adding and removing various roles 16 | event AdminRoleGranted(address indexed beneficiary, address indexed caller); 17 | 18 | event AdminRoleRemoved(address indexed beneficiary, address indexed caller); 19 | 20 | event MinterRoleGranted( 21 | address indexed beneficiary, 22 | address indexed caller 23 | ); 24 | 25 | event MinterRoleRemoved( 26 | address indexed beneficiary, 27 | address indexed caller 28 | ); 29 | 30 | event SmartContractRoleGranted( 31 | address indexed beneficiary, 32 | address indexed caller 33 | ); 34 | 35 | event SmartContractRoleRemoved( 36 | address indexed beneficiary, 37 | address indexed caller 38 | ); 39 | 40 | /** 41 | * @notice The deployer is automatically given the admin role which will allow them to then grant roles to other addresses 42 | */ 43 | constructor() public { 44 | _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); 45 | } 46 | 47 | ///////////// 48 | // Lookups // 49 | ///////////// 50 | 51 | /** 52 | * @notice Used to check whether an address has the admin role 53 | * @param _address EOA or contract being checked 54 | * @return bool True if the account has the role or false if it does not 55 | */ 56 | function hasAdminRole(address _address) external view returns (bool) { 57 | return hasRole(DEFAULT_ADMIN_ROLE, _address); 58 | } 59 | 60 | /** 61 | * @notice Used to check whether an address has the minter role 62 | * @param _address EOA or contract being checked 63 | * @return bool True if the account has the role or false if it does not 64 | */ 65 | function hasMinterRole(address _address) external view returns (bool) { 66 | return hasRole(MINTER_ROLE, _address); 67 | } 68 | 69 | /** 70 | * @notice Used to check whether an address has the smart contract role 71 | * @param _address EOA or contract being checked 72 | * @return bool True if the account has the role or false if it does not 73 | */ 74 | function hasSmartContractRole(address _address) 75 | external 76 | view 77 | returns (bool) 78 | { 79 | return hasRole(SMART_CONTRACT_ROLE, _address); 80 | } 81 | 82 | /////////////// 83 | // Modifiers // 84 | /////////////// 85 | 86 | /** 87 | * @notice Grants the admin role to an address 88 | * @dev The sender must have the admin role 89 | * @param _address EOA or contract receiving the new role 90 | */ 91 | function addAdminRole(address _address) external { 92 | grantRole(DEFAULT_ADMIN_ROLE, _address); 93 | emit AdminRoleGranted(_address, _msgSender()); 94 | } 95 | 96 | /** 97 | * @notice Removes the admin role from an address 98 | * @dev The sender must have the admin role 99 | * @param _address EOA or contract affected 100 | */ 101 | function removeAdminRole(address _address) external { 102 | revokeRole(DEFAULT_ADMIN_ROLE, _address); 103 | emit AdminRoleRemoved(_address, _msgSender()); 104 | } 105 | 106 | /** 107 | * @notice Grants the minter role to an address 108 | * @dev The sender must have the admin role 109 | * @param _address EOA or contract receiving the new role 110 | */ 111 | function addMinterRole(address _address) external { 112 | grantRole(MINTER_ROLE, _address); 113 | emit MinterRoleGranted(_address, _msgSender()); 114 | } 115 | 116 | /** 117 | * @notice Removes the minter role from an address 118 | * @dev The sender must have the admin role 119 | * @param _address EOA or contract affected 120 | */ 121 | function removeMinterRole(address _address) external { 122 | revokeRole(MINTER_ROLE, _address); 123 | emit MinterRoleRemoved(_address, _msgSender()); 124 | } 125 | 126 | /** 127 | * @notice Grants the smart contract role to an address 128 | * @dev The sender must have the admin role 129 | * @param _address EOA or contract receiving the new role 130 | */ 131 | function addSmartContractRole(address _address) external { 132 | grantRole(SMART_CONTRACT_ROLE, _address); 133 | emit SmartContractRoleGranted(_address, _msgSender()); 134 | } 135 | 136 | /** 137 | * @notice Removes the smart contract role from an address 138 | * @dev The sender must have the admin role 139 | * @param _address EOA or contract affected 140 | */ 141 | function removeSmartContractRole(address _address) external { 142 | revokeRole(SMART_CONTRACT_ROLE, _address); 143 | emit SmartContractRoleRemoved(_address, _msgSender()); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /contracts/DreamGenesisNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.6.12; 4 | 5 | import "./ERC721/ERC721WithSameTokenURIForAllTokens.sol"; 6 | import "@openzeppelin/contracts/math/SafeMath.sol"; 7 | import "./DigitalaxAccessControls.sol"; 8 | 9 | /** 10 | * @title Digitalax Genesis NFT 11 | * @dev To facilitate the genesis sale for the Digitialax platform 12 | */ 13 | contract DigitalaxGenesisNFT is ERC721WithSameTokenURIForAllTokens("DigitalaxGenesis", "DXG") { 14 | using SafeMath for uint256; 15 | 16 | // @notice event emitted upon construction of this contract, used to bootstrap external indexers 17 | event DigitalaxGenesisNFTContractDeployed(); 18 | 19 | // @notice event emitted when a contributor buys a Genesis NFT 20 | event GenesisPurchased( 21 | address indexed buyer, 22 | uint256 indexed tokenId, 23 | uint256 contribution 24 | ); 25 | 26 | // @notice event emitted when a admin mints a Genesis NFT 27 | event AdminGenesisMinted( 28 | address indexed beneficiary, 29 | address indexed admin, 30 | uint256 indexed tokenId 31 | ); 32 | 33 | // @notice event emitted when a contributors amount is increased 34 | event ContributionIncreased( 35 | address indexed buyer, 36 | uint256 contribution 37 | ); 38 | 39 | // @notice event emitted when end date is changed 40 | event GenesisEndUpdated( 41 | uint256 genesisEndTimestamp, 42 | address indexed admin 43 | ); 44 | 45 | // @notice event emitted when DigitalaxAccessControls is updated 46 | event AccessControlsUpdated( 47 | address indexed newAdress 48 | ); 49 | 50 | // @notice responsible for enforcing admin access 51 | DigitalaxAccessControls public accessControls; 52 | 53 | // @notice all funds will be sent to this address pon purchase of a Genesis NFT 54 | address payable public fundsMultisig; 55 | 56 | // @notice start date for them the Genesis sale is open to the public, before this data no purchases can be made 57 | uint256 public genesisStartTimestamp; 58 | 59 | // @notice end date for them the Genesis sale is closed, no more purchased can be made after this point 60 | uint256 public genesisEndTimestamp; 61 | 62 | // @notice set after end time has been changed once, prevents further changes to end timestamp 63 | bool public genesisEndTimestampLocked; 64 | 65 | // @notice the minimum amount a buyer can contribute in a single go 66 | uint256 public constant minimumContributionAmount = 0.1 ether; 67 | 68 | // @notice the maximum accumulative amount a user can contribute to the genesis sale 69 | uint256 public constant maximumContributionAmount = 2 ether; 70 | 71 | // @notice accumulative => contribution total 72 | mapping(address => uint256) public contribution; 73 | 74 | // @notice global accumulative contribution amount 75 | uint256 public totalContributions; 76 | 77 | // @notice max number of paid contributions to the genesis sale 78 | uint256 public constant maxGenesisContributionTokens = 460; 79 | 80 | uint256 public totalAdminMints; 81 | 82 | constructor( 83 | DigitalaxAccessControls _accessControls, 84 | address payable _fundsMultisig, 85 | uint256 _genesisStartTimestamp, 86 | uint256 _genesisEndTimestamp, 87 | string memory _tokenURI 88 | ) public { 89 | accessControls = _accessControls; 90 | fundsMultisig = _fundsMultisig; 91 | genesisStartTimestamp = _genesisStartTimestamp; 92 | genesisEndTimestamp = _genesisEndTimestamp; 93 | tokenURI_ = _tokenURI; 94 | emit DigitalaxGenesisNFTContractDeployed(); 95 | } 96 | 97 | /** 98 | * @dev Proxy method for facilitating a single point of entry to either buy or contribute additional value to the Genesis sale 99 | * @dev Cannot contribute less than minimumContributionAmount 100 | * @dev Cannot contribute accumulative more than than maximumContributionAmount 101 | */ 102 | function buyOrIncreaseContribution() external payable { 103 | if (contribution[_msgSender()] == 0) { 104 | buy(); 105 | } else { 106 | increaseContribution(); 107 | } 108 | } 109 | 110 | /** 111 | * @dev Facilitating the initial purchase of a Genesis NFT 112 | * @dev Cannot contribute less than minimumContributionAmount 113 | * @dev Cannot contribute accumulative more than than maximumContributionAmount 114 | * @dev Reverts if already owns an genesis token 115 | * @dev Buyer receives a NFT on success 116 | * @dev All funds move to fundsMultisig 117 | */ 118 | function buy() public payable { 119 | require(contribution[_msgSender()] == 0, "DigitalaxGenesisNFT.buy: You already own a genesis NFT"); 120 | require( 121 | _getNow() >= genesisStartTimestamp && _getNow() <= genesisEndTimestamp, 122 | "DigitalaxGenesisNFT.buy: No genesis are available outside of the genesis window" 123 | ); 124 | 125 | uint256 _contributionAmount = msg.value; 126 | require( 127 | _contributionAmount >= minimumContributionAmount, 128 | "DigitalaxGenesisNFT.buy: Contribution does not meet minimum requirement" 129 | ); 130 | 131 | require( 132 | _contributionAmount <= maximumContributionAmount, 133 | "DigitalaxGenesisNFT.buy: You cannot exceed the maximum contribution amount" 134 | ); 135 | 136 | require(remainingGenesisTokens() > 0, "DigitalaxGenesisNFT.buy: Total number of genesis token holders reached"); 137 | 138 | contribution[_msgSender()] = _contributionAmount; 139 | totalContributions = totalContributions.add(_contributionAmount); 140 | 141 | (bool fundsTransferSuccess,) = fundsMultisig.call{value : _contributionAmount}(""); 142 | require(fundsTransferSuccess, "DigitalaxGenesisNFT.buy: Unable to send contribution to funds multisig"); 143 | 144 | uint256 tokenId = totalSupply().add(1); 145 | _safeMint(_msgSender(), tokenId); 146 | 147 | emit GenesisPurchased(_msgSender(), tokenId, _contributionAmount); 148 | } 149 | 150 | /** 151 | * @dev Facilitates an owner to increase there contribution 152 | * @dev Cannot contribute less than minimumContributionAmount 153 | * @dev Cannot contribute accumulative more than than maximumContributionAmount 154 | * @dev Reverts if caller does not already owns an genesis token 155 | * @dev All funds move to fundsMultisig 156 | */ 157 | function increaseContribution() public payable { 158 | require( 159 | _getNow() >= genesisStartTimestamp && _getNow() <= genesisEndTimestamp, 160 | "DigitalaxGenesisNFT.increaseContribution: No increases are possible outside of the genesis window" 161 | ); 162 | 163 | require( 164 | contribution[_msgSender()] > 0, 165 | "DigitalaxGenesisNFT.increaseContribution: You do not own a genesis NFT" 166 | ); 167 | 168 | uint256 _amountToIncrease = msg.value; 169 | contribution[_msgSender()] = contribution[_msgSender()].add(_amountToIncrease); 170 | 171 | require( 172 | contribution[_msgSender()] <= maximumContributionAmount, 173 | "DigitalaxGenesisNFT.increaseContribution: You cannot exceed the maximum contribution amount" 174 | ); 175 | 176 | totalContributions = totalContributions.add(_amountToIncrease); 177 | 178 | (bool fundsTransferSuccess,) = fundsMultisig.call{value : _amountToIncrease}(""); 179 | require( 180 | fundsTransferSuccess, 181 | "DigitalaxGenesisNFT.increaseContribution: Unable to send contribution to funds multisig" 182 | ); 183 | 184 | emit ContributionIncreased(_msgSender(), _amountToIncrease); 185 | } 186 | 187 | // Admin 188 | 189 | /** 190 | * @dev Allows a whitelisted admin to mint a token and issue it to a beneficiary 191 | * @dev One token per holder 192 | * @dev All holders contribution as set o zero on creation 193 | */ 194 | function adminBuy(address _beneficiary) external { 195 | require( 196 | accessControls.hasAdminRole(_msgSender()), 197 | "DigitalaxGenesisNFT.adminBuy: Sender must be admin" 198 | ); 199 | require(_beneficiary != address(0), "DigitalaxGenesisNFT.adminBuy: Beneficiary cannot be ZERO"); 200 | require(balanceOf(_beneficiary) == 0, "DigitalaxGenesisNFT.adminBuy: Beneficiary already owns a genesis NFT"); 201 | 202 | uint256 tokenId = totalSupply().add(1); 203 | _safeMint(_beneficiary, tokenId); 204 | 205 | // Increase admin mint counts 206 | totalAdminMints = totalAdminMints.add(1); 207 | 208 | emit AdminGenesisMinted(_beneficiary, _msgSender(), tokenId); 209 | } 210 | 211 | /** 212 | * @dev Allows a whitelisted admin to update the end date of the genesis 213 | */ 214 | function updateGenesisEnd(uint256 _end) external { 215 | require( 216 | accessControls.hasAdminRole(_msgSender()), 217 | "DigitalaxGenesisNFT.updateGenesisEnd: Sender must be admin" 218 | ); 219 | // If already passed, dont allow opening again 220 | require(genesisEndTimestamp > _getNow(), "DigitalaxGenesisNFT.updateGenesisEnd: End time already passed"); 221 | 222 | // Only allow setting this once 223 | require(!genesisEndTimestampLocked, "DigitalaxGenesisNFT.updateGenesisEnd: End time locked"); 224 | 225 | genesisEndTimestamp = _end; 226 | 227 | // Lock future end time modifications 228 | genesisEndTimestampLocked = true; 229 | 230 | emit GenesisEndUpdated(genesisEndTimestamp, _msgSender()); 231 | } 232 | 233 | /** 234 | * @dev Allows a whitelisted admin to update the start date of the genesis 235 | */ 236 | function updateAccessControls(DigitalaxAccessControls _accessControls) external { 237 | require( 238 | accessControls.hasAdminRole(_msgSender()), 239 | "DigitalaxGenesisNFT.updateAccessControls: Sender must be admin" 240 | ); 241 | require(address(_accessControls) != address(0), "DigitalaxGenesisNFT.updateAccessControls: Zero Address"); 242 | accessControls = _accessControls; 243 | 244 | emit AccessControlsUpdated(address(_accessControls)); 245 | } 246 | 247 | /** 248 | * @dev Returns total remaining number of tokens available in the Genesis sale 249 | */ 250 | function remainingGenesisTokens() public view returns (uint256) { 251 | return _getMaxGenesisContributionTokens() - (totalSupply() - totalAdminMints); 252 | } 253 | 254 | // Internal 255 | 256 | function _getNow() internal virtual view returns (uint256) { 257 | return block.timestamp; 258 | } 259 | 260 | function _getMaxGenesisContributionTokens() internal virtual view returns (uint256) { 261 | return maxGenesisContributionTokens; 262 | } 263 | 264 | /** 265 | * @dev Before token transfer hook to enforce that no token can be moved to another address until the genesis sale has ended 266 | */ 267 | function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override { 268 | if (from != address(0) && _getNow() <= genesisEndTimestamp) { 269 | revert("DigitalaxGenesisNFT._beforeTokenTransfer: Transfers are currently locked at this time"); 270 | } 271 | } 272 | } -------------------------------------------------------------------------------- /contracts/DreamNFTStaking.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPLv2 2 | 3 | pragma solidity 0.6.12; 4 | 5 | import "@openzeppelin/contracts/math/SafeMath.sol"; 6 | import "./DigitalaxAccessControls.sol"; 7 | import "./DigitalaxGenesisNFT.sol"; 8 | import "../interfaces/IERC20.sol"; 9 | import "../interfaces/IDigitalaxRewards.sol"; 10 | import "../interfaces/IDigitalaxNFT.sol"; 11 | 12 | /** 13 | * @title Digitalax Staking 14 | * @dev Stake NFTs, earn tokens on the Digitialax platform 15 | * @author Adrian Guerrera (deepyr) 16 | */ 17 | 18 | contract DigitalaxNFTStaking { 19 | using SafeMath for uint256; 20 | bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; 21 | 22 | IERC20 public rewardsToken; 23 | IDigitalaxNFT public parentNFT; 24 | DigitalaxAccessControls public accessControls; 25 | IDigitalaxRewards public rewardsContract; 26 | 27 | 28 | /// @notice total ethereum staked currently in the gensesis staking contract 29 | uint256 public stakedEthTotal; 30 | uint256 public lastUpdateTime; 31 | 32 | uint256 public rewardsPerTokenPoints; 33 | uint256 public totalUnclaimedRewards; 34 | 35 | uint256 constant pointMultiplier = 10e18; 36 | 37 | /** 38 | @notice Struct to track what user is staking which tokens 39 | @dev tokenIds are all the tokens staked by the staker 40 | @dev balance is the current ether balance of the staker 41 | @dev rewardsEarned is the total reward for the staker till now 42 | @dev rewardsReleased is how much reward has been paid to the staker 43 | */ 44 | struct Staker { 45 | uint256[] tokenIds; 46 | mapping (uint256 => uint256) tokenIndex; 47 | uint256 balance; 48 | uint256 lastRewardPoints; 49 | uint256 rewardsEarned; 50 | uint256 rewardsReleased; 51 | } 52 | 53 | /// @notice mapping of a staker to its current properties 54 | mapping (address => Staker) public stakers; 55 | 56 | // Mapping from token ID to owner address 57 | mapping (uint256 => address) public tokenOwner; 58 | 59 | /// @notice sets the token to be claimable or not, cannot claim if it set to false 60 | bool public tokensClaimable; 61 | bool initialised; 62 | 63 | /// @notice event emitted when a user has staked a token 64 | event Staked(address owner, uint256 amount); 65 | 66 | /// @notice event emitted when a user has unstaked a token 67 | event Unstaked(address owner, uint256 amount); 68 | 69 | /// @notice event emitted when a user claims reward 70 | event RewardPaid(address indexed user, uint256 reward); 71 | 72 | /// @notice Allows reward tokens to be claimed 73 | event ClaimableStatusUpdated(bool status); 74 | 75 | /// @notice Emergency unstake tokens without rewards 76 | event EmergencyUnstake(address indexed user, uint256 tokenId); 77 | 78 | /// @notice Admin update of rewards contract 79 | event RewardsTokenUpdated(address indexed oldRewardsToken, address newRewardsToken ); 80 | 81 | constructor() public { 82 | } 83 | /** 84 | * @dev Single gateway to intialize the staking contract after deploying 85 | * @dev Sets the contract with the MONA NFT and MONA reward token 86 | */ 87 | function initStaking( 88 | IERC20 _rewardsToken, 89 | IDigitalaxNFT _parentNFT, 90 | DigitalaxAccessControls _accessControls 91 | ) 92 | external 93 | { 94 | require(!initialised, "Already initialised"); 95 | rewardsToken = _rewardsToken; 96 | parentNFT = _parentNFT; 97 | accessControls = _accessControls; 98 | lastUpdateTime = block.timestamp; 99 | initialised = true; 100 | } 101 | 102 | 103 | /// @notice Lets admin set the Rewards Token 104 | function setRewardsContract( 105 | address _addr 106 | ) 107 | external 108 | { 109 | require( 110 | accessControls.hasAdminRole(msg.sender), 111 | "DigitalaxParentStaking.setRewardsContract: Sender must be admin" 112 | ); 113 | require(_addr != address(0)); 114 | address oldAddr = address(rewardsContract); 115 | rewardsContract = IDigitalaxRewards(_addr); 116 | emit RewardsTokenUpdated(oldAddr, _addr); 117 | } 118 | 119 | /// @notice Lets admin set the Rewards to be claimable 120 | function setTokensClaimable( 121 | bool _enabled 122 | ) 123 | external 124 | { 125 | require( 126 | accessControls.hasAdminRole(msg.sender), 127 | "DigitalaxParentStaking.setTokensClaimable: Sender must be admin" 128 | ); 129 | tokensClaimable = _enabled; 130 | emit ClaimableStatusUpdated(_enabled); 131 | } 132 | 133 | /// @dev Getter functions for Staking contract 134 | /// @dev Get the tokens staked by a user 135 | function getStakedTokens( 136 | address _user 137 | ) 138 | external 139 | view 140 | returns (uint256[] memory tokenIds) 141 | { 142 | return stakers[_user].tokenIds; 143 | } 144 | 145 | 146 | /// @dev Get the amount a staked nft is valued at ie bought at 147 | function getContribution ( 148 | uint256 _tokenId 149 | ) 150 | public 151 | view 152 | returns (uint256) 153 | { 154 | return parentNFT.primarySalePrice(_tokenId); 155 | } 156 | 157 | /// @notice Stake MONA NFTs and earn reward tokens. 158 | function stake( 159 | uint256 tokenId 160 | ) 161 | external 162 | { 163 | // require(); 164 | _stake(msg.sender, tokenId); 165 | } 166 | 167 | /// @notice Stake multiple MONA NFTs and earn reward tokens. 168 | function stakeBatch(uint256[] memory tokenIds) 169 | external 170 | { 171 | for (uint i = 0; i < tokenIds.length; i++) { 172 | _stake(msg.sender, tokenIds[i]); 173 | } 174 | } 175 | 176 | /// @notice Stake all your MONA NFTs and earn reward tokens. 177 | function stakeAll() 178 | external 179 | { 180 | uint256 balance = parentNFT.balanceOf(msg.sender); 181 | for (uint i = 0; i < balance; i++) { 182 | _stake(msg.sender, parentNFT.tokenOfOwnerByIndex(msg.sender,i)); 183 | } 184 | } 185 | 186 | 187 | /** 188 | * @dev All the staking goes through this function 189 | * @dev Rewards to be given out is calculated 190 | * @dev Balance of stakers are updated as they stake the nfts based on ether price 191 | */ 192 | function _stake( 193 | address _user, 194 | uint256 _tokenId 195 | ) 196 | internal 197 | { 198 | Staker storage staker = stakers[_user]; 199 | 200 | if (staker.balance == 0 && staker.lastRewardPoints == 0 ) { 201 | staker.lastRewardPoints = rewardsPerTokenPoints; 202 | } 203 | 204 | updateReward(_user); 205 | uint256 amount = getContribution(_tokenId); 206 | staker.balance = staker.balance.add(amount); 207 | stakedEthTotal = stakedEthTotal.add(amount); 208 | staker.tokenIds.push(_tokenId); 209 | staker.tokenIndex[staker.tokenIds.length - 1]; 210 | tokenOwner[_tokenId] = _user; 211 | parentNFT.safeTransferFrom( 212 | _user, 213 | address(this), 214 | _tokenId 215 | ); 216 | 217 | emit Staked(_user, _tokenId); 218 | } 219 | 220 | /// @notice Unstake Genesis MONA NFTs. 221 | function unstake( 222 | uint256 _tokenId 223 | ) 224 | external 225 | { 226 | require( 227 | tokenOwner[_tokenId] == msg.sender, 228 | "DigitalaxParentStaking._unstake: Sender must have staked tokenID" 229 | ); 230 | claimReward(msg.sender); 231 | _unstake(msg.sender, _tokenId); 232 | } 233 | 234 | /// @notice Stake multiple MONA NFTs and claim reward tokens. 235 | function unstakeBatch( 236 | uint256[] memory tokenIds 237 | ) 238 | external 239 | { 240 | claimReward(msg.sender); 241 | for (uint i = 0; i < tokenIds.length; i++) { 242 | if (tokenOwner[tokenIds[i]] == msg.sender) { 243 | _unstake(msg.sender, tokenIds[i]); 244 | } 245 | } 246 | } 247 | 248 | /** 249 | * @dev All the unstaking goes through this function 250 | * @dev Rewards to be given out is calculated 251 | * @dev Balance of stakers are updated as they unstake the nfts based on ether price 252 | */ 253 | function _unstake( 254 | address _user, 255 | uint256 _tokenId 256 | ) 257 | internal 258 | { 259 | 260 | Staker storage staker = stakers[_user]; 261 | 262 | uint256 amount = getContribution(_tokenId); 263 | staker.balance = staker.balance.sub(amount); 264 | stakedEthTotal = stakedEthTotal.sub(amount); 265 | 266 | uint256 lastIndex = staker.tokenIds.length - 1; 267 | uint256 lastIndexKey = staker.tokenIds[lastIndex]; 268 | uint256 tokenIdIndex = staker.tokenIndex[_tokenId]; 269 | 270 | staker.tokenIds[tokenIdIndex] = lastIndexKey; 271 | staker.tokenIndex[lastIndexKey] = tokenIdIndex; 272 | if (staker.tokenIds.length > 0) { 273 | staker.tokenIds.pop(); 274 | delete staker.tokenIndex[_tokenId]; 275 | } 276 | 277 | if (staker.balance == 0) { 278 | delete stakers[_user]; 279 | } 280 | delete tokenOwner[_tokenId]; 281 | 282 | parentNFT.safeTransferFrom( 283 | address(this), 284 | _user, 285 | _tokenId 286 | ); 287 | 288 | emit Unstaked(_user, _tokenId); 289 | 290 | } 291 | 292 | // Unstake without caring about rewards. EMERGENCY ONLY. 293 | function emergencyUnstake(uint256 _tokenId) public { 294 | require( 295 | tokenOwner[_tokenId] == msg.sender, 296 | "DigitalaxParentStaking._unstake: Sender must have staked tokenID" 297 | ); 298 | _unstake(msg.sender, _tokenId); 299 | emit EmergencyUnstake(msg.sender, _tokenId); 300 | 301 | } 302 | 303 | 304 | /// @dev Updates the amount of rewards owed for each user before any tokens are moved 305 | function updateReward( 306 | address _user 307 | ) 308 | public 309 | { 310 | 311 | rewardsContract.updateRewards(); 312 | uint256 parentRewards = rewardsContract.parentRewards(lastUpdateTime, block.timestamp); 313 | 314 | if (stakedEthTotal > 0) { 315 | rewardsPerTokenPoints = rewardsPerTokenPoints.add(parentRewards 316 | .mul(1e18) 317 | .mul(pointMultiplier) 318 | .div(stakedEthTotal)); 319 | } 320 | 321 | lastUpdateTime = block.timestamp; 322 | uint256 rewards = rewardsOwing(_user); 323 | 324 | Staker storage staker = stakers[_user]; 325 | if (_user != address(0)) { 326 | staker.rewardsEarned = staker.rewardsEarned.add(rewards); 327 | staker.lastRewardPoints = rewardsPerTokenPoints; 328 | } 329 | } 330 | 331 | 332 | /// @notice Returns the rewards owing for a user 333 | /// @dev The rewards are dynamic and normalised from the other pools 334 | /// @dev This gets the rewards from each of the periods as one multiplier 335 | function rewardsOwing( 336 | address _user 337 | ) 338 | public 339 | view 340 | returns(uint256) 341 | { 342 | uint256 newRewardPerToken = rewardsPerTokenPoints.sub(stakers[_user].lastRewardPoints); 343 | uint256 rewards = stakers[_user].balance.mul(newRewardPerToken) 344 | .div(1e18) 345 | .div(pointMultiplier); 346 | return rewards; 347 | } 348 | 349 | 350 | /// @notice Returns the about of rewards yet to be claimed 351 | function unclaimedRewards( 352 | address _user 353 | ) 354 | external 355 | view 356 | returns(uint256) 357 | { 358 | if (stakedEthTotal == 0) { 359 | return 0; 360 | } 361 | 362 | uint256 parentRewards = rewardsContract.parentRewards(lastUpdateTime, 363 | block.timestamp); 364 | 365 | uint256 newRewardPerToken = rewardsPerTokenPoints.add(parentRewards 366 | .mul(1e18) 367 | .mul(pointMultiplier) 368 | .div(stakedEthTotal)) 369 | .sub(stakers[_user].lastRewardPoints); 370 | 371 | uint256 rewards = stakers[_user].balance.mul(newRewardPerToken) 372 | .div(1e18) 373 | .div(pointMultiplier); 374 | return rewards.add(stakers[_user].rewardsEarned).sub(stakers[_user].rewardsReleased); 375 | } 376 | 377 | 378 | /// @notice Lets a user with rewards owing to claim tokens 379 | function claimReward( 380 | address _user 381 | ) 382 | public 383 | { 384 | require( 385 | tokensClaimable == true, 386 | "Tokens cannnot be claimed yet" 387 | ); 388 | updateReward(_user); 389 | 390 | Staker storage staker = stakers[_user]; 391 | 392 | uint256 payableAmount = staker.rewardsEarned.sub(staker.rewardsReleased); 393 | staker.rewardsReleased = staker.rewardsReleased.add(payableAmount); 394 | 395 | /// @dev accounts for dust 396 | uint256 rewardBal = rewardsToken.balanceOf(address(this)); 397 | if (payableAmount > rewardBal) { 398 | payableAmount = rewardBal; 399 | } 400 | 401 | rewardsToken.transfer(_user, payableAmount); 402 | emit RewardPaid(_user, payableAmount); 403 | } 404 | 405 | 406 | function onERC721Received( 407 | address, 408 | address, 409 | uint256, 410 | bytes calldata data 411 | ) 412 | public returns(bytes4) 413 | { 414 | return _ERC721_RECEIVED; 415 | } 416 | 417 | 418 | 419 | } -------------------------------------------------------------------------------- /contracts/DreamToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.12; 2 | 3 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 4 | import "@openzeppelin/contracts/math/SafeMath.sol"; 5 | import "@openzeppelin/contracts/GSN/Context.sol"; 6 | import "./DreamAccessControls.sol"; 7 | 8 | /** 9 | * @notice DreamToken Governance Token = ERC20 + mint + burn. 10 | * @author Adrian Guerrera (deepyr) 11 | * @author Attr: BokkyPooBah (c) The Optino Project 12 | * @dev https://github.com/ogDAO/Governance/ 13 | */ 14 | 15 | // SPDX-License-Identifier: GPLv2 16 | contract DreamToken is Context, IERC20 { 17 | using SafeMath for uint256; 18 | 19 | string _symbol; 20 | string _name; 21 | uint8 _decimals; 22 | uint256 _totalSupply; 23 | mapping(address => uint256) balances; 24 | 25 | mapping(address => mapping(address => uint256)) allowed; 26 | uint256 public cap; 27 | bool public freezeCap; 28 | 29 | DreamAccessControls public accessControls; 30 | 31 | event CapUpdated(uint256 cap, bool freezeCap); 32 | 33 | constructor( 34 | string memory symbol_, 35 | string memory name_, 36 | uint8 decimals_, 37 | DreamAccessControls accessControls_, 38 | address tokenOwner, 39 | uint256 initialSupply 40 | ) public { 41 | _symbol = symbol_; 42 | _name = name_; 43 | _decimals = decimals_; 44 | accessControls = accessControls_; 45 | balances[tokenOwner] = initialSupply; 46 | _totalSupply = initialSupply; 47 | emit Transfer(address(0), tokenOwner, _totalSupply); 48 | } 49 | 50 | function symbol() external view returns (string memory) { 51 | return _symbol; 52 | } 53 | 54 | function name() external view returns (string memory) { 55 | return _name; 56 | } 57 | 58 | function decimals() external view returns (uint8) { 59 | return _decimals; 60 | } 61 | 62 | function totalSupply() external view override returns (uint256) { 63 | return _totalSupply.sub(balances[address(0)]); 64 | } 65 | 66 | function balanceOf(address tokenOwner) 67 | external 68 | view 69 | override 70 | returns (uint256 balance) 71 | { 72 | return balances[tokenOwner]; 73 | } 74 | 75 | function transfer(address to, uint256 tokens) 76 | external 77 | override 78 | returns (bool success) 79 | { 80 | balances[_msgSender()] = balances[_msgSender()].sub(tokens); 81 | balances[to] = balances[to].add(tokens); 82 | emit Transfer(_msgSender(), to, tokens); 83 | return true; 84 | } 85 | 86 | function approve(address spender, uint256 tokens) 87 | external 88 | override 89 | returns (bool success) 90 | { 91 | allowed[_msgSender()][spender] = tokens; 92 | emit Approval(_msgSender(), spender, tokens); 93 | return true; 94 | } 95 | 96 | function transferFrom( 97 | address from, 98 | address to, 99 | uint256 tokens 100 | ) external override returns (bool success) { 101 | balances[from] = balances[from].sub(tokens); 102 | allowed[from][_msgSender()] = allowed[from][_msgSender()].sub(tokens); 103 | balances[to] = balances[to].add(tokens); 104 | emit Transfer(from, to, tokens); 105 | return true; 106 | } 107 | 108 | function allowance(address tokenOwner, address spender) 109 | external 110 | view 111 | override 112 | returns (uint256 remaining) 113 | { 114 | return allowed[tokenOwner][spender]; 115 | } 116 | 117 | function setCap(uint256 _cap, bool _freezeCap) external { 118 | require( 119 | accessControls.hasAdminRole(_msgSender()), 120 | "DreamToken.setCap: Sender must be admin" 121 | ); 122 | require( 123 | _freezeCap || _cap >= _totalSupply, 124 | "Cap less than totalSupply" 125 | ); 126 | require(!freezeCap, "Cap frozen"); 127 | (cap, freezeCap) = (_cap, _freezeCap); 128 | emit CapUpdated(cap, freezeCap); 129 | } 130 | 131 | function availableToMint() external view returns (uint256 tokens) { 132 | if (accessControls.hasMinterRole(_msgSender())) { 133 | if (cap > 0) { 134 | tokens = cap.sub(_totalSupply.sub(balances[address(0)])); 135 | } else { 136 | tokens = uint256(-1); 137 | } 138 | } 139 | } 140 | 141 | function mint(address tokenOwner, uint256 tokens) 142 | external 143 | returns (bool success) 144 | { 145 | require( 146 | accessControls.hasMinterRole(_msgSender()), 147 | "DreamToken.mint: Sender must have permission to mint" 148 | ); 149 | require(cap == 0 || _totalSupply + tokens <= cap, "Cap exceeded"); 150 | balances[tokenOwner] = balances[tokenOwner].add(tokens); 151 | _totalSupply = _totalSupply.add(tokens); 152 | emit Transfer(address(0), tokenOwner, tokens); 153 | return true; 154 | } 155 | 156 | function burn(uint256 tokens) external returns (bool success) { 157 | balances[_msgSender()] = balances[_msgSender()].sub(tokens); 158 | _totalSupply = _totalSupply.sub(tokens); 159 | emit Transfer(_msgSender(), address(0), tokens); 160 | return true; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /contracts/ERC1155/ERC1155.sol: -------------------------------------------------------------------------------- 1 | // Contract based from the following: 2 | // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/aaa5ef81cf75454d1c337dc3de03d12480849ad1/contracts/token/ERC1155/ERC1155.sol 3 | 4 | // SPDX-License-Identifier: MIT 5 | 6 | pragma solidity ^0.6.0; 7 | 8 | import "@openzeppelin/contracts/token/ERC1155/IERC1155MetadataURI.sol"; 9 | import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; 10 | import "@openzeppelin/contracts/GSN/Context.sol"; 11 | import "@openzeppelin/contracts/introspection/ERC165.sol"; 12 | import "@openzeppelin/contracts/math/SafeMath.sol"; 13 | import "@openzeppelin/contracts/utils/Address.sol"; 14 | 15 | /** 16 | * 17 | * @dev Implementation of the basic standard multi-token. 18 | * See https://eips.ethereum.org/EIPS/eip-1155 19 | * Originally based on code by Enjin: https://github.com/enjin/erc-1155 20 | * 21 | * _Available since v3.1._ 22 | * 23 | * @notice Modifications to uri logic made by BlockRocket.tech 24 | */ 25 | contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { 26 | using SafeMath for uint256; 27 | using Address for address; 28 | 29 | // Mapping from token ID to account balances 30 | mapping (uint256 => mapping(address => uint256)) private _balances; 31 | 32 | // Mapping from account to operator approvals 33 | mapping (address => mapping(address => bool)) private _operatorApprovals; 34 | 35 | // Token ID to its URI 36 | mapping (uint256 => string) internal tokenUris; 37 | 38 | // Token ID to its total supply 39 | mapping(uint256 => uint256) public tokenTotalSupply; 40 | 41 | /* 42 | * bytes4(keccak256('balanceOf(address,uint256)')) == 0x00fdd58e 43 | * bytes4(keccak256('balanceOfBatch(address[],uint256[])')) == 0x4e1273f4 44 | * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 45 | * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5 46 | * bytes4(keccak256('safeTransferFrom(address,address,uint256,uint256,bytes)')) == 0xf242432a 47 | * bytes4(keccak256('safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)')) == 0x2eb2c2d6 48 | * 49 | * => 0x00fdd58e ^ 0x4e1273f4 ^ 0xa22cb465 ^ 50 | * 0xe985e9c5 ^ 0xf242432a ^ 0x2eb2c2d6 == 0xd9b67a26 51 | */ 52 | bytes4 private constant _INTERFACE_ID_ERC1155 = 0xd9b67a26; 53 | 54 | /* 55 | * bytes4(keccak256('uri(uint256)')) == 0x0e89341c 56 | */ 57 | bytes4 private constant _INTERFACE_ID_ERC1155_METADATA_URI = 0x0e89341c; 58 | 59 | constructor () public { 60 | // register the supported interfaces to conform to ERC1155 via ERC165 61 | _registerInterface(_INTERFACE_ID_ERC1155); 62 | 63 | // register the supported interfaces to conform to ERC1155MetadataURI via ERC165 64 | _registerInterface(_INTERFACE_ID_ERC1155_METADATA_URI); 65 | } 66 | 67 | /** 68 | * @dev See {IERC1155MetadataURI-uri}. 69 | */ 70 | function uri(uint256 tokenId) external view override returns (string memory) { 71 | return tokenUris[tokenId]; 72 | } 73 | 74 | /** 75 | * @dev See {IERC1155-balanceOf}. 76 | * 77 | * Requirements: 78 | * 79 | * - `account` cannot be the zero address. 80 | */ 81 | function balanceOf(address account, uint256 id) public view override returns (uint256) { 82 | require(account != address(0), "ERC1155: balance query for the zero address"); 83 | return _balances[id][account]; 84 | } 85 | 86 | /** 87 | * @dev See {IERC1155-balanceOfBatch}. 88 | * 89 | * Requirements: 90 | * 91 | * - `accounts` and `ids` must have the same length. 92 | */ 93 | function balanceOfBatch( 94 | address[] memory accounts, 95 | uint256[] memory ids 96 | ) 97 | public 98 | view 99 | override 100 | returns (uint256[] memory) 101 | { 102 | require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); 103 | 104 | uint256[] memory batchBalances = new uint256[](accounts.length); 105 | 106 | for (uint256 i = 0; i < accounts.length; ++i) { 107 | require(accounts[i] != address(0), "ERC1155: batch balance query for the zero address"); 108 | batchBalances[i] = _balances[ids[i]][accounts[i]]; 109 | } 110 | 111 | return batchBalances; 112 | } 113 | 114 | /** 115 | * @dev See {IERC1155-setApprovalForAll}. 116 | */ 117 | function setApprovalForAll(address operator, bool approved) public virtual override { 118 | require(_msgSender() != operator, "ERC1155: setting approval status for self"); 119 | 120 | _operatorApprovals[_msgSender()][operator] = approved; 121 | emit ApprovalForAll(_msgSender(), operator, approved); 122 | } 123 | 124 | /** 125 | * @dev See {IERC1155-isApprovedForAll}. 126 | */ 127 | function isApprovedForAll(address account, address operator) public view override returns (bool) { 128 | return _operatorApprovals[account][operator]; 129 | } 130 | 131 | /** 132 | * @dev See {IERC1155-safeTransferFrom}. 133 | */ 134 | function safeTransferFrom( 135 | address from, 136 | address to, 137 | uint256 id, 138 | uint256 amount, 139 | bytes memory data 140 | ) 141 | public 142 | virtual 143 | override 144 | { 145 | require(to != address(0), "ERC1155: transfer to the zero address"); 146 | require( 147 | from == _msgSender() || isApprovedForAll(from, _msgSender()), 148 | "ERC1155: caller is not owner nor approved" 149 | ); 150 | 151 | address operator = _msgSender(); 152 | 153 | _beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data); 154 | 155 | _balances[id][from] = _balances[id][from].sub(amount, "ERC1155: insufficient balance for transfer"); 156 | _balances[id][to] = _balances[id][to].add(amount); 157 | 158 | emit TransferSingle(operator, from, to, id, amount); 159 | 160 | _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); 161 | } 162 | 163 | /** 164 | * @dev See {IERC1155-safeBatchTransferFrom}. 165 | */ 166 | function safeBatchTransferFrom( 167 | address from, 168 | address to, 169 | uint256[] memory ids, 170 | uint256[] memory amounts, 171 | bytes memory data 172 | ) 173 | public 174 | virtual 175 | override 176 | { 177 | require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); 178 | require(to != address(0), "ERC1155: transfer to the zero address"); 179 | require( 180 | from == _msgSender() || isApprovedForAll(from, _msgSender()), 181 | "ERC1155: transfer caller is not owner nor approved" 182 | ); 183 | 184 | address operator = _msgSender(); 185 | 186 | _beforeTokenTransfer(operator, from, to, ids, amounts, data); 187 | 188 | for (uint256 i = 0; i < ids.length; ++i) { 189 | uint256 id = ids[i]; 190 | uint256 amount = amounts[i]; 191 | 192 | _balances[id][from] = _balances[id][from].sub( 193 | amount, 194 | "ERC1155: insufficient balance for transfer" 195 | ); 196 | _balances[id][to] = _balances[id][to].add(amount); 197 | } 198 | 199 | emit TransferBatch(operator, from, to, ids, amounts); 200 | 201 | _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); 202 | } 203 | 204 | /** 205 | * @dev Sets a new URI for a given token ID 206 | */ 207 | function _setURI(uint256 tokenId, string memory newuri) internal virtual { 208 | tokenUris[tokenId] = newuri; 209 | } 210 | 211 | /** 212 | * @dev Creates `amount` tokens of token type `id`, and assigns them to `account`. 213 | * 214 | * Emits a {TransferSingle} event. 215 | * 216 | * Requirements: 217 | * 218 | * - `account` cannot be the zero address. 219 | * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the 220 | * acceptance magic value. 221 | */ 222 | function _mint(address account, uint256 id, uint256 amount, bytes memory data) internal virtual { 223 | require(account != address(0), "ERC1155: mint to the zero address"); 224 | 225 | address operator = _msgSender(); 226 | 227 | _beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data); 228 | 229 | _balances[id][account] = _balances[id][account].add(amount); 230 | tokenTotalSupply[id] = tokenTotalSupply[id].add(amount); 231 | emit TransferSingle(operator, address(0), account, id, amount); 232 | 233 | _doSafeTransferAcceptanceCheck(operator, address(0), account, id, amount, data); 234 | } 235 | 236 | /** 237 | * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. 238 | * 239 | * Requirements: 240 | * 241 | * - `ids` and `amounts` must have the same length. 242 | * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the 243 | * acceptance magic value. 244 | */ 245 | function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual { 246 | require(to != address(0), "ERC1155: mint to the zero address"); 247 | require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); 248 | 249 | address operator = _msgSender(); 250 | 251 | _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); 252 | 253 | for (uint i = 0; i < ids.length; i++) { 254 | uint256 id = ids[i]; 255 | uint256 amount = amounts[i]; 256 | _balances[id][to] = amount.add(_balances[id][to]); 257 | tokenTotalSupply[id] = tokenTotalSupply[id].add(amount); 258 | } 259 | 260 | emit TransferBatch(operator, address(0), to, ids, amounts); 261 | 262 | _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); 263 | } 264 | 265 | /** 266 | * @dev Destroys `amount` tokens of token type `id` from `account` 267 | * 268 | * Requirements: 269 | * 270 | * - `account` cannot be the zero address. 271 | * - `account` must have at least `amount` tokens of token type `id`. 272 | */ 273 | function _burn(address account, uint256 id, uint256 amount) internal virtual { 274 | require(account != address(0), "ERC1155: burn from the zero address"); 275 | 276 | address operator = _msgSender(); 277 | 278 | _beforeTokenTransfer(operator, account, address(0), _asSingletonArray(id), _asSingletonArray(amount), ""); 279 | 280 | _balances[id][account] = _balances[id][account].sub( 281 | amount, 282 | "ERC1155: burn amount exceeds balance" 283 | ); 284 | 285 | tokenTotalSupply[id] = tokenTotalSupply[id].sub(amount); 286 | 287 | emit TransferSingle(operator, account, address(0), id, amount); 288 | } 289 | 290 | /** 291 | * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. 292 | * 293 | * Requirements: 294 | * 295 | * - `ids` and `amounts` must have the same length. 296 | */ 297 | function _burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) internal virtual { 298 | require(account != address(0), "ERC1155: burn from the zero address"); 299 | require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); 300 | 301 | address operator = _msgSender(); 302 | 303 | _beforeTokenTransfer(operator, account, address(0), ids, amounts, ""); 304 | 305 | for (uint i = 0; i < ids.length; i++) { 306 | uint256 id = ids[i]; 307 | uint256 amount = amounts[i]; 308 | _balances[id][account] = _balances[id][account].sub( 309 | amount, 310 | "ERC1155: burn amount exceeds balance" 311 | ); 312 | 313 | tokenTotalSupply[id] = tokenTotalSupply[id].sub(amount); 314 | } 315 | 316 | emit TransferBatch(operator, account, address(0), ids, amounts); 317 | } 318 | 319 | /** 320 | * @dev Hook that is called before any token transfer. This includes minting 321 | * and burning, as well as batched variants. 322 | * 323 | * The same hook is called on both single and batched variants. For single 324 | * transfers, the length of the `id` and `amount` arrays will be 1. 325 | * 326 | * Calling conditions (for each `id` and `amount` pair): 327 | * 328 | * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens 329 | * of token type `id` will be transferred to `to`. 330 | * - When `from` is zero, `amount` tokens of token type `id` will be minted 331 | * for `to`. 332 | * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` 333 | * will be burned. 334 | * - `from` and `to` are never both zero. 335 | * - `ids` and `amounts` have the same, non-zero length. 336 | * 337 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 338 | */ 339 | function _beforeTokenTransfer( 340 | address operator, 341 | address from, 342 | address to, 343 | uint256[] memory ids, 344 | uint256[] memory amounts, 345 | bytes memory data 346 | ) 347 | internal virtual 348 | { } 349 | 350 | function _doSafeTransferAcceptanceCheck( 351 | address operator, 352 | address from, 353 | address to, 354 | uint256 id, 355 | uint256 amount, 356 | bytes memory data 357 | ) 358 | private 359 | { 360 | if (to.isContract()) { 361 | try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { 362 | if (response != IERC1155Receiver(to).onERC1155Received.selector) { 363 | revert("ERC1155: ERC1155Receiver rejected tokens"); 364 | } 365 | } catch Error(string memory reason) { 366 | revert(reason); 367 | } catch { 368 | revert("ERC1155: transfer to non ERC1155Receiver implementer"); 369 | } 370 | } 371 | } 372 | 373 | function _doSafeBatchTransferAcceptanceCheck( 374 | address operator, 375 | address from, 376 | address to, 377 | uint256[] memory ids, 378 | uint256[] memory amounts, 379 | bytes memory data 380 | ) 381 | private 382 | { 383 | if (to.isContract()) { 384 | try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (bytes4 response) { 385 | if (response != IERC1155Receiver(to).onERC1155BatchReceived.selector) { 386 | revert("ERC1155: ERC1155Receiver rejected tokens"); 387 | } 388 | } catch Error(string memory reason) { 389 | revert(reason); 390 | } catch { 391 | revert("ERC1155: transfer to non ERC1155Receiver implementer"); 392 | } 393 | } 394 | } 395 | 396 | function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { 397 | uint256[] memory array = new uint256[](1); 398 | array[0] = element; 399 | 400 | return array; 401 | } 402 | } 403 | -------------------------------------------------------------------------------- /contracts/ERC1155/ERC1155Burnable.sol: -------------------------------------------------------------------------------- 1 | //imported from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/aaa5ef81cf75454d1c337dc3de03d12480849ad1/contracts/token/ERC1155/ERC1155Burnable.sol 2 | 3 | // SPDX-License-Identifier: MIT 4 | 5 | pragma solidity 0.6.12; 6 | 7 | import "./ERC1155.sol"; 8 | 9 | /** 10 | * @dev Extension of {ERC1155} that allows token holders to destroy both their 11 | * own tokens and those that they have been approved to use. 12 | * 13 | * _Available since v3.1._ 14 | */ 15 | abstract contract ERC1155Burnable is ERC1155 { 16 | function burn(address account, uint256 id, uint256 amount) public virtual { 17 | require( 18 | account == _msgSender() || isApprovedForAll(account, _msgSender()), 19 | "ERC1155: caller is not owner nor approved" 20 | ); 21 | 22 | _burn(account, id, amount); 23 | } 24 | 25 | function burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) public virtual { 26 | require( 27 | account == _msgSender() || isApprovedForAll(account, _msgSender()), 28 | "ERC1155: caller is not owner nor approved" 29 | ); 30 | 31 | _burnBatch(account, ids, amounts); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contracts/ERC998/IERC998ERC1155TopDown.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.6.12; 4 | 5 | import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; 6 | 7 | // Based on: https://github.com/rocksideio/ERC998-ERC1155-TopDown/blob/695963195606304374015c49d166ab2fbeb42ea9/contracts/IERC998ERC1155TopDown.sol 8 | interface IERC998ERC1155TopDown is IERC1155Receiver { 9 | 10 | event ReceivedChild(address indexed from, uint256 indexed toTokenId, address indexed childContract, uint256 childTokenId, uint256 amount); 11 | event TransferSingleChild(uint256 indexed fromTokenId, address indexed to, address indexed childContract, uint256 childTokenId, uint256 amount); 12 | event TransferBatchChild(uint256 indexed fromTokenId, address indexed to, address indexed childContract, uint256[] childTokenIds, uint256[] amounts); 13 | 14 | function childContractsFor(uint256 tokenId) external view returns (address[] memory childContracts); 15 | 16 | function childIdsForOn(uint256 tokenId, address childContract) external view returns (uint256[] memory childIds); 17 | 18 | function childBalance(uint256 tokenId, address childContract, uint256 childTokenId) external view returns (uint256); 19 | } 20 | -------------------------------------------------------------------------------- /contracts/Utils/BokkyPooBahsDateTimeLibrary.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.0; 2 | 3 | // ---------------------------------------------------------------------------- 4 | // BokkyPooBah's DateTime Library v1.01 5 | // 6 | // A gas-efficient Solidity date and time library 7 | // 8 | // https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary 9 | // 10 | // Tested date range 1970/01/01 to 2345/12/31 11 | // 12 | // Conventions: 13 | // Unit | Range | Notes 14 | // :-------- |:-------------:|:----- 15 | // timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC 16 | // year | 1970 ... 2345 | 17 | // month | 1 ... 12 | 18 | // day | 1 ... 31 | 19 | // hour | 0 ... 23 | 20 | // minute | 0 ... 59 | 21 | // second | 0 ... 59 | 22 | // dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday 23 | // 24 | // 25 | // Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. 26 | // ---------------------------------------------------------------------------- 27 | 28 | library BokkyPooBahsDateTimeLibrary { 29 | 30 | uint constant SECONDS_PER_DAY = 24 * 60 * 60; 31 | uint constant SECONDS_PER_HOUR = 60 * 60; 32 | uint constant SECONDS_PER_MINUTE = 60; 33 | int constant OFFSET19700101 = 2440588; 34 | 35 | uint constant DOW_MON = 1; 36 | uint constant DOW_TUE = 2; 37 | uint constant DOW_WED = 3; 38 | uint constant DOW_THU = 4; 39 | uint constant DOW_FRI = 5; 40 | uint constant DOW_SAT = 6; 41 | uint constant DOW_SUN = 7; 42 | 43 | // ------------------------------------------------------------------------ 44 | // Calculate the number of days from 1970/01/01 to year/month/day using 45 | // the date conversion algorithm from 46 | // http://aa.usno.navy.mil/faq/docs/JD_Formula.php 47 | // and subtracting the offset 2440588 so that 1970/01/01 is day 0 48 | // 49 | // days = day 50 | // - 32075 51 | // + 1461 * (year + 4800 + (month - 14) / 12) / 4 52 | // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 53 | // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 54 | // - offset 55 | // ------------------------------------------------------------------------ 56 | function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) { 57 | require(year >= 1970); 58 | int _year = int(year); 59 | int _month = int(month); 60 | int _day = int(day); 61 | 62 | int __days = _day 63 | - 32075 64 | + 1461 * (_year + 4800 + (_month - 14) / 12) / 4 65 | + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12 66 | - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4 67 | - OFFSET19700101; 68 | 69 | _days = uint(__days); 70 | } 71 | 72 | // ------------------------------------------------------------------------ 73 | // Calculate year/month/day from the number of days since 1970/01/01 using 74 | // the date conversion algorithm from 75 | // http://aa.usno.navy.mil/faq/docs/JD_Formula.php 76 | // and adding the offset 2440588 so that 1970/01/01 is day 0 77 | // 78 | // int L = days + 68569 + offset 79 | // int N = 4 * L / 146097 80 | // L = L - (146097 * N + 3) / 4 81 | // year = 4000 * (L + 1) / 1461001 82 | // L = L - 1461 * year / 4 + 31 83 | // month = 80 * L / 2447 84 | // dd = L - 2447 * month / 80 85 | // L = month / 11 86 | // month = month + 2 - 12 * L 87 | // year = 100 * (N - 49) + year + L 88 | // ------------------------------------------------------------------------ 89 | function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) { 90 | int __days = int(_days); 91 | 92 | int L = __days + 68569 + OFFSET19700101; 93 | int N = 4 * L / 146097; 94 | L = L - (146097 * N + 3) / 4; 95 | int _year = 4000 * (L + 1) / 1461001; 96 | L = L - 1461 * _year / 4 + 31; 97 | int _month = 80 * L / 2447; 98 | int _day = L - 2447 * _month / 80; 99 | L = _month / 11; 100 | _month = _month + 2 - 12 * L; 101 | _year = 100 * (N - 49) + _year + L; 102 | 103 | year = uint(_year); 104 | month = uint(_month); 105 | day = uint(_day); 106 | } 107 | 108 | function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) { 109 | timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; 110 | } 111 | function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) { 112 | timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; 113 | } 114 | function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) { 115 | (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); 116 | } 117 | function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { 118 | (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); 119 | uint secs = timestamp % SECONDS_PER_DAY; 120 | hour = secs / SECONDS_PER_HOUR; 121 | secs = secs % SECONDS_PER_HOUR; 122 | minute = secs / SECONDS_PER_MINUTE; 123 | second = secs % SECONDS_PER_MINUTE; 124 | } 125 | 126 | function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) { 127 | if (year >= 1970 && month > 0 && month <= 12) { 128 | uint daysInMonth = _getDaysInMonth(year, month); 129 | if (day > 0 && day <= daysInMonth) { 130 | valid = true; 131 | } 132 | } 133 | } 134 | function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) { 135 | if (isValidDate(year, month, day)) { 136 | if (hour < 24 && minute < 60 && second < 60) { 137 | valid = true; 138 | } 139 | } 140 | } 141 | function isLeapYear(uint timestamp) internal pure returns (bool leapYear) { 142 | (uint year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); 143 | leapYear = _isLeapYear(year); 144 | } 145 | function _isLeapYear(uint year) internal pure returns (bool leapYear) { 146 | leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); 147 | } 148 | function isWeekDay(uint timestamp) internal pure returns (bool weekDay) { 149 | weekDay = getDayOfWeek(timestamp) <= DOW_FRI; 150 | } 151 | function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) { 152 | weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; 153 | } 154 | function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) { 155 | (uint year, uint month,) = _daysToDate(timestamp / SECONDS_PER_DAY); 156 | daysInMonth = _getDaysInMonth(year, month); 157 | } 158 | function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) { 159 | if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { 160 | daysInMonth = 31; 161 | } else if (month != 2) { 162 | daysInMonth = 30; 163 | } else { 164 | daysInMonth = _isLeapYear(year) ? 29 : 28; 165 | } 166 | } 167 | // 1 = Monday, 7 = Sunday 168 | function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) { 169 | uint _days = timestamp / SECONDS_PER_DAY; 170 | dayOfWeek = (_days + 3) % 7 + 1; 171 | } 172 | 173 | function getYear(uint timestamp) internal pure returns (uint year) { 174 | (year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); 175 | } 176 | function getMonth(uint timestamp) internal pure returns (uint month) { 177 | (,month,) = _daysToDate(timestamp / SECONDS_PER_DAY); 178 | } 179 | function getDay(uint timestamp) internal pure returns (uint day) { 180 | (,,day) = _daysToDate(timestamp / SECONDS_PER_DAY); 181 | } 182 | function getHour(uint timestamp) internal pure returns (uint hour) { 183 | uint secs = timestamp % SECONDS_PER_DAY; 184 | hour = secs / SECONDS_PER_HOUR; 185 | } 186 | function getMinute(uint timestamp) internal pure returns (uint minute) { 187 | uint secs = timestamp % SECONDS_PER_HOUR; 188 | minute = secs / SECONDS_PER_MINUTE; 189 | } 190 | function getSecond(uint timestamp) internal pure returns (uint second) { 191 | second = timestamp % SECONDS_PER_MINUTE; 192 | } 193 | 194 | function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { 195 | (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); 196 | year += _years; 197 | uint daysInMonth = _getDaysInMonth(year, month); 198 | if (day > daysInMonth) { 199 | day = daysInMonth; 200 | } 201 | newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; 202 | require(newTimestamp >= timestamp); 203 | } 204 | function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { 205 | (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); 206 | month += _months; 207 | year += (month - 1) / 12; 208 | month = (month - 1) % 12 + 1; 209 | uint daysInMonth = _getDaysInMonth(year, month); 210 | if (day > daysInMonth) { 211 | day = daysInMonth; 212 | } 213 | newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; 214 | require(newTimestamp >= timestamp); 215 | } 216 | function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { 217 | newTimestamp = timestamp + _days * SECONDS_PER_DAY; 218 | require(newTimestamp >= timestamp); 219 | } 220 | function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { 221 | newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; 222 | require(newTimestamp >= timestamp); 223 | } 224 | function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { 225 | newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; 226 | require(newTimestamp >= timestamp); 227 | } 228 | function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { 229 | newTimestamp = timestamp + _seconds; 230 | require(newTimestamp >= timestamp); 231 | } 232 | 233 | function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { 234 | (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); 235 | year -= _years; 236 | uint daysInMonth = _getDaysInMonth(year, month); 237 | if (day > daysInMonth) { 238 | day = daysInMonth; 239 | } 240 | newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; 241 | require(newTimestamp <= timestamp); 242 | } 243 | function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { 244 | (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); 245 | uint yearMonth = year * 12 + (month - 1) - _months; 246 | year = yearMonth / 12; 247 | month = yearMonth % 12 + 1; 248 | uint daysInMonth = _getDaysInMonth(year, month); 249 | if (day > daysInMonth) { 250 | day = daysInMonth; 251 | } 252 | newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; 253 | require(newTimestamp <= timestamp); 254 | } 255 | function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { 256 | newTimestamp = timestamp - _days * SECONDS_PER_DAY; 257 | require(newTimestamp <= timestamp); 258 | } 259 | function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { 260 | newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; 261 | require(newTimestamp <= timestamp); 262 | } 263 | function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { 264 | newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; 265 | require(newTimestamp <= timestamp); 266 | } 267 | function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { 268 | newTimestamp = timestamp - _seconds; 269 | require(newTimestamp <= timestamp); 270 | } 271 | 272 | function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) { 273 | require(fromTimestamp <= toTimestamp); 274 | (uint fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); 275 | (uint toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); 276 | _years = toYear - fromYear; 277 | } 278 | function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) { 279 | require(fromTimestamp <= toTimestamp); 280 | (uint fromYear, uint fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); 281 | (uint toYear, uint toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); 282 | _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; 283 | } 284 | function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) { 285 | require(fromTimestamp <= toTimestamp); 286 | _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; 287 | } 288 | function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) { 289 | require(fromTimestamp <= toTimestamp); 290 | _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; 291 | } 292 | function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) { 293 | require(fromTimestamp <= toTimestamp); 294 | _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; 295 | } 296 | function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) { 297 | require(fromTimestamp <= toTimestamp); 298 | _seconds = toTimestamp - fromTimestamp; 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /contracts/Utils/CloneFactory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.12; 2 | 3 | /// @notice https://github.com/optionality/clone-factory/blob/32782f82dfc5a00d103a7e61a17a5dedbd1e8e9d/contracts/CloneFactory.sol 4 | // SPDX-License-Identifier: MIT 5 | /* 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2018 Murray Software, LLC. 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining 11 | a copy of this software and associated documentation files (the 12 | "Software"), to deal in the Software without restriction, including 13 | without limitation the rights to use, copy, modify, merge, publish, 14 | distribute, sublicense, and/or sell copies of the Software, and to 15 | permit persons to whom the Software is furnished to do so, subject to 16 | the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included 19 | in all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 25 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 26 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 27 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | //solhint-disable max-line-length 30 | //solhint-disable no-inline-assembly 31 | 32 | contract CloneFactory { 33 | 34 | function createClone(address target) internal returns (address result) { 35 | bytes20 targetBytes = bytes20(target); 36 | assembly { 37 | let clone := mload(0x40) 38 | mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) 39 | mstore(add(clone, 0x14), targetBytes) 40 | mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) 41 | result := create(0, clone, 0x37) 42 | } 43 | } 44 | 45 | function isClone(address target, address query) internal view returns (bool result) { 46 | bytes20 targetBytes = bytes20(target); 47 | assembly { 48 | let clone := mload(0x40) 49 | mstore(clone, 0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000) 50 | mstore(add(clone, 0xa), targetBytes) 51 | mstore(add(clone, 0x1e), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) 52 | 53 | let other := add(clone, 0x40) 54 | extcodecopy(query, other, 0, 0x2d) 55 | result := and( 56 | eq(mload(clone), mload(other)), 57 | eq(mload(add(clone, 0xd)), mload(add(other, 0xd))) 58 | ) 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /contracts/Utils/RealMath.sol: -------------------------------------------------------------------------------- 1 | 2 | pragma solidity ^0.6.10; 3 | 4 | /** 5 | * RealMath: fixed-point math library, based on fractional and integer parts. 6 | * Using int128 as real88x40, which isn't in Solidity yet. 7 | * 40 fractional bits gets us down to 1E-12 precision, while still letting us 8 | * go up to galaxy scale counting in meters. 9 | * Internally uses the wider int256 for some math. 10 | * 11 | * Note that for addition, subtraction, and mod (%), you should just use the 12 | * built-in Solidity operators. Functions for these operations are not provided. 13 | * 14 | * Note that the fancy functions like sqrt, atan2, etc. aren't as accurate as 15 | * they should be. They are (hopefully) Good Enough for doing orbital mechanics 16 | * on block timescales in a game context, but they may not be good enough for 17 | * other applications. 18 | */ 19 | 20 | library RealMath { 21 | 22 | 23 | /**@dev 24 | * How many total bits are there? 25 | */ 26 | int256 constant REAL_BITS = 128; 27 | 28 | /**@dev 29 | * How many fractional bits are there? 30 | */ 31 | int256 constant REAL_FBITS = 40; 32 | 33 | /**@dev 34 | * How many integer bits are there? 35 | */ 36 | int256 constant REAL_IBITS = REAL_BITS - REAL_FBITS; 37 | 38 | /**@dev 39 | * What's the first non-fractional bit 40 | */ 41 | int128 constant REAL_ONE = int128(1) << int128(REAL_FBITS); 42 | 43 | /**@dev 44 | * What's the last fractional bit? 45 | */ 46 | int128 constant REAL_HALF = REAL_ONE >> int128(1); 47 | 48 | /**@dev 49 | * What's two? Two is pretty useful. 50 | */ 51 | int128 constant REAL_TWO = REAL_ONE << int128(1); 52 | 53 | /**@dev 54 | * And our logarithms are based on ln(2). 55 | */ 56 | int128 constant REAL_LN_TWO = 762123384786; 57 | 58 | 59 | /** 60 | * Convert an integer to a real. Preserves sign. 61 | */ 62 | function toReal(int88 ipart) public pure returns (int128) { 63 | return int128(ipart) * REAL_ONE; 64 | } 65 | 66 | /** 67 | * Shift real_arg left or right until it is between 1 and 2. Return the 68 | * rescaled value, and the number of bits of right shift applied. Shift may be negative. 69 | * 70 | * Expresses real_arg as real_scaled * 2^shift, setting shift to put real_arg between [1 and 2). 71 | * 72 | * Rejects 0 or negative arguments. 73 | */ 74 | function rescale(int128 real_arg) internal pure returns (int128 real_scaled, int88 shift) { 75 | if (real_arg <= 0) { 76 | // Not in domain! 77 | revert(); 78 | } 79 | 80 | // Find the high bit 81 | int88 high_bit = findbit(hibit(uint256(real_arg))); 82 | 83 | // We'll shift so the high bit is the lowest non-fractional bit. 84 | shift = high_bit - int88(REAL_FBITS); 85 | 86 | if (shift < 0) { 87 | // Shift left 88 | real_scaled = real_arg << int128(-shift); 89 | } else if (shift >= 0) { 90 | // Shift right 91 | real_scaled = real_arg >> int128(shift); 92 | } 93 | } 94 | 95 | /** 96 | * Zero all but the highest set bit of a number. 97 | * See 98 | */ 99 | function hibit(uint256 val) internal pure returns (uint256) { 100 | // Set all the bits below the highest set bit 101 | val |= (val >> 1); 102 | val |= (val >> 2); 103 | val |= (val >> 4); 104 | val |= (val >> 8); 105 | val |= (val >> 16); 106 | val |= (val >> 32); 107 | val |= (val >> 64); 108 | val |= (val >> 128); 109 | return val ^ (val >> 1); 110 | } 111 | 112 | 113 | /** 114 | * Given a number with one bit set, finds the index of that bit. 115 | */ 116 | function findbit(uint256 val) internal pure returns (uint8 index) { 117 | index = 0; 118 | // We and the value with alternating bit patters of various pitches to find it. 119 | 120 | if (val & 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA != 0) { 121 | // Picth 1 122 | index |= 1; 123 | } 124 | if (val & 0xCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC != 0) { 125 | // Pitch 2 126 | index |= 2; 127 | } 128 | if (val & 0xF0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0 != 0) { 129 | // Pitch 4 130 | index |= 4; 131 | } 132 | if (val & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 != 0) { 133 | // Pitch 8 134 | index |= 8; 135 | } 136 | if (val & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000 != 0) { 137 | // Pitch 16 138 | index |= 16; 139 | } 140 | if (val & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000 != 0) { 141 | // Pitch 32 142 | index |= 32; 143 | } 144 | if (val & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000 != 0) { 145 | // Pitch 64 146 | index |= 64; 147 | } 148 | if (val & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000 != 0) { 149 | // Pitch 128 150 | index |= 128; 151 | } 152 | } 153 | 154 | 155 | /** 156 | * Divide one real by another real. Truncates overflows. 157 | */ 158 | function div(int128 real_numerator, int128 real_denominator) public pure returns (int128) { 159 | // We use the reverse of the multiplication trick: convert numerator from 160 | // x.y to (x+z).(y+w) fixed point, then divide by denom in z.w fixed point. 161 | return int128((int256(real_numerator) * REAL_ONE) / int256(real_denominator)); 162 | } 163 | 164 | /** 165 | * Multiply one real by another. Truncates overflows. 166 | */ 167 | function mul(int128 real_a, int128 real_b) public pure returns (int128) { 168 | // When multiplying fixed point in x.y and z.w formats we get (x+z).(y+w) format. 169 | // So we just have to clip off the extra REAL_FBITS fractional bits. 170 | return int128((int256(real_a) * int256(real_b)) >> REAL_FBITS); 171 | } 172 | 173 | 174 | /** 175 | * Raise a number to a positive integer power in O(log power) time. 176 | * See 177 | */ 178 | function ipow(int128 real_base, int88 exponent) public pure returns (int128) { 179 | if (exponent < 0) { 180 | // Negative powers are not allowed here. 181 | revert(); 182 | } 183 | 184 | // Start with the 0th power 185 | int128 real_result = REAL_ONE; 186 | while (exponent != 0) { 187 | // While there are still bits set 188 | if ((exponent & 0x1) == 0x1) { 189 | // If the low bit is set, multiply in the (many-times-squared) base 190 | real_result = mul(real_result, real_base); 191 | } 192 | // Shift off the low bit 193 | exponent = exponent >> 1; 194 | // Do the squaring 195 | real_base = mul(real_base, real_base); 196 | } 197 | 198 | // Return the final result. 199 | return real_result; 200 | } 201 | 202 | /** 203 | * Calculate the natural log of a number. Rescales the input value and uses 204 | * the algorithm outlined at and 205 | * the ipow implementation. 206 | * 207 | * Lets you artificially limit the number of iterations. 208 | * 209 | * Note that it is potentially possible to get an un-converged value; lack 210 | * of convergence does not throw. 211 | */ 212 | function lnLimited(int128 real_arg, int max_iterations) public pure returns (int128) { 213 | if (real_arg <= 0) { 214 | // Outside of acceptable domain 215 | revert(); 216 | } 217 | 218 | if (real_arg == REAL_ONE) { 219 | // Handle this case specially because people will want exactly 0 and 220 | // not ~2^-39 ish. 221 | return 0; 222 | } 223 | 224 | // We know it's positive, so rescale it to be between [1 and 2) 225 | int128 real_rescaled; 226 | int88 shift; 227 | (real_rescaled, shift) = rescale(real_arg); 228 | 229 | // Compute the argument to iterate on 230 | int128 real_series_arg = div(real_rescaled - REAL_ONE, real_rescaled + REAL_ONE); 231 | 232 | // We will accumulate the result here 233 | int128 real_series_result = 0; 234 | 235 | for (int88 n = 0; n < max_iterations; n++) { 236 | // Compute term n of the series 237 | int128 real_term = div(ipow(real_series_arg, 2 * n + 1), toReal(2 * n + 1)); 238 | // And add it in 239 | real_series_result += real_term; 240 | if (real_term == 0) { 241 | // We must have converged. Next term is too small to represent. 242 | break; 243 | } 244 | // If we somehow never converge I guess we will run out of gas 245 | } 246 | 247 | // Double it to account for the factor of 2 outside the sum 248 | real_series_result = mul(real_series_result, REAL_TWO); 249 | 250 | // Now compute and return the overall result 251 | return mul(toReal(shift), REAL_LN_TWO) + real_series_result; 252 | 253 | } 254 | 255 | /** 256 | * Calculate a natural logarithm with a sensible maximum iteration count to 257 | * wait until convergence. Note that it is potentially possible to get an 258 | * un-converged value; lack of convergence does not throw. 259 | */ 260 | function ln(int128 real_arg) public pure returns (int128) { 261 | return lnLimited(real_arg, 50); 262 | } 263 | 264 | /** 265 | * Calculate e^x. Uses the series given at 266 | * . 267 | * 268 | * Lets you artificially limit the number of iterations. 269 | * 270 | * Note that it is potentially possible to get an un-converged value; lack 271 | * of convergence does not throw. 272 | */ 273 | function expLimited(int128 real_arg, int max_iterations) public pure returns (int128) { 274 | // We will accumulate the result here 275 | int128 real_result = 0; 276 | 277 | // We use this to save work computing terms 278 | int128 real_term = REAL_ONE; 279 | 280 | for (int88 n = 0; n < max_iterations; n++) { 281 | // Add in the term 282 | real_result += real_term; 283 | 284 | // Compute the next term 285 | real_term = mul(real_term, div(real_arg, toReal(n + 1))); 286 | 287 | if (real_term == 0) { 288 | // We must have converged. Next term is too small to represent. 289 | break; 290 | } 291 | // If we somehow never converge I guess we will run out of gas 292 | } 293 | 294 | // Return the result 295 | return real_result; 296 | 297 | } 298 | 299 | /** 300 | * Calculate e^x with a sensible maximum iteration count to wait until 301 | * convergence. Note that it is potentially possible to get an un-converged 302 | * value; lack of convergence does not throw. 303 | */ 304 | function exp(int128 real_arg) public pure returns (int128) { 305 | return expLimited(real_arg, 50); 306 | } 307 | 308 | } -------------------------------------------------------------------------------- /contracts/Utils/UniswapV2Library.sol: -------------------------------------------------------------------------------- 1 | 2 | pragma solidity 0.6.12; 3 | 4 | import "@openzeppelin/contracts/math/SafeMath.sol"; 5 | import "../../interfaces/IUniswapV2Pair.sol"; 6 | 7 | 8 | library UniswapV2Library { 9 | using SafeMath for uint; 10 | 11 | // returns sorted token addresses, used to handle return values from pairs sorted in this order 12 | function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { 13 | require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES'); 14 | (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); 15 | require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS'); 16 | } 17 | 18 | // calculates the CREATE2 address for a pair without making any external calls 19 | function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) { 20 | (address token0, address token1) = sortTokens(tokenA, tokenB); 21 | pair = address(uint(keccak256(abi.encodePacked( 22 | hex'ff', 23 | factory, 24 | keccak256(abi.encodePacked(token0, token1)), 25 | hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash 26 | )))); 27 | } 28 | 29 | // fetches and sorts the reserves for a pair 30 | function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) { 31 | (address token0,) = sortTokens(tokenA, tokenB); 32 | (uint reserve0, uint reserve1,) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves(); 33 | (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); 34 | } 35 | 36 | // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset 37 | function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) { 38 | require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT'); 39 | require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); 40 | amountB = amountA.mul(reserveB) / reserveA; 41 | } 42 | 43 | // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset 44 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) { 45 | require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT'); 46 | require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); 47 | uint amountInWithFee = amountIn.mul(997); 48 | uint numerator = amountInWithFee.mul(reserveOut); 49 | uint denominator = reserveIn.mul(1000).add(amountInWithFee); 50 | amountOut = numerator / denominator; 51 | } 52 | 53 | // given an output amount of an asset and pair reserves, returns a required input amount of the other asset 54 | function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) { 55 | require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT'); 56 | require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); 57 | uint numerator = reserveIn.mul(amountOut).mul(1000); 58 | uint denominator = reserveOut.sub(amountOut).mul(997); 59 | amountIn = (numerator / denominator).add(1); 60 | } 61 | 62 | // performs chained getAmountOut calculations on any number of pairs 63 | function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) { 64 | require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); 65 | amounts = new uint[](path.length); 66 | amounts[0] = amountIn; 67 | for (uint i; i < path.length - 1; i++) { 68 | (uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]); 69 | amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); 70 | } 71 | } 72 | 73 | // performs chained getAmountIn calculations on any number of pairs 74 | function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) { 75 | require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); 76 | amounts = new uint[](path.length); 77 | amounts[amounts.length - 1] = amountOut; 78 | for (uint i = path.length - 1; i > 0; i--) { 79 | (uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]); 80 | amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /contracts/Utils/UniswapZAP.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.12; 2 | 3 | 4 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 5 | // 6 | // LiquidityZAP - UniswapZAP 7 | // Copyright (c) 2020 deepyr.com 8 | // 9 | // UniswapZAP takes ETH and converts to a Uniswap liquidity tokens. 10 | // 11 | // This program is free software: you can redistribute it and/or modify 12 | // it under the terms of the GNU General Public License as published by 13 | // the Free Software Foundation, either version 3 of the License 14 | // 15 | // This program is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with this program. 22 | // If not, see . 23 | // 24 | // The above copyright notice and this permission notice shall be included 25 | // in all copies or substantial portions of the Software. 26 | // 27 | // Authors: 28 | // * Adrian Guerrera / Deepyr Pty Ltd 29 | // 30 | // Attribution: CORE / cvault.finance 31 | // https://github.com/cVault-finance/CORE-periphery/blob/master/contracts/COREv1Router.sol 32 | // --------------------------------------------------------------------- 33 | // SPDX-License-Identifier: GPL-3.0-or-later 34 | // --------------------------------------------------------------------- 35 | 36 | import "../../interfaces/IUniswapV2Pair.sol"; 37 | import "../../interfaces/IWETH9.sol"; 38 | // import "../../interfaces/IERC20.sol"; 39 | import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; 40 | import "@openzeppelin/contracts/math/SafeMath.sol"; 41 | import "./UniswapV2Library.sol"; 42 | 43 | contract UniswapZAP { 44 | 45 | using SafeMath for uint256; 46 | using SafeERC20 for IERC20; 47 | 48 | IERC20 public rewardsToken; 49 | address public lpToken; 50 | IWETH public WETH; 51 | bool private initialized; 52 | 53 | function initUniswapZAP(IERC20 _rewardsToken, IWETH _WETH, address _lpToken) internal { 54 | require(!initialized); 55 | rewardsToken = _rewardsToken; 56 | WETH = _WETH; 57 | lpToken = _lpToken; 58 | initialized = true; 59 | } 60 | 61 | receive() external virtual payable { 62 | if(msg.sender != address(WETH)){ 63 | addLiquidityETHOnly(msg.sender); 64 | } 65 | } 66 | 67 | 68 | function addLiquidityETHOnly(address payable to) public payable { 69 | require(to != address(0), "Invalid address"); 70 | 71 | uint256 buyAmount = msg.value.div(2); 72 | require(buyAmount > 0, "Insufficient ETH amount"); 73 | WETH.deposit{value : msg.value}(); 74 | 75 | (uint256 reserveWeth, uint256 reserveTokens) = getPairReserves(); 76 | uint256 outTokens = UniswapV2Library.getAmountOut(buyAmount, reserveWeth, reserveTokens); 77 | 78 | WETH.transfer(lpToken, buyAmount); 79 | 80 | (address token0, address token1) = UniswapV2Library.sortTokens(address(WETH), address(rewardsToken)); 81 | IUniswapV2Pair(lpToken).swap(address(rewardsToken) == token0 ? outTokens : 0, address(rewardsToken) == token1 ? outTokens : 0, address(this), ""); 82 | 83 | _addLiquidity(outTokens, buyAmount, to); 84 | 85 | } 86 | 87 | function _addLiquidity(uint256 tokenAmount, uint256 wethAmount, address payable to) internal { 88 | (uint256 wethReserve, uint256 tokenReserve) = getPairReserves(); 89 | 90 | uint256 optimalTokenAmount = UniswapV2Library.quote(wethAmount, wethReserve, tokenReserve); 91 | 92 | uint256 optimalWETHAmount; 93 | if (optimalTokenAmount > tokenAmount) { 94 | optimalWETHAmount = UniswapV2Library.quote(tokenAmount, tokenReserve, wethReserve); 95 | optimalTokenAmount = tokenAmount; 96 | } 97 | else 98 | optimalWETHAmount = wethAmount; 99 | 100 | assert(WETH.transfer(lpToken, optimalWETHAmount)); 101 | assert(rewardsToken.transfer(lpToken, optimalTokenAmount)); 102 | 103 | IUniswapV2Pair(lpToken).mint(to); 104 | 105 | //refund dust 106 | if (tokenAmount > optimalTokenAmount) 107 | rewardsToken.transfer(to, tokenAmount.sub(optimalTokenAmount)); 108 | 109 | if (wethAmount > optimalWETHAmount) { 110 | uint256 withdrawAmount = wethAmount.sub(optimalWETHAmount); 111 | WETH.withdraw(withdrawAmount); 112 | to.transfer(withdrawAmount); 113 | } 114 | } 115 | 116 | 117 | function getLPTokenPerEthUnit(uint ethAmt) public view returns (uint liquidity){ 118 | (uint256 reserveWeth, uint256 reserveTokens) = getPairReserves(); 119 | uint256 outTokens = UniswapV2Library.getAmountOut(ethAmt.div(2), reserveWeth, reserveTokens); 120 | uint _totalSupply = IUniswapV2Pair(lpToken).totalSupply(); 121 | 122 | (address token0, ) = UniswapV2Library.sortTokens(address(WETH), address(rewardsToken)); 123 | (uint256 amount0, uint256 amount1) = token0 == address(rewardsToken) ? (outTokens, ethAmt.div(2)) : (ethAmt.div(2), outTokens); 124 | (uint256 _reserve0, uint256 _reserve1) = token0 == address(rewardsToken) ? (reserveTokens, reserveWeth) : (reserveWeth, reserveTokens); 125 | liquidity = min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1); 126 | } 127 | 128 | function getPairReserves() internal view returns (uint256 wethReserves, uint256 tokenReserves) { 129 | (address token0,) = UniswapV2Library.sortTokens(address(WETH), address(rewardsToken)); 130 | (uint256 reserve0, uint reserve1,) = IUniswapV2Pair(lpToken).getReserves(); 131 | (wethReserves, tokenReserves) = token0 == address(rewardsToken) ? (reserve1, reserve0) : (reserve0, reserve1); 132 | } 133 | 134 | function min(uint256 a, uint256 b) internal pure returns (uint256 c) { 135 | c = a <= b ? a : b; 136 | } 137 | 138 | } -------------------------------------------------------------------------------- /contracts/Utils/WETH9.sol: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2015, 2016, 2017 Dapphub 2 | 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | pragma solidity ^0.6.12; 17 | 18 | contract WETH9 { 19 | string public name = "Wrapped Ether"; 20 | string public symbol = "WETH"; 21 | uint8 public decimals = 18; 22 | 23 | event Approval(address indexed src, address indexed guy, uint wad); 24 | event Transfer(address indexed src, address indexed dst, uint wad); 25 | event Deposit(address indexed dst, uint wad); 26 | event Withdrawal(address indexed src, uint wad); 27 | 28 | mapping (address => uint) public balanceOf; 29 | mapping (address => mapping (address => uint)) public allowance; 30 | 31 | receive() external payable { 32 | deposit(); 33 | } 34 | function deposit() public payable { 35 | balanceOf[msg.sender] += msg.value; 36 | emit Deposit(msg.sender, msg.value); 37 | } 38 | function withdraw(uint wad) public { 39 | require(balanceOf[msg.sender] >= wad); 40 | balanceOf[msg.sender] -= wad; 41 | msg.sender.transfer(wad); 42 | emit Withdrawal(msg.sender, wad); 43 | } 44 | 45 | function totalSupply() public view returns (uint) { 46 | return address(this).balance; 47 | } 48 | 49 | function approve(address guy, uint wad) public returns (bool) { 50 | allowance[msg.sender][guy] = wad; 51 | emit Approval(msg.sender, guy, wad); 52 | return true; 53 | } 54 | 55 | function transfer(address dst, uint wad) public returns (bool) { 56 | return transferFrom(msg.sender, dst, wad); 57 | } 58 | 59 | function transferFrom(address src, address dst, uint wad) 60 | public 61 | returns (bool) 62 | { 63 | require(balanceOf[src] >= wad); 64 | 65 | if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { 66 | require(allowance[src][msg.sender] >= wad); 67 | allowance[src][msg.sender] -= wad; 68 | } 69 | 70 | balanceOf[src] -= wad; 71 | balanceOf[dst] += wad; 72 | 73 | emit Transfer(src, dst, wad); 74 | 75 | return true; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /contracts/clothing/DreamClothingFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.6.12; 4 | pragma experimental ABIEncoderV2; 5 | 6 | import "@openzeppelin/contracts/GSN/Context.sol"; 7 | import "./DreamClothingNFT.sol"; 8 | import "./DigitalaxMaterials.sol"; 9 | import "../DigitalaxAccessControls.sol"; 10 | 11 | /** 12 | * @title Digitalax Garment Factory 13 | * @dev To facilitate the creation of child and parents NFTs 14 | * @dev This contract needs to be given the smart contract role in order to be given access to mint tokens 15 | */ 16 | contract DreamClothingFactory is Context { 17 | // @notice event emitted on garment creation 18 | event GarmentCreated(uint256 indexed garmentTokenId); 19 | 20 | // @notice the parent ERC721 garment token 21 | DreamClothingNFT public garmentToken; 22 | 23 | // @notice the child ERC1155 strand tokens 24 | DigitalaxMaterials public materials; 25 | 26 | // @notice access controls 27 | DigitalaxAccessControls public accessControls; 28 | 29 | constructor( 30 | DreamClothingNFT _garmentToken, 31 | DigitalaxMaterials _materials, 32 | DigitalaxAccessControls _accessControls 33 | ) public { 34 | garmentToken = _garmentToken; 35 | materials = _materials; 36 | accessControls = _accessControls; 37 | } 38 | 39 | /** 40 | @notice Creates a single child ERC1155 token 41 | @dev Only callable with minter role 42 | @return childTokenId the generated child Token ID 43 | */ 44 | function createNewChild(string calldata _uri) 45 | external 46 | returns (uint256 childTokenId) 47 | { 48 | require( 49 | accessControls.hasMinterRole(_msgSender()), 50 | "DreamClothingFactory.createNewChild: Sender must be minter" 51 | ); 52 | return materials.createChild(_uri); 53 | } 54 | 55 | /** 56 | @notice Creates a batch of child ERC1155 tokens 57 | @dev Only callable with minter role 58 | @return childTokenIds the generated child Token IDs 59 | */ 60 | function createNewChildren(string[] calldata _uris) 61 | external 62 | returns (uint256[] memory childTokenIds) 63 | { 64 | require( 65 | accessControls.hasMinterRole(_msgSender()), 66 | "DreamClothingFactory.createNewChildren: Sender must be minter" 67 | ); 68 | return materials.batchCreateChildren(_uris); 69 | } 70 | 71 | /** 72 | @notice Creates a single ERC721 parent token, along with a batch of assigned child ERC1155 tokens 73 | @dev Only callable with minter role 74 | */ 75 | function mintParentWithChildren( 76 | string calldata garmentTokenUri, 77 | address designer, 78 | uint256[] calldata childTokenIds, 79 | uint256[] calldata childTokenAmounts, 80 | address beneficiary 81 | ) external { 82 | require( 83 | accessControls.hasMinterRole(_msgSender()), 84 | "DreamClothingFactory.mintParentWithChildren: Sender must be minter" 85 | ); 86 | // Generate parent 721 token 87 | uint256 garmentTokenId = garmentToken.mint( 88 | beneficiary, 89 | garmentTokenUri, 90 | designer 91 | ); 92 | 93 | // Batch mint child tokens and assign to generated 721 token ID 94 | materials.batchMintChildren( 95 | childTokenIds, 96 | childTokenAmounts, 97 | address(garmentToken), 98 | abi.encodePacked(garmentTokenId) 99 | ); 100 | 101 | // Emit completion event 102 | emit GarmentCreated(garmentTokenId); 103 | } 104 | 105 | /** 106 | @notice Creates a single ERC721 parent token without any linked child tokens 107 | @dev Only callable with minter role 108 | */ 109 | function mintParentWithoutChildren( 110 | string calldata garmentTokenUri, 111 | address designer, 112 | address beneficiary 113 | ) external { 114 | require( 115 | accessControls.hasMinterRole(_msgSender()), 116 | "DreamClothingFactory.mintParentWithoutChildren: Sender must be minter" 117 | ); 118 | 119 | // Generate parent 721 token 120 | uint256 garmentTokenId = garmentToken.mint( 121 | beneficiary, 122 | garmentTokenUri, 123 | designer 124 | ); 125 | 126 | // Emit completion event 127 | emit GarmentCreated(garmentTokenId); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /contracts/clothing/DreamMaterials.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.6.12; 4 | pragma experimental ABIEncoderV2; 5 | 6 | import "../ERC1155/ERC1155Burnable.sol"; 7 | import "../DreamAccessControls.sol"; 8 | 9 | /** 10 | * @title Dream Material NFT a.k.a. child NFTs 11 | * @dev Issues ERC-1155 tokens which can be held by the parent ERC-721 contract 12 | */ 13 | contract DreamMaterials is ERC1155Burnable { 14 | // @notice event emitted on contract creation 15 | event DreamMaterialsDeployed(); 16 | 17 | // @notice a single child has been created 18 | event ChildCreated(uint256 indexed childId); 19 | 20 | // @notice a batch of children have been created 21 | event ChildrenCreated(uint256[] childIds); 22 | 23 | string public name; 24 | string public symbol; 25 | 26 | // @notice current token ID pointer 27 | uint256 public tokenIdPointer; 28 | 29 | // @notice enforcing access controls 30 | DreamAccessControls public accessControls; 31 | 32 | constructor( 33 | string memory _name, 34 | string memory _symbol, 35 | DreamAccessControls _accessControls 36 | ) public { 37 | name = _name; 38 | symbol = _symbol; 39 | accessControls = _accessControls; 40 | emit DreamMaterialsDeployed(); 41 | } 42 | 43 | /////////////////////////// 44 | // Creating new children // 45 | /////////////////////////// 46 | 47 | /** 48 | @notice Creates a single child ERC1155 token 49 | @dev Only callable with smart contact role 50 | @return id the generated child Token ID 51 | */ 52 | function createChild(string calldata _uri) external returns (uint256 id) { 53 | require( 54 | accessControls.hasSmartContractRole(_msgSender()), 55 | "DreamMaterials.createChild: Sender must be smart contract" 56 | ); 57 | 58 | require( 59 | bytes(_uri).length > 0, 60 | "DreamMaterials.createChild: URI is a blank string" 61 | ); 62 | 63 | tokenIdPointer = tokenIdPointer.add(1); 64 | 65 | id = tokenIdPointer; 66 | _setURI(id, _uri); 67 | 68 | emit ChildCreated(id); 69 | } 70 | 71 | /** 72 | @notice Creates a batch of child ERC1155 tokens 73 | @dev Only callable with smart contact role 74 | @return tokenIds the generated child Token IDs 75 | */ 76 | function batchCreateChildren(string[] calldata _uris) 77 | external 78 | returns (uint256[] memory tokenIds) 79 | { 80 | require( 81 | accessControls.hasSmartContractRole(_msgSender()), 82 | "DreamMaterials.batchCreateChildren: Sender must be smart contract" 83 | ); 84 | 85 | require( 86 | _uris.length > 0, 87 | "DreamMaterials.batchCreateChildren: No data supplied in array" 88 | ); 89 | 90 | tokenIds = new uint256[](_uris.length); 91 | for (uint256 i = 0; i < _uris.length; i++) { 92 | string memory uri = _uris[i]; 93 | require( 94 | bytes(uri).length > 0, 95 | "DreamMaterials.batchCreateChildren: URI is a blank string" 96 | ); 97 | tokenIdPointer = tokenIdPointer.add(1); 98 | 99 | _setURI(tokenIdPointer, uri); 100 | tokenIds[i] = tokenIdPointer; 101 | } 102 | 103 | // Batched event for GAS savings 104 | emit ChildrenCreated(tokenIds); 105 | } 106 | 107 | ////////////////////////////////// 108 | // Minting of existing children // 109 | ////////////////////////////////// 110 | 111 | /** 112 | @notice Mints a single child ERC1155 tokens, increasing its supply by the _amount specified. msg.data along with the 113 | parent contract as the recipient can be used to map the created children to a given parent token 114 | @dev Only callable with smart contact role 115 | */ 116 | function mintChild( 117 | uint256 _childTokenId, 118 | uint256 _amount, 119 | address _beneficiary, 120 | bytes calldata _data 121 | ) external { 122 | require( 123 | accessControls.hasSmartContractRole(_msgSender()), 124 | "DreamMaterials.mintChild: Sender must be smart contract" 125 | ); 126 | 127 | require( 128 | bytes(tokenUris[_childTokenId]).length > 0, 129 | "DreamMaterials.mintChild: Strand does not exist" 130 | ); 131 | require(_amount > 0, "DreamMaterials.mintChild: No amount specified"); 132 | 133 | _mint(_beneficiary, _childTokenId, _amount, _data); 134 | } 135 | 136 | /** 137 | @notice Mints a batch of child ERC1155 tokens, increasing its supply by the _amounts specified. msg.data along with the 138 | parent contract as the recipient can be used to map the created children to a given parent token 139 | @dev Only callable with smart contact role 140 | */ 141 | function batchMintChildren( 142 | uint256[] calldata _childTokenIds, 143 | uint256[] calldata _amounts, 144 | address _beneficiary, 145 | bytes calldata _data 146 | ) external { 147 | require( 148 | accessControls.hasSmartContractRole(_msgSender()), 149 | "DreamMaterials.batchMintChildren: Sender must be smart contract" 150 | ); 151 | 152 | require( 153 | _childTokenIds.length == _amounts.length, 154 | "DreamMaterials.batchMintChildren: Array lengths are invalid" 155 | ); 156 | require( 157 | _childTokenIds.length > 0, 158 | "DreamMaterials.batchMintChildren: No data supplied in arrays" 159 | ); 160 | 161 | // Check the strands exist and no zero amounts 162 | for (uint256 i = 0; i < _childTokenIds.length; i++) { 163 | uint256 strandId = _childTokenIds[i]; 164 | require( 165 | bytes(tokenUris[strandId]).length > 0, 166 | "DreamMaterials.batchMintChildren: Strand does not exist" 167 | ); 168 | 169 | uint256 amount = _amounts[i]; 170 | require( 171 | amount > 0, 172 | "DreamMaterials.batchMintChildren: Invalid amount" 173 | ); 174 | } 175 | 176 | _mintBatch(_beneficiary, _childTokenIds, _amounts, _data); 177 | } 178 | 179 | function updateAccessControls(DreamAccessControls _accessControls) 180 | external 181 | { 182 | require( 183 | accessControls.hasAdminRole(_msgSender()), 184 | "DreamMaterials.updateAccessControls: Sender must be admin" 185 | ); 186 | 187 | require( 188 | address(_accessControls) != address(0), 189 | "DreamMaterials.updateAccessControls: New access controls cannot be ZERO address" 190 | ); 191 | 192 | accessControls = _accessControls; 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /contracts/clothing/IDreamClothingNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.6.12; 4 | 5 | import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; 6 | 7 | interface IDreamClothingNFT is IERC721 { 8 | function isApproved(uint256 _tokenId, address _operator) 9 | external 10 | view 11 | returns (bool); 12 | 13 | function setPrimarySalePrice(uint256 _tokenId, uint256 _salePrice) external; 14 | 15 | function dreamDesigners(uint256 _tokenId) external view returns (address); 16 | } 17 | -------------------------------------------------------------------------------- /contracts/mock/AlwaysRevertingEthReceiver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.6.12; 4 | 5 | contract AlwaysRevertingEthReceiver { 6 | receive() external payable { 7 | revert("No thanks"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /contracts/mock/BiddingContractMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.6.12; 4 | 5 | import "../DreamAuction.sol"; 6 | 7 | contract BiddingContractMock { 8 | DreamAuction public auctionContract; 9 | 10 | constructor(DreamAuction _auctionContract) public { 11 | auctionContract = _auctionContract; 12 | } 13 | 14 | function bid(uint256 _clothingokenId) external payable { 15 | auctionContract.placeBid{value: msg.value}(_clothingTokenId); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contracts/mock/DigitalaxGenesisNFTMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.6.12; 4 | 5 | import "../DigitalaxGenesisNFT.sol"; 6 | 7 | contract DigitalaxGenesisNFTMock is DigitalaxGenesisNFT { 8 | uint256 public nowOverride; 9 | uint256 public maxGenesisContributionTokensOverride; 10 | 11 | constructor( 12 | DigitalaxAccessControls _accessControls, 13 | address payable _fundsMultisig, 14 | uint256 _genesisStart, 15 | uint256 _genesisEnd, 16 | string memory _tokenURI 17 | ) 18 | DigitalaxGenesisNFT(_accessControls, _fundsMultisig, _genesisStart, _genesisEnd, _tokenURI) 19 | public {} 20 | 21 | function addContribution(uint256 _contributionAmount) external { 22 | contribution[_msgSender()] = _contributionAmount; 23 | totalContributions = totalContributions.add(_contributionAmount); 24 | } 25 | 26 | function setNowOverride(uint256 _now) external { 27 | nowOverride = _now; 28 | } 29 | 30 | function setMaxGenesisContributionTokensOverride(uint256 _maxGenesisContributionTokensOverride) external { 31 | maxGenesisContributionTokensOverride = _maxGenesisContributionTokensOverride; 32 | } 33 | 34 | function _getNow() internal override view returns (uint256) { 35 | return nowOverride; 36 | } 37 | 38 | function _getMaxGenesisContributionTokens() internal override view returns (uint256) { 39 | return maxGenesisContributionTokensOverride; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /contracts/mock/DreamAuctionMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.6.12; 4 | 5 | import "../DreamAuction.sol"; 6 | 7 | contract DreamAuctionMock is DreamAuction { 8 | uint256 public nowOverride; 9 | 10 | constructor( 11 | DreamAccessControls _accessControls, 12 | IDreamClothingNFT _clothingNft, 13 | address payable _platformReserveAddress 14 | ) 15 | public 16 | DreamAuction(_accessControls, _clothingNft, _platformReserveAddress) 17 | {} 18 | 19 | function setNowOverride(uint256 _now) external { 20 | nowOverride = _now; 21 | } 22 | 23 | function _getNow() internal view override returns (uint256) { 24 | return nowOverride; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/mock/ERC1155Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.6.0; 4 | 5 | import "../ERC1155/ERC1155.sol"; 6 | 7 | contract ERC1155Mock is ERC1155 { 8 | 9 | function mint(uint256 id, uint256 amount) external { 10 | _mint(msg.sender, id, amount, ""); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /contracts/mock/ERC1155ReceiverMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.6.0; 4 | 5 | import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; 6 | import "./ERC165Mock.sol"; 7 | 8 | contract ERC1155ReceiverMock is IERC1155Receiver, ERC165Mock { 9 | bytes4 private _recRetval; 10 | bool private _recReverts; 11 | bytes4 private _batRetval; 12 | bool private _batReverts; 13 | 14 | event Received(address operator, address from, uint256 id, uint256 value, bytes data, uint256 gas); 15 | event BatchReceived(address operator, address from, uint256[] ids, uint256[] values, bytes data, uint256 gas); 16 | 17 | constructor ( 18 | bytes4 recRetval, 19 | bool recReverts, 20 | bytes4 batRetval, 21 | bool batReverts 22 | ) 23 | public 24 | { 25 | _recRetval = recRetval; 26 | _recReverts = recReverts; 27 | _batRetval = batRetval; 28 | _batReverts = batReverts; 29 | } 30 | 31 | function onERC1155Received( 32 | address operator, 33 | address from, 34 | uint256 id, 35 | uint256 value, 36 | bytes calldata data 37 | ) 38 | external 39 | override 40 | returns(bytes4) 41 | { 42 | require(!_recReverts, "ERC1155ReceiverMock: reverting on receive"); 43 | emit Received(operator, from, id, value, data, gasleft()); 44 | return _recRetval; 45 | } 46 | 47 | function onERC1155BatchReceived( 48 | address operator, 49 | address from, 50 | uint256[] calldata ids, 51 | uint256[] calldata values, 52 | bytes calldata data 53 | ) 54 | external 55 | override 56 | returns(bytes4) 57 | { 58 | require(!_batReverts, "ERC1155ReceiverMock: reverting on batch receive"); 59 | emit BatchReceived(operator, from, ids, values, data, gasleft()); 60 | return _batRetval; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /contracts/mock/ERC165Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.6.0; 4 | 5 | import "@openzeppelin/contracts/introspection/ERC165.sol"; 6 | 7 | contract ERC165Mock is ERC165 { 8 | function registerInterface(bytes4 interfaceId) public { 9 | _registerInterface(interfaceId); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /contracts/mock/ERC721ReceiverMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.6.0; 4 | 5 | import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; 6 | 7 | contract ERC721ReceiverMock is IERC721Receiver { 8 | bytes4 private _retval; 9 | bool private _reverts; 10 | 11 | event Received(address operator, address from, uint256 tokenId, bytes data, uint256 gas); 12 | 13 | constructor (bytes4 retval, bool reverts) public { 14 | _retval = retval; 15 | _reverts = reverts; 16 | } 17 | 18 | function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) 19 | public override returns (bytes4) 20 | { 21 | require(!_reverts, "ERC721ReceiverMock: reverting"); 22 | emit Received(operator, from, tokenId, data, gasleft()); 23 | return _retval; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /contracts/mock/MockERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.6.12; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | contract MockERC20 is ERC20 { 8 | constructor( 9 | string memory name, 10 | string memory symbol, 11 | uint256 supply 12 | ) public ERC20(name, symbol) { 13 | _mint(msg.sender, supply); 14 | } 15 | 16 | function mint(address _to, uint256 _amount) public { 17 | _mint(_to, _amount); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/mock/MockStaking.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPLv2 2 | 3 | pragma solidity 0.6.12; 4 | 5 | import "@openzeppelin/contracts/math/SafeMath.sol"; 6 | import "../DreamAccessControls.sol"; 7 | import "../DreamGenesisNFT.sol"; 8 | import "../../interfaces/IERC20.sol"; 9 | 10 | /** 11 | * @title Dream Staking 12 | * @dev Stake NFTs, earn tokens on the Digitialax platform 13 | * @author Adrian Guerrera (deepyr) 14 | */ 15 | 16 | /// @dev an interface to interact with the Genesis MONA NFT that will 17 | interface IDreamGenesisNFT { 18 | function contribution(address user) external view returns (uint256); 19 | 20 | function totalContributions() external view returns (uint256); 21 | 22 | function tokenOfOwnerByIndex(address owner, uint256 index) 23 | external 24 | view 25 | returns (uint256); 26 | 27 | function balanceOf(address owner) external view returns (uint256); 28 | 29 | function safeTransferFrom( 30 | address from, 31 | address to, 32 | uint256 tokenId 33 | ) external; 34 | } 35 | 36 | /// @dev an interface to interact with the Genesis MONA NFT that will 37 | interface IDreamRewards { 38 | function updateRewards() external returns (bool); 39 | 40 | function genesisRewards(uint256 _from, uint256 _to) 41 | external 42 | view 43 | returns (uint256); 44 | 45 | function parentRewards(uint256 _from, uint256 _to) 46 | external 47 | view 48 | returns (uint256); 49 | 50 | function LPRewards(uint256 _from, uint256 _to) 51 | external 52 | view 53 | returns (uint256); 54 | 55 | function lastRewardTime() external view returns (uint256); 56 | } 57 | 58 | contract MockStaking { 59 | using SafeMath for uint256; 60 | bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; 61 | 62 | /// @notice 63 | IERC20 public rewardsToken; 64 | IDreamGenesisNFT public genesisNFT; 65 | DreamAccessControls public accessControls; 66 | IDreamRewards public rewardsContract; 67 | 68 | // @notice all funds will be sent to this address pon purchase of a Genesis NFT 69 | address payable public fundsMultisig; 70 | 71 | /// @notice total ethereum staked currently in the gensesis staking contract 72 | uint256 public stakedEthTotal; 73 | uint256 public lastUpdateTime; 74 | 75 | uint256 public rewardsPerTokenPoints; 76 | uint256 public totalUnclaimedRewards; 77 | 78 | uint256 constant pointMultiplier = 10e32; 79 | 80 | /** 81 | @notice to track what user is staking what tokens 82 | @notice tokenIds are all the tokens staked by the staker 83 | @notice balance is the current ether balance of the staker 84 | @notice rewardsEarned is the total reward for the staker till now 85 | @notice rewardsReleased is how much reward has been paid to the staker 86 | */ 87 | struct Staker { 88 | uint256[] tokenIds; 89 | mapping(uint256 => uint256) tokenIndex; 90 | uint256 balance; 91 | uint256 lastRewardPoints; 92 | uint256 rewardsEarned; 93 | uint256 rewardsReleased; 94 | } 95 | 96 | /// @notice mapping of a staker to its current properties 97 | mapping(address => Staker) public stakers; 98 | 99 | // Mapping from token ID to owner address 100 | mapping(uint256 => address) public tokenOwner; 101 | 102 | /// @notice tokenId => amount contributed 103 | mapping(uint256 => uint256) public contribution; 104 | uint256 public totalContributions; 105 | // @notice the maximum accumulative amount a user can contribute to the genesis sale 106 | uint256 public constant maximumContributionAmount = 2 ether; 107 | 108 | /// @notice sets the token to be claimable or not, cannot claim if it set to false 109 | bool public tokensClaimable; 110 | 111 | /// @notice event emitted when a user has staked a token 112 | event Staked(address owner, uint256 amount); 113 | 114 | /// @notice event emitted when a user has unstaked a token 115 | event Unstaked(address owner, uint256 amount); 116 | 117 | /// @notice event emitted when a user claims reward 118 | event RewardPaid(address indexed user, uint256 reward); 119 | 120 | /// @notice 121 | event ClaimableStatusUpdated(bool _status); 122 | 123 | // @notice event emitted when a contributors amount is increased 124 | event ContributionIncreased(uint256 indexed tokenId, uint256 contribution); 125 | 126 | constructor(uint256 _stakedEthTotal) public { 127 | stakedEthTotal = _stakedEthTotal; 128 | } 129 | 130 | /** 131 | * @dev Single gateway to intialize the staking contract after deploying 132 | * @dev Sets the contract with the MONA genesis nfts and a reward token so that they can be used for staking and giving out reward 133 | */ 134 | function initGenesisStaking( 135 | address payable _fundsMultisig, 136 | IERC20 _rewardsToken, 137 | IDreamGenesisNFT _genesisNFT, 138 | DreamAccessControls _accessControls 139 | ) public { 140 | // AG: require !init 141 | fundsMultisig = _fundsMultisig; 142 | rewardsToken = _rewardsToken; 143 | genesisNFT = _genesisNFT; 144 | accessControls = _accessControls; 145 | } 146 | 147 | function setRewardsContract(address _addr) public { 148 | require(_addr != address(0)); 149 | rewardsContract = IDreamRewards(_addr); 150 | } 151 | 152 | // AG add setters for reward tokens 153 | function setTokensClaimable(bool _enabled) public { 154 | tokensClaimable = _enabled; 155 | emit ClaimableStatusUpdated(_enabled); 156 | } 157 | 158 | function setStakedEthTotal(uint256 _stakedEthTotal) public { 159 | stakedEthTotal = _stakedEthTotal; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /contracts/mock/MockVault.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.6.12; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import "../garment/DreamMaterials.sol"; 7 | 8 | contract MockVault { 9 | DreamMaterials public materials; 10 | IERC20 public supportedERC20Asset; 11 | uint256 public supportedERC20AssetSyntheticStrandId; 12 | 13 | // using init rather than constructor as we need to know the contract address in the test to give it smart contract role 14 | function init( 15 | DreamMaterials _materials, 16 | IERC20 _supportedERC20Asset, 17 | string memory _supportedAssetSyntheticStrandUri 18 | ) external { 19 | materials = _materials; 20 | 21 | // If this contract supported many assets, this would be in a 'whitelist' method of sorts (maybe without the createChild and instead with a strandId) 22 | supportedERC20Asset = _supportedERC20Asset; 23 | supportedERC20AssetSyntheticStrandId = materials.createChild( 24 | _supportedAssetSyntheticStrandUri 25 | ); 26 | } 27 | 28 | function mintAssetBackedSyntheticMaterial(uint256 _depositAmount) external { 29 | // Danger: Transfer does not guarantee this contract will receive all tokens depending on the token implementation 30 | supportedERC20Asset.transferFrom( 31 | msg.sender, 32 | address(this), 33 | _depositAmount 34 | ); 35 | 36 | //mint balance of strand to sender 37 | materials.mintChild( 38 | supportedERC20AssetSyntheticStrandId, 39 | _depositAmount, 40 | msg.sender, 41 | abi.encodePacked("") 42 | ); 43 | } 44 | 45 | function mintAssetBackedSyntheticMaterialToClothing( 46 | address _clothingAddress, 47 | uint256 _clothingId, 48 | uint256 _depositAmount 49 | ) external { 50 | //TODO: this should really check owner of clothing ID is msg.sender otherwise you could add to someone elses clothing 51 | 52 | // Danger: Transfer does not guarantee this contract will receive all tokens depending on the token implementation 53 | supportedERC20Asset.transferFrom( 54 | msg.sender, 55 | address(this), 56 | _depositAmount 57 | ); 58 | 59 | //mint balance of strand to sender 60 | materials.mintChild( 61 | supportedERC20AssetSyntheticStrandId, 62 | _depositAmount, 63 | _clothingAddress, 64 | abi.encodePacked(_clothingId) 65 | ); 66 | } 67 | 68 | function claimUnderlyingAssetFromMaterial( 69 | uint256 _strandId, 70 | uint256 _claimAmount 71 | ) external { 72 | //🔥 73 | materials.burn(msg.sender, _strandId, _claimAmount); 74 | supportedERC20Asset.transfer(msg.sender, _claimAmount); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /interfaces/IDigitalaxAuction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPLv2 2 | 3 | pragma solidity 0.6.12; 4 | 5 | /// @dev an interface to interact with the Genesis MONA NFT that will 6 | interface IDigitalaxAuction { 7 | function getHighestBidder(uint256 _garmentTokenId) external view returns ( 8 | address payable _bidder, 9 | uint256 _bid, 10 | uint256 _lastBidTime 11 | ); -------------------------------------------------------------------------------- /interfaces/IDigitalaxGenesisNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPLv2 2 | 3 | pragma solidity 0.6.12; 4 | 5 | /// @dev an interface to interact with the Genesis MONA NFT that will 6 | interface IDigitalaxGenesisNFT { 7 | function contribution(address user) external view returns (uint256); 8 | function totalContributions() external view returns (uint256); 9 | function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); 10 | function balanceOf(address owner) external view returns (uint256); 11 | function safeTransferFrom(address from, address to, uint256 tokenId) external; 12 | } 13 | -------------------------------------------------------------------------------- /interfaces/IDigitalaxNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPLv2 2 | 3 | pragma solidity 0.6.12; 4 | 5 | /// @dev an interface to interact with the Genesis MONA NFT that will 6 | interface IDigitalaxNFT { 7 | function primarySalePrice(uint256 tokenId) external view returns (uint256); 8 | function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); 9 | function balanceOf(address owner) external view returns (uint256); 10 | function safeTransferFrom(address from, address to, uint256 tokenId) external; 11 | } 12 | -------------------------------------------------------------------------------- /interfaces/IDigitalaxRewards.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPLv2 2 | 3 | pragma solidity 0.6.12; 4 | 5 | /// @dev an interface to interact with the Genesis MONA NFT that will 6 | interface IDigitalaxRewards { 7 | function updateRewards() external returns (bool); 8 | function genesisRewards(uint256 _from, uint256 _to) external view returns(uint256); 9 | function parentRewards(uint256 _from, uint256 _to) external view returns(uint256); 10 | function LPRewards(uint256 _from, uint256 _to) external view returns(uint256); 11 | function lastRewardTime() external view returns (uint256); 12 | } 13 | -------------------------------------------------------------------------------- /interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.2; 2 | // SPDX-License-Identifier: UNLICENSED 3 | 4 | 5 | interface IERC20 { 6 | function name() external view returns (string memory); 7 | function symbol() external view returns (string memory); 8 | function decimals() external view returns (uint8); 9 | function totalSupply() external view returns (uint256); 10 | function balanceOf(address owner) external view returns (uint256); 11 | function transfer(address to, uint256 amount) external returns (bool); 12 | function transferFrom(address from, address to, uint256 amount) external returns (bool); 13 | function approve(address spender, uint256 amount) external returns (bool); 14 | function allowance(address owner, address spender) external view returns (uint256); 15 | 16 | event Transfer(address indexed from, address indexed to, uint256 amount); 17 | event Approval(address indexed owner, address indexed spender, uint256 amount); 18 | } 19 | 20 | -------------------------------------------------------------------------------- /interfaces/IUniswapV2Factory.sol: -------------------------------------------------------------------------------- 1 | 2 | pragma solidity >=0.5.0; 3 | 4 | 5 | interface IUniswapV2Factory { 6 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 7 | 8 | function feeTo() external view returns (address); 9 | function feeToSetter() external view returns (address); 10 | 11 | function getPair(address tokenA, address tokenB) external view returns (address pair); 12 | function allPairs(uint) external view returns (address pair); 13 | function allPairsLength() external view returns (uint); 14 | 15 | function createPair(address tokenA, address tokenB) external returns (address pair); 16 | 17 | function setFeeTo(address) external; 18 | function setFeeToSetter(address) external; 19 | } -------------------------------------------------------------------------------- /interfaces/IUniswapV2Pair.sol: -------------------------------------------------------------------------------- 1 | 2 | pragma solidity >=0.5.0; 3 | 4 | interface IUniswapV2Pair { 5 | event Approval(address indexed owner, address indexed spender, uint value); 6 | event Transfer(address indexed from, address indexed to, uint value); 7 | 8 | function name() external pure returns (string memory); 9 | function symbol() external pure returns (string memory); 10 | function decimals() external pure returns (uint8); 11 | function totalSupply() external view returns (uint); 12 | function balanceOf(address owner) external view returns (uint); 13 | function allowance(address owner, address spender) external view returns (uint); 14 | 15 | function approve(address spender, uint value) external returns (bool); 16 | function transfer(address to, uint value) external returns (bool); 17 | function transferFrom(address from, address to, uint value) external returns (bool); 18 | 19 | function DOMAIN_SEPARATOR() external view returns (bytes32); 20 | function PERMIT_TYPEHASH() external pure returns (bytes32); 21 | function nonces(address owner) external view returns (uint); 22 | 23 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 24 | 25 | event Mint(address indexed sender, uint amount0, uint amount1); 26 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 27 | event Swap( 28 | address indexed sender, 29 | uint amount0In, 30 | uint amount1In, 31 | uint amount0Out, 32 | uint amount1Out, 33 | address indexed to 34 | ); 35 | event Sync(uint112 reserve0, uint112 reserve1); 36 | 37 | function MINIMUM_LIQUIDITY() external pure returns (uint); 38 | function factory() external view returns (address); 39 | function token0() external view returns (address); 40 | function token1() external view returns (address); 41 | function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); 42 | function price0CumulativeLast() external view returns (uint); 43 | function price1CumulativeLast() external view returns (uint); 44 | function kLast() external view returns (uint); 45 | 46 | function mint(address to) external returns (uint liquidity); 47 | function burn(address to) external returns (uint amount0, uint amount1); 48 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; 49 | function skim(address to) external; 50 | function sync() external; 51 | 52 | function initialize(address, address) external; 53 | } 54 | -------------------------------------------------------------------------------- /interfaces/IWETH9.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface IWETH { 4 | function deposit() external payable; 5 | function transfer(address to, uint value) external returns (bool); 6 | function withdraw(uint) external; 7 | } -------------------------------------------------------------------------------- /outputs/SetContributions.csv: -------------------------------------------------------------------------------- 1 | tokens,contributions 2 | 1,0.1 3 | 2,0.0 4 | 3,2.0 5 | 4,2.0 6 | 5,2.0 7 | 6,0.1 8 | 7,0.0 9 | 8,0.2 10 | 9,0.1 11 | 10,0.1 12 | 11,2.0 13 | 12,0.0 14 | 13,0.1 15 | 14,0.1 16 | 15,1.0 17 | 16,1.6 18 | 17,0.1 19 | 18,0.1 20 | 19,1.0 21 | 20,0.75 22 | 21,2.0 23 | 22,2.0 24 | 23,0.1 25 | 24,0.6 26 | 25,2.0 27 | 26,0.1 28 | 27,0.1 29 | 28,2.0 30 | 29,2.0 31 | 30,0.5 32 | 31,1.5 33 | 32,0.25 34 | 33,2.0 35 | 34,0.1 36 | 35,0.1 37 | 36,0.1 38 | 37,0.1 39 | 38,0.0 40 | 39,2.0 41 | 40,0.1 42 | 41,0.1 43 | 42,1.0 44 | 43,2.0 45 | 44,0.1 46 | 45,0.1 47 | 46,0.1 48 | 47,0.1 49 | 48,2.0 50 | 49,0.1 51 | 50,0.1 52 | 51,0.1 53 | 52,0.1 54 | 53,0.1 55 | 54,0.1 56 | 55,0.1 57 | 56,0.1 58 | 57,2.0 59 | 58,0.1 60 | 59,1.15 61 | 60,0.2 62 | 61,0.1 63 | 62,2.0 64 | 63,0.3 65 | 64,0.35 66 | 65,0.1 67 | 66,2.0 68 | 67,0.1 69 | 68,0.1 70 | 69,0.45 71 | 70,0.1 72 | 71,0.0 73 | 72,0.2 74 | 73,2.0 75 | 74,0.0 76 | 75,0.1 77 | 76,0.1 78 | 77,0.1 79 | 78,0.0 80 | 79,0.1 81 | 80,1.0 82 | 81,0.1 83 | 82,0.1 84 | 83,1.0 85 | 84,0.1 86 | 85,0.1 87 | 86,0.1 88 | 87,2.0 89 | 88,0.15 90 | 89,0.15 91 | 90,0.15 92 | 91,0.1 93 | 92,0.1 94 | 93,0.15 95 | 94,0.15 96 | 95,0.4 97 | 96,0.15 98 | 97,0.1 99 | 98,2.0 100 | 99,0.1 101 | 100,0.15 102 | 101,0.15 103 | 102,0.12 104 | 103,0.12 105 | 104,0.1 106 | 105,0.12 107 | 106,0.11 108 | 107,0.11 109 | 108,0.11 110 | 109,0.1 111 | 110,0.11 112 | 111,0.121 113 | 112,0.13 114 | 113,0.1132 115 | 114,0.11 116 | 115,0.1 117 | 116,0.106 118 | 117,0.0 119 | 118,0.103 120 | 119,0.154 121 | 120,0.1 122 | 121,0.11111 123 | 122,0.1106 124 | 123,0.118 125 | 124,0.1 126 | 125,2.0 127 | 126,0.1 128 | 127,0.11 129 | 128,0.2 130 | 129,0.1 131 | 130,0.1064 132 | 131,2.0 133 | 132,0.1 134 | 133,0.1 135 | 134,2.0 136 | 135,0.1 137 | 136,0.1 138 | 137,0.1 139 | 138,0.1 140 | 139,0.1 141 | 140,0.1 142 | 141,0.1 143 | 142,0.1 144 | 143,0.1 145 | 144,0.11 146 | 145,0.1 147 | 146,0.1 148 | 147,0.101 149 | 148,0.1 150 | 149,0.1 151 | 150,0.1 152 | 151,0.1 153 | 152,0.1 154 | 153,0.1101 155 | 154,0.1 156 | 155,0.102 157 | 156,0.11 158 | 157,0.1 159 | 158,0.1 160 | 159,0.1 161 | 160,0.1 162 | 161,0.1 163 | 162,0.1 164 | 163,1.0 165 | 164,1.0 166 | 165,0.1 167 | 166,0.0 168 | 167,0.1 169 | 168,0.1 170 | 169,0.12 171 | 170,0.1 172 | 171,0.8 173 | 172,0.2 174 | 173,0.0 175 | 174,0.1 176 | 175,0.1 177 | 176,0.1 178 | 177,1.1 179 | 178,0.101 180 | 179,0.4 181 | 180,0.4 182 | 181,0.2 183 | 182,2.0 184 | 183,0.1 185 | 184,0.1 186 | 185,0.1 187 | 186,0.0 188 | 187,0.35 189 | 188,0.1 190 | 189,2.0 191 | 190,1.0 192 | 191,0.1 193 | 192,0.22 194 | 193,0.1 195 | 194,1.0 196 | 195,1.05 197 | 196,0.5 198 | 197,0.0 199 | 198,0.2 200 | 199,0.5 201 | 200,0.25 202 | 201,0.2 203 | 202,0.0 204 | 203,2.0 205 | 204,2.0 206 | 205,2.0 207 | 206,2.0 208 | 207,2.0 209 | 208,0.0 210 | 209,0.5 211 | 210,0.0 212 | 211,0.1 213 | 212,0.5 214 | 213,0.0 215 | 214,0.2 216 | 215,0.0 217 | 216,0.15 218 | 217,0.1 219 | 218,0.0 220 | 219,0.0 221 | 220,0.0 222 | 221,0.1 223 | 222,2.0 224 | 223,2.0 225 | 224,0.1 226 | 225,0.0 227 | 226,2.0 228 | 227,2.0 229 | 228,2.0 230 | 229,0.1 231 | 230,0.1 232 | 231,0.1 233 | 232,0.1 234 | 233,0.1 235 | 234,0.1 236 | 235,0.0 237 | 236,1.0 238 | 237,0.1 239 | 238,0.1 240 | 239,0.1 241 | 240,2.0 242 | 241,0.1 243 | 242,0.1 244 | 243,0.1 245 | 244,0.1 246 | 245,0.3 247 | 246,0.1 248 | 247,0.1 249 | 248,0.0 250 | 249,2.0 251 | 250,0.1 252 | 251,2.0 253 | 252,0.1 254 | 253,0.1 255 | 254,0.1 256 | 255,2.0 257 | 256,2.0 258 | 257,0.1 259 | 258,0.12 260 | 259,0.1 261 | 260,0.4 262 | 261,0.8 263 | 262,2.0 264 | 263,0.1 265 | 264,1.0 266 | 265,0.4 267 | 266,0.5 268 | 267,0.4 269 | 268,1.51 270 | 269,0.13 271 | 270,0.13 272 | 271,0.13 273 | 272,0.22 274 | 273,0.1 275 | 274,0.1 276 | 275,0.1 277 | 276,0.1 278 | 277,2.0 279 | 278,0.1 280 | 279,0.1 281 | 280,0.1 282 | 281,0.1 283 | 282,2.0 284 | 283,0.1 285 | 284,2.0 286 | 285,0.1 287 | 286,1.5 288 | 287,0.1 289 | 288,2.0 290 | 289,2.0 291 | 290,1.1 292 | 291,2.0 293 | 292,0.11 294 | 293,0.1 295 | 294,0.1 296 | 295,0.1 297 | 296,1.95 298 | 297,0.1 299 | 298,0.4 300 | 299,0.1 301 | 300,0.2 302 | 301,0.3 303 | 302,0.1 304 | 303,0.1 305 | 304,0.1 306 | 305,0.1 307 | 306,0.1 308 | 307,0.13 309 | 308,2.0 310 | 309,2.0 311 | 310,2.0 312 | 311,0.1 313 | 312,0.5 314 | 313,0.5 315 | 314,1.0 316 | 315,0.1 317 | 316,0.12 318 | 317,0.0 319 | 318,0.1 320 | 319,2.0 321 | 320,1.0 322 | 321,0.1 323 | 322,1.9 324 | 323,2.0 325 | 324,2.0 326 | 325,2.0 327 | 326,0.1 328 | 327,0.1 329 | 328,2.0 330 | 329,1.0 331 | 330,2.0 332 | 331,2.0 333 | 332,2.0 334 | 333,2.0 335 | 334,0.0 336 | 335,0.6 337 | 336,0.0 338 | 337,2.0 339 | 338,0.0 340 | 339,2.0 341 | 340,2.0 342 | 341,2.0 343 | 342,2.0 344 | 343,2.0 345 | 344,2.0 346 | 345,0.1 347 | 346,2.0 348 | 347,0.5 349 | 348,1.0 350 | 349,0.1 351 | 350,0.1 352 | 351,0.5 353 | 352,2.0 354 | 353,1.0 355 | 354,2.0 356 | 355,1.6 357 | 356,1.0 358 | 357,0.1 359 | 358,2.0 360 | 359,1.0 361 | 360,0.1 362 | 361,1.0 363 | 362,1.7 364 | 363,0.1 365 | 364,0.65 366 | 365,0.1 367 | 366,0.2 368 | 367,0.74 369 | 368,0.1 370 | 369,0.1 371 | 370,0.2 372 | 371,0.1 373 | 372,0.1 374 | 373,0.1 375 | 374,0.1 376 | 375,0.1 377 | 376,2.0 378 | 377,0.1 379 | 378,0.1 380 | 379,0.1 381 | 380,0.1 382 | 381,1.7 383 | 382,2.0 384 | 383,0.1 385 | 384,0.1 386 | 385,0.1 387 | 386,0.1 388 | 387,0.1 389 | 388,0.1 390 | 389,0.1 391 | 390,0.1 392 | 391,0.1 393 | 392,0.1 394 | 393,2.0 395 | 394,1.0 396 | 395,0.1 397 | 396,2.0 398 | 397,0.0 399 | 398,2.0 400 | 399,0.0 401 | 400,2.0 402 | 401,0.0 403 | 402,2.0 404 | 403,0.1 405 | 404,2.0 406 | 405,0.1 407 | 406,0.1 408 | 407,0.32 409 | 408,0.33 410 | 409,0.1 411 | 410,0.1 412 | 411,0.1 413 | 412,0.1 414 | 413,0.1 415 | 414,2.0 416 | 415,0.1 417 | 416,2.0 418 | 417,0.1 419 | 418,2.0 420 | 419,0.5 421 | 420,0.5 422 | 421,1.0 423 | 422,2.0 424 | 423,1.0 425 | 424,0.2 426 | 425,2.0 427 | 426,0.25 428 | 427,0.15 429 | 428,2.0 430 | 429,2.0 431 | 430,2.0 432 | 431,2.0 433 | 432,0.5 434 | 433,1.0 435 | 434,2.0 436 | 435,1.0 437 | 436,1.0 438 | 437,0.1 439 | 438,0.1 440 | 439,2.0 441 | 440,0.1 442 | 441,2.0 443 | 442,0.5 444 | 443,0.1 445 | 444,0.1 446 | 445,0.25 447 | 446,0.1 448 | 447,0.1 449 | 448,2.0 450 | 449,1.5 451 | 450,0.1 452 | 451,0.1 453 | 452,2.0 454 | 453,2.0 455 | 454,2.0 456 | 455,0.1 457 | 456,2.0 458 | 457,2.0 459 | 458,0.1 460 | 459,2.0 461 | 460,0.1 462 | -------------------------------------------------------------------------------- /outputs/bonusPerWeek.csv: -------------------------------------------------------------------------------- 1 | Week,Genesis,Parent,LP,WeeklyRewards 2 | 0,350000000000000000000,, 3 | 1,350000000000000000000,, 4 | -------------------------------------------------------------------------------- /outputs/tokensAllocationPerWeek.csv: -------------------------------------------------------------------------------- 1 | ,WeeklyRewards 2 | 0,250000000000000000000 3 | 1,250000000000000000000 4 | 2,500000000000000000000 5 | 3,500000000000000000000 6 | 4,400000000000000000000 7 | 5,400000000000000000000 8 | 6,400000000000000000000 9 | 7,400000000000000000000 10 | 8,354314952297490000000 11 | 9,330361071822450000000 12 | 10,308026621704700000000 13 | 11,287202118444000000000 14 | 12,267785480301100000000 15 | 13,249681526893200000000 16 | 14,232801512619900000000 17 | 15,217062691631600000000 18 | 16,202387912209400000000 19 | 17,188705238567700000000 20 | 18,175947598224400000000 21 | 19,164052453211800000000 22 | 20,152961493515100000000 23 | 21,142620351237000000000 24 | 22,132978334086200000000 25 | 23,123988176883400000000 26 | 24,115605809867400000000 27 | 25,107790142665600000000 28 | 26,100502862868200000000 29 | 27,93708248221218700000 30 | 28,87372991515676900000 31 | 29,81466037315912000000 32 | 30,75958429725583700000 33 | 31,70823170445894500000 34 | 32,66035086429897600000 35 | 33,61570706484191700000 36 | 34,57408146213103400000 37 | 35,53527000741354700000 38 | 36,49908244689340200000 39 | 37,46534138910694700000 40 | 38,43388143534976600000 41 | 39,40454836889204400000 42 | 40,37719839900797400000 43 | 41,35169745611345300000 44 | 42,32792053455682700000 45 | 43,30575107984104000000 46 | 44,28508041727335600000 47 | 45,26580721924188600000 48 | 46,24783700850752000000 49 | 47,23108169507638900000 50 | 48,21545914438261600000 51 | 49,20089277466457500000 52 | 50,18731118156100800000 53 | 51,17464778808676500000 -------------------------------------------------------------------------------- /scripts/__pycache__/contract_addresses.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/contract_addresses.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/contracts.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/contracts.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/deploy_AdminBuyGenesis.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/deploy_AdminBuyGenesis.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/deploy_DigitalaxStaking.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/deploy_DigitalaxStaking.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/deploy_MONA.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/deploy_MONA.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/deploy_StakingDev.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/deploy_StakingDev.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/deploy_StakingMainnet.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/deploy_StakingMainnet.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/deploy_UniswapAddLiquidity.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/deploy_UniswapAddLiquidity.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/deploy_UniswapPool.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/deploy_UniswapPool.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/deploy_setContributions.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/deploy_setContributions.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/deploy_setRewards.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/deploy_setRewards.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/deploy_setTokensClaimable.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/deploy_setTokensClaimable.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/rewardsWeekly.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/rewardsWeekly.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/settings.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/scripts/__pycache__/settings.cpython-38.pyc -------------------------------------------------------------------------------- /scripts/check_contributions.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | from .settings import * 3 | from .contracts import * 4 | from .contract_addresses import * 5 | import time 6 | import csv 7 | 8 | 9 | LOCATION_TO_DUMP_CSV = "./outputs/SetContributions.csv" 10 | 11 | def main(): 12 | genesis_nft_address = CONTRACTS[network.show_active()]["genesis_nft"] 13 | genesis_nft = DigitalaxGenesisNFT.at(genesis_nft_address) 14 | total_supply = genesis_nft.totalSupply() 15 | headers = ['tokens','contributions'] 16 | owner_address = genesis_nft.ownerOf(460) 17 | contribution = genesis_nft.contribution(owner_address) 18 | print(owner_address) 19 | print(contribution) 20 | rows = [] 21 | """ for token_id in range(1, total_supply+1): 22 | owner_address = genesis_nft.ownerOf(token_id) 23 | 24 | contribution = genesis_nft.contribution(owner_address)/TENPOW18 25 | row = [token_id, contribution] 26 | rows.append(row) 27 | 28 | with open(LOCATION_TO_DUMP_CSV,'w') as csvfile: 29 | csvwriter = csv.writer(csvfile) 30 | 31 | csvwriter.writerow(headers) 32 | csvwriter.writerows(rows) 33 | 34 | """ 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /scripts/contract_addresses.py: -------------------------------------------------------------------------------- 1 | CONTRACTS = { 2 | "ropsten": { 3 | "access_control":"", 4 | "fund_multisig":"", 5 | "weth":"", 6 | "mona_token":"", 7 | "lp_token":"", 8 | "genesis_nft":"", 9 | "parent_nft":"", 10 | "genesis_staking":"", 11 | "parent_staking":"", 12 | "lp_staking":"", 13 | "rewards_contract":"", 14 | "child_nft":"" 15 | }, 16 | "mainnet": { 17 | "access_control":"0x03DF7F2B0904a92c754178874796fa64aaF8A762", 18 | "fund_multisig":"0x10C0B0DA2A682C12bD36516A95CB8474C02d83De", 19 | "weth":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", 20 | "mona_token":"0x275f5Ad03be0Fa221B4C6649B8AeE09a42D9412A", 21 | "lp_token":"0xe6936df3D937CFc2CcF5B84ddbFD5455b468bBb9", 22 | "genesis_nft":"0x89505d2a27b7e8AC56252081d721ECd525E4241e", 23 | "parent_nft":"0x0b509f4b044f713a91bb50535914f7ad160532fe", 24 | "genesis_staking":"0xa202D5B0892f2981bA86C981884cebA49B8AE096", 25 | "parent_staking":"0xc802912c379a1ef995a23c07346bd8373049fa39", 26 | "lp_staking":"0xA0d1345244C89b5574ba50bd6530d4EBd237e826", 27 | "rewards_contract":"0xC155DDd8aA737aA53bBCea9EA62CAC0A3EEc942f" 28 | }, 29 | "rinkeby": { 30 | "access_control":"0xE97FB4E889f662CB5EeAbde404831B931208D110", 31 | "weth":"0x52Bb89399F4d137D7cA2a8bc909C7F5cdFA0D688", 32 | "mona_token":"0x9C0Da8a6c581c77a788C7983CBd2d7A73520Da68", 33 | "lp_token":"0x458A5d28E62A3bbcb214C5868eAf19D641448Dc9", 34 | "genesis_nft":"0x54Cd135D890A3224632F4edCAC1b6e43B086b9d9", 35 | "parent_nft":"0x23666Ab5dB229723bf4F155cA1817bc8AA05Cfc0", 36 | "genesis_staking":"0xCA23c6BFaEf7C394c163655EA8928A214D3dCaEE", 37 | "parent_staking":"0xaBa8D5ea863C2D85760dA2DDeE0c9e0f37c0184F", 38 | "lp_staking":"0xCB6095715C2c1339874c80aFab7856b0188e26bD", 39 | "rewards_contract":"0x98A20D420bDC161a0ABeC656d147841f793b14b6", 40 | }, 41 | "kovan": { 42 | "access_control":"0x654729D270BCB3b86670A8a56550fB86A7c15d54", 43 | "fund_multisig":"", 44 | "mona_token":"0xF5B85f3c075260a5746441d0ff5aAf0e9DbB6ADc", 45 | "weth":"0xA1a92054fFcCEff80164E00F1F2dEE6a2D2F6EA9", 46 | "lp_token":"0x3C0110d163abf0DBf6814229316289f9023c633B", 47 | "genesis_nft":"0xeF3cD749B6c4DA46953Bd650487a3df9cf2750A7", 48 | "parent_nft":"0xb1407BDF65aCc9f4E81D5a11141A7CeC393449a2", 49 | "genesis_staking":"", 50 | "parent_staking":"", 51 | "lp_staking":"", 52 | "rewards_contract":"", 53 | "child_nft":"0x50d2164D64061f2e90A868C11962ac212d7053C5" 54 | }, 55 | "goerli": { 56 | "access_control":"0x947bC90254F66B304728e6C0a4B594390b11DEB1", 57 | "fund_multisig":"0x097838ACe90874EC491Bf8A6c72Ce4793987158d", 58 | "mona_token":"0x2f5B22A108Caeb3cBc3e34b50757C5EB14d05619", 59 | "weth":"0x31aC5b4beaceADbcaa68C9E74B49cD8d770a8C88", 60 | "lp_token":"0xA935ADfE2857245141b61D430fdcCdd5300155D2", 61 | "genesis_nft":"0xBc0939DdCFBc741D1DbDcd23deB7e9C202b8e30d", 62 | "parent_nft":"0xa69a9ad0ddCBc646E19b6d36ADFe505229dbC98a", 63 | "genesis_staking":"0x8e9a059d94e0CCB48DcEBfd1969BD92B2972f663", 64 | "parent_staking":"0xe343B4FD1Cf9C32264477395d714042256045F36", 65 | "lp_staking":"0x907a755Ab4faf43Ea83b721595666643292B228d", 66 | "rewards_contract":"0x23342Eed3bB8Bb9602C048881104e8222e48BE97", 67 | "child_nft":"0x8509E9011DA1229AABA88aFBe193781B29F55325" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /scripts/contracts.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | from .settings import * 3 | from .contract_addresses import * 4 | 5 | def load_accounts(): 6 | if network.show_active() == 'mainnet': 7 | # replace with your keys 8 | accounts.load("digitalax") 9 | # add accounts if active network is goerli 10 | if network.show_active() in ['goerli', 'ropsten','kovan','rinkeby']: 11 | # 0x2A40019ABd4A61d71aBB73968BaB068ab389a636 12 | accounts.add('4ca89ec18e37683efa18e0434cd9a28c82d461189c477f5622dae974b43baebf') 13 | # 0x1F3389Fc75Bf55275b03347E4283f24916F402f7 14 | accounts.add('fa3c06c67426b848e6cef377a2dbd2d832d3718999fbe377236676c9216d8ec0') 15 | 16 | def deploy_access_control(): 17 | access_control_address = CONTRACTS[network.show_active()]["access_control"] 18 | if access_control_address == '': 19 | access_control = DigitalaxAccessControls.deploy({'from': accounts[0]}) 20 | else: 21 | access_control = DigitalaxAccessControls.at(access_control_address) 22 | # new_admin = web3.toChecksumAddress('0x66d7Dd55646100541F2B6ec15781b6d4C8372b1c') 23 | # access_control.addAdminRole(new_admin, {'from': accounts[0]}) 24 | return access_control 25 | 26 | def deploy_uniswap_pool(tokenA, tokenB): 27 | uniswap_pool_address = CONTRACTS[network.show_active()]["lp_token"] 28 | if uniswap_pool_address == '': 29 | uniswap_factory = interface.IUniswapV2Factory(UNISWAP_FACTORY) 30 | tx = uniswap_factory.createPair(tokenA, tokenB, {'from': accounts[0]}) 31 | assert 'PairCreated' in tx.events 32 | uniswap_pool = interface.IUniswapV2Pair(web3.toChecksumAddress(tx.events['PairCreated']['pair'])) 33 | else: 34 | uniswap_pool = interface.IUniswapV2Pair(uniswap_pool_address) 35 | return uniswap_pool 36 | 37 | def get_uniswap_pool(): 38 | uniswap_pool_address = CONTRACTS[network.show_active()]["lp_token"] 39 | return interface.IUniswapV2Pair(uniswap_pool_address) 40 | 41 | def deploy_mona_token(access_control, symbol, name, treasury, initial_supply ,cap): 42 | mona_token_address = CONTRACTS[network.show_active()]["mona_token"] 43 | if mona_token_address == '': 44 | decimals = 18 45 | mona_token = MONA.deploy(symbol, name, decimals,access_control, treasury, initial_supply, {'from': accounts[0]}) 46 | mona_token.setCap(cap, False, {'from': accounts[0]}) 47 | else: 48 | mona_token = MONA.at(mona_token_address) 49 | return mona_token 50 | 51 | def get_mona_token(): 52 | mona_token_address = CONTRACTS[network.show_active()]["mona_token"] 53 | return MONA.at(mona_token_address) 54 | 55 | def deploy_weth_token(): 56 | weth_token_address = CONTRACTS[network.show_active()]["weth"] 57 | if weth_token_address == '': 58 | weth_token = WETH9.deploy({'from': accounts[0]}) 59 | else: 60 | weth_token = WETH9.at(weth_token_address) 61 | return weth_token 62 | 63 | def get_weth_token(): 64 | weth_token_address = web3.toChecksumAddress(CONTRACTS[network.show_active()]["weth"]) 65 | return WETH9.at(weth_token_address) 66 | 67 | def deploy_genesis_nft(funds_multisig, access_control, start_time, end_time): 68 | genesis_nft_address = CONTRACTS[network.show_active()]["genesis_nft"] 69 | if genesis_nft_address == "": 70 | genesis_nft = DigitalaxGenesisNFT.deploy( 71 | access_control 72 | , funds_multisig 73 | , start_time 74 | , end_time 75 | , GENESIS_TOKEN_URI 76 | , {'from': accounts[0]}) 77 | else: 78 | genesis_nft = DigitalaxGenesisNFT.at(genesis_nft_address) 79 | return genesis_nft 80 | 81 | def get_genesis_nft(): 82 | genesis_nft_address = web3.toChecksumAddress(CONTRACTS[network.show_active()]["genesis_nft"]) 83 | return DigitalaxGenesisNFT.at(genesis_nft_address) 84 | 85 | def deploy_child_nft(funds_multisig): 86 | child_nft_address = CONTRACTS[network.show_active()]["child_nft"] 87 | if child_nft_address == "": 88 | child_nft = DigitalaxMaterials.deploy( 89 | MATERIAL_NAME 90 | , MATERIAL_SYMBOL 91 | , funds_multisig 92 | , {'from': accounts[0]}) 93 | else: 94 | child_nft = DigitalaxMaterials.at(child_nft_address) 95 | return child_nft 96 | 97 | def deploy_parent_nft(access_control,child_nft): 98 | parent_nft_address = CONTRACTS[network.show_active()]["parent_nft"] 99 | if parent_nft_address == "": 100 | parent_nft = DigitalaxGarmentNFT.deploy( 101 | access_control 102 | , child_nft 103 | , {'from': accounts[0]}) 104 | else: 105 | parent_nft = DigitalaxGarmentNFT.at(parent_nft_address) 106 | return parent_nft 107 | 108 | def get_parent_nft(): 109 | parent_nft_address = web3.toChecksumAddress(CONTRACTS[network.show_active()]["parent_nft"]) 110 | return DigitalaxGarmentNFT.at(parent_nft_address) 111 | 112 | def deploy_genesis_staking(funds_multisig, rewards_token, genesis_nft, access_control): 113 | genesis_staking_address = CONTRACTS[network.show_active()]["genesis_staking"] 114 | if genesis_staking_address == "": 115 | genesis_staking = DigitalaxGenesisStaking.deploy({'from': accounts[0]}) 116 | genesis_staking.initGenesisStaking(funds_multisig, rewards_token, genesis_nft, access_control,{'from': accounts[0]}) 117 | else: 118 | genesis_staking = DigitalaxGenesisStaking.at(genesis_staking_address) 119 | return genesis_staking 120 | 121 | def get_genesis_staking(): 122 | genesis_staking_address = CONTRACTS[network.show_active()]["genesis_staking"] 123 | genesis_staking = DigitalaxGenesisStaking.at(genesis_staking_address) 124 | return genesis_staking 125 | 126 | def deploy_parent_staking(rewards_token, nft_token, access_control): 127 | parent_staking_address = CONTRACTS[network.show_active()]["parent_staking"] 128 | if parent_staking_address == "": 129 | parent_staking = DigitalaxNFTStaking.deploy({'from': accounts[0]}) 130 | parent_staking.initStaking(rewards_token, nft_token, access_control,{'from': accounts[0]}) 131 | else: 132 | parent_staking = DigitalaxNFTStaking.at(parent_staking_address) 133 | return parent_staking 134 | 135 | def get_parent_staking(): 136 | parent_staking_address = CONTRACTS[network.show_active()]["parent_staking"] 137 | parent_staking = DigitalaxNFTStaking.at(parent_staking_address) 138 | return parent_staking 139 | 140 | def deploy_lp_staking(rewards_token, lp_token,weth_token, access_control): 141 | lp_staking_address = CONTRACTS[network.show_active()]["lp_staking"] 142 | lp_token_address = CONTRACTS[network.show_active()]["lp_token"] 143 | 144 | if lp_staking_address == "": 145 | lp_staking = DigitalaxLPStaking.deploy({'from': accounts[0]}) 146 | lp_staking.initLPStaking(rewards_token, lp_token, weth_token, access_control,{'from': accounts[0]}) 147 | else: 148 | lp_staking = DigitalaxLPStaking.at(lp_staking_address) 149 | return lp_staking 150 | 151 | def get_lp_staking(): 152 | lp_staking_address = CONTRACTS[network.show_active()]["lp_staking"] 153 | lp_staking = DigitalaxLPStaking.at(lp_staking_address) 154 | return lp_staking 155 | 156 | 157 | def deploy_rewards(rewards_token,genesis_staking,parent_staking,lp_staking, access_control, start_time,last_time, g_paid, p_paid, lp_paid): 158 | rewards_address = CONTRACTS[network.show_active()]["rewards_contract"] 159 | if rewards_address == "": 160 | rewards = DigitalaxRewards.deploy(rewards_token, 161 | access_control, 162 | genesis_staking, 163 | parent_staking, 164 | lp_staking, 165 | start_time, 166 | last_time, 167 | g_paid, 168 | p_paid, 169 | lp_paid, 170 | {'from': accounts[0]}) 171 | else: 172 | rewards = DigitalaxRewards.at(rewards_address) 173 | return rewards 174 | 175 | 176 | def deploy_new_rewards(rewards_token,genesis_staking,parent_staking,lp_staking, access_control, start_time,last_time, g_paid, p_paid, lp_paid): 177 | rewards_address = CONTRACTS[network.show_active()]["rewards_contract"] 178 | rewards = DigitalaxRewards.deploy(rewards_token, 179 | access_control, 180 | genesis_staking, 181 | parent_staking, 182 | lp_staking, 183 | start_time, 184 | last_time, 185 | g_paid, 186 | p_paid, 187 | lp_paid, 188 | {'from': accounts[0]}) 189 | return rewards 190 | 191 | 192 | def get_rewards(): 193 | rewards_address = CONTRACTS[network.show_active()]["rewards_contract"] 194 | rewards = DigitalaxRewards.at(rewards_address) 195 | return rewards -------------------------------------------------------------------------------- /scripts/deploy_AdminBuyGenesis.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | from .settings import * 3 | from .contracts import * 4 | from .contract_addresses import * 5 | import time 6 | 7 | 8 | def main(): 9 | load_accounts() 10 | 11 | # User to get Genesis NFT 12 | ##user = web3.toChecksumAddress('0x2A40019ABd4A61d71aBB73968BaB068ab389a636') 13 | user = web3.toChecksumAddress('0x1F3389Fc75Bf55275b03347E4283f24916F402f7') 14 | ##user = web3.toChecksumAddress('0x2F55acCE6958d390dc32606230B6BdA2dfec2102') 15 | 16 | # Get Contracts 17 | genesis_nft_address = CONTRACTS[network.show_active()]["genesis_nft"] 18 | genesis_nft = DigitalaxGenesisNFT.at(genesis_nft_address) 19 | 20 | # Mint NFTs 21 | genesis_nft.adminBuy(user, {'from':accounts[0]}) 22 | genesis_nft.transferFrom(user, web3.toChecksumAddress('0x2F55acCE6958d390dc32606230B6BdA2dfec2102'),1,{'from':accounts[1]}) 23 | 24 | genesis_nft.adminBuy(user, {'from':accounts[0]}) 25 | genesis_nft.transferFrom(user, web3.toChecksumAddress('0x2F55acCE6958d390dc32606230B6BdA2dfec2102'),2,{'from':accounts[1]}) 26 | 27 | genesis_nft.adminBuy(user, {'from':accounts[0]}) 28 | genesis_nft.transferFrom(user, web3.toChecksumAddress('0x2F55acCE6958d390dc32606230B6BdA2dfec2102'),3,{'from':accounts[1]}) 29 | 30 | 31 | genesis_nft.adminBuy(user, {'from':accounts[0]}) 32 | genesis_nft.transferFrom(user, web3.toChecksumAddress('0x2F55acCE6958d390dc32606230B6BdA2dfec2102'),4,{'from':accounts[1]}) 33 | 34 | genesis_nft.adminBuy(user, {'from':accounts[0]}) 35 | genesis_nft.transferFrom(user, web3.toChecksumAddress('0xb0CD38895f459d835541bd12eCB09CE99f57d7f9'),5,{'from':accounts[1]}) 36 | 37 | genesis_nft.adminBuy(user, {'from':accounts[0]}) 38 | genesis_nft.transferFrom(user, web3.toChecksumAddress('0xb0CD38895f459d835541bd12eCB09CE99f57d7f9'),6,{'from':accounts[1]}) 39 | 40 | genesis_nft.adminBuy(user, {'from':accounts[0]}) 41 | genesis_nft.transferFrom(user, web3.toChecksumAddress('0xb0CD38895f459d835541bd12eCB09CE99f57d7f9'),7,{'from':accounts[1]}) 42 | 43 | 44 | genesis_nft.adminBuy(user, {'from':accounts[0]}) 45 | genesis_nft.transferFrom(user, web3.toChecksumAddress('0xb0CD38895f459d835541bd12eCB09CE99f57d7f9'),8,{'from':accounts[1]}) 46 | 47 | genesis_nft.adminBuy(user, {'from':accounts[0]}) 48 | genesis_nft.transferFrom(user, web3.toChecksumAddress('0xb0CD38895f459d835541bd12eCB09CE99f57d7f9'),9,{'from':accounts[1]}) 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /scripts/deploy_AdminMintParent.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | from .settings import * 3 | from .contracts import * 4 | from .contract_addresses import * 5 | import time 6 | 7 | 8 | def main(): 9 | load_accounts() 10 | 11 | # User to get Genesis NFT 12 | ##user = web3.toChecksumAddress('0x2A40019ABd4A61d71aBB73968BaB068ab389a636') 13 | ##user = web3.toChecksumAddress('0x1F3389Fc75Bf55275b03347E4283f24916F402f7') 14 | 15 | ## Replace with beneficiary address 16 | user = web3.toChecksumAddress('0x2F55acCE6958d390dc32606230B6BdA2dfec2102') 17 | 18 | # Get Contracts 19 | parent_nft_address = CONTRACTS[network.show_active()]["parent_nft"] 20 | parent_nft = DreamClothingNFT.at(parent_nft_address) 21 | 22 | # Mint NFTs 23 | parent_nft.mint(user, 'https://gateway.pinata.cloud/ipfs/QmbTVX9J3vS5tiwhJzuh8XPRfthQK6BDb57462cRoh7RgM', user, {'from':accounts[0]}); 24 | parent_nft.mint(user, 'https://gateway.pinata.cloud/ipfs/Qmf6Y22UbEim8gnrgbYhF2PiPB25TwqskzbGLJVeaaqcR1', user, {'from':accounts[0]}); 25 | parent_nft.mint(user, 'https://gateway.pinata.cloud/ipfs/QmbTVX9J3vS5tiwhJzuh8XPRfthQK6BDb57462cRoh7RgM', user, {'from':accounts[0]}); 26 | parent_nft.mint(user, 'https://gateway.pinata.cloud/ipfs/Qmf6Y22UbEim8gnrgbYhF2PiPB25TwqskzbGLJVeaaqcR1', user, {'from':accounts[0]}); 27 | 28 | parent_nft.setPrimarySalePrice(1, 100, {'from':accounts[0]}); 29 | parent_nft.setPrimarySalePrice(2, 200, {'from':accounts[0]}); 30 | parent_nft.setPrimarySalePrice(3, 300, {'from':accounts[0]}); 31 | parent_nft.setPrimarySalePrice(4, 400, {'from':accounts[0]}); 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /scripts/deploy_MONA.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | from .settings import * 3 | from .contracts import * 4 | from .contract_addresses import * 5 | import time 6 | 7 | 8 | def main(): 9 | if network.show_active() == 'mainnet': 10 | # replace with your keys 11 | accounts.load("dream") 12 | # add accounts if active network is goerli 13 | if network.show_active() in ['goerli', 'ropsten','kovan','rinkeby']: 14 | # 0x2A40019ABd4A61d71aBB73968BaB068ab389a636 15 | accounts.add('4ca89ec18e37683efa18e0434cd9a28c82d461189c477f5622dae974b43baebf') 16 | # 0x1F3389Fc75Bf55275b03347E4283f24916F402f7 17 | accounts.add('fa3c06c67426b848e6cef377a2dbd2d832d3718999fbe377236676c9216d8ec0') 18 | 19 | access_control = CONTRACTS[network.show_active()]["access_control"] 20 | treasury = web3.toChecksumAddress('0x66d7Dd55646100541F2B6ec15781b6d4C8372b1c') 21 | 22 | if access_control == '': 23 | access_control = deploy_access_control() 24 | 25 | 26 | mona_token = deploy_mona_token(access_control, MONA_SYMBOL, MONA_NAME, treasury, MONA_TREASURY_SUPPLY, MONA_TOKEN_CAP) 27 | 28 | 29 | -------------------------------------------------------------------------------- /scripts/deploy_StakingDev.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | from .settings import * 3 | from .contracts import * 4 | from .contract_addresses import * 5 | import time 6 | 7 | from .deploy_setRewards import * 8 | from .deploy_setContributions import * 9 | from .deploy_setBonus import * 10 | from .deploy_setRewards import * 11 | 12 | def main(): 13 | # Acocunts 14 | load_accounts() 15 | funds_multisig = accounts[0] 16 | treasury = accounts[0] 17 | # AG: Get these parameters for Mainnet 18 | # treasury = web3.toChecksumAddress('0x66d7Dd55646100541F2B6ec15781b6d4C8372b1c') 19 | 20 | genesis_start_time = chain.time() +10 21 | genesis_end_time = chain.time() + 100 22 | start_time = chain.time() 23 | 24 | # MONA Token 25 | access_control = deploy_access_control() 26 | mona_token = deploy_mona_token(access_control, MONA_SYMBOL, MONA_NAME, treasury, MONA_TREASURY_SUPPLY, MONA_TOKEN_CAP) 27 | 28 | # Uniswap Pool 29 | weth_token = deploy_weth_token() 30 | lp_token = deploy_uniswap_pool(mona_token, weth_token) 31 | print("Uniswap Pool Token (LP): ", str(lp_token)) 32 | 33 | # Initial ETH deposit 34 | # weth_token.deposit({'from': accounts[0], 'value': '0.011 ether'}) 35 | # mona_token.transfer(lp_token, 20 * 10**18, {'from':accounts[0]}) 36 | # weth_token.transfer( lp_token,'0.010 ether',{'from':accounts[0]}) 37 | # lp_token.mint(treasury,{'from':accounts[0]}) 38 | 39 | #AG: need to add some liquidity 40 | 41 | # Staking Tokens 42 | genesis_nft = deploy_genesis_nft(funds_multisig, access_control, genesis_start_time, genesis_end_time) 43 | child_nft = deploy_child_nft(funds_multisig) 44 | parent_nft = deploy_parent_nft(access_control, child_nft) 45 | 46 | # Staking Contracts 47 | # genesis_staking = CONTRACTS[network.show_active()]["genesis_staking"] 48 | genesis_staking = deploy_genesis_staking(funds_multisig, mona_token,genesis_nft,access_control) 49 | lp_staking = deploy_lp_staking(mona_token,lp_token,weth_token,access_control) 50 | parent_staking = deploy_parent_staking(mona_token,parent_nft,access_control) 51 | 52 | # Rewards Contract 53 | rewards = deploy_rewards(mona_token,genesis_staking,parent_staking,lp_staking,access_control,start_time, 0, 0, 0, 0) 54 | if rewards.weeklyRewardsPerSecond(0) == 0: 55 | set_bonus(genesis_staking, rewards) 56 | rewards = set_rewards(rewards) 57 | print("rewards per second for week[0] =",rewards.weeklyRewardsPerSecond(0)* 7*24*60*60 /TENPOW18) 58 | print("rewards per second for week[8]=",rewards.weeklyRewardsPerSecond(8)* 7*24*60*60/TENPOW18) 59 | 60 | # Set Rewards contract 61 | genesis_staking.setRewardsContract(rewards,{'from': accounts[0]}) 62 | parent_staking.setRewardsContract(rewards,{'from': accounts[0]}) 63 | lp_staking.setRewardsContract(rewards,{'from': accounts[0]}) 64 | 65 | # Set Minter permissions 66 | access_control.addMinterRole(rewards, {'from': accounts[0]}) 67 | 68 | # Set Genesis Contributions 69 | set_contributions(genesis_staking) 70 | 71 | token_id = 1 72 | genesis_contribution = genesis_staking.getGenesisContribution(token_id) 73 | print("genesis contribution for token[",token_id,"]",genesis_contribution) 74 | 75 | # rewards.up 76 | -------------------------------------------------------------------------------- /scripts/deploy_StakingMainnet.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | from .settings import * 3 | from .contracts import * 4 | from .contract_addresses import * 5 | import time 6 | 7 | from .deploy_setRewards import * 8 | from .deploy_setBonus import * 9 | from .deploy_setContributions import * 10 | 11 | def main(): 12 | # Acocunts 13 | load_accounts() 14 | funds_multisig = CONTRACTS[network.show_active()]["fund_multisig"] 15 | treasury = CONTRACTS[network.show_active()]["fund_multisig"] 16 | # AG: Get these parameters for Mainnet 17 | 18 | 19 | # MONA Token 20 | access_control = deploy_access_control() 21 | mona_token = deploy_mona_token(access_control, MONA_SYMBOL, MONA_NAME, treasury, MONA_TREASURY_SUPPLY + MONA_UNISWAP_SUPPLY, MONA_TOKEN_CAP) 22 | 23 | # mona_token.transfer(treasury, MONA_TREASURY_SUPPLY, {'from':accounts[0]}) 24 | 25 | # # Uniswap Pool 26 | weth_token = get_weth_token() 27 | # lp_token = deploy_uniswap_pool(mona_token, weth_token) 28 | lp_token = get_uniswap_pool() 29 | print("Uniswap Pool Token (LP): ", str(lp_token)) 30 | 31 | # Initial ETH deposit 32 | # weth_token.deposit({'from': accounts[0], 'value': '10 ether'}) 33 | # mona_token.transfer(lp_token, MONA_UNISWAP_SUPPLY, {'from':accounts[0]}) 34 | # weth_token.transfer( lp_token,'10 ether',{'from':accounts[0]}) 35 | # lp_token.mint(treasury,{'from':accounts[0]}) 36 | 37 | #AG: need to add some liquidity 38 | 39 | # Staking Tokens 40 | genesis_nft = get_genesis_nft() 41 | parent_nft = get_parent_nft() 42 | 43 | # Staking Contracts 44 | genesis_staking = deploy_genesis_staking(funds_multisig, mona_token,genesis_nft,access_control) 45 | parent_staking = deploy_parent_staking(mona_token,parent_nft,access_control) 46 | lp_staking = deploy_lp_staking(mona_token,lp_token,weth_token,access_control) 47 | 48 | # Set Genesis Contributions 49 | token_id = 356 50 | genesis_contribution = genesis_staking.getGenesisContribution(token_id) 51 | if genesis_contribution == 0 : 52 | set_contributions(genesis_staking) 53 | 54 | token_id = 356 55 | genesis_contribution = genesis_staking.getGenesisContribution(token_id) 56 | print("genesis contribution for token[",token_id,"]",genesis_contribution) 57 | 58 | # # Rewards Contract 59 | rewards = deploy_rewards(mona_token,genesis_staking,parent_staking,lp_staking,access_control,REWARDS_START_TIME) 60 | if rewards.weeklyRewardsPerSecond(0) == 0: 61 | set_bonus(genesis_staking, rewards) 62 | set_rewards(rewards) 63 | print("rewards per second for week[0] =",rewards.weeklyRewardsPerSecond(0)* 7*24*60*60 /TENPOW18) 64 | print("rewards per second for week[8]=",rewards.weeklyRewardsPerSecond(8)* 7*24*60*60/TENPOW18) 65 | 66 | # # Set Rewards contract 67 | genesis_staking.setRewardsContract(rewards,{'from': accounts[0]}) 68 | parent_staking.setRewardsContract(rewards,{'from': accounts[0]}) 69 | lp_staking.setRewardsContract(rewards,{'from': accounts[0]}) 70 | 71 | # # Set Minter permissions 72 | access_control.addMinterRole(rewards, {'from': accounts[0]}) 73 | 74 | -------------------------------------------------------------------------------- /scripts/deploy_UniswapAddLiquidity.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | from .settings import * 3 | from .contracts import * 4 | from .contract_addresses import * 5 | import time 6 | 7 | 8 | def main(): 9 | load_accounts() 10 | 11 | treasury = web3.toChecksumAddress('0x66d7Dd55646100541F2B6ec15781b6d4C8372b1c') 12 | 13 | # Deploy Contracts 14 | weth_token = deploy_weth_token() 15 | mona_token = get_mona_token() 16 | 17 | # Deploy Uniswap Pool 18 | uniswap_pool = deploy_uniswap_pool(mona_token, weth_token) 19 | 20 | weth_token.deposit({'from': accounts[0], 'value': 0.11*10**18}) 21 | mona_token.transfer(uniswap_pool, 20 * 10**18, {'from':accounts[0]}) 22 | weth_token.transfer( uniswap_pool,0.1 * 10**18,{'from':accounts[0]}) 23 | uniswap_pool.mint(treasury,{'from':accounts[0]}) 24 | print(str(uniswap_pool)) 25 | 26 | 27 | -------------------------------------------------------------------------------- /scripts/deploy_UniswapPool.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | from .settings import * 3 | from .contracts import * 4 | from .contract_addresses import * 5 | import time 6 | 7 | 8 | def main(): 9 | load_accounts() 10 | 11 | treasury = web3.toChecksumAddress('0x66d7Dd55646100541F2B6ec15781b6d4C8372b1c') 12 | mona_token = CONTRACTS[network.show_active()]["mona_token"] 13 | 14 | # Deploy Contracts 15 | access_control = CONTRACTS[network.show_active()]["access_control"] 16 | if access_control == '': 17 | access_control = deploy_access_control() 18 | if mona_token == '': 19 | mona_token = deploy_mona_token(access_control, MONA_SYMBOL, MONA_NAME, treasury, MONA_TREASURY_SUPPLY, MONA_TOKEN_CAP) 20 | 21 | weth_token = deploy_weth_token() 22 | 23 | # Deploy Uniswap Pool 24 | uniswap_pool = deploy_uniswap_pool(mona_token, weth_token) 25 | 26 | print(str(uniswap_pool)) 27 | 28 | 29 | -------------------------------------------------------------------------------- /scripts/deploy_setAdminContributions.py: -------------------------------------------------------------------------------- 1 | import csv 2 | from .contracts import * 3 | 4 | ###########LOCATION############## 5 | LOCATION_TO_RETRIEVE_CSV = "./outputs/SetAdminContributions.csv" 6 | 7 | def set_contributions(genesis_staking): 8 | tokens = [] 9 | amounts = [] 10 | count = 0 11 | with open(LOCATION_TO_RETRIEVE_CSV) as csvfile: 12 | csvreader = csv.reader(csvfile) 13 | next(csvreader) #Skip Header 14 | for row in csvreader: 15 | if count > 50: 16 | genesis_staking.setContributions(tokens,amounts,{'from':accounts[0]}) 17 | tokens = [] 18 | amounts = [] 19 | count = 0 20 | tokens.append(int(row[0])) 21 | amounts.append(float(row[1])*10**18) 22 | count = count + 1 23 | 24 | print('tokens-----------', tokens) 25 | print('amounts -----------',amounts) 26 | genesis_staking.setContributions(tokens,amounts,{'from':accounts[0]}) 27 | 28 | return genesis_staking 29 | 30 | def main(): 31 | # Acocunts 32 | load_accounts() 33 | 34 | # Get rewards contract 35 | genesis_staking_address = CONTRACTS[network.show_active()]["genesis_staking"] 36 | genesis_staking = DreamGenesisStaking.at(genesis_staking_address) 37 | 38 | # Set Rewards 39 | set_contributions(genesis_staking) -------------------------------------------------------------------------------- /scripts/deploy_setBonus.py: -------------------------------------------------------------------------------- 1 | import csv 2 | from .contracts import * 3 | 4 | ###########LOCATION############## 5 | LOCATION_TO_RETRIEVE_CSV = './outputs/bonusPerWeek.csv' 6 | 7 | def set_bonus(pool, rewards): 8 | rewardWeeks = [] 9 | amounts = [] 10 | 11 | with open(LOCATION_TO_RETRIEVE_CSV) as csvfile: 12 | csvreader = csv.reader(csvfile) 13 | next(csvreader) #Skip Header 14 | for row in csvreader: 15 | rewardWeeks.append(row[0]) 16 | amounts.append(float(row[1])) 17 | 18 | 19 | print("reward weeks ------",rewardWeeks) 20 | print("amounts per week ---",amounts) 21 | 22 | rewards.bonusRewards(pool,rewardWeeks,amounts,{'from':accounts[0]}) 23 | 24 | return rewards 25 | 26 | def main(): 27 | # Acocunts 28 | load_accounts() 29 | 30 | # Get rewards contract 31 | rewards_address = CONTRACTS[network.show_active()]["rewards_contract"] 32 | rewards = DreamRewards.at(rewards_address) 33 | genesis_staking_address = CONTRACTS[network.show_active()]["genesis_staking"] 34 | 35 | # Set Rewards 36 | set_bonus(genesis_staking_address, rewards) -------------------------------------------------------------------------------- /scripts/deploy_setContributions.py: -------------------------------------------------------------------------------- 1 | import csv 2 | from .contracts import * 3 | 4 | ###########LOCATION############## 5 | LOCATION_TO_RETRIEVE_CSV = "./outputs/SetContributions.csv" 6 | 7 | def set_contributions(genesis_staking): 8 | tokens = [] 9 | amounts = [] 10 | count = 0 11 | with open(LOCATION_TO_RETRIEVE_CSV) as csvfile: 12 | csvreader = csv.reader(csvfile) 13 | next(csvreader) #Skip Header 14 | for row in csvreader: 15 | if count > 50: 16 | genesis_staking.setContributions(tokens,amounts,{'from':accounts[0]}) 17 | tokens = [] 18 | amounts = [] 19 | count = 0 20 | tokens.append(int(row[0])) 21 | amounts.append(float(row[1])*10**18) 22 | count = count + 1 23 | 24 | print('tokens-----------', tokens) 25 | print('amounts -----------',amounts) 26 | genesis_staking.setContributions(tokens,amounts,{'from':accounts[0]}) 27 | 28 | return genesis_staking 29 | 30 | def main(): 31 | # Acocunts 32 | load_accounts() 33 | 34 | # Get rewards contract 35 | genesis_staking_address = CONTRACTS[network.show_active()]["genesis_staking"] 36 | genesis_staking = DreamGenesisStaking.at(genesis_staking_address) 37 | 38 | # Set Rewards 39 | set_contributions(genesis_staking) -------------------------------------------------------------------------------- /scripts/deploy_setRewards.py: -------------------------------------------------------------------------------- 1 | import csv 2 | from .contracts import * 3 | 4 | ###########LOCATION############## 5 | LOCATION_TO_RETRIEVE_CSV = './outputs/tokensAllocationPerWeek.csv' 6 | 7 | def set_rewards(rewards): 8 | rewardWeeks = [] 9 | amounts = [] 10 | 11 | with open(LOCATION_TO_RETRIEVE_CSV) as csvfile: 12 | csvreader = csv.reader(csvfile) 13 | next(csvreader) #Skip Header 14 | for row in csvreader: 15 | rewardWeeks.append(row[0]) 16 | amounts.append(float(row[1])) 17 | 18 | 19 | print("reward weeks ------",rewardWeeks) 20 | print("amounts per week ---",amounts) 21 | 22 | rewards.setRewards(rewardWeeks,amounts,{'from':accounts[0]}) 23 | 24 | return rewards 25 | 26 | def main(): 27 | # Acocunts 28 | load_accounts() 29 | 30 | # Get rewards contract 31 | rewards_address = CONTRACTS[network.show_active()]["rewards_contract"] 32 | rewards = DreamRewards.at(rewards_address) 33 | 34 | # Set Rewards 35 | set_rewards(rewards) -------------------------------------------------------------------------------- /scripts/deploy_setTokensClaimable.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | from .settings import * 3 | from .contracts import * 4 | from .contract_addresses import * 5 | import time 6 | 7 | 8 | def main(): 9 | load_accounts() 10 | 11 | # Get Contracts 12 | genesis_staking = get_genesis_staking() 13 | parent_staking = get_parent_staking() 14 | lp_staking = get_lp_staking() 15 | 16 | # Set Tokens Claimable 17 | genesis_staking.setTokensClaimable(True, {'from':accounts[0]}) 18 | parent_staking.setTokensClaimable(True, {'from':accounts[0]}) 19 | lp_staking.setTokensClaimable(True, {'from':accounts[0]}) 20 | -------------------------------------------------------------------------------- /scripts/deploy_updateParentStaking.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | from .settings import * 3 | from .contracts import * 4 | from .contract_addresses import * 5 | import time 6 | 7 | from .deploy_setRewards import * 8 | from .deploy_setBonus import * 9 | from .deploy_setContributions import * 10 | 11 | def main(): 12 | # Acocunts 13 | load_accounts() 14 | funds_multisig = CONTRACTS[network.show_active()]["fund_multisig"] 15 | treasury = CONTRACTS[network.show_active()]["fund_multisig"] 16 | # AG: Get these parameters for Mainnet 17 | 18 | 19 | # MONA Token 20 | access_control = deploy_access_control() 21 | mona_token = get_mona_token() 22 | 23 | # Staking Token 24 | parent_nft = get_parent_nft() 25 | 26 | # Parent Staking Contract 27 | parent_staking = DreamNFTStaking.deploy({'from': accounts[0]}) 28 | parent_staking.initStaking(mona_token, parent_nft, access_control, {'from': accounts[0]}) 29 | 30 | rewards = get_rewards() 31 | # # Set Rewards contract 32 | parent_staking.setRewardsContract(rewards,{'from': accounts[0]}) 33 | rewards.setParentStaking(parent_staking,{'from': accounts[0]}) 34 | parent_staking.setTokensClaimable(True, {'from':accounts[0]}) 35 | 36 | -------------------------------------------------------------------------------- /scripts/deploy_updateRewards.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | 3 | from brownie import network 4 | from brownie.network.gas.strategies import GasNowScalingStrategy 5 | from brownie.network import gas_price 6 | from .settings import * 7 | from .contracts import * 8 | from .contract_addresses import * 9 | import time 10 | 11 | from .deploy_setRewards import * 12 | from .deploy_setBonus import * 13 | from .deploy_setContributions import * 14 | 15 | def main(): 16 | # Acocunts 17 | load_accounts() 18 | 19 | gas_strategy = GasNowScalingStrategy("fast", increment=1.2) 20 | gas_price(gas_strategy) 21 | 22 | # MONA Token 23 | access_control = deploy_access_control() 24 | mona_token = get_mona_token() 25 | 26 | # Get Contracts 27 | genesis_staking = get_genesis_staking() 28 | parent_staking = get_parent_staking() 29 | lp_staking = get_lp_staking() 30 | rewards = get_rewards() 31 | 32 | # # Set Tokens Claimable 33 | genesis_staking.setTokensClaimable(False, {'from':accounts[0]}) 34 | parent_staking.setTokensClaimable(False, {'from':accounts[0]}) 35 | lp_staking.setTokensClaimable(False, {'from':accounts[0]}) 36 | 37 | # Accounting snapshot 38 | last_rewards = rewards.lastRewardTime({'from':accounts[0]}) 39 | print("Last Rewards: ", str(last_rewards)) 40 | 41 | genesis_paid = rewards.genesisRewardsPaid({'from':accounts[0]}) 42 | parent_paid = rewards.parentRewardsPaid({'from':accounts[0]}) 43 | lp_paid = rewards.lpRewardsPaid({'from':accounts[0]}) 44 | print("Rewards Paid: G:", str(genesis_paid), " P:", str(parent_paid), " L:",str(lp_paid)) 45 | 46 | week_points0 = rewards.weeklyWeightPoints(0, {'from':accounts[0]}) 47 | print("Weekly Points0:", str(week_points0)) 48 | week_points1 = rewards.weeklyWeightPoints(1, {'from':accounts[0]}) 49 | print("Weekly Points1:", str(week_points1)) 50 | 51 | # # Rewards Contract 52 | new_rewards = deploy_new_rewards(mona_token,genesis_staking,parent_staking,lp_staking, 53 | access_control,REWARDS_START_TIME, last_rewards, 54 | genesis_paid, parent_paid, lp_paid) 55 | 56 | # Set weekly rewards 57 | set_bonus(genesis_staking, new_rewards) 58 | set_rewards(new_rewards) 59 | print("rewards per second for week[0] =",new_rewards.weeklyRewardsPerSecond(0)* 7*24*60*60 /TENPOW18) 60 | print("rewards per second for week[8]=",new_rewards.weeklyRewardsPerSecond(8)* 7*24*60*60/TENPOW18) 61 | 62 | new_rewards.setInitialPoints(0, week_points0[0], week_points0[1], week_points0[2],{'from': accounts[0]}) 63 | new_rewards.setInitialPoints(1, week_points1[0], week_points1[1], week_points1[2],{'from': accounts[0]}) 64 | 65 | # Add Minter permissions 66 | access_control.addMinterRole(new_rewards, {'from': accounts[0]}) 67 | 68 | # Set Rewards contract on staking pooks 69 | genesis_staking.setRewardsContract(new_rewards,{'from': accounts[0]}) 70 | parent_staking.setRewardsContract(new_rewards,{'from': accounts[0]}) 71 | lp_staking.setRewardsContract(new_rewards,{'from': accounts[0]}) 72 | 73 | # Set Tokens Claimable 74 | genesis_staking.setTokensClaimable(True, {'from':accounts[0]}) 75 | parent_staking.setTokensClaimable(True, {'from':accounts[0]}) 76 | lp_staking.setTokensClaimable(True, {'from':accounts[0]}) 77 | 78 | # Refresh the updated time to check it works 79 | new_rewards.updateRewards({'from': accounts[0]}) 80 | -------------------------------------------------------------------------------- /scripts/get_UniswapPair.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | from .settings import * 3 | from .contracts import * 4 | from .contract_addresses import * 5 | 6 | def get_lp_token(tokenA, tokenB): 7 | load_accounts() 8 | 9 | uniswap_pool_address = CONTRACTS[network.show_active()]["lp_token"] 10 | if uniswap_pool_address == '': 11 | uniswap_factory = interface.IUniswapV2Factory(UNISWAP_FACTORY) 12 | tx = uniswap_factory.getPair(tokenA, tokenB, {'from': accounts[0]}) 13 | return tx 14 | 15 | def main(): 16 | mona_token = CONTRACTS[network.show_active()]["mona_token"] 17 | 18 | # Deploy Contracts 19 | access_control = CONTRACTS[network.show_active()]["access_control"] 20 | weth_token = deploy_weth_token() 21 | address = get_lp_token(mona_token,weth_token) 22 | print(address) -------------------------------------------------------------------------------- /scripts/get_token_indexes.py: -------------------------------------------------------------------------------- 1 | from brownie import * 2 | from .settings import * 3 | from .contracts import * 4 | from .contract_addresses import * 5 | import json 6 | import csv 7 | import collections 8 | LOCATION_TO_DUMP_CSV = "./outputs/TokenOwner.csv" 9 | def main(): 10 | 11 | rows = [] 12 | genesis_staking_address = CONTRACTS[network.show_active()]["genesis_staking"] 13 | genesis_staking = DreamGenesisStaking.at(genesis_staking_address) 14 | for x in range(500): 15 | 16 | tokenOwner = genesis_staking.tokenOwner(x) 17 | print(tokenOwner) 18 | rows.append(tokenOwner) 19 | 20 | 21 | print("duplicates --------") 22 | print([item for item, count in collections.Counter(rows).items() if count > 1]) 23 | counts = dict(collections.Counter(rows)) 24 | 25 | print("---counts---") 26 | for count in counts.items(): 27 | if count[1] > 1: 28 | print(count) 29 | 30 | -------------------------------------------------------------------------------- /scripts/rewards.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | ## An mvp python script to model reward payouts 5 | 6 | def exponentialDist(tokens : float): 7 | weights = np.exp(-np.arange(0,10) * 0.7) 8 | normalization = np.sum(weights) 9 | 10 | return tokens * weights / normalization 11 | 12 | totalTokens = 9000 13 | gTokenReserved_month0 = 700 14 | tokensMonth_1_2 = 2000 15 | 16 | nG_investors = 240 17 | maxG = 2 18 | minG = 0.1 19 | 20 | nP_investors = 50 21 | maxP = 20 22 | minP = 0.5 23 | 24 | nM_investors = 10 25 | maxM = 20 26 | minM = 0.0001 27 | 28 | tokensAllocationPerMonth = np.zeros(12) 29 | tokensAllocationPerMonth[0:2] = tokensMonth_1_2 30 | tokensAllocationPerMonth[2:] = exponentialDist(totalTokens - np.sum(tokensAllocationPerMonth[0:1])) 31 | plt.plot(tokensAllocationPerMonth, label="Tokens released every month") 32 | plt.legend() 33 | plt.show() 34 | 35 | def getReturnWeights(g_net : float, p_net : float, m_net : float): 36 | order = np.max([np.log(p_net/(g_net + m_net)) / np.log(10), 0]) 37 | d = np.exp(-order) 38 | normalization = g_net + d * p_net + m_net 39 | 40 | return g_net / normalization, d * p_net / normalization, m_net / normalization 41 | 42 | def invest(): 43 | # fig, ax = plt.subplots(12, 3) 44 | 45 | for month in range(12): 46 | gReturns = np.zeros(nG_investors) 47 | pReturns = np.zeros(nP_investors) 48 | mReturns = np.zeros(nM_investors) 49 | 50 | gInvestment = minG + np.random.rand(nG_investors) * (maxG - minG) 51 | pInvestment = minP + np.random.rand(nP_investors) * (maxP - minP) 52 | mInvestment = minM + np.random.rand(nM_investors) * (maxM - minM) 53 | 54 | tokensThisMonth = tokensAllocationPerMonth[month] 55 | 56 | g_net = np.sum(gInvestment) 57 | p_net = np.sum(pInvestment) 58 | m_net = np.sum(mInvestment) 59 | 60 | if month == 0: 61 | tokensThisMonth -= gTokenReserved_month0 62 | 63 | gReturns[:] += gTokenReserved_month0 * gInvestment / g_net 64 | 65 | gW, pW, mW = getReturnWeights(g_net, p_net, m_net) 66 | print("Weights " + str(month) + " - gW:" + str(gW) + " pW:" + str(pW) + " mW:" + str(mW)) 67 | 68 | gReturns[:] += gW * tokensThisMonth * gInvestment / g_net 69 | pReturns[:] += pW * tokensThisMonth * pInvestment / p_net 70 | mReturns[:] += mW * tokensThisMonth * mInvestment / m_net 71 | 72 | # ax[month, 0].plot(gReturns, color="r", label="G, Investment:{Investment:.2f}, Return:{Return:.2f}".format(Investment=g_net, Return=np.sum(gReturns))) 73 | # ax[month, 0].legend(loc="upper right") 74 | # ax[month, 1].plot(pReturns, color="g", label="P, Investment:{Investment:.2f}, Return:{Return:.2f}".format(Investment=p_net, Return=np.sum(pReturns))) 75 | # ax[month, 1].legend(loc='upper right') 76 | # ax[month, 2].plot(mReturns, color="b", label="M, Investment:{Investment:.2f}, Return:{Return:.2f}".format(Investment=m_net, Return=np.sum(mReturns))) 77 | # ax[month, 2].legend(loc='upper right') 78 | 79 | 80 | # plt.show() 81 | 82 | invest() 83 | -------------------------------------------------------------------------------- /scripts/rewardsWeekly.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import pandas as pd 4 | ## An mvp python script to model reward payouts 5 | ############CHANGE THIS AS REQUIRED############# 6 | LOCATION_TO_DUMP_CSV = "./outputs/tokensAllocationPerWeek.csv" 7 | 8 | totalTokens = 9000 9 | tokensMonth_1_2 = 2000 10 | 11 | def exponentialDist(tokens : float): 12 | weights = np.exp(-np.arange(0,44) * 0.07) 13 | normalization = np.sum(weights) 14 | 15 | return tokens * weights / normalization 16 | 17 | 18 | def getRewardsWeekly(): 19 | tokensAllocationPerWeek = np.zeros(52) 20 | tokensAllocationPerWeek[0:8] = tokensMonth_1_2 / 4 21 | tokensAllocationPerWeek[8:] = exponentialDist(totalTokens - np.sum(tokensAllocationPerWeek[0:8])) 22 | print(tokensAllocationPerWeek) 23 | print(np.sum(tokensAllocationPerWeek)) 24 | plt.plot(tokensAllocationPerWeek, label="Tokens released every week") 25 | plt.legend() 26 | plt.show() 27 | col_name = ['WeeklyRewards'] 28 | pd.DataFrame(tokensAllocationPerWeek).to_csv(LOCATION_TO_DUMP_CSV,header = col_name) 29 | return tokensAllocationPerWeek 30 | 31 | 32 | def main(): 33 | getRewardsWeekly() 34 | -------------------------------------------------------------------------------- /scripts/settings.py: -------------------------------------------------------------------------------- 1 | ########################### 2 | # Deployment Settings 3 | ########################### 4 | TENPOW18 = 10 ** 18 5 | ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' 6 | ETH_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' 7 | UNISWAP_FACTORY = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f' 8 | 9 | ########################### 10 | # Genesis NFT Tokens 11 | ########################### 12 | GENESIS_TOKENS = 500 13 | GENESIS_AUCTION_TIME = 300 14 | GENESIS_TOKEN_URI = 'https://gateway.pinata.cloud/ipfs/QmRjiYPGEm3GkWYW6Mpp3ZGHvYA6odo8pHbPNvtTjLfYF4' 15 | 16 | ########################### 17 | # MONA Token 18 | ########################### 19 | 20 | MONA_NAME = "Dream" 21 | MONA_SYMBOL = "MONA" 22 | MONA_TOKEN_CAP = 10000 * TENPOW18 23 | MONA_TREASURY_SUPPLY = 1000 * TENPOW18 24 | MONA_UNISWAP_SUPPLY = 200 * TENPOW18 25 | 26 | ########################### 27 | # Rewards 28 | ########################### 29 | 30 | REWARDS_START_TIME = 1606932000 31 | 32 | ########################### 33 | # Dream Materials 34 | ########################### 35 | 36 | MATERIAL_NAME = "MINIMO" 37 | MATERIAL_SYMBOL = "MIN" 38 | -------------------------------------------------------------------------------- /tests/__pycache__/conftest.cpython-38-pytest-6.0.1.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/tests/__pycache__/conftest.cpython-38-pytest-6.0.1.pyc -------------------------------------------------------------------------------- /tests/__pycache__/settings.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/tests/__pycache__/settings.cpython-38.pyc -------------------------------------------------------------------------------- /tests/__pycache__/test_genesis_nft.cpython-38-pytest-6.0.1.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/tests/__pycache__/test_genesis_nft.cpython-38-pytest-6.0.1.pyc -------------------------------------------------------------------------------- /tests/__pycache__/test_rewards.cpython-38-pytest-6.0.1.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/tests/__pycache__/test_rewards.cpython-38-pytest-6.0.1.pyc -------------------------------------------------------------------------------- /tests/__pycache__/test_staking.cpython-38-pytest-6.0.1.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/tests/__pycache__/test_staking.cpython-38-pytest-6.0.1.pyc -------------------------------------------------------------------------------- /tests/__pycache__/test_staking_genesis.cpython-38-pytest-6.0.1.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/tests/__pycache__/test_staking_genesis.cpython-38-pytest-6.0.1.pyc -------------------------------------------------------------------------------- /tests/__pycache__/test_staking_lp.cpython-38-pytest-6.0.1.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/tests/__pycache__/test_staking_lp.cpython-38-pytest-6.0.1.pyc -------------------------------------------------------------------------------- /tests/__pycache__/test_staking_nft.cpython-38-pytest-6.0.1.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/tests/__pycache__/test_staking_nft.cpython-38-pytest-6.0.1.pyc -------------------------------------------------------------------------------- /tests/__pycache__/test_staking_parent.cpython-38-pytest-6.0.1.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartcoder-7/NFT-staking/95080abbdd526ad64ed4c6cf8523ec96e2327f3f/tests/__pycache__/test_staking_parent.cpython-38-pytest-6.0.1.pyc -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | 2 | from brownie import accounts, web3, Wei, chain 3 | from brownie.network.transaction import TransactionReceipt 4 | from brownie.convert import to_address 5 | import pytest 6 | from brownie import Contract 7 | from settings import * 8 | 9 | 10 | ############################################## 11 | # Access Controls 12 | ############################################## 13 | 14 | @pytest.fixture(scope='module', autouse=True) 15 | def access_controls(DigitalaxAccessControls): 16 | access_controls = DigitalaxAccessControls.deploy({'from': accounts[0]}) 17 | return access_controls 18 | 19 | ############################################## 20 | # MONA Token 21 | ############################################## 22 | 23 | @pytest.fixture(scope='module', autouse=True) 24 | def mona_token(MONA, access_controls): 25 | tokenOwner = accounts[2] 26 | initialSupply = 1000 27 | mona_token = MONA.deploy( 28 | MONA_SYMBOL 29 | , MONA_NAME 30 | , 18 31 | , access_controls 32 | , tokenOwner 33 | , initialSupply 34 | , {'from': accounts[0]}) 35 | return mona_token 36 | 37 | @pytest.fixture(scope='module', autouse=True) 38 | def weth_token(WETH9): 39 | weth_token = WETH9.deploy({'from': accounts[0]}) 40 | return weth_token 41 | 42 | ##################################### 43 | #LP TOKEN USE - Replace with LP contract 44 | ###################################### 45 | @pytest.fixture(scope='module', autouse=True) 46 | def lp_token(MONA,weth_token, access_controls): 47 | tokenOwner = accounts[2] 48 | initialSupply = 1000 49 | lp_token = MONA.deploy( 50 | 'LP' 51 | ,'MONALP' 52 | , 18 53 | , access_controls 54 | , tokenOwner 55 | , initialSupply 56 | , {'from': accounts[0]}) 57 | return lp_token 58 | 59 | ############################################## 60 | # NFT Tokens 61 | ############################################## 62 | 63 | @pytest.fixture(scope='module', autouse=True) 64 | def genesis_nft(DigitalaxGenesisNFT, access_controls): 65 | fundsMultisig = accounts[1] 66 | genesisStartTimestamp = chain.time() +10 67 | genesisEndTimestamp = chain.time() + 10 + GENESIS_AUCTION_TIME 68 | 69 | genesis_nft = DigitalaxGenesisNFT.deploy( 70 | access_controls 71 | , fundsMultisig 72 | , genesisStartTimestamp 73 | , genesisEndTimestamp 74 | , GENESIS_TOKEN_URI 75 | , {"from": accounts[0]}) 76 | return genesis_nft 77 | 78 | 79 | @pytest.fixture(scope='module', autouse=True) 80 | def parent_nft(DigitalaxGenesisNFT, access_controls): 81 | fundsMultisig = accounts[1] 82 | genesisStartTimestamp = chain.time() +10 83 | genesisEndTimestamp = chain.time() + 10 + GENESIS_AUCTION_TIME 84 | 85 | parent_nft = DigitalaxGenesisNFT.deploy( 86 | access_controls 87 | , fundsMultisig 88 | , genesisStartTimestamp 89 | , genesisEndTimestamp 90 | , GENESIS_TOKEN_URI 91 | , {"from": accounts[0]}) 92 | return parent_nft 93 | 94 | ############################################## 95 | # Staking 96 | ############################################## 97 | 98 | @pytest.fixture(scope='module', autouse=True) 99 | def staked_nft(DigitalaxGenesisNFT, access_controls): 100 | fundsMultisig = accounts[1] 101 | genesisStartTimestamp = chain.time() +10 102 | genesisEndTimestamp = chain.time() + 10 + GENESIS_AUCTION_TIME 103 | staked_nft = DigitalaxGenesisNFT.deploy( 104 | access_controls 105 | , fundsMultisig 106 | , genesisStartTimestamp 107 | , genesisEndTimestamp 108 | , GENESIS_TOKEN_URI 109 | , {"from": accounts[0]}) 110 | chain.sleep(10) 111 | 112 | # Add some transactions for this instance to test 113 | txn = staked_nft.buy({'from':accounts[1],'value':'1 ethers'}) 114 | assert 'GenesisPurchased' in txn.events 115 | txn = staked_nft.buyOrIncreaseContribution({'from':accounts[1],'value':'0.5 ethers'}) 116 | txn = staked_nft.buyOrIncreaseContribution({'from':accounts[2],'value':'0.1 ethers'}) 117 | txn = staked_nft.buyOrIncreaseContribution({'from':accounts[3],'value':'0.2 ethers'}) 118 | txn = staked_nft.buyOrIncreaseContribution({'from':accounts[4],'value':'1.1 ethers'}) 119 | txn = staked_nft.buyOrIncreaseContribution({'from':accounts[5],'value':'1.1 ethers'}) 120 | txn = staked_nft.buyOrIncreaseContribution({'from':accounts[6],'value':'1.7 ethers'}) 121 | txn = staked_nft.buyOrIncreaseContribution({'from':accounts[7],'value':'0.1 ethers'}) 122 | txn = staked_nft.buyOrIncreaseContribution({'from':accounts[8],'value':'0.3 ethers'}) 123 | txn = staked_nft.buyOrIncreaseContribution({'from':accounts[9],'value':'0.5 ethers'}) 124 | assert 'GenesisPurchased' in txn.events 125 | return staked_nft 126 | 127 | 128 | @pytest.fixture(scope='module', autouse=True) 129 | def staking_genesis(DigitalaxGenesisStaking, mona_token, staked_nft, access_controls): 130 | staking_genesis = DigitalaxGenesisStaking.deploy({'from': accounts[0]}) 131 | staking_genesis.initGenesisStaking( 132 | accounts[1] 133 | , mona_token 134 | , staked_nft 135 | , access_controls 136 | , {"from": accounts[0]}) 137 | # So the genesis contracts did not have any way to check how much was contributed 138 | # So instead we put in the amounts using setContributions() 139 | # The conftest.py should have the contributions set 140 | tokens = [1,2,3,4,5,6,7,8,9] 141 | amounts = [1.5*TENPOW18,0.1*TENPOW18,0.2*TENPOW18,1*TENPOW18,1*TENPOW18,1.7*TENPOW18,0.1*TENPOW18,0.3*TENPOW18,0.5*TENPOW18] 142 | staking_genesis.setContributions(tokens,amounts) 143 | staking_genesis.setTokensClaimable(True) 144 | 145 | return staking_genesis 146 | 147 | @pytest.fixture(scope='module', autouse=True) 148 | def staking_nft(DigitalaxNFTStaking, mona_token, parent_nft, access_controls): 149 | #rewardsPerSecond = REWARDS_PER_SECOND 150 | staking_nft = DigitalaxNFTStaking.deploy({'from': accounts[0]}) 151 | staking_nft.initStaking( 152 | mona_token 153 | , parent_nft 154 | , access_controls 155 | , {"from": accounts[0]}) 156 | return staking_nft 157 | 158 | @pytest.fixture(scope='module', autouse=True) 159 | def staking_lp(DigitalaxLPStaking,lp_token, mona_token, weth_token, access_controls): 160 | #rewardsPerSecond = REWARDS_PER_SECOND 161 | staking_lp = DigitalaxLPStaking.deploy({'from': accounts[0]}) 162 | staking_lp.initLPStaking( 163 | mona_token 164 | , lp_token 165 | , weth_token 166 | , access_controls 167 | , {"from": accounts[0]}) 168 | 169 | return staking_lp 170 | 171 | 172 | 173 | ############################################## 174 | # Rewards 175 | ############################################## 176 | @pytest.fixture(scope='module', autouse=True) 177 | def staking_genesis_mock(MockStaking): 178 | return MockStaking.deploy(0.5*TENPOW18, {'from':accounts[0]}) 179 | @pytest.fixture(scope='module', autouse=True) 180 | def staking_nft_mock(MockStaking): 181 | return MockStaking.deploy(0.5*TENPOW18, {'from':accounts[0]}) 182 | @pytest.fixture(scope='module', autouse=True) 183 | def staking_lp_mock(MockStaking): 184 | return MockStaking.deploy(0*TENPOW18, {'from':accounts[0]}) 185 | 186 | @pytest.fixture(scope='module', autouse=True) 187 | def staking_rewards_mock(DigitalaxRewards,MockStaking, mona_token, access_controls, staking_genesis_mock, staking_nft_mock, staking_lp_mock): 188 | start_time = chain.time() 189 | staking_rewards_mock = DigitalaxRewards.deploy( 190 | mona_token, 191 | access_controls, 192 | staking_genesis_mock, 193 | staking_nft_mock, 194 | staking_lp_mock, 195 | start_time, 196 | start_time,0,0,0, 197 | {'from':accounts[0]} 198 | ) 199 | access_controls.addMinterRole(staking_rewards_mock) 200 | assert access_controls.hasMinterRole(staking_rewards_mock) == True 201 | staking_genesis_mock.setRewardsContract(staking_rewards_mock) 202 | staking_nft_mock.setRewardsContract(staking_rewards_mock) 203 | staking_lp_mock.setRewardsContract(staking_rewards_mock) 204 | 205 | weeks = [0,1,2,3,4,5] 206 | rewards = [700*TENPOW18,700*TENPOW18,500*TENPOW18,350*TENPOW18,150*TENPOW18,100*TENPOW18] 207 | staking_rewards_mock.setRewards(weeks,rewards) 208 | 209 | weeks = [0,1] 210 | rewards = [450*TENPOW18,350*TENPOW18] 211 | staking_rewards_mock.bonusRewards(staking_genesis_mock,weeks,rewards) 212 | 213 | return staking_rewards_mock 214 | 215 | 216 | @pytest.fixture(scope='module', autouse=True) 217 | def staking_rewards(DigitalaxRewards,mona_token,access_controls,staked_nft,staking_genesis,staking_nft,staking_lp_mock): 218 | start_time = chain.time() 219 | staking_rewards = DigitalaxRewards.deploy( 220 | mona_token, 221 | access_controls, 222 | staking_genesis, 223 | staking_nft, 224 | staking_lp_mock, 225 | start_time, 226 | start_time,0,0,0, 227 | {'from':accounts[0]} 228 | ) 229 | access_controls.addMinterRole(staking_rewards) 230 | assert access_controls.hasMinterRole(staking_rewards) == True 231 | staking_genesis.setRewardsContract(staking_rewards) 232 | # staking_nft.setRewardsContract(staking_rewards) 233 | # staking_lp.setRewardsContract(staking_rewards) 234 | 235 | weeks = [0,1,2,3,4,5] 236 | rewards = [700*TENPOW18,700*TENPOW18,500*TENPOW18,350*TENPOW18,150*TENPOW18,100*TENPOW18] 237 | staking_rewards.setRewards(weeks,rewards) 238 | 239 | weeks = [0,1] 240 | rewards = [450*TENPOW18,350*TENPOW18] 241 | staking_rewards.bonusRewards(staking_genesis,weeks,rewards) 242 | 243 | chain.sleep(GENESIS_AUCTION_TIME +20) 244 | chain.mine() 245 | staking_genesis.setTokensClaimable(True, {'from':accounts[0]}) 246 | for tokenId in range(1,7): 247 | staked_nft.setApprovalForAll(staking_genesis, True, {'from':accounts[tokenId]}) 248 | staking_genesis.stake(tokenId,{'from':accounts[tokenId]}) 249 | 250 | totalEth = (1.5 +0.1 +0.2 +1 +1 +1.7)*TENPOW18 251 | 252 | #Ask why there is 200 more wei 253 | assert staking_genesis.stakedEthTotal() == totalEth 254 | 255 | return staking_rewards 256 | 257 | -------------------------------------------------------------------------------- /tests/settings.py: -------------------------------------------------------------------------------- 1 | ########################### 2 | # Test Settings 3 | ########################### 4 | TENPOW18 = 10 ** 18 5 | ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' 6 | ETH_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' 7 | 8 | ########################### 9 | # Access control 10 | ########################### 11 | #ACCESS_CONTROL = 12 | FUND_MULTISIG_ADDRESS = '0x10C0B0DA2A682C12bD36516A95CB8474C02d83De' 13 | 14 | ########################### 15 | # Genesis NFT Tokens 16 | ########################### 17 | 18 | GENESIS_TOKENS = 500 19 | GENESIS_AUCTION_TIME = 50000 20 | GENESIS_TOKEN_URI = 'https://gateway.pinata.cloud/ipfs/QmRjiYPGEm3GkWYW6Mpp3ZGHvYA6odo8pHbPNvtTjLfYF4' 21 | 22 | ########################### 23 | # MONA Token 24 | ########################### 25 | 26 | MONA_NAME = "Monavale" 27 | MONA_SYMBOL = "MONA" 28 | MONA_TOKENS = 10000 * TENPOW18 29 | MONA_TREASURY = 1000 * TENPOW18 30 | 31 | ########################### 32 | # Rewards 33 | ########################### 34 | 35 | BONUS = 700 * TENPOW18 -------------------------------------------------------------------------------- /tests/test_genesis_nft.py: -------------------------------------------------------------------------------- 1 | from brownie import accounts, web3, Wei, reverts, chain 2 | from brownie.network.transaction import TransactionReceipt 3 | from brownie.convert import to_address 4 | import pytest 5 | from brownie import Contract 6 | from settings import * 7 | 8 | @pytest.fixture(autouse=True) 9 | def isolation(fn_isolation): 10 | pass 11 | 12 | # def test_buy_NFT_during_genesis(genesis_nft): 13 | # #genesis start timestamp slept 14 | # chain.sleep(15) 15 | # chain.mine() 16 | # txn = genesis_nft.buy({'from':accounts[2],'value':'1 ethers'}) 17 | # assert 'GenesisPurchased' in txn.events 18 | 19 | # def test_buy_NFT_during_genesis_and_end(genesis_nft): 20 | # #genesis start timestamp slept 21 | # chain.sleep(15) 22 | # chain.mine() 23 | # txn = genesis_nft.buy({'from':accounts[2],'value':'1 ethers'}) 24 | # assert 'GenesisPurchased' in txn.events 25 | # txn = genesis_nft.buyOrIncreaseContribution({'from':accounts[2],'value':'0.5 ethers'}) 26 | # assert 'ContributionIncreased' in txn.events 27 | # chain.sleep(GENESIS_AUCTION_TIME) 28 | 29 | # def test_staked_nft_to_transfer(staked_nft): 30 | # chain.sleep(GENESIS_AUCTION_TIME) 31 | # chain.mine() 32 | # tokenId = 1 33 | # ######### token id and from_address (accounts[id]) have same ids 34 | # from_address = accounts[1] 35 | # to_address = accounts[9] 36 | # staked_nft.transferFrom(from_address,to_address,tokenId,{'from':from_address}) 37 | # assert staked_nft.ownerOf(tokenId) == to_address 38 | # tokenId = 6 39 | # from_address = accounts[6] 40 | 41 | # staked_nft.transferFrom(from_address,to_address,tokenId,{'from':from_address}) 42 | # assert staked_nft.ownerOf(tokenId) == to_address 43 | # assert staked_nft.balanceOf(to_address) == 2 44 | 45 | -------------------------------------------------------------------------------- /tests/test_staking_genesis.py: -------------------------------------------------------------------------------- 1 | from brownie import accounts, web3, Wei, reverts, chain 2 | from brownie.network.transaction import TransactionReceipt 3 | from brownie.convert import to_address 4 | import pytest 5 | from brownie import Contract 6 | from settings import * 7 | 8 | @pytest.fixture(autouse=True) 9 | def isolation(fn_isolation): 10 | pass 11 | 12 | def staked_nft_all(staking_genesis, staked_nft): 13 | chain.sleep(GENESIS_AUCTION_TIME) 14 | 15 | for tokenId in range(1,7): 16 | staked_nft.setApprovalForAll(staking_genesis, True, {'from':accounts[tokenId]}) 17 | txn = staking_genesis.stake(tokenId,{'from':accounts[tokenId]}) 18 | 19 | totalEth = (1.5 +0.1 +0.2 +1 +1 +1.7)*TENPOW18 20 | 21 | #Ask why there is 200 more wei 22 | assert staking_genesis.stakedEthTotal() == totalEth 23 | assert 'Staked' in txn.events 24 | return staked_nft 25 | 26 | 27 | def test_stake_genesis_nft(staking_genesis, staked_nft): 28 | balance_of_staking_user = staking_genesis.stakers(accounts[2])[0] 29 | tokenId = 2 30 | 31 | assert balance_of_staking_user == 0.1*TENPOW18 32 | assert staked_nft.ownerOf(tokenId) == staking_genesis 33 | 34 | balance_of_staking_user = staking_genesis.stakers(accounts[3])[0] 35 | tokenId = 3 36 | 37 | assert balance_of_staking_user == 0.2*TENPOW18 38 | assert staked_nft.ownerOf(tokenId) == staking_genesis 39 | 40 | 41 | 42 | # Fail when trying to deposit something that is not mine 43 | def test_fail_stake_not_owner(staking_genesis, staked_nft): 44 | 45 | staked_nft.setApprovalForAll(staking_genesis, True, {'from':accounts[2]}) 46 | tokenId = 2 47 | with reverts(): 48 | staking_genesis.stake(tokenId,{'from':accounts[3]}) 49 | 50 | 51 | 52 | def test_unstake_genesis_nft(staking_genesis, staked_nft): 53 | ## First staking tokens that will be unstaked 54 | 55 | 56 | chain.sleep(2000) 57 | chain.mine() 58 | ## see if reward generation is correct. 59 | 60 | ## For account 2 staking is 0.2 ## 61 | balance_of_user_after_staking = staking_genesis.stakers(accounts[3])[0] 62 | assert balance_of_user_after_staking == 0.2*TENPOW18 63 | 64 | token_id_to_unstake = 3 65 | 66 | 67 | txn = staking_genesis.unstake(token_id_to_unstake, {'from': accounts[3]}) 68 | balance_of_user_after_unstaking = staking_genesis.stakers(accounts[3])[0] 69 | 70 | net_balance_of_user = balance_of_user_after_staking - balance_of_user_after_unstaking 71 | 72 | assert net_balance_of_user == 0.2 * TENPOW18 73 | assert balance_of_user_after_unstaking == 0 74 | 75 | assert staking_genesis.stakedEthTotal() == 5.3 * TENPOW18 76 | assert staked_nft.ownerOf(token_id_to_unstake) == accounts[3] 77 | assert 'Unstaked' in txn.events 78 | 79 | 80 | 81 | def test_rewards_genesis_staking(staked_nft,staking_genesis): 82 | 83 | chain.sleep(10000) 84 | 85 | print("stakers struct[balance]=",staking_genesis.stakers(accounts[2])[0]) 86 | print("stakers struct[lastRewardPoints]=",staking_genesis.stakers(accounts[2])[1]) 87 | print("stakers struct[lastRewardEarned]=",staking_genesis.stakers(accounts[2])[2]) 88 | print("stakers struct[rewardsReleased]=",staking_genesis.stakers(accounts[2])[3]) 89 | rewardsOwing = staking_genesis.rewardsOwing(accounts[2]) 90 | 91 | print("rewardsOwing--->",rewardsOwing) 92 | print("total reward points -->",staking_genesis.rewardsPerTokenPoints()) 93 | 94 | 95 | -------------------------------------------------------------------------------- /tests/test_staking_lp.py: -------------------------------------------------------------------------------- 1 | from brownie import accounts, web3, Wei, reverts, chain 2 | from brownie.network.transaction import TransactionReceipt 3 | from brownie.convert import to_address 4 | import pytest 5 | from brownie import Contract 6 | from settings import * 7 | 8 | @pytest.fixture(autouse=True) 9 | def isolation(fn_isolation): 10 | pass 11 | 12 | # def test_stake_genesis_nft(staking, staked_nft): 13 | # chain.sleep(GENESIS_AUCTION_TIME) 14 | # staked_nft.setApprovalForAll(staking_contract, True, {'from':accounts[2]}) 15 | # txn = staking_contract.stake({'from':accounts[2]}) 16 | # assert 'Staked' in txn.events 17 | 18 | -------------------------------------------------------------------------------- /tests/test_staking_parent.py: -------------------------------------------------------------------------------- 1 | from brownie import accounts, web3, Wei, reverts, chain 2 | from brownie.network.transaction import TransactionReceipt 3 | from brownie.convert import to_address 4 | import pytest 5 | from brownie import Contract 6 | from settings import * 7 | 8 | @pytest.fixture(autouse=True) 9 | def isolation(fn_isolation): 10 | pass 11 | 12 | # def staked_nft_all(staking_nft, parent_nft): 13 | # chain.sleep(GENESIS_AUCTION_TIME) 14 | 15 | # for tokenId in range(1,7): 16 | # parent_nft.setApprovalForAll(staking_nft, True, {'from':accounts[tokenId]}) 17 | # txn = staking_nft.stake(tokenId,{'from':accounts[tokenId]}) 18 | 19 | # # totalEth = 1.5*TENPOW18+0.1*TENPOW18+0.2*TENPOW18+1*TENPOW18+1*TENPOW18+1.7*TENPOW18 20 | # # assert staking_nft.stakedEthTotal() == totalEth 21 | # assert 'Staked' in txn.events 22 | # return parent_nft 23 | 24 | 25 | # def test_stake_genesis_nft(staking_nft, parent_nft): 26 | # balance_of_staking_user = staking_nft.stakers(accounts[2])[0] 27 | # tokenId = 2 28 | 29 | # assert balance_of_staking_user == 0.1*TENPOW18 30 | # assert parent_nft.ownerOf(tokenId) == staking_nft 31 | 32 | # balance_of_staking_user = staking_nft.stakers(accounts[3])[0] 33 | # tokenId = 3 34 | 35 | # assert balance_of_staking_user == 0.2*TENPOW18 36 | # assert parent_nft.ownerOf(tokenId) == staking_nft 37 | 38 | 39 | 40 | 41 | # # Fail when trying to deposit something that is not mine 42 | # def test_fail_stake_not_owner(staking_nft, parent_nft): 43 | 44 | # parent_nft.setApprovalForAll(staking_nft, True, {'from':accounts[2]}) 45 | # tokenId = 2 46 | # with reverts(): 47 | # staking_nft.stake(tokenId,{'from':accounts[3]}) 48 | 49 | 50 | 51 | 52 | 53 | # So the genesis contracts did not have any way to check how much was contributed 54 | # So instead we put in the amounts using setContributions() 55 | # The conftest.py should have the contributions set 56 | # We will eventually need to add a setContributions script, later 57 | 58 | 59 | # # Things the genesisis staking contract should check 60 | # Deposit genesis token into staking contract 61 | # Get the amount of staked ETH contributed for a user 62 | # Withdraw token from staking contract 63 | 64 | 65 | # Claim reward, not finished, but do it for now and we'll finish it --------------------------------------------------------------------------------