├── .gitignore ├── LICENSE ├── README.md ├── assets └── protocol-overview.png ├── contracts ├── core │ ├── Addresses.sol │ ├── Aggregator.sol │ ├── Collector.sol │ ├── Config.sol │ ├── ConfigMarket.sol │ ├── DEX.sol │ ├── Events.sol │ ├── Factory.sol │ ├── Governance.sol │ ├── Market.sol │ ├── Modifiers.sol │ ├── Set.sol │ ├── Storage.sol │ ├── Topic.sol │ ├── UseConfig.sol │ ├── Utils.sol │ ├── Viewer.sol │ └── Withdraw.sol ├── dev │ ├── Agent.sol │ ├── DOGVP.sol │ ├── IWPVP.sol │ ├── JPYCVP.sol │ ├── Token.sol │ └── WPVP.sol ├── interfaces │ ├── IAddresses.sol │ ├── ICollector.sol │ ├── IConfig.sol │ ├── IConfigMarket.sol │ ├── IEvents.sol │ ├── IFactory.sol │ ├── IModifiers.sol │ ├── INFT.sol │ ├── ISet.sol │ ├── IStorage.sol │ ├── ITopic.sol │ ├── IUtils.sol │ ├── IVP.sol │ ├── IViewer.sol │ └── IWithdraw.sol └── lib │ ├── EIP712Base.sol │ ├── EIP712MetaTransaction.sol │ ├── ERC20Freigeld.sol │ ├── ERC20Permit.sol │ ├── NFT.sol │ └── SafeMath.sol ├── hardhat.config.js ├── package.json ├── test ├── test.js └── utils.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | #Hardhat files 4 | cache 5 | artifacts 6 | scripts 7 | contracts/debug 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Warashibe Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HiÐΞ Protocol 2 | 3 | HiÐΞ Protocol is a DAO protocol for sustainable NFT rewards on Ethereum blockchain. 4 | 5 | ![](./assets/protocol-overview.png) 6 | 7 | ## Contract Addresses 8 | 9 | - WP (ERC20): [0xc8c0b377f9f164bdb008c0e9fa57a3d9da2dabcd](https://polygonscan.com/address/0xc8c0b377f9f164bdb008c0e9fa57a3d9da2dabcd) 10 | - HIDETOPICS (ERC721): [0x8e0A0c9B284ecA398963C6AD557894B8019D1349](https://polygonscan.com/address/0x8e0A0c9B284ecA398963C6AD557894B8019D1349) 11 | - HIDEARTICLES (ERC721): [0xa9B62Bee64872f61bEe28730C388db7B675A05b7](https://polygonscan.com/address/0xa9B62Bee64872f61bEe28730C388db7B675A05b7) 12 | - Storage: [0x079797b28e07f56f715e6b1b97A50c49661ee940](https://polygonscan.com/address/0x079797b28e07f56f715e6b1b97A50c49661ee940) 13 | - Set: [0x47B341c469dC85D1df72cEed9B8474F3cbc327Eb](https://polygonscan.com/address/0x47B341c469dC85D1df72cEed9B8474F3cbc327Eb) 14 | - Addresses: [0xE063EdF15AA4dc00e0f918cd586f92d55CdDb0c8](https://polygonscan.com/address/0xE063EdF15AA4dc00e0f918cd586f92d55CdDb0c8) 15 | - Events: [0x84E64d63516549cc4185555f8487206931aF11Ff](https://polygonscan.com/address/0x84E64d63516549cc4185555f8487206931aF11Ff) 16 | - Modifiers: [0xFbEfda40773aA8497f7fBcF5A8d8ec47Aa4f16dB](https://polygonscan.com/address/0xFbEfda40773aA8497f7fBcF5A8d8ec47Aa4f16dB) 17 | - Config: [0xc3C38734B4F7BedA719201C01A45a3Ad0b8CDf7a](https://polygonscan.com/address/0xc3C38734B4F7BedA719201C01A45a3Ad0b8CDf7a) 18 | - ConfigMarket: [0x60E4b100eeba67D5C96179794e419083822a0CB3](https://polygonscan.com/address/0x60E4b100eeba67D5C96179794e419083822a0CB3) 19 | - Collector: [0x90a5F6BCE49afDC3754508ADABf84Fe80678EdA7](https://polygonscan.com/address/0x90a5F6BCE49afDC3754508ADABf84Fe80678EdA7) 20 | - Governance: [0xA024df1a5bFaA8B0fE57109a1608643572e8c5B9](https://polygonscan.com/address/0xA024df1a5bFaA8B0fE57109a1608643572e8c5B9) 21 | - Factory: [0xD9B97Ba39FFBDc381efD5eCd5493Ed26F72F74A6](https://polygonscan.com/address/0xD9B97Ba39FFBDc381efD5eCd5493Ed26F72F74A6) 22 | - Utils: [0x99C9305b8243Ddcf72B2cd13b0aEb8338c7c1bA2](https://polygonscan.com/address/0x99C9305b8243Ddcf72B2cd13b0aEb8338c7c1bA2) 23 | - Viewer: [0xFA046A2EBE4Abf23C70F43827EFabFEE28F92F17](https://polygonscan.com/address/0xFA046A2EBE4Abf23C70F43827EFabFEE28F92F17) 24 | - Market: [0x56c34DAC84f6726083155ee8d4Da6c29Afa9198f](https://polygonscan.com/address/0x56c34DAC84f6726083155ee8d4Da6c29Afa9198f) 25 | - DEX: [0x231d667aE3c1e964B4Fa880f1d2214bec416aC90](https://polygonscan.com/address/0x231d667aE3c1e964B4Fa880f1d2214bec416aC90) 26 | - Withdraw: [0x437a01c9672a4bFD90185DAbDE35AD8f6feDFec4](https://polygonscan.com/address/0x437a01c9672a4bFD90185DAbDE35AD8f6feDFec4) 27 | - VP: [0x07c134d225B6bbf3D47d79CCffa30186617Db252](https://polygonscan.com/address/0x07c134d225B6bbf3D47d79CCffa30186617Db252) 28 | - JPYCVP: [0x208732f071d977C0a5b67dd83Fe7843da6f29Dd0](https://polygonscan.com/address/0x208732f071d977C0a5b67dd83Fe7843da6f29Dd0) 29 | - WPVP: [0xea01F364d9794fE3dA3045C3445A971007c5B680](https://polygonscan.com/address/0xea01F364d9794fE3dA3045C3445A971007c5B680) 30 | - Aggregator: [0x51d0d8b5695E8cd7108B0083D5ba90001D98e888](https://polygonscan.com/address/0x51d0d8b5695E8cd7108B0083D5ba90001D98e888) 31 | -------------------------------------------------------------------------------- /assets/protocol-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/warashibe/hide-protocol/9f2a070b6b3c9f0f2b98c434ba0e903bf34d8943/assets/protocol-overview.png -------------------------------------------------------------------------------- /contracts/core/Addresses.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "../interfaces/IStorage.sol"; 4 | import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; 5 | 6 | contract Addresses is Ownable { 7 | 8 | address private _store; 9 | 10 | /* constructor */ 11 | 12 | constructor(address _addr) { 13 | setStore(_addr); 14 | } 15 | 16 | /* storage adaptors */ 17 | 18 | function _getAddress(bytes memory _key) internal view returns(address){ 19 | return IStorage(_store).getAddress(keccak256(_key)); 20 | } 21 | 22 | function _setAddress(bytes memory _key, address _addr) internal{ 23 | return IStorage(_store).setAddress(keccak256(_key), _addr); 24 | } 25 | 26 | /* get contract addresses */ 27 | 28 | function store() public view returns(address) { 29 | return _store; 30 | } 31 | 32 | function set() public view returns(address) { 33 | return _getAddress(abi.encode("set")); 34 | } 35 | 36 | function config() public view returns(address) { 37 | return _getAddress(abi.encode("config")); 38 | } 39 | 40 | function config_market() public view returns(address) { 41 | return _getAddress(abi.encode("config_market")); 42 | } 43 | 44 | function governance() public view returns(address) { 45 | return _getAddress(abi.encode("governance")); 46 | } 47 | 48 | function events() public view returns(address) { 49 | return _getAddress(abi.encode("events")); 50 | } 51 | 52 | function market() public view returns(address) { 53 | return _getAddress(abi.encode("market")); 54 | } 55 | 56 | function withdraw() public view returns(address) { 57 | return _getAddress(abi.encode("withdraw")); 58 | } 59 | 60 | function collector() public view returns(address) { 61 | return _getAddress(abi.encode("collector")); 62 | } 63 | 64 | function factory() public view returns(address) { 65 | return _getAddress(abi.encode("factory")); 66 | } 67 | 68 | function dex() public view returns(address) { 69 | return _getAddress(abi.encode("dex")); 70 | } 71 | 72 | function topics() public view returns(address) { 73 | return _getAddress(abi.encode("topics")); 74 | } 75 | 76 | function utils() public view returns(address) { 77 | return _getAddress(abi.encode("utils")); 78 | } 79 | 80 | function addresses() public view returns(address) { 81 | return address(this); 82 | } 83 | 84 | function viewer() public view returns(address) { 85 | return _getAddress(abi.encode("viewer")); 86 | } 87 | 88 | function modifiers() public view returns(address) { 89 | return _getAddress(abi.encode("modifiers")); 90 | } 91 | 92 | /* set contract addresses */ 93 | 94 | function setConfig(address _addr) public onlyOwner { 95 | _setAddress(abi.encode("config"),_addr); 96 | } 97 | 98 | function setConfigMarket(address _addr) public onlyOwner { 99 | _setAddress(abi.encode("config_market"),_addr); 100 | } 101 | 102 | function setGovernance(address _addr) public onlyOwner { 103 | _setAddress(abi.encode("governance"),_addr); 104 | } 105 | 106 | function setTopics(address _addr) public onlyOwner { 107 | _setAddress(abi.encode("topics"),_addr); 108 | } 109 | 110 | function setMarket(address _addr) public onlyOwner { 111 | _setAddress(abi.encode("market"),_addr); 112 | } 113 | 114 | function setEvents(address _addr) public onlyOwner { 115 | _setAddress(abi.encode("events"),_addr); 116 | } 117 | 118 | function setWithdraw(address _addr) public onlyOwner { 119 | _setAddress(abi.encode("withdraw"),_addr); 120 | } 121 | 122 | function setCollector(address _addr) public onlyOwner { 123 | _setAddress(abi.encode("collector"),_addr); 124 | } 125 | 126 | function setFactory(address _addr) public onlyOwner { 127 | _setAddress(abi.encode("factory"),_addr); 128 | } 129 | 130 | function setDEX(address _addr) public onlyOwner { 131 | _setAddress(abi.encode("dex"),_addr); 132 | } 133 | 134 | function setUtils(address _addr) public onlyOwner { 135 | _setAddress(abi.encode("utils"),_addr); 136 | } 137 | 138 | function setStore(address _addr) public onlyOwner { 139 | _store = _addr; 140 | } 141 | 142 | function setSet(address _addr) public onlyOwner { 143 | _setAddress(abi.encode("set"),_addr); 144 | } 145 | 146 | function setViewer(address _addr) public onlyOwner { 147 | _setAddress(abi.encode("viewer"),_addr); 148 | } 149 | 150 | function setModifiers(address _addr) public onlyOwner { 151 | _setAddress(abi.encode("modifiers"),_addr); 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /contracts/core/Aggregator.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "./UseConfig.sol"; 5 | import "../interfaces/IViewer.sol"; 6 | import "../interfaces/IVP.sol"; 7 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 8 | import "../lib/NFT.sol"; 9 | 10 | contract Aggregator is UseConfig { 11 | constructor(address _addr) UseConfig(_addr){} 12 | 13 | function infoTopic(string memory _name) public view returns(uint topic, address[] memory pairs, address[] memory tokens, uint[] memory budgets){ 14 | topic = v().topic_indexes(_name); 15 | pairs = v().topic_pairs(topic); 16 | tokens = new address[](pairs.length); 17 | budgets = new uint[](pairs.length); 18 | for(uint i = 0; i < pairs.length; i++){ 19 | address token = v().pair_tokens(pairs[i]); 20 | tokens[i] = token; 21 | budgets[i] = IERC20(token).totalSupply() + v().claimable(pairs[i]); 22 | } 23 | } 24 | 25 | function infoVote(uint _poll, uint _amount, uint _topic, address _voter) public view returns(uint[4] memory vp ,uint[2] memory amounts, uint[2] memory budgets, uint[2] memory balances){ 26 | Poll memory p = v().polls(_poll); 27 | vp[0] = IVP(p.pool).getVP(_voter); 28 | vp[1] = IVP(p.pool).getTotalVP(); 29 | vp[2] = p.total_votes; 30 | vp[3] = v().poll_topic_votes(_poll, _topic); 31 | (uint mintable, uint converted) = v().getMintable(_poll, _amount, _topic); 32 | amounts[0] = mintable; 33 | amounts[1] = converted; 34 | budgets[0] = IERC20(v().getPair(_poll, _topic)).totalSupply() + v().claimable(v().getPair(_poll, _topic)); 35 | budgets[1] = budgets[0] + converted; 36 | balances[0] = IERC20(v().getPair(_poll, _topic)).balanceOf(_voter); 37 | balances[1] = balances[0] + mintable; 38 | } 39 | 40 | function infoUser(address _user, address[] memory _tokens) public view returns(uint[] memory balances, address[] memory pairs, address[] memory tokens, uint[] memory shares, uint[] memory kudos, uint[] memory topics){ 41 | pairs = v().user_pairs(_user); 42 | tokens = new address[](pairs.length); 43 | topics = new uint[](pairs.length); 44 | balances = new uint[](pairs.length); 45 | shares = new uint[](pairs.length); 46 | kudos = new uint[](pairs.length); 47 | for(uint i = 0; i < pairs.length; i++){ 48 | address token = v().pair_tokens(pairs[i]); 49 | tokens[i] = token; 50 | topics[i] = v().pair_topics(pairs[i]); 51 | balances[i] = IERC20(pairs[i]).balanceOf(_user); 52 | shares[i] = v().share_sqrt(pairs[i], _user); 53 | kudos[i] = v().kudos(pairs[i], _user); 54 | } 55 | } 56 | function getExistPairs(uint[] memory topics, address[] memory _tokens) internal view returns(address[] memory _pairs, uint[] memory _topics, address[] memory tar_tokens){ 57 | uint index = 0; 58 | _pairs = new address[](topics.length * _tokens.length); 59 | _topics = new uint[](topics.length * _tokens.length); 60 | tar_tokens = new address[](topics.length * _tokens.length); 61 | for(uint i2 = 0; i2 < topics.length; i2++){ 62 | for(uint i4 = 0; i4 < _tokens.length; i4++){ 63 | address pair = v().pairs(_tokens[i4], topics[i2]); 64 | if(pair != address(0)){ 65 | _pairs[index] = pair; 66 | _topics[index] = topics[i2]; 67 | tar_tokens[index] = _tokens[i4]; 68 | index++; 69 | } 70 | } 71 | } 72 | } 73 | 74 | function getVotableTopics(address _nft, uint _id, address _voter, uint[] memory topics, address[] memory _tokens) internal view returns(uint[] memory votableTopics, uint[] memory max_amounts){ 75 | uint i3 = 0; 76 | (address[] memory _pairs, uint[] memory _topics, ) = getExistPairs(topics, _tokens); 77 | votableTopics = new uint[](_pairs.length); 78 | max_amounts = new uint[](_pairs.length); 79 | for(uint i = 0; i < _pairs.length; i++){ 80 | if(_pairs[i] != address(0)){ 81 | uint balance = IERC20(_pairs[i]).balanceOf(_voter); 82 | if(balance > 0 && v().burn_limits(v().pair_tokens(_pairs[i])) - v().user_item_burn(msg.sender, _nft, _id, _pairs[i]) > 0 && IERC721(_nft).ownerOf(_id) != msg.sender){ 83 | votableTopics[i3] = _topics[i]; 84 | max_amounts[i3] = v().burn_limits(v().pair_tokens(_pairs[i])) - v().user_item_burn(msg.sender, _nft, _id, _pairs[i]); 85 | i3 += 1; 86 | } 87 | } 88 | } 89 | } 90 | 91 | function getVotablePairs(address _nft, uint _id, address _voter, uint[] memory topics, address[] memory _tokens) internal view returns(address[] memory tokens, address[] memory votable_pairs){ 92 | uint i3 = 0; 93 | (address[] memory _pairs, , address[] memory vtokens) = getExistPairs(topics, _tokens); 94 | tokens = new address[](_pairs.length); 95 | votable_pairs = new address[](_pairs.length); 96 | for(uint i = 0; i < _pairs.length; i++){ 97 | if(_pairs[i] != address(0)){ 98 | uint balance = IERC20(_pairs[i]).balanceOf(_voter); 99 | if(balance > 0 && v().burn_limits(v().pair_tokens(_pairs[i])) - v().user_item_burn(msg.sender, _nft, _id, _pairs[i]) > 0 && IERC721(_nft).ownerOf(_id) != msg.sender){ 100 | votable_pairs[i3] = _pairs[i]; 101 | tokens[i3] = vtokens[i]; 102 | i3 += 1; 103 | } 104 | } 105 | } 106 | } 107 | 108 | function infoItem(address _nft, uint _id, address _voter, address[] memory _tokens) public view returns(uint[] memory topics, uint[] memory votableTopics, uint[] memory max_amounts, address[] memory votable_pairs, address[] memory tokens){ 109 | uint[] memory _topics = v().item_topics(_nft, _id); 110 | bool existsFree = false; 111 | for(uint i = 0; i < _topics.length; i++){ 112 | if(_topics[i] == v().free_topic()){ 113 | existsFree = true; 114 | break; 115 | } 116 | } 117 | topics = new uint[](existsFree ? _topics.length : _topics.length + 1); 118 | for(uint i = 0; i < _topics.length; i++){ 119 | topics[i] = _topics[i]; 120 | } 121 | if(!existsFree){ 122 | topics[topics.length - 1] = v().free_topic(); 123 | } 124 | (votableTopics, max_amounts) = getVotableTopics(_nft, _id, _voter, topics, _tokens); 125 | (tokens, votable_pairs) = getVotablePairs(_nft, _id, _voter, topics, _tokens); 126 | } 127 | 128 | function infoDEX(address[] memory pairs, address _holder) public view returns(uint[] memory pools, uint[] memory shares, uint[] memory total_shares, uint[] memory max_mintable, uint[] memory per){ 129 | pools = new uint[](pairs.length); 130 | shares = new uint[](pairs.length); 131 | total_shares = new uint[](pairs.length); 132 | max_mintable = new uint[](pairs.length); 133 | per = new uint[](pairs.length); 134 | for(uint i = 0; i < pairs.length; i++){ 135 | pools[i] = v().getConvertible(pairs[i]); 136 | shares[i] = v().balanceOf(pairs[i], _holder); 137 | total_shares[i] = v().totalSupply(pairs[i]); 138 | max_mintable[i] = shares[i] == 0 ? 0 : v().getConvertibleAmount(pairs[i], shares[i], _holder); 139 | per[i] = max_mintable[i] == 0 ? 0 : max_mintable[i] * 10 ** 9 / shares[i]; 140 | } 141 | } 142 | 143 | function infoBudgets(address[] memory pairs) public view returns(uint[] memory budgets, uint[] memory topics, string[] memory topic_ids, address[] memory tokens){ 144 | budgets = new uint[](pairs.length); 145 | topics = new uint[](pairs.length); 146 | topic_ids = new string[](pairs.length); 147 | tokens = new address[](pairs.length); 148 | for(uint i = 0; i < pairs.length; i++){ 149 | budgets[i] = v().getConvertible(pairs[i]) + IERC20(pairs[i]).totalSupply(); 150 | topics[i] = v().pair_topics(pairs[i]); 151 | topic_ids[i] = v().topic_names(topics[i]); 152 | tokens[i] = v().pair_tokens(pairs[i]); 153 | } 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /contracts/core/Collector.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/access/AccessControl.sol"; 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 7 | 8 | contract Collector is Ownable, AccessControl { 9 | 10 | bytes32 public constant AGENT = keccak256("AGENT"); 11 | 12 | address public collector; 13 | address[] public tokens; 14 | uint[] public fees; 15 | 16 | constructor(address[] memory _tokens, uint[] memory _fees, address _collector) { 17 | tokens = _tokens; 18 | fees = _fees; 19 | collector = _collector; 20 | _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); 21 | } 22 | 23 | function setTokens(address[] memory _tokens, uint[] memory _fees) public onlyOwner { 24 | tokens = _tokens; 25 | fees = _fees; 26 | } 27 | 28 | function setCollector(address _collector) public onlyOwner { 29 | collector = _collector; 30 | } 31 | 32 | function addAgent(address _agent) public onlyOwner { 33 | grantRole(AGENT, _agent); 34 | } 35 | 36 | function removeAgent(address _agent) public onlyOwner { 37 | revokeRole(AGENT, _agent); 38 | } 39 | 40 | function collect(address sender) external onlyRole(AGENT) { 41 | bool paid = false; 42 | for(uint i = 0; i < tokens.length; i++){ 43 | if(IERC20(tokens[i]).balanceOf(sender) >= fees[i]){ 44 | IERC20(tokens[i]).transferFrom(sender, collector, fees[i]); 45 | paid = true; 46 | break; 47 | } 48 | } 49 | require(paid, "fee could not be paid"); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /contracts/core/Config.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; 4 | import "../interfaces/ITopic.sol"; 5 | import "../interfaces/IStorage.sol"; 6 | import "../interfaces/ISet.sol"; 7 | import "../interfaces/IVP.sol"; 8 | import "../interfaces/IUtils.sol"; 9 | import "../interfaces/IViewer.sol"; 10 | import "../interfaces/IModifiers.sol"; 11 | import "../interfaces/IAddresses.sol"; 12 | 13 | contract Config is Ownable { 14 | 15 | address private addr; 16 | 17 | /* constructor */ 18 | 19 | constructor(address _addr) { 20 | addr = _addr; 21 | } 22 | 23 | /* storage adaptors */ 24 | 25 | function _pushUintSet(bytes memory _key, uint _uint) internal{ 26 | return ISet(IAddresses(addr).set()).pushUintSet(keccak256(_key), _uint); 27 | } 28 | 29 | function _pushAddressSet(bytes memory _key, address _addr) internal{ 30 | return ISet(IAddresses(addr).set()).pushAddressSet(keccak256(_key), _addr); 31 | } 32 | 33 | function _setString(bytes memory _key, string memory _str) internal{ 34 | return IStorage(IAddresses(addr).store()).setString(keccak256(_key), _str); 35 | } 36 | 37 | function _setAddress(bytes memory _key, address _addr) internal{ 38 | return IStorage(IAddresses(addr).store()).setAddress(keccak256(_key), _addr); 39 | } 40 | 41 | function _setUint(bytes memory _key, uint _uint) internal{ 42 | return IStorage(IAddresses(addr).store()).setUint(keccak256(_key), _uint); 43 | } 44 | 45 | function _setBool(bytes memory _key, bool _bool) internal{ 46 | return IStorage(IAddresses(addr).store()).setBool(keccak256(_key), _bool); 47 | } 48 | 49 | function _setUintArray(bytes memory _key, uint[] memory _uints) internal{ 50 | return IStorage(IAddresses(addr).store()).setUintArray(keccak256(_key), _uints); 51 | } 52 | 53 | function _deleteUintArray(bytes memory _key) internal{ 54 | return IStorage(IAddresses(addr).store()).deleteUintArray(keccak256(_key)); 55 | } 56 | 57 | /* protocol parameters */ 58 | 59 | function setFreigeldRate(uint _numerator, uint _denominator) public onlyOwner { 60 | require(_numerator <= _denominator, "numerator must be less than or equal to denominator"); 61 | _setUint(abi.encode("freigeld_numerator"), _numerator); 62 | _setUint(abi.encode("freigeld_denominator"), _denominator); 63 | } 64 | 65 | function _setPollCount(uint _uint) internal { 66 | _setUint(abi.encode("poll_count"),_uint); 67 | } 68 | 69 | function setFreeTopic(uint _uint) external { 70 | IModifiers(IAddresses(addr).modifiers()).onlyFactory(msg.sender); 71 | return _setUint(abi.encode("free_topic"),_uint); 72 | } 73 | 74 | /* protocol state setters */ 75 | 76 | function pushTopicPairs(uint _uint, address _addr) external { 77 | IModifiers(IAddresses(addr).modifiers()).onlyGovernanceOrMarket(msg.sender); 78 | _pushAddressSet(abi.encode("topic_pairs", _uint), _addr); 79 | } 80 | 81 | function pushUserPairs(address _addr1, address _addr2) external { 82 | IModifiers(IAddresses(addr).modifiers()).onlyGovernanceOrMarket(msg.sender); 83 | _pushAddressSet(abi.encode("user_pairs", _addr1), _addr2); 84 | } 85 | 86 | function pushPollTopics(uint _uint1, uint _uint2) external { 87 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 88 | _pushUintSet(abi.encode("poll_topics", _uint1), _uint2); 89 | } 90 | 91 | function setPollTopicVotes(uint _uint1, uint _uint2, uint _uint3) external { 92 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 93 | _setUint(abi.encode("poll_topic_votes", _uint1, _uint2), _uint3); 94 | } 95 | 96 | function setPoolNames(address _addr, string memory _str) external { 97 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 98 | _setString(abi.encode("pool_names",_addr), _str); 99 | } 100 | 101 | function setPoolAddresses(string memory _str, address _addr) external { 102 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 103 | _setAddress(abi.encode("pool_addresses",_str), _addr); 104 | } 105 | 106 | function setTopicNames(uint _uint, string memory _str) external { 107 | IModifiers(IAddresses(addr).modifiers()).onlyFactory(msg.sender); 108 | _setString(abi.encode("topic_names",_uint), _str); 109 | } 110 | 111 | function setTopicIndexes(string memory _str, uint _uint) external { 112 | IModifiers(IAddresses(addr).modifiers()).onlyFactory(msg.sender); 113 | _setUint(abi.encode("topic_indexes",_str), _uint); 114 | } 115 | 116 | function setTokenVersion(address _addr, uint _uint) external { 117 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 118 | _setUint(abi.encode("token_version",_addr), _uint); 119 | } 120 | 121 | function setPairs(address _addr1, uint _uint, address _addr2) external { 122 | IModifiers(IAddresses(addr).modifiers()).onlyFactoryOrGovernance(msg.sender); 123 | _setAddress(abi.encode("pairs", _addr1, _uint), _addr2); 124 | _setAddress(abi.encode("pair_tokens", _addr2), _addr1); 125 | _setUint(abi.encode("pair_topics", _addr2), _uint); 126 | } 127 | 128 | function setClaimable(address _addr, uint _uint) external { 129 | IModifiers(IAddresses(addr).modifiers()).onlyGovernanceOrDEX(msg.sender); 130 | _setUint(abi.encode("claimable",_addr), _uint); 131 | } 132 | 133 | function setPolls(address _pool, address _token, uint _amount, uint _block, uint[] memory _topics) external returns (uint _count) { 134 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 135 | _count = IViewer(IAddresses(addr).viewer()).poll_count(); 136 | _setUint(abi.encode("polls", _count, "phase"), 1); 137 | _setUint(abi.encode("polls", _count, "id"), _count); 138 | _setAddress(abi.encode("polls", _count, "pool"), _pool); 139 | _setAddress(abi.encode("polls", _count, "token"), _token); 140 | _setUint(abi.encode("polls", _count, "amount"), _amount); 141 | _setUint(abi.encode("polls", _count, "block_until"), _block); 142 | _setUintArray(abi.encode("polls", _count, "topics"), _topics); 143 | _setPollCount(_count + 1); 144 | } 145 | 146 | function setPollTopics(uint _poll, uint[] memory _topics) external { 147 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 148 | _setUintArray(abi.encode("polls", _poll, "topics"), _topics); 149 | } 150 | 151 | function setPollsMinted(uint _poll, uint _uint) external { 152 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 153 | _setUint(abi.encode("polls", _poll, "minted"), _uint); 154 | } 155 | 156 | function setPollBlockUntil(uint _poll, uint _uint) external { 157 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 158 | _setUint(abi.encode("polls", _poll, "block_until"), _uint); 159 | } 160 | 161 | function setPollsTotalVotes(uint _poll, uint _uint) external { 162 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 163 | _setUint(abi.encode("polls", _poll, "total_votes"), _uint); 164 | } 165 | 166 | function setPollsMintable(uint _poll, uint _uint) external { 167 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 168 | _setUint(abi.encode("polls", _poll, "mintable"), _uint); 169 | } 170 | 171 | function setPollAmount(uint _poll, uint _uint) external { 172 | IModifiers(IAddresses(addr).modifiers()).onlyGovernanceOrWithdraw(msg.sender); 173 | _setUint(abi.encode("polls", _poll, "amount"), _uint); 174 | } 175 | 176 | function setPollsPhase(uint _poll, uint _uint) external { 177 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 178 | _setUint(abi.encode("polls", _poll, "phase"), _uint); 179 | } 180 | 181 | function setVotes(uint _uint1, address _addr, uint _uint2) external { 182 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 183 | _setUint(abi.encode("votes", _uint1, _addr), _uint2); 184 | } 185 | 186 | function setTopicVotes(uint _uint1, address _addr, uint _uint2, uint _uint3) external { 187 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 188 | _setUint(abi.encode("topic_votes", _uint1, _addr, _uint2), _uint3); 189 | } 190 | 191 | function setMinted(uint _uint1, address _addr, uint _uint2) external { 192 | IModifiers(IAddresses(addr).modifiers()).onlyGovernance(msg.sender); 193 | _setUint(abi.encode("minted", _uint1, _addr), _uint2); 194 | } 195 | 196 | } 197 | -------------------------------------------------------------------------------- /contracts/core/ConfigMarket.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; 4 | import "../interfaces/ITopic.sol"; 5 | import "../interfaces/IStorage.sol"; 6 | import "../interfaces/ISet.sol"; 7 | import "../interfaces/IVP.sol"; 8 | import "../interfaces/IUtils.sol"; 9 | import "../interfaces/IViewer.sol"; 10 | import "../interfaces/IAddresses.sol"; 11 | import "../interfaces/IModifiers.sol"; 12 | 13 | contract ConfigMarket is Ownable { 14 | 15 | address private addr; 16 | 17 | /* constructor */ 18 | 19 | constructor(address _addr) { 20 | addr = _addr; 21 | } 22 | 23 | /* storage adaptors */ 24 | 25 | function _pushUintSet(bytes memory _key, uint _uint) internal{ 26 | return ISet(IAddresses(addr).set()).pushUintSet(keccak256(_key), _uint); 27 | } 28 | 29 | function _pushAddressSet(bytes memory _key, address _addr) internal{ 30 | return ISet(IAddresses(addr).set()).pushAddressSet(keccak256(_key), _addr); 31 | } 32 | 33 | function _setString(bytes memory _key, string memory _str) internal{ 34 | return IStorage(IAddresses(addr).store()).setString(keccak256(_key), _str); 35 | } 36 | 37 | function _setAddress(bytes memory _key, address _addr) internal{ 38 | return IStorage(IAddresses(addr).store()).setAddress(keccak256(_key), _addr); 39 | } 40 | 41 | function _setUint(bytes memory _key, uint _uint) internal{ 42 | return IStorage(IAddresses(addr).store()).setUint(keccak256(_key), _uint); 43 | } 44 | 45 | function _setBool(bytes memory _key, bool _bool) internal{ 46 | return IStorage(IAddresses(addr).store()).setBool(keccak256(_key), _bool); 47 | } 48 | 49 | function _setUintArray(bytes memory _key, uint[] memory _uints) internal{ 50 | return IStorage(IAddresses(addr).store()).setUintArray(keccak256(_key), _uints); 51 | } 52 | 53 | function _deleteUintArray(bytes memory _key) internal{ 54 | return IStorage(IAddresses(addr).store()).deleteUintArray(keccak256(_key)); 55 | } 56 | 57 | /* protocol parameters */ 58 | 59 | function setLastBlock(address _addr, uint _uint) external { 60 | return _setUint(abi.encode("lastBlock", _addr), _uint); 61 | } 62 | 63 | function setLastBlocks(address _addr, address _addr2, uint _uint) external { 64 | return _setUint(abi.encode("lastBlocks", _addr, _addr2), _uint); 65 | } 66 | 67 | function setDilutionRate(uint _numerator, uint _denominator) public onlyOwner { 68 | require(_numerator <= _denominator, "numerator must be less than or equal to denominator"); 69 | _setUint(abi.encode("dilution_numerator"), _numerator); 70 | _setUint(abi.encode("dilution_denominator"), _denominator); 71 | } 72 | 73 | function setCreatorPercentage(uint _uint) public onlyOwner { 74 | require(_uint <= 10000, "creator_percentage must be less than or equal to 10000"); 75 | _setUint(abi.encode("creator_percentage"),_uint); 76 | } 77 | 78 | function setBurnLimits(address _addr, uint _uint) external onlyOwner{ 79 | _setUint(abi.encode("burn_limits",_addr), _uint); 80 | } 81 | 82 | /* protocol state setters */ 83 | 84 | function pushItemPairs(address _addr1, uint _uint, address _addr2) external { 85 | IModifiers(IAddresses(addr).modifiers()).onlyGovernanceOrMarket(msg.sender); 86 | _pushAddressSet(abi.encode("item_pairs", _addr1, _uint), _addr2); 87 | } 88 | 89 | function setItemTopics(address _addr, uint _uint, uint[] memory _uint_arr) external { 90 | IModifiers(IAddresses(addr).modifiers()).onlyMarket(msg.sender); 91 | _setUintArray(abi.encode("item_topics",_addr, _uint), _uint_arr); 92 | } 93 | 94 | function deleteItemTopics(address _addr, uint _uint) external { 95 | IModifiers(IAddresses(addr).modifiers()).onlyMarket(msg.sender); 96 | _deleteUintArray(abi.encode("item_topics",_addr, _uint)); 97 | } 98 | 99 | function setItems(address _addr, uint _uint, bool _bool) external { 100 | IModifiers(IAddresses(addr).modifiers()).onlyMarket(msg.sender); 101 | _setBool(abi.encode("items",_addr, _uint), _bool); 102 | } 103 | 104 | function setTotalShareSqrt(address _addr, uint _uint) external { 105 | IModifiers(IAddresses(addr).modifiers()).onlyDEXOrMarket(msg.sender); 106 | _setUint(abi.encode("total_share_sqrt",_addr), _uint); 107 | } 108 | 109 | function setTotalShare(address _addr, uint _uint) external { 110 | IModifiers(IAddresses(addr).modifiers()).onlyDEXOrMarket(msg.sender); 111 | _setUint(abi.encode("total_share",_addr), _uint); 112 | } 113 | 114 | function setGenesises(address _addr, uint _uint) external { 115 | IModifiers(IAddresses(addr).modifiers()).onlyDEXOrMarket(msg.sender); 116 | _setUint(abi.encode("genesises",_addr), _uint); 117 | } 118 | 119 | function setClaimed(address _addr, uint _uint) external { 120 | IModifiers(IAddresses(addr).modifiers()).onlyDEX(msg.sender); 121 | _setUint(abi.encode("claimed",_addr), _uint); 122 | } 123 | 124 | function setKudos(address _addr1, address _addr2, uint _uint) external { 125 | IModifiers(IAddresses(addr).modifiers()).onlyDEXOrMarket(msg.sender); 126 | _setUint(abi.encode("kudos",_addr1, _addr2), _uint); 127 | } 128 | 129 | function setTotalKudos(address _addr, uint _uint) external { 130 | IModifiers(IAddresses(addr).modifiers()).onlyDEXOrMarket(msg.sender); 131 | _setUint(abi.encode("total_kudos",_addr), _uint); 132 | } 133 | 134 | function setUserItemBurn(address _addr1, address _addr2, uint _uint1, address _addr3, uint _uint2) external{ 135 | IModifiers(IAddresses(addr).modifiers()).onlyMarket(msg.sender); 136 | _setUint(abi.encode("user_item_burn",_addr1, _addr2, _uint1, _addr3), _uint2); 137 | } 138 | 139 | function setShare(address _addr1, address _addr2, uint _uint) external { 140 | IModifiers(IAddresses(addr).modifiers()).onlyDEXOrMarket(msg.sender); 141 | _setUint(abi.encode("share",_addr1, _addr2), _uint); 142 | } 143 | 144 | function setShareSqrt(address _addr1, address _addr2, uint _uint) external { 145 | IModifiers(IAddresses(addr).modifiers()).onlyDEXOrMarket(msg.sender); 146 | _setUint(abi.encode("share_sqrt",_addr1, _addr2), _uint); 147 | } 148 | 149 | function setItemIndexes(string memory _str, address _addr, uint _uint) external { 150 | IModifiers(IAddresses(addr).modifiers()).onlyMarket(msg.sender); 151 | _setUint(abi.encode("item_indexes_id", _str), _uint); 152 | _setAddress(abi.encode("item_indexes_contract", _str), _addr); 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /contracts/core/DEX.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; 6 | import "../lib/EIP712MetaTransaction.sol"; 7 | import "./UseConfig.sol"; 8 | import "../interfaces/ITopic.sol"; 9 | import "../interfaces/ICollector.sol"; 10 | import "hardhat/console.sol"; 11 | contract DEX is Ownable, UseConfig, EIP712MetaTransaction { 12 | 13 | constructor(address _addr) UseConfig(_addr) EIP712MetaTransaction("DEX", "1"){} 14 | 15 | function convert (address _pair, uint _amount, string memory _ref) public { 16 | uint _supply = v().totalSupply(_pair); 17 | uint share = v().toShare(_pair, _amount); 18 | if(share > v().shareOf(_pair, msgSender())) { 19 | _amount = v().toAmount(_pair, v().shareOf(_pair, msgSender())); 20 | share = v().toShare(_pair, _amount); 21 | } 22 | require(_amount > 0, "amount cannot be zero"); 23 | ICollector(a().collector()).collect(msgSender()); 24 | uint mintable = v().getConvertibleAmount(_pair, _amount, msgSender()); 25 | 26 | ITopic(_pair).mint(msgSender(), mintable); 27 | m().setTotalShareSqrt(_pair, _supply - _amount); 28 | m().setTotalShare(_pair, v().total_share(_pair) - share); 29 | m().setShareSqrt(_pair, msgSender(), v().share_sqrt(_pair, msgSender()) - share); 30 | m().setLastBlocks(_pair, msgSender(), block.number); 31 | m().setLastBlock(_pair, block.number); 32 | if(v().claimable(_pair) >= mintable){ 33 | c().setClaimable(_pair, v().claimable(_pair) - mintable); 34 | }else{ 35 | m().setClaimed(_pair, ITopic(_pair).totalInterests() - (mintable - v().claimable(_pair))); 36 | c().setClaimable(_pair, 0); 37 | } 38 | e().convert(_pair, _amount, msgSender(), mintable, _ref); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /contracts/core/Events.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | import "../core/UseConfig.sol"; 7 | 8 | contract Events is Ownable, UseConfig, AccessControlEnumerable { 9 | 10 | bytes32 public constant EMITTER_ROLE = keccak256("EMITTER_ROLE"); 11 | 12 | event Vote(uint indexed poll, uint indexed topic, uint vp, address indexed voter, address token, uint minted, uint share, string ref); 13 | 14 | event Burn(address indexed nft, uint indexed id, address indexed burner, address owner, address token, uint reward, uint payback, string ref); 15 | 16 | event Convert(address indexed token, uint share, address holder, uint amount, string ref); 17 | 18 | event CreateTopic(address indexed owner, string name, string id, string ref); 19 | 20 | event AddItem(address indexed owner, address indexed nft, uint id, uint[] topics, string ref); 21 | 22 | event UpdateItem(address indexed owner, address indexed nft, uint id, uint[] topics, string ref); 23 | 24 | event RemoveItem(address indexed owner, address indexed nft, uint id, string ref); 25 | 26 | modifier onlyEmitter() { 27 | require(hasRole(EMITTER_ROLE,msg.sender), "only EMITTER can execute"); 28 | _; 29 | } 30 | 31 | constructor(address _addr) UseConfig(_addr) { 32 | _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); 33 | _setupRole(EMITTER_ROLE, _msgSender()); 34 | } 35 | 36 | function vote(uint _poll, uint _topic, uint _vp, address voter, address token, uint _minted, uint _share, string memory ref) external onlyEmitter { 37 | emit Vote(_poll, _topic, _vp, voter, token, _minted, _share, ref); 38 | } 39 | 40 | function burn(address nft, uint id, address from, address to, address token, uint reward, uint payback, string memory ref) external onlyEmitter { 41 | emit Burn(nft, id, from, to, token, reward, payback, ref); 42 | } 43 | 44 | function convert(address token, uint share, address holder, uint amount, string memory ref) external onlyEmitter { 45 | emit Convert(token, share, holder, amount, ref); 46 | } 47 | 48 | function createTopic(address owner, string memory name, string memory id, string memory ref) external onlyEmitter { 49 | emit CreateTopic(owner, name, id, ref); 50 | } 51 | 52 | function addItem(address owner, address nft, uint id, uint[] memory topics, string memory ref) external onlyEmitter { 53 | emit AddItem(owner, nft, id, topics, ref); 54 | } 55 | 56 | function updateItem(address owner, address nft, uint id, uint[] memory topics, string memory ref) external onlyEmitter { 57 | emit UpdateItem(owner, nft, id, topics, ref); 58 | } 59 | 60 | function removeItem(address owner, address nft, uint id, string memory ref) external onlyEmitter { 61 | emit RemoveItem(owner, nft, id, ref); 62 | } 63 | 64 | function addEmitter(address _emmiter) public onlyOwner { 65 | grantRole(EMITTER_ROLE, _emmiter); 66 | } 67 | 68 | function removeEmitter(address _emmiter) public onlyOwner { 69 | revokeRole(EMITTER_ROLE, _emmiter); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /contracts/core/Factory.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "./Topic.sol"; 4 | import "./UseConfig.sol"; 5 | import "../interfaces/INFT.sol"; 6 | import "../interfaces/ICollector.sol"; 7 | import "../lib/EIP712MetaTransaction.sol"; 8 | import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; 9 | 10 | contract Factory is Ownable, UseConfig, EIP712MetaTransaction { 11 | 12 | constructor(address _addr) UseConfig(_addr) EIP712MetaTransaction("Factory", "1") {} 13 | 14 | function _issue (string memory _name, string memory _sym, address _addr) internal returns (address _token){ 15 | Topic _topic = new Topic(_name, _sym, v().freigeld_numerator(), v().freigeld_denominator(), _addr); 16 | return address(_topic); 17 | } 18 | 19 | function issue (string memory _name, string memory _sym, address _addr) external returns (address _token){ 20 | mod().onlyGovernance(msgSender()); 21 | return _issue(_name, _sym, _addr); 22 | } 23 | 24 | function createFreeTopic (string memory _name, string memory _id, string memory _ref) public onlyOwner{ 25 | uint _topic = _createTopic(_name, _id, _ref); 26 | c().setFreeTopic(_topic); 27 | } 28 | 29 | function createTopic (string memory _name, string memory _id, string memory _ref) public returns (uint _index) { 30 | ICollector(a().collector()).collect(msgSender()); 31 | _index = _createTopic(_name, _id, _ref); 32 | } 33 | 34 | function _createTopic (string memory _name, string memory _id, string memory _ref) internal returns (uint _index) { 35 | require(v().topic_indexes(_name) == 0, "topic name is taken"); 36 | _index = INFT(a().topics()).mint(msgSender(), _id); 37 | c().setTopicNames(_index, _name); 38 | c().setTopicIndexes(_name, _index); 39 | e().createTopic(msgSender(), _name, _id, _ref); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /contracts/core/Governance.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | import "./UseConfig.sol"; 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; 7 | import "../lib/EIP712MetaTransaction.sol"; 8 | import "../interfaces/IVP.sol"; 9 | import "../interfaces/ICollector.sol"; 10 | import "../interfaces/ITopic.sol"; 11 | import "../interfaces/IFactory.sol"; 12 | 13 | contract Governance is Ownable, UseConfig, EIP712MetaTransaction { 14 | 15 | constructor(address _addr) UseConfig(_addr) EIP712MetaTransaction("Governance", "1") {} 16 | 17 | function addPool (address _pool, string memory _name) public { 18 | require(IVP(_pool).owner() == msgSender(), "only pool owner can execute"); 19 | require(bytes(v().pool_names(_pool)).length == 0, "pool is already registered"); 20 | require(v().pool_addresses(_name) == address(0), "pool name is taken"); 21 | ICollector(a().collector()).collect(msgSender()); 22 | c().setPoolNames(_pool,_name); 23 | c().setPoolAddresses(_name, _pool); 24 | } 25 | 26 | function updatePollTopics(uint _poll, uint[] memory _topics) public { 27 | mod().existsPoll(_poll); 28 | Poll memory p = v().polls(_poll); 29 | require(IVP(p.pool).owner() == msgSender(), "only pool owner can execute"); 30 | c().setPollTopics(_poll, _topics); 31 | 32 | } 33 | 34 | function setPoll (address _pool, address _token, uint _amount, uint _blocks, uint[] memory _topics) public { 35 | mod().existsPool(_pool); 36 | require(IVP(_pool).owner() == msgSender(), "only pool owner can execute"); 37 | IERC20Metadata(_token).transferFrom(msgSender(), a().withdraw(), _amount); 38 | uint _poll = c().setPolls(_pool, _token, _amount, block.number + _blocks, _topics); 39 | c().pushPollTopics(_poll, v().free_topic()); 40 | uint free_topic = v().free_topic(); 41 | if(v().getPair(_poll, free_topic) == address(0)){ 42 | string memory topic_name = v().topic_names(free_topic); 43 | address _pair_token = IFactory(a().factory()).issue(topic_name, topic_name, address(a())); 44 | c().setPairs(_token, free_topic, _pair_token); 45 | c().setTokenVersion(_pair_token, 2); 46 | } 47 | 48 | } 49 | 50 | function closePoll (uint _poll) public { 51 | mod().existsPoll(_poll); 52 | Poll memory p = v().polls(_poll); 53 | require(IVP(p.pool).owner() == msgSender(), "only pool owner can execute"); 54 | require(p.phase == 1, "poll already closed"); 55 | uint mintable = p.amount - p.minted; 56 | c().setPollsMintable(_poll, mintable); 57 | if(p.block_until > block.number){ 58 | c().setPollBlockUntil(_poll, block.number); 59 | } 60 | uint[] memory topics = v().poll_topics(_poll); 61 | uint minted = 0; 62 | for(uint i = 0; i < topics.length; i++){ 63 | uint _minted = mintable * v().poll_topic_votes(_poll, topics[i]) / p.total_votes; 64 | if(i == topics.length - 1){ 65 | _minted = mintable - minted; 66 | } 67 | address _pair = v().getPair(_poll, topics[i]); 68 | c().setClaimable(_pair, v().claimable(_pair) + _minted); 69 | minted += _minted; 70 | } 71 | c().setPollsMinted(_poll, p.amount); 72 | c().setPollsPhase(_poll, 2); 73 | } 74 | 75 | function _claim (uint _poll, uint _topic, uint _converted_amount, uint mintable, uint _amount, string memory _ref) internal { 76 | Poll memory _Poll = v().polls(_poll); 77 | c().setVotes(_poll, msgSender(), v().getVote(_poll, msgSender()) + _amount); 78 | c().setTopicVotes(_poll, msgSender(), _topic, v().getVote(_poll, msgSender()) + _amount); 79 | c().setPollsTotalVotes(_poll, _Poll.total_votes + _amount); 80 | IVP(_Poll.pool).vote(msgSender(), _amount); 81 | address _pair = v().getPair(_poll, _topic); 82 | ITopic(_pair).mint(msgSender(), mintable); 83 | c().setClaimable(_pair, v().claimable(_pair) + (_converted_amount - mintable)); 84 | c().pushUserPairs(msgSender(), _pair); 85 | c().pushTopicPairs(_topic, _pair); 86 | e().vote(_poll, _topic, _amount, msgSender(), _pair, mintable, _converted_amount - mintable, _ref); 87 | } 88 | 89 | function _setPair (address _token, uint _topic) internal { 90 | if(v().pairs(_token, _topic) == address(0)){ 91 | string memory name = u().concat(u().concat(IERC20Metadata(_token).name(),"/"), v().topic_names(_topic)); 92 | address _pair_token = IFactory(a().factory()).issue(name, name, address(a())); 93 | c().setPairs(_token, _topic, _pair_token); 94 | c().setTokenVersion(_pair_token, 2); 95 | } 96 | } 97 | 98 | function vote (uint _poll, uint _amount, uint _topic, string memory _ref) public { 99 | mod().existsPoll(_poll); 100 | mod().existsTopic(_topic); 101 | Poll memory p = v().polls(_poll); 102 | require(p.block_until >= block.number, "poll is over"); 103 | require(p.amount - p.minted > 0, "pool is empty"); 104 | require(v().getTopicVote(_poll, msgSender(), _topic) == 0, "already voted"); 105 | require(u().includes(p.topics, _topic), "topic not votable"); 106 | ICollector(a().collector()).collect(msgSender()); 107 | _setPair(p.token, _topic); 108 | (uint mintable, uint converted) = v().getMintable(_poll, _amount, _topic); 109 | c().setPollTopicVotes(_poll, _topic, v().poll_topic_votes(_poll, _topic) + _amount); 110 | c().pushPollTopics(_poll, _topic); 111 | c().setPollsMinted(_poll, p.minted + converted); 112 | _claim(_poll, _topic, converted, mintable, _amount, _ref); 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /contracts/core/Market.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "hardhat/console.sol"; 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | import "../lib/NFT.sol"; 6 | import "../interfaces/IWithdraw.sol"; 7 | import "../interfaces/ICollector.sol"; 8 | import "./UseConfig.sol"; 9 | import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; 10 | import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; 11 | import "../lib/EIP712MetaTransaction.sol"; 12 | 13 | contract Market is Ownable, UseConfig, EIP712MetaTransaction { 14 | address public nft; 15 | constructor(address _nft, address _addr) UseConfig(_addr) EIP712MetaTransaction("Market", "1") { 16 | nft = _nft; 17 | } 18 | 19 | function updateItem (address _nft, uint _id, uint[] memory _topics, string memory _ref) public { 20 | require(msgSender() == IERC721(_nft).ownerOf(_id), "item must be registered by owner"); 21 | require(v().items(_nft, _id) == true, "item not registered"); 22 | ICollector(a().collector()).collect(msgSender()); 23 | m().setItemTopics(_nft, _id, _topics); 24 | e().updateItem(msgSender(), _nft, _id, _topics, _ref); 25 | } 26 | 27 | function addItem (address _nft, uint _id, uint[] memory _topics, string memory _ref) public { 28 | require(msgSender() == IERC721(_nft).ownerOf(_id), "item must be registered by owner"); 29 | require(v().items(_nft, _id) == false, "item already registered"); 30 | m().setItemTopics(_nft, _id, _topics); 31 | m().setItems(_nft, _id, true); 32 | e().addItem(msgSender(), _nft, _id, _topics, _ref); 33 | } 34 | 35 | function removeItem (address _nft, uint _id, string memory _ref) public { 36 | require(msgSender() == IERC721(_nft).ownerOf(_id), "item must be registered by owner"); 37 | require(v().items(_nft, _id) == true, "item not registered"); 38 | ICollector(a().collector()).collect(msgSender()); 39 | m().setItems(_nft, _id, false); 40 | m().deleteItemTopics(_nft, _id); 41 | e().removeItem(msgSender(), _nft, _id, _ref); 42 | } 43 | 44 | function createItem (string memory _str, uint[] memory _topics, string memory _ref) public { 45 | (, uint _id) = v().item_indexes(_str); 46 | require(_id == 0, "item already registered"); 47 | ICollector(a().collector()).collect(msgSender()); 48 | uint id = NFT(nft).mint(msgSender(), _str); 49 | m().setItemIndexes(_str, nft, id); 50 | addItem(nft, id, _topics, _ref); 51 | } 52 | function _isBurnable(address _nft, uint _id, address _pair, uint _amount) internal view { 53 | require(v().items(_nft, _id), "item not registered"); 54 | require(msgSender() != IERC721(_nft).ownerOf(_id), "item owner cannot vote"); 55 | uint _topic = v().pair_topics(_pair); 56 | uint limit = v().burn_limits(v().pair_tokens(_pair)); 57 | uint burned = v().user_item_burn(msgSender(), _nft, _id, _pair); 58 | require(limit == 0 || _amount <= limit - burned, "amount is larger than limit"); 59 | bool existsTopic = v().free_topic() == _topic ? true : false; 60 | if(!existsTopic){ 61 | for(uint i = 0; i < v().item_topics(_nft, _id).length; i++){ 62 | if(v().item_topics(_nft, _id)[i] == _topic){ 63 | existsTopic = true; 64 | break; 65 | } 66 | } 67 | } 68 | require(existsTopic, "item does not have the topic"); 69 | } 70 | 71 | function burnFor (address _nft, uint _id, address _pair, uint _amount, string memory ref) public { 72 | _isBurnable(_nft, _id, _pair, _amount); 73 | ICollector(a().collector()).collect(msgSender()); 74 | address item_owner = NFT(_nft).ownerOf(_id); 75 | uint _reward = _amount * v().creator_percentage() / 10000; 76 | ERC20Burnable(_pair).burnFrom(msgSender(),_amount); 77 | IWithdraw(a().withdraw()).withdraw(item_owner, msgSender(), _amount, v().pair_tokens(_pair)); 78 | m().setTotalKudos(_pair, v().total_kudos(_pair) + _amount); 79 | addShare(_pair, _reward, item_owner); 80 | addShare(_pair, _amount - _reward, msgSender()); 81 | c().pushUserPairs(item_owner, _pair); 82 | c().pushUserPairs(msgSender(), _pair); 83 | m().pushItemPairs(_nft, _id, _pair); 84 | uint burned = v().user_item_burn(msgSender(), _nft, _id, _pair); 85 | m().setUserItemBurn(msgSender(), _nft, _id, _pair, burned + _amount); 86 | e().burn(_nft, _id, msgSender(), item_owner, _pair, _reward, _amount - _reward, ref); 87 | } 88 | 89 | function addShare(address _pair, uint _amount, address _holder) internal { 90 | uint _balance = v().balanceOf(_pair, _holder); 91 | uint _new_balance = u().sqrt(_balance * _balance + _amount); 92 | uint diff = _new_balance - _balance; 93 | uint share = v().toShare(_pair, diff); 94 | uint _supply = v().totalSupply(_pair); 95 | bool reset = _supply == 0 || share / _supply > 10 ** 15; 96 | if(reset) _supply = 0; 97 | if(reset) m().setGenesises(_pair, block.number); 98 | m().setTotalShare(_pair, reset ? share : v().total_share(_pair) + share); 99 | m().setTotalShareSqrt(_pair, _supply + diff); 100 | m().setShareSqrt(_pair, _holder, v().shareOf(_pair, _holder) + share); 101 | m().setLastBlocks(_pair, _holder, block.number); 102 | m().setLastBlock(_pair, block.number); 103 | m().setKudos(_pair, _holder, v().kudos(_pair, _holder) + _amount); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /contracts/core/Modifiers.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "../interfaces/IAddresses.sol"; 4 | import "../interfaces/IViewer.sol"; 5 | 6 | contract Modifiers { 7 | address private addr; 8 | /* constructor */ 9 | 10 | constructor(address _addr) { 11 | addr = _addr; 12 | } 13 | 14 | /* exists */ 15 | function existsPool (address _pool) external view { 16 | require(bytes(IViewer(IAddresses(addr).viewer()).pool_names(_pool)).length != 0, "pool does not exist"); 17 | } 18 | 19 | function existsPoll (uint _poll) external view { 20 | require(IViewer(IAddresses(addr).viewer()).polls(_poll).block_until != 0, "poll does not exist"); 21 | } 22 | 23 | function existsTopic (uint _topic) external view { 24 | require(bytes(IViewer(IAddresses(addr).viewer()).topic_names(_topic)).length != 0, "topic does not exist"); 25 | } 26 | 27 | 28 | /* modifiers */ 29 | 30 | function onlyDEXOrMarket(address _sender) public view { 31 | require(_sender == IAddresses(addr).dex() || _sender == IAddresses(addr).market(), "only DEX or market can execute"); 32 | } 33 | 34 | function onlyGovernanceOrDEX(address _sender) public view { 35 | require(_sender == IAddresses(addr).governance() || _sender == IAddresses(addr).dex(), "only governance or DEX can execute"); 36 | } 37 | 38 | function onlyGovernanceOrMarket(address _sender) public view { 39 | require(_sender == IAddresses(addr).governance() || _sender == IAddresses(addr).market(), "only governance or market can execute"); 40 | } 41 | 42 | function onlyGovernanceOrWithdraw(address _sender) public view { 43 | require(_sender == IAddresses(addr).governance() || _sender == IAddresses(addr).withdraw(), "only governance or withdraw can execute"); 44 | } 45 | 46 | function onlyGovernance (address _sender) public view { 47 | require(_sender == IAddresses(addr).governance(), "only governance can execute"); 48 | } 49 | 50 | function onlyFactory (address _sender) public view { 51 | require(_sender == IAddresses(addr).factory(), "only factory can execute"); 52 | } 53 | 54 | function onlyFactoryOrGovernance (address _sender) public view { 55 | require(_sender == IAddresses(addr).factory() || _sender == IAddresses(addr).governance(), "only factory or governance can execute"); 56 | } 57 | 58 | function onlyMarket (address _sender) public view { 59 | require(_sender == IAddresses(addr).market(), "only market can execute"); 60 | } 61 | 62 | function onlyDEX (address _sender) public view { 63 | require(_sender == IAddresses(addr).dex(), "only DEX can execute"); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /contracts/core/Set.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; 4 | import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; 5 | 6 | contract Set is AccessControlEnumerable, Ownable { 7 | bytes32 public constant EDITOR_ROLE = keccak256("EDITOR_ROLE"); 8 | 9 | mapping(bytes32 => uint[]) uIntSet; 10 | mapping(bytes32 => string[]) stringSet; 11 | mapping(bytes32 => address[]) addressSet; 12 | mapping(bytes32 => bytes[]) bytesSet; 13 | mapping(bytes32 => bool[]) boolSet; 14 | mapping(bytes32 => int[]) intSet; 15 | 16 | mapping(bytes32 => mapping(uint => uint)) uIntMap; 17 | mapping(bytes32 => mapping(string => uint)) stringMap; 18 | mapping(bytes32 => mapping(address => uint)) addressMap; 19 | mapping(bytes32 => mapping(bytes => uint)) bytesMap; 20 | mapping(bytes32 => mapping(bool => uint)) boolMap; 21 | mapping(bytes32 => mapping(int => uint)) intMap; 22 | 23 | constructor() { 24 | _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); 25 | _setupRole(EDITOR_ROLE, _msgSender()); 26 | } 27 | 28 | modifier onlyEditor() { 29 | require(hasRole(EDITOR_ROLE,msg.sender), "only EDITOR can execute"); 30 | _; 31 | } 32 | 33 | function addEditor(address _editor) public onlyOwner { 34 | grantRole(EDITOR_ROLE, _editor); 35 | } 36 | 37 | function removeEditor(address _editor) public onlyOwner { 38 | revokeRole(EDITOR_ROLE, _editor); 39 | } 40 | 41 | 42 | function getUintSet(bytes32 _key) external view returns(uint[] memory) { 43 | return uIntSet[_key]; 44 | } 45 | 46 | function getUintSetAt(bytes32 _key, uint _i) external view returns(uint) { 47 | return uIntSet[_key][_i]; 48 | } 49 | 50 | function pushUintSet(bytes32 _key, uint _uint) onlyEditor external { 51 | if(uIntMap[_key][_uint] == 0){ 52 | uIntSet[_key].push(_uint); 53 | uIntMap[_key][_uint] = uIntSet[_key].length; 54 | } 55 | } 56 | 57 | function removeUintSet(bytes32 _key, uint _uint) onlyEditor external { 58 | if(uIntMap[_key][_uint] != 0){ 59 | if(uIntMap[_key][_uint] != uIntSet[_key].length){ 60 | uIntSet[_key][uIntMap[_key][_uint] - 1] = uIntSet[_key][uIntSet[_key].length - 1]; 61 | } 62 | uIntSet[_key].pop(); 63 | } 64 | delete uIntMap[_key][_uint]; 65 | } 66 | 67 | 68 | function getStringSet(bytes32 _key) external view returns(string[] memory) { 69 | return stringSet[_key]; 70 | } 71 | 72 | function getStringSetAt(bytes32 _key, uint _i) external view returns(string memory) { 73 | return stringSet[_key][_i]; 74 | } 75 | 76 | function pushStringSet(bytes32 _key, string memory _string) onlyEditor external { 77 | if(stringMap[_key][_string] == 0){ 78 | stringSet[_key].push(_string); 79 | stringMap[_key][_string] = stringSet[_key].length; 80 | } 81 | } 82 | 83 | function removeStringSet(bytes32 _key, string memory _string) onlyEditor external { 84 | if(stringMap[_key][_string] != 0){ 85 | if(stringMap[_key][_string] != stringSet[_key].length){ 86 | stringSet[_key][stringMap[_key][_string] - 1] = stringSet[_key][stringSet[_key].length - 1]; 87 | } 88 | stringSet[_key].pop(); 89 | } 90 | } 91 | 92 | 93 | function getAddressSet(bytes32 _key) external view returns(address[] memory) { 94 | return addressSet[_key]; 95 | } 96 | 97 | function getAddressSetAt(bytes32 _key, uint _i) external view returns(address) { 98 | return addressSet[_key][_i]; 99 | } 100 | 101 | function pushAddressSet(bytes32 _key, address _val) onlyEditor external { 102 | if(addressMap[_key][_val] == 0){ 103 | addressSet[_key].push(_val); 104 | addressMap[_key][_val] = addressSet[_key].length; 105 | } 106 | } 107 | 108 | function removeAddressSet(bytes32 _key, address _val) onlyEditor external { 109 | if(addressMap[_key][_val] != 0){ 110 | if(addressMap[_key][_val] != addressSet[_key].length){ 111 | addressSet[_key][addressMap[_key][_val] - 1] = addressSet[_key][addressSet[_key].length - 1]; 112 | } 113 | addressSet[_key].pop(); 114 | } 115 | } 116 | 117 | 118 | function getBytesSet(bytes32 _key) external view returns(bytes[] memory) { 119 | return bytesSet[_key]; 120 | } 121 | 122 | function getBytesSetAt(bytes32 _key, uint _i) external view returns(bytes memory) { 123 | return bytesSet[_key][_i]; 124 | } 125 | 126 | function pushBytesSet(bytes32 _key, bytes memory _bytes) onlyEditor external { 127 | if(bytesMap[_key][_bytes] == 0){ 128 | bytesSet[_key].push(_bytes); 129 | bytesMap[_key][_bytes] = bytesSet[_key].length; 130 | } 131 | } 132 | 133 | function removeBytesSet(bytes32 _key, bytes memory _bytes) onlyEditor external { 134 | if(bytesMap[_key][_bytes] != 0){ 135 | if(bytesMap[_key][_bytes] != bytesSet[_key].length){ 136 | bytesSet[_key][bytesMap[_key][_bytes] - 1] = bytesSet[_key][bytesSet[_key].length - 1]; 137 | } 138 | bytesSet[_key].pop(); 139 | } 140 | } 141 | 142 | 143 | function getBoolSet(bytes32 _key) external view returns(bool[] memory) { 144 | return boolSet[_key]; 145 | } 146 | 147 | function getBoolSetAt(bytes32 _key, uint _i) external view returns(bool) { 148 | return boolSet[_key][_i]; 149 | } 150 | 151 | function pushBoolSet(bytes32 _key, bool _val) onlyEditor external { 152 | if(boolMap[_key][_val] == 0){ 153 | boolSet[_key].push(_val); 154 | boolMap[_key][_val] = boolSet[_key].length; 155 | } 156 | } 157 | 158 | function removeBoolSet(bytes32 _key, bool _val) onlyEditor external { 159 | if(boolMap[_key][_val] != 0){ 160 | if(boolMap[_key][_val] != boolSet[_key].length){ 161 | boolSet[_key][boolMap[_key][_val] - 1] = boolSet[_key][boolSet[_key].length - 1]; 162 | } 163 | boolSet[_key].pop(); 164 | } 165 | } 166 | 167 | function getIntSet(bytes32 _key) external view returns(int[] memory) { 168 | return intSet[_key]; 169 | } 170 | 171 | function getIntSetAt(bytes32 _key, uint _i) external view returns(int) { 172 | return intSet[_key][_i]; 173 | } 174 | 175 | function pushIntSet(bytes32 _key, int _val) onlyEditor external { 176 | if(intMap[_key][_val] == 0){ 177 | intSet[_key].push(_val); 178 | intMap[_key][_val] = intSet[_key].length; 179 | } 180 | } 181 | 182 | function removeIntSet(bytes32 _key, int _val) onlyEditor external { 183 | if(intMap[_key][_val] != 0){ 184 | if(intMap[_key][_val] != intSet[_key].length){ 185 | intSet[_key][intMap[_key][_val] - 1] = intSet[_key][intSet[_key].length - 1]; 186 | } 187 | intSet[_key].pop(); 188 | } 189 | } 190 | 191 | } 192 | -------------------------------------------------------------------------------- /contracts/core/Storage.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; 4 | import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; 5 | 6 | contract Storage is AccessControlEnumerable, Ownable { 7 | bytes32 public constant EDITOR_ROLE = keccak256("EDITOR_ROLE"); 8 | 9 | mapping(bytes32 => uint) uIntStorage; 10 | mapping(bytes32 => string) stringStorage; 11 | mapping(bytes32 => address) addressStorage; 12 | mapping(bytes32 => bytes) bytesStorage; 13 | mapping(bytes32 => bool) boolStorage; 14 | mapping(bytes32 => int) intStorage; 15 | 16 | mapping(bytes32 => uint[]) uIntArrayStorage; 17 | mapping(bytes32 => string[]) stringArrayStorage; 18 | mapping(bytes32 => address[]) addressArrayStorage; 19 | mapping(bytes32 => bytes[]) bytesArrayStorage; 20 | mapping(bytes32 => bool[]) boolArrayStorage; 21 | mapping(bytes32 => int[]) intArrayStorage; 22 | 23 | constructor() { 24 | _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); 25 | _setupRole(EDITOR_ROLE, _msgSender()); 26 | } 27 | 28 | modifier onlyEditor() { 29 | require(hasRole(EDITOR_ROLE,msg.sender), "only EDITOR can execute"); 30 | _; 31 | } 32 | 33 | function addEditor(address _editor) public onlyOwner { 34 | grantRole(EDITOR_ROLE, _editor); 35 | } 36 | 37 | function removeEditor(address _editor) public onlyOwner { 38 | revokeRole(EDITOR_ROLE, _editor); 39 | } 40 | 41 | function getUint(bytes32 _key) external view returns(uint) { 42 | return uIntStorage[_key]; 43 | } 44 | 45 | function getString(bytes32 _key) external view returns(string memory) { 46 | return stringStorage[_key]; 47 | } 48 | 49 | function getAddress(bytes32 _key) external view returns(address) { 50 | return addressStorage[_key]; 51 | } 52 | 53 | function getBytes(bytes32 _key) external view returns(bytes memory) { 54 | return bytesStorage[_key]; 55 | } 56 | 57 | function getBool(bytes32 _key) external view returns(bool) { 58 | return boolStorage[_key]; 59 | } 60 | 61 | function getInt(bytes32 _key) external view returns(int) { 62 | return intStorage[_key]; 63 | } 64 | 65 | function getUintArray(bytes32 _key) external view returns(uint[] memory) { 66 | return uIntArrayStorage[_key]; 67 | } 68 | 69 | function getStringArray(bytes32 _key) external view returns(string[] memory) { 70 | return stringArrayStorage[_key]; 71 | } 72 | 73 | function getAddressArray(bytes32 _key) external view returns(address[] memory) { 74 | return addressArrayStorage[_key]; 75 | } 76 | 77 | function getBytesArray(bytes32 _key) external view returns(bytes[] memory) { 78 | return bytesArrayStorage[_key]; 79 | } 80 | 81 | function getBoolArray(bytes32 _key) external view returns(bool[] memory) { 82 | return boolArrayStorage[_key]; 83 | } 84 | 85 | function getIntArray(bytes32 _key) external view returns(int[] memory) { 86 | return intArrayStorage[_key]; 87 | } 88 | 89 | function setUint(bytes32 _key, uint _value) onlyEditor external { 90 | uIntStorage[_key] = _value; 91 | } 92 | 93 | function setString(bytes32 _key, string memory _value) onlyEditor external { 94 | stringStorage[_key] = _value; 95 | } 96 | 97 | function setAddress(bytes32 _key, address _value) onlyEditor external { 98 | addressStorage[_key] = _value; 99 | } 100 | 101 | function setBytes(bytes32 _key, bytes memory _value) onlyEditor external { 102 | bytesStorage[_key] = _value; 103 | } 104 | 105 | function setBool(bytes32 _key, bool _value) onlyEditor external { 106 | boolStorage[_key] = _value; 107 | } 108 | 109 | function setInt(bytes32 _key, int _value) onlyEditor external { 110 | intStorage[_key] = _value; 111 | } 112 | 113 | function setUintArray(bytes32 _key, uint[] memory _value) onlyEditor external { 114 | uIntArrayStorage[_key] = _value; 115 | } 116 | 117 | function setStringArray(bytes32 _key, string[] memory _value) onlyEditor external { 118 | stringArrayStorage[_key] = _value; 119 | } 120 | 121 | function setAddressArray(bytes32 _key, address[] memory _value) onlyEditor external { 122 | addressArrayStorage[_key] = _value; 123 | } 124 | 125 | function setBytesArray(bytes32 _key, bytes[] memory _value) onlyEditor external { 126 | bytesArrayStorage[_key] = _value; 127 | } 128 | 129 | function setBoolArray(bytes32 _key, bool[] memory _value) onlyEditor external { 130 | boolArrayStorage[_key] = _value; 131 | } 132 | 133 | function setIntArray(bytes32 _key, int[] memory _value) onlyEditor external { 134 | intArrayStorage[_key] = _value; 135 | } 136 | 137 | 138 | function deleteUint(bytes32 _key) onlyEditor external { 139 | delete uIntStorage[_key]; 140 | } 141 | 142 | function deleteString(bytes32 _key) onlyEditor external { 143 | delete stringStorage[_key]; 144 | } 145 | 146 | function deleteAddress(bytes32 _key) onlyEditor external { 147 | delete addressStorage[_key]; 148 | } 149 | 150 | function deleteBytes(bytes32 _key) onlyEditor external { 151 | delete bytesStorage[_key]; 152 | } 153 | 154 | function deleteBool(bytes32 _key) onlyEditor external { 155 | delete boolStorage[_key]; 156 | } 157 | 158 | function deleteInt(bytes32 _key) onlyEditor external { 159 | delete intStorage[_key]; 160 | } 161 | function deleteUintArray(bytes32 _key) onlyEditor external { 162 | delete uIntArrayStorage[_key]; 163 | } 164 | 165 | function deleteStringArray(bytes32 _key) onlyEditor external { 166 | delete stringArrayStorage[_key]; 167 | } 168 | 169 | function deleteAddressArray(bytes32 _key) onlyEditor external { 170 | delete addressArrayStorage[_key]; 171 | } 172 | 173 | function deleteBytesArray(bytes32 _key) onlyEditor external { 174 | delete bytesArrayStorage[_key]; 175 | } 176 | 177 | function deleteBoolArray(bytes32 _key) onlyEditor external { 178 | delete boolArrayStorage[_key]; 179 | } 180 | 181 | function deleteIntArray(bytes32 _key) onlyEditor external { 182 | delete intArrayStorage[_key]; 183 | } 184 | 185 | } 186 | -------------------------------------------------------------------------------- /contracts/core/Topic.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | import "../lib/ERC20Permit.sol"; 6 | import "./UseConfig.sol"; 7 | 8 | contract Topic is Ownable, ERC20Permit, UseConfig { 9 | 10 | constructor(string memory _name, string memory _sym, uint _numerator, uint _denominator, address _addr) ERC20Freigeld(_name, _sym) ERC20Permit(_name) UseConfig(_addr) { 11 | _setRate(_numerator, _denominator); 12 | } 13 | 14 | function setRate (uint256 _numerator, uint256 _denominator) external { 15 | mod().onlyGovernance(msg.sender); 16 | _setRate(_numerator, _denominator); 17 | } 18 | 19 | function mint (address _to, uint _amount) external { 20 | mod().onlyGovernanceOrDEX(msg.sender); 21 | _mint(_to, _amount); 22 | } 23 | 24 | function burn(uint256 amount) public virtual { 25 | _burn(_msgSender(), amount); 26 | } 27 | 28 | function burnFrom(address account, uint256 amount) public virtual { 29 | uint256 currentAllowance = allowance(account, _msgSender()); 30 | require(currentAllowance >= amount, "ERC20: burn amount exceeds allowance"); 31 | _approve(account, _msgSender(), currentAllowance - amount); 32 | _burn(account, amount); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /contracts/core/UseConfig.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "../interfaces/IConfig.sol"; 5 | import "../interfaces/IConfigMarket.sol"; 6 | import "../interfaces/IUtils.sol"; 7 | import "../interfaces/IViewer.sol"; 8 | import "../interfaces/IAddresses.sol"; 9 | import "../interfaces/IEvents.sol"; 10 | import "../interfaces/IModifiers.sol"; 11 | import "@openzeppelin/contracts/access/Ownable.sol"; 12 | 13 | contract UseConfig is Ownable { 14 | address private _addresses; 15 | 16 | constructor(address _addr) { 17 | _addresses = _addr; 18 | } 19 | 20 | function c() internal view returns (IConfig) { 21 | return IConfig(IAddresses(_addresses).config()); 22 | } 23 | 24 | function m() internal view returns (IConfigMarket) { 25 | return IConfigMarket(IAddresses(_addresses).config_market()); 26 | } 27 | 28 | function mod() internal view returns (IModifiers) { 29 | return IModifiers(IAddresses(_addresses).modifiers()); 30 | } 31 | 32 | function v() internal view returns (IViewer) { 33 | return IViewer(IAddresses(_addresses).viewer()); 34 | } 35 | 36 | function u() internal view returns (IUtils) { 37 | return IUtils(IAddresses(_addresses).utils()); 38 | } 39 | 40 | function a() internal view returns (IAddresses) { 41 | return IAddresses(_addresses); 42 | } 43 | 44 | function e() internal view returns (IEvents) { 45 | return IEvents(IAddresses(_addresses).events()); 46 | } 47 | 48 | function addresses() external view returns (address) { 49 | return _addresses; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /contracts/core/Utils.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract Utils { 5 | 6 | /* constructor */ 7 | 8 | constructor() {} 9 | 10 | /* pure utils */ 11 | 12 | function concat( string memory a, string memory b) public pure returns(string memory) { 13 | return string(abi.encodePacked(a, b)); 14 | } 15 | 16 | function includes (uint[] memory _arr, uint _item) external pure returns(bool _included){ 17 | if(_arr.length == 0){ 18 | _included = true; 19 | }else{ 20 | for(uint i = 0;i<_arr.length;i++){ 21 | if(_arr[i] == _item){ 22 | _included = true; 23 | break; 24 | } 25 | } 26 | } 27 | } 28 | 29 | function sqrt(uint x) public pure returns (uint){ 30 | uint n = x / 2; 31 | uint lstX = 0; 32 | while (n != lstX){ 33 | lstX = n; 34 | n = (n + x/n) / 2; 35 | } 36 | return uint(n); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /contracts/core/Viewer.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "../interfaces/ITopic.sol"; 4 | import "../interfaces/IStorage.sol"; 5 | import "../interfaces/ISet.sol"; 6 | import "../interfaces/IVP.sol"; 7 | import "../interfaces/IUtils.sol"; 8 | import "../interfaces/IAddresses.sol"; 9 | import "../interfaces/IModifiers.sol"; 10 | import "hardhat/console.sol"; 11 | 12 | struct Poll { 13 | uint id; 14 | address pool; 15 | address token; 16 | uint block_until; 17 | uint amount; 18 | uint minted; 19 | uint total_votes; 20 | uint mintable; 21 | uint phase; 22 | uint [] topics; 23 | } 24 | 25 | contract Viewer { 26 | address private addr; 27 | /* constructor */ 28 | 29 | constructor(address _addr) { 30 | addr = _addr; 31 | } 32 | 33 | /* pure utils */ 34 | 35 | function sqrt(uint x) internal view returns (uint){ 36 | return IUtils(IAddresses(addr).utils()).sqrt(x); 37 | } 38 | 39 | /* storage adaptors */ 40 | 41 | function _getString(bytes memory _key) internal view returns(string memory){ 42 | return IStorage(IAddresses(addr).store()).getString(keccak256(_key)); 43 | } 44 | 45 | function _getAddress(bytes memory _key) internal view returns(address){ 46 | return IStorage(IAddresses(addr).store()).getAddress(keccak256(_key)); 47 | } 48 | 49 | function _getUint(bytes memory _key) internal view returns(uint){ 50 | return IStorage(IAddresses(addr).store()).getUint(keccak256(_key)); 51 | } 52 | 53 | function _getUintSet(bytes memory _key) internal view returns(uint[] memory){ 54 | return ISet(IAddresses(addr).set()).getUintSet(keccak256(_key)); 55 | } 56 | 57 | function _getAddressSet(bytes memory _key) internal view returns(address[] memory){ 58 | return ISet(IAddresses(addr).set()).getAddressSet(keccak256(_key)); 59 | } 60 | 61 | function _getBool(bytes memory _key) internal view returns(bool){ 62 | return IStorage(IAddresses(addr).store()).getBool(keccak256(_key)); 63 | } 64 | 65 | function _getUintArray(bytes memory _key) internal view returns(uint[] memory){ 66 | return IStorage(IAddresses(addr).store()).getUintArray(keccak256(_key)); 67 | } 68 | 69 | /* protocol parameters */ 70 | 71 | function totalSupply(address pair) public view returns (uint256 _supply) { 72 | uint256 minus = dilution_denominator() == 0 ? 0 : total_share_sqrt(pair) * (block.number - lastBlock(pair)) * dilution_numerator() / dilution_denominator(); 73 | _supply = total_share_sqrt(pair) > minus ? total_share_sqrt(pair) - minus : 0; 74 | } 75 | 76 | function balanceOf(address pair, address account) public view returns (uint _balance) { 77 | _balance = total_share(pair) == 0 ? 0 : totalSupply(pair) * shareOf(pair, account) / total_share(pair); 78 | } 79 | 80 | function burn_limits(address _addr) public view returns(uint) { 81 | return _getUint(abi.encode("burn_limits", _addr)); 82 | } 83 | 84 | function lastBlock(address _addr) public view returns(uint) { 85 | return _getUint(abi.encode("lastBlock", _addr)); 86 | } 87 | 88 | function lastBlocks(address _addr, address _addr2) public view returns(uint) { 89 | return _getUint(abi.encode("lastBlocks", _addr, _addr2)); 90 | } 91 | 92 | function user_pairs(address _addr) public view returns(address[] memory) { 93 | return _getAddressSet(abi.encode("user_pairs", _addr)); 94 | } 95 | 96 | function topic_pairs(uint _uint) public view returns(address[] memory) { 97 | return _getAddressSet(abi.encode("topic_pairs", _uint)); 98 | } 99 | 100 | function item_pairs(address _addr, uint _uint) public view returns(address[] memory) { 101 | return _getAddressSet(abi.encode("item_pairs", _addr, _uint)); 102 | } 103 | 104 | function poll_topics(uint _uint) public view returns(uint[] memory) { 105 | return _getUintSet(abi.encode("poll_topics", _uint)); 106 | } 107 | 108 | function poll_topic_votes(uint _uint, uint _topic) public view returns(uint) { 109 | return _getUint(abi.encode("poll_topic_votes", _uint, _topic)); 110 | } 111 | 112 | function item_topics(address _addr, uint _uint) public view returns(uint[] memory) { 113 | return _getUintArray(abi.encode("item_topics", _addr, _uint)); 114 | } 115 | 116 | function items(address _addr, uint _uint) public view returns(bool) { 117 | return _getBool(abi.encode("items", _addr, _uint)); 118 | } 119 | 120 | function freigeld_numerator () public view returns (uint){ 121 | return _getUint(abi.encode("freigeld_numerator")); 122 | } 123 | 124 | function freigeld_denominator () public view returns (uint){ 125 | return _getUint(abi.encode("freigeld_denominator")); 126 | } 127 | 128 | function dilution_numerator () public view returns (uint){ 129 | return _getUint(abi.encode("dilution_numerator")); 130 | } 131 | 132 | function dilution_denominator () public view returns (uint){ 133 | return _getUint(abi.encode("dilution_denominator")); 134 | } 135 | 136 | function creator_percentage () public view returns (uint){ 137 | return _getUint(abi.encode("creator_percentage")); 138 | } 139 | 140 | function poll_count () public view returns (uint){ 141 | return _getUint(abi.encode("poll_count")); 142 | } 143 | 144 | function free_topic () public view returns (uint){ 145 | return _getUint(abi.encode("free_topic")); 146 | } 147 | 148 | /* protocol state getters */ 149 | 150 | function polls(uint _uint) public view returns(Poll memory){ 151 | return Poll({ 152 | phase:_getUint(abi.encode("polls", _uint, "phase")), 153 | id: _getUint(abi.encode("polls", _uint, "id")), 154 | pool: _getAddress(abi.encode("polls", _uint, "pool")), 155 | amount: _getUint(abi.encode("polls", _uint, "amount")), 156 | block_until: _getUint(abi.encode("polls", _uint, "block_until")), 157 | total_votes: _getUint(abi.encode("polls", _uint, "total_votes")), 158 | mintable: _getUint(abi.encode("polls", _uint, "mintable")), 159 | minted: _getUint(abi.encode("polls", _uint, "minted")), 160 | topics: _getUintArray(abi.encode("polls", _uint, "topics")), 161 | token: _getAddress(abi.encode("polls", _uint, "token")) 162 | }); 163 | } 164 | 165 | function pool_names(address _addr) public view returns(string memory){ 166 | return _getString(abi.encode("pool_names",_addr)); 167 | } 168 | 169 | function pool_addresses(string memory _str) public view returns(address){ 170 | return _getAddress(abi.encode("pool_addresses",_str)); 171 | } 172 | 173 | function topic_names(uint _uint) public view returns(string memory){ 174 | return _getString(abi.encode("topic_names",_uint)); 175 | } 176 | 177 | function topic_indexes(string memory _str) public view returns(uint){ 178 | return _getUint(abi.encode("topic_indexes",_str)); 179 | } 180 | 181 | function item_indexes(string memory _str) public view returns(address nft, uint id){ 182 | id =_getUint(abi.encode("item_indexes_id",_str)); 183 | nft = _getAddress(abi.encode("item_indexes_contract",_str)); 184 | } 185 | 186 | 187 | function user_item_burn(address _addr1, address _addr2, uint _uint1, address _addr3) public view returns(uint){ 188 | return _getUint(abi.encode("user_item_burn", _addr1, _addr2, _uint1, _addr3)); 189 | } 190 | 191 | function pairs(address _addr, uint _uint) public view returns(address){ 192 | return _getAddress(abi.encode("pairs",_addr, _uint)); 193 | } 194 | 195 | function pair_tokens(address _addr) public view returns(address){ 196 | return _getAddress(abi.encode("pair_tokens",_addr)); 197 | } 198 | 199 | function pair_topics(address _addr) public view returns(uint){ 200 | return _getUint(abi.encode("pair_topics",_addr)); 201 | } 202 | 203 | function kudos(address _addr1, address _addr2) public view returns(uint){ 204 | return _getUint(abi.encode("kudos",_addr1, _addr2)); 205 | } 206 | 207 | function total_kudos(address _addr) public view returns(uint){ 208 | return _getUint(abi.encode("total_kudos",_addr)); 209 | } 210 | 211 | function total_share_sqrt(address _addr) public view returns(uint){ 212 | return _getUint(abi.encode("total_share_sqrt",_addr)); 213 | } 214 | 215 | function total_share(address _addr) public view returns(uint){ 216 | return _getUint(abi.encode("total_share",_addr)); 217 | } 218 | 219 | function token_version(address _addr) public view returns(uint){ 220 | return _getUint(abi.encode("token_version",_addr)); 221 | } 222 | 223 | function genesises(address _addr) public view returns(uint){ 224 | return _getUint(abi.encode("genesises",_addr)); 225 | } 226 | 227 | function claimable(address _addr) public view returns(uint){ 228 | return _getUint(abi.encode("claimable",_addr)); 229 | } 230 | 231 | function claimed(address _addr) public view returns(uint){ 232 | return _getUint(abi.encode("claimed",_addr)); 233 | } 234 | 235 | function share(address _addr1, address _addr2) public view returns(uint){ 236 | return _getUint(abi.encode("share",_addr1, _addr2)); 237 | } 238 | 239 | function share_sqrt(address _addr1, address _addr2) public view returns(uint){ 240 | return _getUint(abi.encode("share_sqrt",_addr1, _addr2)); 241 | } 242 | 243 | function votes(uint _uint, address _addr) public view returns(uint){ 244 | return _getUint(abi.encode("votes",_uint, _addr)); 245 | } 246 | 247 | function topic_votes(uint _uint1, address _addr, uint _uint2) public view returns(uint){ 248 | return _getUint(abi.encode("topic_votes",_uint1, _addr, _uint2)); 249 | } 250 | 251 | function minted(uint _uint, address _addr) public view returns(uint){ 252 | return _getUint(abi.encode("minted",_uint, _addr)); 253 | } 254 | 255 | 256 | /* state aggrigators */ 257 | 258 | function getConvertibleAmount(address _pair, uint _amount, address _holder) public view returns(uint mintable){ 259 | uint _share_sqrt = balanceOf(_pair, _holder); 260 | if(_amount > _share_sqrt){ 261 | mintable = 0; 262 | }else{ 263 | uint total_sqrt = totalSupply(_pair); 264 | uint claimable_amount = getConvertible(_pair); 265 | mintable = claimable_amount * _amount / total_sqrt; 266 | } 267 | } 268 | 269 | function getAvailable (uint _poll) public view returns (uint available){ 270 | Poll memory _Poll = polls(_poll); 271 | available = _Poll.amount - _Poll.minted; 272 | } 273 | 274 | function getMintable (uint _poll, uint _amount, uint _topic) public view returns (uint mintable, uint converted){ 275 | Poll memory p = polls(_poll); 276 | converted = getAvailable(_poll) * _amount / IVP(p.pool).getTotalVP(); 277 | uint sqrt_amount = sqrt(converted); 278 | uint sqrt_share = total_share_sqrt(getPair(_poll, _topic)); 279 | mintable = converted * sqrt_amount / (sqrt_amount + sqrt_share); 280 | } 281 | 282 | function getVote(uint _uint, address _addr) public view returns (uint) { 283 | return votes(_uint, _addr); 284 | } 285 | 286 | function getTopicVote(uint _uint1, address _addr, uint _uint2) public view returns (uint) { 287 | return topic_votes(_uint1, _addr, _uint2); 288 | } 289 | function getPair(uint _poll, uint _topic) public view returns (address _token) { 290 | _token = pairs(polls(_poll).token, _topic); 291 | } 292 | function getPool (string memory _name) public view returns (address _addr) { 293 | require(pool_addresses(_name) != address(0), "pool does not exist"); 294 | _addr = pool_addresses(_name); 295 | } 296 | 297 | function getConvertible (address _pair) public view returns (uint _amount){ 298 | if(token_version(_pair) == 2){ 299 | _amount = ITopic(_pair).totalInterests() + claimable(_pair) - claimed(_pair); 300 | }else if(claimable(_pair) < claimed(_pair)) { 301 | _amount = 0; 302 | } else { 303 | _amount = claimable(_pair) - claimed(_pair); 304 | } 305 | } 306 | 307 | function toShare(address _pair, uint256 amount) public view returns (uint256 _share) { 308 | _share = totalSupply(_pair) == 0 ? amount : amount * total_share(_pair) / totalSupply(_pair); 309 | } 310 | 311 | function toAmount(address _pair, uint256 _share) public view returns (uint256 _amount) { 312 | _amount = total_share(_pair) == 0 ? 0 : _share * totalSupply(_pair) / total_share(_pair); 313 | } 314 | 315 | function shareOf(address _pair, address account) public view returns (uint256 _share) { 316 | _share = lastBlocks(_pair, account) < genesises(_pair) ? 0 : share_sqrt(_pair, account); 317 | } 318 | 319 | } 320 | -------------------------------------------------------------------------------- /contracts/core/Withdraw.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import "../core/UseConfig.sol"; 7 | import "../interfaces/IVP.sol"; 8 | import "../lib/EIP712MetaTransaction.sol"; 9 | 10 | contract Withdraw is Ownable, UseConfig, EIP712MetaTransaction { 11 | 12 | constructor(address _addr) UseConfig(_addr) EIP712MetaTransaction("Withdraw", "1") {} 13 | 14 | function withdraw(address _to, address _voter, uint _amount, address _token) external { 15 | mod().onlyMarket(msg.sender); 16 | uint _reward = _amount * 80 / 100; 17 | IERC20(_token).transfer(_to, _reward); 18 | IERC20(_token).transfer(_voter, _amount - _reward); 19 | } 20 | 21 | function addFund (uint _poll, uint _amount) public { 22 | mod().existsPoll(_poll); 23 | Poll memory p = v().polls(_poll); 24 | require(p.phase == 1, "poll already closed"); 25 | IERC20(p.token).transferFrom(msgSender(), address(this), _amount); 26 | c().setPollAmount(_poll, p.amount + _amount); 27 | } 28 | 29 | function removeFund (uint _poll, uint _amount) public { 30 | mod().existsPoll(_poll); 31 | Poll memory p = v().polls(_poll); 32 | require(p.phase == 1, "poll already closed"); 33 | require(IVP(p.pool).owner() == msgSender(), "only pool owner can execute"); 34 | uint mintable = p.amount - p.minted; 35 | require(mintable >= _amount, "amount too large"); 36 | IERC20(p.token).transfer(msgSender(), _amount); 37 | c().setPollAmount(_poll, p.amount - _amount); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /contracts/dev/Agent.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "../core/Collector.sol"; 4 | 5 | contract Agent { 6 | address collector; 7 | constructor(address _collector) { 8 | collector = _collector; 9 | } 10 | 11 | function test() public { 12 | Collector(collector).collect(msg.sender); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /contracts/dev/DOGVP.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import "../core/UseConfig.sol"; 7 | import "../dev/IWPVP.sol"; 8 | 9 | contract DOGVP is Ownable, UseConfig { 10 | mapping(address => uint) public used_vp; 11 | uint public total_used_vp; 12 | address public vp; 13 | 14 | constructor(address _addr, address _addr2) UseConfig(_addr2) { 15 | vp = _addr; 16 | } 17 | 18 | function getTotalVP () public view returns (uint) { 19 | return IWPVP(vp).totalWP() - total_used_vp; 20 | } 21 | 22 | function getVP (address _voter) public view returns (uint) { 23 | return IWPVP(vp).paybacks(_voter) - used_vp[_voter]; 24 | } 25 | 26 | function vote (address _voter, uint _amount) external { 27 | mod().onlyGovernance(msg.sender); 28 | require(getVP(_voter) >= _amount, "VP not enough"); 29 | used_vp[_voter] += _amount; 30 | total_used_vp += _amount; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /contracts/dev/IWPVP.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface IWPVP { 5 | function totalWP() external view returns(uint); 6 | 7 | function earnings(address _addr) external view returns(uint); 8 | 9 | function paybacks(address _addr) external view returns(uint); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /contracts/dev/JPYCVP.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import "../core/UseConfig.sol"; 7 | import "../dev/IWPVP.sol"; 8 | 9 | contract JPYCVP is Ownable, UseConfig { 10 | mapping(address => uint) public used_vp; 11 | uint public total_used_vp; 12 | address public vp; 13 | 14 | constructor(address _addr, address _addr2) UseConfig(_addr2) { 15 | vp = _addr; 16 | } 17 | 18 | function getTotalVP () public view returns (uint) { 19 | return IWPVP(vp).totalWP() - total_used_vp; 20 | } 21 | 22 | function getVP (address _voter) public view returns (uint) { 23 | return IWPVP(vp).earnings(_voter) - used_vp[_voter]; 24 | } 25 | 26 | function vote (address _voter, uint _amount) external { 27 | mod().onlyGovernance(msg.sender); 28 | require(getVP(_voter) >= _amount, "VP not enough"); 29 | used_vp[_voter] += _amount; 30 | total_used_vp += _amount; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /contracts/dev/Token.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | 5 | contract Token is ERC20 { 6 | 7 | constructor(string memory _name, string memory _sym, uint _amount) ERC20(_name, _sym) { 8 | _mint(msg.sender, _amount); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /contracts/dev/WPVP.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; 4 | import "@openzeppelin/contracts/access/AccessControl.sol"; 5 | 6 | contract WPVP is AccessControl, Ownable { 7 | bytes32 public constant EDITOR_ROLE = keccak256("EDITOR_ROLE"); 8 | uint public totalWP; 9 | mapping(address => uint) public earnings; 10 | mapping(address => uint) public paybacks; 11 | 12 | constructor() public { 13 | _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); 14 | _setupRole(EDITOR_ROLE, _msgSender()); 15 | } 16 | 17 | modifier onlyEditor() { 18 | require(hasRole(EDITOR_ROLE,msg.sender), "only EDITOR can execute"); 19 | _; 20 | } 21 | 22 | function addEditor(address _editor) public onlyOwner { 23 | grantRole(EDITOR_ROLE, _editor); 24 | } 25 | 26 | function removeEditor(address _editor) public onlyOwner { 27 | revokeRole(EDITOR_ROLE, _editor); 28 | } 29 | 30 | function recordWP(address from, address to, uint amount) external onlyEditor{ 31 | earnings[from] += amount; 32 | paybacks[to] += amount; 33 | totalWP += amount; 34 | } 35 | 36 | function setTotalWP(uint amount) external onlyOwner { 37 | totalWP = amount; 38 | } 39 | 40 | function bulkRecordWP(address[] memory from, address[] memory to, uint[] memory _earnings, uint[] memory _paybacks) public onlyOwner { 41 | require(from.length == _earnings.length && to.length == _paybacks.length, "array lengths must be the same"); 42 | for(uint i = 0;i < from.length;i++){ 43 | earnings[from[i]] = _earnings[i]; 44 | } 45 | for(uint i = 0;i < to.length;i++){ 46 | paybacks[to[i]] = _paybacks[i]; 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /contracts/interfaces/IAddresses.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface IAddresses { 5 | 6 | /* get contract addresses */ 7 | 8 | function config() external view returns(address); 9 | 10 | function config_market() external view returns(address); 11 | 12 | function governance() external view returns(address); 13 | 14 | function market() external view returns(address); 15 | 16 | function events() external view returns(address); 17 | 18 | function withdraw() external view returns(address); 19 | 20 | function collector() external view returns(address); 21 | 22 | function factory() external view returns(address); 23 | 24 | function dex() external view returns(address); 25 | 26 | function topics() external view returns(address); 27 | 28 | function utils() external view returns(address); 29 | 30 | function addresses() external view returns(address); 31 | 32 | function store() external view returns(address); 33 | 34 | function set() external view returns(address); 35 | 36 | function viewer() external view returns(address); 37 | 38 | function modifiers() external view returns(address); 39 | 40 | /* set contract addresses */ 41 | 42 | function setConfig(address _addr) external; 43 | 44 | function setConfigMarket(address _addr) external; 45 | 46 | function setGovernance(address _addr) external; 47 | 48 | function setSet(address _addr) external; 49 | 50 | function setEvents(address _addr) external; 51 | 52 | function setTopics(address _addr) external; 53 | 54 | function setMarket(address _addr) external; 55 | 56 | function setWithdraw(address _addr) external; 57 | 58 | function setCollector(address _addr) external; 59 | 60 | function setFactory(address _addr) external; 61 | 62 | function setDEX(address _addr) external; 63 | 64 | function setUtils(address _addr) external; 65 | 66 | function setStore(address _addr) external; 67 | 68 | function setViewer(address _addr) external; 69 | 70 | function setModifiers(address _addr) external; 71 | 72 | } 73 | -------------------------------------------------------------------------------- /contracts/interfaces/ICollector.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface ICollector { 5 | function collect(address sender) external; 6 | function token() external returns(address); 7 | } 8 | -------------------------------------------------------------------------------- /contracts/interfaces/IConfig.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface IConfig { 5 | 6 | function setPollTopicVotes(uint _uint1, uint _uint2, uint _uint3) external; 7 | 8 | function pushTopicPairs(uint _uint, address _addr) external; 9 | 10 | function pushUserPairs(address _addr1, address _addr2) external; 11 | 12 | function pushPollTopics(uint _uint1, uint _uint2) external; 13 | 14 | function setFreeTopic(uint _uint) external; 15 | 16 | function setPoolNames(address _addr, string memory _str) external; 17 | 18 | function setPoolAddresses(string memory _str, address _addr) external; 19 | 20 | function setTopicNames(uint _uint, string memory _str) external; 21 | 22 | function setTopicIndexes(string memory _str, uint _uint) external; 23 | 24 | function setPairs(address _addr1, uint _uint, address _addr2) external; 25 | 26 | function setClaimable(address _addr, uint _uint) external; 27 | 28 | function setPolls(address _pool, address _token, uint _amount, uint _block, uint[] memory _topics) external returns (uint); 29 | 30 | function setTokenVersion(address _addr, uint _uint) external; 31 | 32 | function setPollAmount(uint _poll, uint _uint) external; 33 | 34 | function setPollTopics(uint _poll, uint[] memory _topics) external; 35 | 36 | function setPollsMinted(uint _poll, uint _uint) external; 37 | 38 | function setPollBlockUntil(uint _poll, uint _uint) external; 39 | 40 | function setPollsTotalVotes(uint _poll, uint _uint) external; 41 | 42 | function setPollsMintable(uint _poll, uint _uint) external; 43 | 44 | function setPollsPhase(uint _poll, uint _uint) external; 45 | 46 | function setVotes(uint _uint1, address _addr, uint _uint2) external; 47 | 48 | function setTopicVotes(uint _uint1, address _addr, uint _uint2, uint _uint3) external; 49 | 50 | function setMinted(uint _uint1, address _addr, uint _uint2) external; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /contracts/interfaces/IConfigMarket.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface IConfigMarket { 5 | 6 | function pushItemPairs(address _addr1, uint _uint, address _addr2) external; 7 | 8 | function setLastBlock(address _addr, uint _uint) external; 9 | 10 | function setLastBlocks(address _addr, address _addr2, uint _uint) external; 11 | 12 | function setDilutionRate(uint _numerator, uint _denominator) external; 13 | 14 | function setBurnLimits(address _addr, uint _uint) external; 15 | 16 | function setItemTopics(address _addr, uint _uint, uint[] memory _uint_arr) external; 17 | 18 | function deleteItemTopics(address _addr, uint _uint) external; 19 | 20 | function setItems(address _addr, uint _uint, bool _bool) external; 21 | 22 | function setDEX(address _addr) external; 23 | 24 | function setCreatorPercentage(uint _uint) external; 25 | 26 | function setKudos(address _addr, address _addr2, uint _uint) external; 27 | 28 | function setTotalKudos(address _addr, uint _uint) external; 29 | 30 | function setTotalShareSqrt(address _addr, uint _uint) external; 31 | 32 | function setTotalShare(address _addr, uint _uint) external; 33 | 34 | function setGenesises(address _addr, uint _uint) external; 35 | 36 | function setClaimed(address _addr, uint _uint) external; 37 | 38 | function setShare(address _addr1, address _addr2, uint _uint) external; 39 | 40 | function setShareSqrt(address _addr1, address _addr2, uint _uint) external; 41 | 42 | function setItemIndexes(string memory _str, address _addr, uint _uint) external; 43 | 44 | function setUserItemBurn(address _addr1, address _addr2, uint _uint1, address _addr3, uint _uint2) external; 45 | } 46 | -------------------------------------------------------------------------------- /contracts/interfaces/IEvents.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface IEvents { 5 | 6 | function vote(uint _poll, uint _topic, uint _vp, address voter, address token, uint _minted, uint _share, string memory ref) external; 7 | 8 | function burn(address nft, uint id, address from, address to, address token, uint reward, uint payback, string memory ref) external; 9 | 10 | function convert(address token, uint share, address holder, uint amount, string memory ref) external; 11 | 12 | function createTopic(address owner, string memory name, string memory id, string memory ref) external; 13 | 14 | function addItem(address owner, address nft, uint id, uint[] memory topics, string memory ref) external; 15 | 16 | function updateItem(address owner, address nft, uint id, uint[] memory topics, string memory ref) external; 17 | 18 | function removeItem(address owner, address nft, uint id, string memory ref) external; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /contracts/interfaces/IFactory.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface IFactory { 5 | function issue (string memory _name, string memory _sym, address _config) external returns (address _token); 6 | } 7 | -------------------------------------------------------------------------------- /contracts/interfaces/IModifiers.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface IModifiers { 5 | 6 | /* get contract addresses */ 7 | 8 | function governance() external view returns(address); 9 | 10 | function market() external view returns(address); 11 | 12 | function collector() external view returns(address); 13 | 14 | function factory() external view returns(address); 15 | 16 | function dex() external view returns(address); 17 | 18 | function topics() external view returns(address); 19 | 20 | 21 | 22 | /* exists */ 23 | function existsPool (address _pool) external view; 24 | 25 | function existsPoll (uint _poll) external view; 26 | 27 | function existsTopic (uint _topic) external view; 28 | 29 | 30 | /* modifiers */ 31 | function onlyGovernanceOrDEX(address _sender) external view; 32 | 33 | function onlyGovernanceOrMarket(address _sender) external view; 34 | 35 | function onlyGovernanceOrWithdraw(address _sender) external view; 36 | 37 | function onlyGovernance(address _sender) external view; 38 | 39 | function onlyFactory(address _sender) external view; 40 | 41 | function onlyMarket(address _sender) external view; 42 | 43 | function onlyDEX(address _sender) external view; 44 | 45 | function onlyDEXOrMarket(address _sender) external view; 46 | 47 | function onlyFactoryOrGovernance(address _sender) external view; 48 | 49 | } 50 | -------------------------------------------------------------------------------- /contracts/interfaces/INFT.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface INFT { 5 | function mint (address _to, string memory _url) external returns(uint); 6 | } 7 | -------------------------------------------------------------------------------- /contracts/interfaces/ISet.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface ISet { 5 | 6 | function addEditor(address _editor) external; 7 | 8 | function removeEditor(address _editor) external; 9 | 10 | 11 | function getUintSet(bytes32 _key) external view returns(uint[] memory); 12 | 13 | function getUintSetAt(bytes32 _key, uint _i) external view returns(uint); 14 | 15 | function pushUintSet(bytes32 _key, uint _uint) external; 16 | 17 | function removeUintSet(bytes32 _key, uint _uint) external; 18 | 19 | 20 | function getStringSet(bytes32 _key) external view returns(string[] memory); 21 | 22 | function getStringSetAt(bytes32 _key, uint _i) external view returns(string memory); 23 | 24 | function pushStringSet(bytes32 _key, string memory _string) external; 25 | 26 | function removeStringSet(bytes32 _key, string memory _string) external; 27 | 28 | 29 | function getAddressSet(bytes32 _key) external view returns(address[] memory); 30 | 31 | function getAddressSetAt(bytes32 _key, uint _i) external view returns(address); 32 | 33 | function pushAddressSet(bytes32 _key, address _val) external; 34 | 35 | function removeAddressSet(bytes32 _key, address _val) external; 36 | 37 | 38 | function getBytesSet(bytes32 _key) external view returns(bytes[] memory); 39 | 40 | function getBytesSetAt(bytes32 _key, uint _i) external view returns(bytes memory); 41 | 42 | function pushBytesSet(bytes32 _key, bytes memory _bytes) external; 43 | 44 | function removeBytesSet(bytes32 _key, bytes memory _bytes) external; 45 | 46 | 47 | function getBoolSet(bytes32 _key) external view returns(bool[] memory); 48 | 49 | function getBoolSetAt(bytes32 _key, uint _i) external view returns(bool); 50 | 51 | function pushBoolSet(bytes32 _key, bool _val) external; 52 | 53 | function removeBoolSet(bytes32 _key, bool _val) external; 54 | 55 | 56 | function getIntSet(bytes32 _key) external view returns(int[] memory); 57 | 58 | function getIntSetAt(bytes32 _key, uint _i) external view returns(int); 59 | 60 | function pushIntSet(bytes32 _key, int _val) external; 61 | 62 | function removeIntSet(bytes32 _key, int _val) external; 63 | 64 | } 65 | -------------------------------------------------------------------------------- /contracts/interfaces/IStorage.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface IStorage { 5 | function getUint(bytes32 _key) external view returns(uint); 6 | 7 | function getString(bytes32 _key) external view returns(string memory); 8 | 9 | function getAddress(bytes32 _key) external view returns(address); 10 | 11 | function getBool(bytes32 _key) external view returns(bool); 12 | 13 | function getUintArray(bytes32 _key) external view returns(uint[] memory); 14 | 15 | function setUint(bytes32 _key, uint _value) external; 16 | 17 | function setString(bytes32 _key, string memory _value) external; 18 | 19 | function setAddress(bytes32 _key, address _value) external; 20 | 21 | function setBool(bytes32 _key, bool _value) external; 22 | 23 | function setUintArray(bytes32 _key, uint[] memory _value) external; 24 | 25 | function deleteUintArray(bytes32 _key) external; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /contracts/interfaces/ITopic.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | interface ITopic is IERC20 { 7 | function mint (address _to, uint _amount) external; 8 | function totalInterests () external view returns(uint); 9 | } 10 | -------------------------------------------------------------------------------- /contracts/interfaces/IUtils.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface IUtils { 5 | 6 | function concat( string memory a, string memory b) external pure returns(string memory); 7 | 8 | function includes (uint[] memory _arr, uint _item) external pure returns(bool); 9 | 10 | function sqrt(uint x) external pure returns (uint); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /contracts/interfaces/IVP.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface IVP { 5 | function owner () external view returns (address); 6 | 7 | function getTotalVP () external view returns (uint); 8 | 9 | function getVP (address _voter) external view returns (uint); 10 | 11 | function vote (address _voter, uint _amount) external; 12 | } 13 | -------------------------------------------------------------------------------- /contracts/interfaces/IViewer.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | struct Poll { 5 | uint id; 6 | address pool; 7 | address token; 8 | uint block_until; 9 | uint amount; 10 | uint minted; 11 | uint total_votes; 12 | uint mintable; 13 | uint phase; 14 | uint [] topics; 15 | } 16 | 17 | interface IViewer { 18 | 19 | /* protocol parameters */ 20 | 21 | function burn_limits(address _addr) external view returns (uint); 22 | 23 | function totalSupply(address pair) external view returns (uint); 24 | 25 | function balanceOf(address pair, address account) external view returns (uint); 26 | 27 | function lastBlock() external view returns(uint); 28 | 29 | function lastSupply() external view returns(uint); 30 | 31 | function lastBlocks(address _addr) external view returns(uint); 32 | 33 | function poll_topic_votes(uint _uint, uint _topic) external view returns(uint); 34 | 35 | function poll_topics(uint _uint) external view returns(uint[] memory); 36 | 37 | function item_topics(address _addr, uint _uint) external view returns(uint[] memory); 38 | 39 | function items(address _addr, uint _uint) external view returns(bool); 40 | 41 | function item_indexes(string memory _str) external view returns(address, uint); 42 | 43 | function dilution_numerator () external view returns (uint); 44 | 45 | function dilution_denominator () external view returns (uint); 46 | 47 | function freigeld_numerator () external view returns (uint); 48 | 49 | function freigeld_denominator () external view returns (uint); 50 | 51 | function creator_percentage () external view returns (uint); 52 | 53 | function poll_count () external view returns (uint); 54 | 55 | function free_topic () external view returns (uint); 56 | 57 | /* protocol state getters */ 58 | 59 | function polls(uint _uint) external view returns(Poll memory); 60 | 61 | function pool_names(address _addr) external view returns(string memory); 62 | 63 | function pool_addresses(string memory _str) external view returns(address); 64 | 65 | function topic_names(uint _uint) external view returns(string memory); 66 | 67 | function topic_indexes(string memory _str) external view returns(uint); 68 | 69 | function pairs(address _addr, uint _uint) external view returns(address); 70 | 71 | function pair_tokens(address _addr) external view returns(address); 72 | 73 | function user_pairs(address _addr) external view returns(address[] memory); 74 | 75 | function topic_pairs(uint _uint) external view returns(address[] memory); 76 | 77 | function item_pairs(address _addr, uint _uint) external view returns(address[] memory); 78 | 79 | function pair_topics(address _addr) external view returns(uint); 80 | 81 | function kudos(address _addr1, address _addr2) external view returns(uint); 82 | 83 | function total_kudos(address _addr) external view returns(uint); 84 | 85 | function total_share_sqrt(address _addr) external view returns(uint); 86 | 87 | function total_share(address _addr) external view returns(uint); 88 | 89 | function token_version(address _addr) external view returns(uint); 90 | 91 | function genesises(address _addr) external view returns(uint); 92 | 93 | function claimable(address _addr) external view returns(uint); 94 | 95 | function claimed(address _addr) external view returns(uint); 96 | 97 | function share(address _addr1, address _addr2) external view returns(uint); 98 | 99 | function share_sqrt(address _addr1, address _addr2) external view returns(uint); 100 | 101 | function votes(uint _uint, address _addr) external view returns(uint); 102 | 103 | function topic_votes(uint _uint1, address _addr, uint _uint2) external view returns(uint); 104 | 105 | function minted(uint _uint, address _addr) external view returns(uint); 106 | 107 | 108 | /* state aggrigators */ 109 | 110 | function getConvertibleAmount(address _pair, uint _amount, address _holder) external view returns(uint); 111 | 112 | function getAvailable (uint _poll) external view returns (uint); 113 | 114 | function getMintable (uint _poll, uint _amount, uint _topic) external view returns (uint mintable, uint converted); 115 | 116 | function getVote(uint _uint, address _addr) external view returns (uint); 117 | 118 | function getTopicVote(uint _uint1, address _addr, uint _uint2) external view returns (uint); 119 | 120 | function getPair(uint _poll, uint _topic) external view returns (address); 121 | 122 | function getPool (string memory _name) external view returns (address); 123 | 124 | function getConvertible (address _pair) external view returns (uint); 125 | 126 | function user_item_burn(address _addr1, address _addr2, uint _uint1, address _addr3) external view returns(uint); 127 | 128 | function toShare(address _pair, uint256 amount) external view returns (uint256 _share); 129 | 130 | function toAmount(address _pair, uint256 _share) external view returns (uint256 _amount); 131 | 132 | function shareOf(address _pair, address account) external view returns (uint256 _share); 133 | } 134 | -------------------------------------------------------------------------------- /contracts/interfaces/IWithdraw.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface IWithdraw { 5 | function withdraw(address _to, address _voter, uint _amount, address _token) external; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /contracts/lib/EIP712Base.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | contract EIP712Base { 6 | 7 | struct EIP712Domain { 8 | string name; 9 | string version; 10 | uint256 chainId; 11 | address verifyingContract; 12 | } 13 | 14 | bytes32 internal constant EIP712_DOMAIN_TYPEHASH = keccak256(bytes("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")); 15 | 16 | bytes32 internal domainSeperator; 17 | 18 | constructor(string memory name, string memory version) { 19 | domainSeperator = keccak256(abi.encode( 20 | EIP712_DOMAIN_TYPEHASH, 21 | keccak256(bytes(name)), 22 | keccak256(bytes(version)), 23 | getChainID(), 24 | address(this) 25 | )); 26 | } 27 | 28 | function getChainID() internal view returns (uint256 id) { 29 | assembly { 30 | id := chainid() 31 | } 32 | } 33 | 34 | function getDomainSeperator() private view returns(bytes32) { 35 | return domainSeperator; 36 | } 37 | 38 | /** 39 | * Accept message hash and returns hash message in EIP712 compatible form 40 | * So that it can be used to recover signer from signature signed using EIP712 formatted data 41 | * https://eips.ethereum.org/EIPS/eip-712 42 | * "\\x19" makes the encoding deterministic 43 | * "\\x01" is the version byte to make it compatible to EIP-191 44 | */ 45 | function toTypedMessageHash(bytes32 messageHash) internal view returns(bytes32) { 46 | return keccak256(abi.encodePacked("\x19\x01", getDomainSeperator(), messageHash)); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /contracts/lib/EIP712MetaTransaction.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | pragma experimental ABIEncoderV2; 5 | 6 | import "./EIP712Base.sol"; 7 | import "./SafeMath.sol"; 8 | 9 | contract EIP712MetaTransaction is EIP712Base { 10 | using SafeMath for uint256; 11 | bytes32 private constant META_TRANSACTION_TYPEHASH = keccak256(bytes("MetaTransaction(uint256 nonce,address from,bytes functionSignature)")); 12 | 13 | event MetaTransactionExecuted(address userAddress, address payable relayerAddress, bytes functionSignature); 14 | mapping(address => uint256) nonces; 15 | 16 | /* 17 | * Meta transaction structure. 18 | * No point of including value field here as if user is doing value transfer then he has the funds to pay for gas 19 | * He should call the desired function directly in that case. 20 | */ 21 | struct MetaTransaction { 22 | uint256 nonce; 23 | address from; 24 | bytes functionSignature; 25 | } 26 | 27 | constructor(string memory name, string memory version) EIP712Base(name, version) {} 28 | 29 | function executeMetaTransaction(address userAddress, bytes memory functionSignature, bytes32 sigR, bytes32 sigS, uint8 sigV) public payable returns(bytes memory) { 30 | MetaTransaction memory metaTx = MetaTransaction({ 31 | nonce: nonces[userAddress], 32 | from: userAddress, 33 | functionSignature: functionSignature 34 | }); 35 | require(verify(userAddress, metaTx, sigR, sigS, sigV), "Signer and signature do not match"); 36 | nonces[userAddress] = nonces[userAddress].add(1); 37 | // Append userAddress at the end to extract it from calling context 38 | (bool success, bytes memory returnData) = address(this).call(abi.encodePacked(functionSignature, userAddress)); 39 | 40 | require(success, "Function call not successfull"); 41 | emit MetaTransactionExecuted(userAddress, payable(msg.sender), functionSignature); 42 | return returnData; 43 | } 44 | 45 | function hashMetaTransaction(MetaTransaction memory metaTx) internal pure returns (bytes32) { 46 | return keccak256(abi.encode( 47 | META_TRANSACTION_TYPEHASH, 48 | metaTx.nonce, 49 | metaTx.from, 50 | keccak256(metaTx.functionSignature) 51 | )); 52 | } 53 | 54 | function getNonce(address user) public view returns(uint256 nonce) { 55 | nonce = nonces[user]; 56 | } 57 | 58 | function verify(address user, MetaTransaction memory metaTx, bytes32 sigR, bytes32 sigS, uint8 sigV) internal view returns (bool) { 59 | address signer = ecrecover(toTypedMessageHash(hashMetaTransaction(metaTx)), sigV, sigR, sigS); 60 | require(signer != address(0), "Invalid signature"); 61 | return signer == user; 62 | } 63 | 64 | function msgSender() internal view returns(address sender) { 65 | if(msg.sender == address(this)) { 66 | bytes memory array = msg.data; 67 | uint256 index = msg.data.length; 68 | assembly { 69 | // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those. 70 | sender := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff) 71 | } 72 | } else { 73 | sender = msg.sender; 74 | } 75 | return sender; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /contracts/lib/ERC20Freigeld.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; 7 | import "@openzeppelin/contracts/utils/Context.sol"; 8 | 9 | /** 10 | * @dev Implementation of the {IERC20} interface. 11 | * 12 | * This implementation is agnostic to the way tokens are created. This means 13 | * that a supply mechanism has to be added in a derived contract using {_mint}. 14 | * For a generic mechanism see {ERC20PresetMinterPauser}. 15 | * 16 | * TIP: For a detailed writeup see our guide 17 | * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How 18 | * to implement supply mechanisms]. 19 | * 20 | * We have followed general OpenZeppelin guidelines: functions revert instead 21 | * of returning `false` on failure. This behavior is nonetheless conventional 22 | * and does not conflict with the expectations of ERC20 applications. 23 | * 24 | * Additionally, an {Approval} event is emitted on calls to {transferFrom}. 25 | * This allows applications to reconstruct the allowance for all accounts just 26 | * by listening to said events. Other implementations of the EIP may not emit 27 | * these events, as it isn't required by the specification. 28 | * 29 | * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} 30 | * functions have been added to mitigate the well-known issues around setting 31 | * allowances. See {IERC20-approve}. 32 | */ 33 | contract ERC20Freigeld is Context, IERC20, IERC20Metadata { 34 | mapping (address => uint256) private _balances; 35 | mapping (address => mapping (address => uint256)) private _allowances; 36 | mapping(address => uint) private _lastBlocks; 37 | 38 | uint256 private _totalSupply; 39 | uint private _lastBlock; 40 | uint private _lastSupply; 41 | uint256 private _rate_denominator = 0; 42 | uint256 private _rate_numerator = 0; 43 | uint256 private _interests = 0; 44 | string private _name; 45 | string private _symbol; 46 | 47 | uint256 private _totalShare; 48 | uint256 private _genesis; 49 | 50 | /** 51 | * @dev Sets the values for {name} and {symbol}. 52 | * 53 | * The defaut value of {decimals} is 18. To select a different value for 54 | * {decimals} you should overload it. 55 | * 56 | * All two of these values are immutable: they can only be set once during 57 | * construction. 58 | */ 59 | constructor (string memory name_, string memory symbol_) { 60 | _name = name_; 61 | _symbol = symbol_; 62 | } 63 | 64 | /** 65 | * @dev Returns the name of the token. 66 | */ 67 | function name() public view virtual override returns (string memory) { 68 | return _name; 69 | } 70 | 71 | /** 72 | * @dev Returns the symbol of the token, usually a shorter version of the 73 | * name. 74 | */ 75 | function symbol() public view virtual override returns (string memory) { 76 | return _symbol; 77 | } 78 | 79 | /** 80 | * @dev Returns the number of decimals used to get its user representation. 81 | * For example, if `decimals` equals `2`, a balance of `505` tokens should 82 | * be displayed to a user as `5,05` (`505 / 10 ** 2`). 83 | * 84 | * Tokens usually opt for a value of 18, imitating the relationship between 85 | * Ether and Wei. This is the value {ERC20} uses, unless this function is 86 | * overridden; 87 | * 88 | * NOTE: This information is only used for _display_ purposes: it in 89 | * no way affects any of the arithmetic of the contract, including 90 | * {IERC20-balanceOf} and {IERC20-transfer}. 91 | */ 92 | function decimals() public view virtual override returns (uint8) { 93 | return 18; 94 | } 95 | 96 | /** 97 | * @dev Returns the amount of interests deducted from the totalSupply. 98 | */ 99 | function totalInterests() public view virtual returns (uint256 _total_interests) { 100 | uint256 _supply = totalSupply(); 101 | _total_interests = _interests + (_totalSupply - _supply); 102 | } 103 | 104 | /** 105 | * @dev See {IERC20-totalSupply}. 106 | */ 107 | function totalSupply() public view virtual override returns (uint256 _supply) { 108 | uint256 minus = _rate_denominator == 0 ? 0 : _totalSupply * (block.number - _lastBlock) * _rate_numerator / _rate_denominator; 109 | _supply = _totalSupply > minus ? _totalSupply - minus : 0; 110 | } 111 | 112 | /** 113 | * @dev See {IERC20-balanceOf}. 114 | */ 115 | function balanceOf(address account) public view virtual override returns (uint256 _balance) { 116 | _balance = _totalShare == 0 ? 0 : totalSupply() * shareOf(account) / _totalShare; 117 | } 118 | 119 | /** 120 | * @dev Convert amount to share. 121 | */ 122 | function toShare(uint256 amount) public view virtual returns (uint256 _share) { 123 | _share = totalSupply() == 0 ? amount : amount * _totalShare / totalSupply(); 124 | } 125 | 126 | /** 127 | * @dev Return the share of the account. 128 | */ 129 | function shareOf(address account) public view virtual returns (uint256 _share) { 130 | _share = _lastBlocks[account] < _genesis ? 0 : _balances[account]; 131 | } 132 | 133 | /** 134 | * @dev See {IERC20-transfer}. 135 | * 136 | * Requirements: 137 | * 138 | * - `recipient` cannot be the zero address. 139 | * - the caller must have a balance of at least `amount`. 140 | */ 141 | function transfer(address recipient, uint256 amount) public virtual override returns (bool) { 142 | _transfer(_msgSender(), recipient, amount); 143 | return true; 144 | } 145 | 146 | /** 147 | * @dev See {IERC20-allowance}. 148 | */ 149 | function allowance(address owner, address spender) public view virtual override returns (uint256) { 150 | return _allowances[owner][spender]; 151 | } 152 | 153 | /** 154 | * @dev See {IERC20-approve}. 155 | * 156 | * Requirements: 157 | * 158 | * - `spender` cannot be the zero address. 159 | */ 160 | function approve(address spender, uint256 amount) public virtual override returns (bool) { 161 | _approve(_msgSender(), spender, amount); 162 | return true; 163 | } 164 | 165 | /** 166 | * @dev See {IERC20-transferFrom}. 167 | * 168 | * Emits an {Approval} event indicating the updated allowance. This is not 169 | * required by the EIP. See the note at the beginning of {ERC20}. 170 | * 171 | * Requirements: 172 | * 173 | * - `sender` and `recipient` cannot be the zero address. 174 | * - `sender` must have a balance of at least `amount`. 175 | * - the caller must have allowance for ``sender``'s tokens of at least 176 | * `amount`. 177 | */ 178 | function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { 179 | _transfer(sender, recipient, amount); 180 | 181 | uint256 currentAllowance = _allowances[sender][_msgSender()]; 182 | require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); 183 | _approve(sender, _msgSender(), currentAllowance - amount); 184 | 185 | return true; 186 | } 187 | 188 | /** 189 | * @dev Atomically increases the allowance granted to `spender` by the caller. 190 | * 191 | * This is an alternative to {approve} that can be used as a mitigation for 192 | * problems described in {IERC20-approve}. 193 | * 194 | * Emits an {Approval} event indicating the updated allowance. 195 | * 196 | * Requirements: 197 | * 198 | * - `spender` cannot be the zero address. 199 | */ 200 | function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { 201 | _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue); 202 | return true; 203 | } 204 | 205 | /** 206 | * @dev Atomically decreases the allowance granted to `spender` by the caller. 207 | * 208 | * This is an alternative to {approve} that can be used as a mitigation for 209 | * problems described in {IERC20-approve}. 210 | * 211 | * Emits an {Approval} event indicating the updated allowance. 212 | * 213 | * Requirements: 214 | * 215 | * - `spender` cannot be the zero address. 216 | * - `spender` must have allowance for the caller of at least 217 | * `subtractedValue`. 218 | */ 219 | function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { 220 | uint256 currentAllowance = _allowances[_msgSender()][spender]; 221 | require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); 222 | _approve(_msgSender(), spender, currentAllowance - subtractedValue); 223 | 224 | return true; 225 | } 226 | 227 | /** 228 | * @dev Moves tokens `amount` from `sender` to `recipient`. 229 | * 230 | * This is internal function is equivalent to {transfer}, and can be used to 231 | * e.g. implement automatic token fees, slashing mechanisms, etc. 232 | * 233 | * Emits a {Transfer} event. 234 | * 235 | * Requirements: 236 | * 237 | * - `sender` cannot be the zero address. 238 | * - `recipient` cannot be the zero address. 239 | * - `sender` must have a balance of at least `amount`. 240 | */ 241 | function _transfer(address sender, address recipient, uint256 amount) internal virtual { 242 | require(sender != address(0), "ERC20: transfer from the zero address"); 243 | require(recipient != address(0), "ERC20: transfer to the zero address"); 244 | _beforeTokenTransfer(sender, recipient, amount); 245 | uint256 share = toShare(amount); 246 | require(shareOf(sender) >= share, "ERC20: transfer amount exceeds balance"); 247 | _balances[sender] -= share; 248 | _balances[recipient] += share; 249 | uint256 _supply = totalSupply(); 250 | _interests += (_totalSupply - _supply); 251 | _totalSupply = totalSupply(); 252 | _lastBlocks[sender] = block.number; 253 | _lastBlocks[recipient] = block.number; 254 | _lastBlock = block.number; 255 | emit Transfer(sender, recipient, amount); 256 | } 257 | 258 | /** @dev Creates `amount` tokens and assigns them to `account`, increasing 259 | * the total supply. 260 | * 261 | * Emits a {Transfer} event with `from` set to the zero address. 262 | * 263 | * Requirements: 264 | * 265 | * - `to` cannot be the zero address. 266 | */ 267 | function _mint(address account, uint256 amount) internal virtual { 268 | require(account != address(0), "ERC20: mint to the zero address"); 269 | _beforeTokenTransfer(address(0), account, amount); 270 | uint256 share = toShare(amount); 271 | uint256 _supply = totalSupply(); 272 | bool reset = _supply == 0 || share / _supply > 10 ** 15; 273 | if(reset) _supply = 0; 274 | _interests += (_totalSupply - _supply); 275 | if(reset) _genesis = block.number; 276 | _totalShare = reset ? share : _totalShare + share; 277 | _totalSupply = _supply + amount; 278 | _balances[account] = shareOf(account) + share; 279 | _lastBlocks[account] = block.number; 280 | _lastBlock = block.number; 281 | emit Transfer(address(0), account, amount); 282 | } 283 | 284 | /** 285 | * @dev Destroys `amount` tokens from `account`, reducing the 286 | * total supply. 287 | * 288 | * Emits a {Transfer} event with `to` set to the zero address. 289 | * 290 | * Requirements: 291 | * 292 | * - `account` cannot be the zero address. 293 | * - `account` must have at least `amount` tokens. 294 | */ 295 | function _burn(address account, uint256 amount) internal virtual { 296 | require(account != address(0), "ERC20: burn from the zero address"); 297 | _beforeTokenTransfer(account, address(0), amount); 298 | uint256 share = toShare(amount); 299 | require(shareOf(account) >= share, "ERC20: burn amount exceeds balance"); 300 | uint256 _supply = totalSupply(); 301 | _interests += (_totalSupply - _supply); 302 | _totalSupply = _supply - amount; 303 | _totalShare -= share; 304 | _balances[account] -= share; 305 | _lastBlocks[account] = block.number; 306 | _lastBlock = block.number; 307 | emit Transfer(account, address(0), amount); 308 | } 309 | 310 | /** 311 | * @dev Sets the interest rate per block with a combination of 312 | * `numerator` and `denominator`. 313 | */ 314 | function _setRate (uint256 _numerator, uint256 _denominator) internal virtual { 315 | require(_numerator <= _denominator, "numerator must be less than or equal to denominator"); 316 | _rate_numerator = _numerator; 317 | _rate_denominator = _denominator; 318 | } 319 | 320 | /** 321 | * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. 322 | * 323 | * This internal function is equivalent to `approve`, and can be used to 324 | * e.g. set automatic allowances for certain subsystems, etc. 325 | * 326 | * Emits an {Approval} event. 327 | * 328 | * Requirements: 329 | * 330 | * - `owner` cannot be the zero address. 331 | * - `spender` cannot be the zero address. 332 | */ 333 | function _approve(address owner, address spender, uint256 amount) internal virtual { 334 | require(owner != address(0), "ERC20: approve from the zero address"); 335 | require(spender != address(0), "ERC20: approve to the zero address"); 336 | 337 | _allowances[owner][spender] = amount; 338 | emit Approval(owner, spender, amount); 339 | } 340 | 341 | /** 342 | * @dev Hook that is called before any transfer of tokens. This includes 343 | * minting and burning. 344 | * 345 | * Calling conditions: 346 | * 347 | * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens 348 | * will be to transferred to `to`. 349 | * - when `from` is zero, `amount` tokens will be minted for `to`. 350 | * - when `to` is zero, `amount` of ``from``'s tokens will be burned. 351 | * - `from` and `to` are never both zero. 352 | * 353 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 354 | */ 355 | function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } 356 | } 357 | -------------------------------------------------------------------------------- /contracts/lib/ERC20Permit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol"; 6 | import "./ERC20Freigeld.sol"; 7 | import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol"; 8 | import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; 9 | import "@openzeppelin/contracts/utils/Counters.sol"; 10 | 11 | /** 12 | * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in 13 | * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. 14 | * 15 | * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by 16 | * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't 17 | * need to send a transaction, and thus is not required to hold Ether at all. 18 | * 19 | * _Available since v3.4._ 20 | */ 21 | abstract contract ERC20Permit is ERC20Freigeld, IERC20Permit, EIP712 { 22 | using Counters for Counters.Counter; 23 | 24 | mapping (address => Counters.Counter) private _nonces; 25 | 26 | // solhint-disable-next-line var-name-mixedcase 27 | bytes32 private immutable _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); 28 | 29 | /** 30 | * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. 31 | * 32 | * It's a good idea to use the same `name` that is defined as the ERC20 token name. 33 | */ 34 | constructor(string memory name) EIP712(name, "1") { 35 | } 36 | 37 | /** 38 | * @dev See {IERC20Permit-permit}. 39 | */ 40 | function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public virtual override { 41 | // solhint-disable-next-line not-rely-on-time 42 | require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); 43 | 44 | bytes32 structHash = keccak256( 45 | abi.encode( 46 | _PERMIT_TYPEHASH, 47 | owner, 48 | spender, 49 | value, 50 | _useNonce(owner), 51 | deadline 52 | ) 53 | ); 54 | 55 | bytes32 hash = _hashTypedDataV4(structHash); 56 | 57 | address signer = ECDSA.recover(hash, v, r, s); 58 | require(signer == owner, "ERC20Permit: invalid signature"); 59 | 60 | _approve(owner, spender, value); 61 | } 62 | 63 | /** 64 | * @dev See {IERC20Permit-nonces}. 65 | */ 66 | function nonces(address owner) public view virtual override returns (uint256) { 67 | return _nonces[owner].current(); 68 | } 69 | 70 | /** 71 | * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. 72 | */ 73 | // solhint-disable-next-line func-name-mixedcase 74 | function DOMAIN_SEPARATOR() external view override returns (bytes32) { 75 | return _domainSeparatorV4(); 76 | } 77 | 78 | /** 79 | * @dev "Consume a nonce": return the current value and increment. 80 | * 81 | * _Available since v4.1._ 82 | */ 83 | function _useNonce(address owner) internal virtual returns (uint256 current) { 84 | Counters.Counter storage nonce = _nonces[owner]; 85 | current = nonce.current(); 86 | nonce.increment(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /contracts/lib/NFT.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 6 | import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; 7 | import "@openzeppelin/contracts/utils/Counters.sol"; 8 | import "@openzeppelin/contracts/access/AccessControl.sol"; 9 | import "@openzeppelin/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol"; 10 | 11 | contract NFT is Ownable, ERC721PresetMinterPauserAutoId { 12 | using Counters for Counters.Counter; 13 | Counters.Counter private _tokenIds; 14 | string private _baseTokenURI; 15 | constructor(string memory _name, string memory _sym, string memory baseTokenURI) ERC721PresetMinterPauserAutoId(_name, _sym, baseTokenURI) {} 16 | 17 | function setBaseURI(string memory baseTokenURI) public onlyOwner { 18 | _baseTokenURI = baseTokenURI; 19 | } 20 | 21 | function addMinter(address _minter) public { 22 | grantRole(MINTER_ROLE, _minter); 23 | } 24 | 25 | function removeAgent(address _minter) public { 26 | revokeRole(MINTER_ROLE, _minter); 27 | } 28 | 29 | function mint (address _to, string memory _url) public onlyRole(MINTER_ROLE) returns(uint id) { 30 | _tokenIds.increment(); 31 | id = _tokenIds.current(); 32 | _mint(_to, id); 33 | _setTokenURI(id, _url); 34 | } 35 | 36 | using Strings for uint256; 37 | 38 | // Optional mapping for token URIs 39 | mapping (uint256 => string) private _tokenURIs; 40 | 41 | /** 42 | * @dev See {IERC721Metadata-tokenURI}. 43 | */ 44 | function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { 45 | require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token"); 46 | 47 | string memory _tokenURI = _tokenURIs[tokenId]; 48 | string memory base = _baseURI(); 49 | 50 | // If there is no base URI, return the token URI. 51 | if (bytes(base).length == 0) { 52 | return _tokenURI; 53 | } 54 | // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked). 55 | if (bytes(_tokenURI).length > 0) { 56 | return string(abi.encodePacked(base, _tokenURI)); 57 | } 58 | 59 | return super.tokenURI(tokenId); 60 | } 61 | 62 | /** 63 | * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. 64 | * 65 | * Requirements: 66 | * 67 | * - `tokenId` must exist. 68 | */ 69 | function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { 70 | require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token"); 71 | _tokenURIs[tokenId] = _tokenURI; 72 | } 73 | 74 | /** 75 | * @dev Destroys `tokenId`. 76 | * The approval is cleared when the token is burned. 77 | * 78 | * Requirements: 79 | * 80 | * - `tokenId` must exist. 81 | * 82 | * Emits a {Transfer} event. 83 | */ 84 | function _burn(uint256 tokenId) internal virtual override { 85 | super._burn(tokenId); 86 | 87 | if (bytes(_tokenURIs[tokenId]).length != 0) { 88 | delete _tokenURIs[tokenId]; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /contracts/lib/SafeMath.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | /** 6 | * @dev Wrappers over Solidity's arithmetic operations with added overflow 7 | * checks. 8 | * 9 | * Arithmetic operations in Solidity wrap on overflow. This can easily result 10 | * in bugs, because programmers usually assume that an overflow raises an 11 | * error, which is the standard behavior in high level programming languages. 12 | * `SafeMath` restores this intuition by reverting the transaction when an 13 | * operation overflows. 14 | * 15 | * Using this library instead of the unchecked operations eliminates an entire 16 | * class of bugs, so it's recommended to use it always. 17 | */ 18 | library SafeMath { 19 | /** 20 | * @dev Returns the addition of two unsigned integers, reverting on 21 | * overflow. 22 | * 23 | * Counterpart to Solidity's `+` operator. 24 | * 25 | * Requirements: 26 | * - Addition cannot overflow. 27 | */ 28 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 29 | uint256 c = a + b; 30 | require(c >= a, "SafeMath: addition overflow"); 31 | 32 | return c; 33 | } 34 | 35 | /** 36 | * @dev Returns the subtraction of two unsigned integers, reverting on 37 | * overflow (when the result is negative). 38 | * 39 | * Counterpart to Solidity's `-` operator. 40 | * 41 | * Requirements: 42 | * - Subtraction cannot overflow. 43 | */ 44 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 45 | return sub(a, b, "SafeMath: subtraction overflow"); 46 | } 47 | 48 | /** 49 | * @dev Returns the subtraction of two unsigned integers, reverting with custom message on 50 | * overflow (when the result is negative). 51 | * 52 | * Counterpart to Solidity's `-` operator. 53 | * 54 | * Requirements: 55 | * - Subtraction cannot overflow. 56 | */ 57 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 58 | require(b <= a, errorMessage); 59 | uint256 c = a - b; 60 | 61 | return c; 62 | } 63 | 64 | /** 65 | * @dev Returns the multiplication of two unsigned integers, reverting on 66 | * overflow. 67 | * 68 | * Counterpart to Solidity's `*` operator. 69 | * 70 | * Requirements: 71 | * - Multiplication cannot overflow. 72 | */ 73 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 74 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 75 | // benefit is lost if 'b' is also tested. 76 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 77 | if (a == 0) { 78 | return 0; 79 | } 80 | 81 | uint256 c = a * b; 82 | require(c / a == b, "SafeMath: multiplication overflow"); 83 | 84 | return c; 85 | } 86 | 87 | /** 88 | * @dev Returns the integer division of two unsigned integers. Reverts on 89 | * division by zero. The result is rounded towards zero. 90 | * 91 | * Counterpart to Solidity's `/` operator. Note: this function uses a 92 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 93 | * uses an invalid opcode to revert (consuming all remaining gas). 94 | * 95 | * Requirements: 96 | * - The divisor cannot be zero. 97 | */ 98 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 99 | return div(a, b, "SafeMath: division by zero"); 100 | } 101 | 102 | /** 103 | * @dev Returns the integer division of two unsigned integers. Reverts with custom message on 104 | * division by zero. The result is rounded towards zero. 105 | * 106 | * Counterpart to Solidity's `/` operator. Note: this function uses a 107 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 108 | * uses an invalid opcode to revert (consuming all remaining gas). 109 | * 110 | * Requirements: 111 | * - The divisor cannot be zero. 112 | */ 113 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 114 | // Solidity only automatically asserts when dividing by 0 115 | require(b > 0, errorMessage); 116 | uint256 c = a / b; 117 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 118 | 119 | return c; 120 | } 121 | 122 | /** 123 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 124 | * Reverts when dividing by zero. 125 | * 126 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 127 | * opcode (which leaves remaining gas untouched) while Solidity uses an 128 | * invalid opcode to revert (consuming all remaining gas). 129 | * 130 | * Requirements: 131 | * - The divisor cannot be zero. 132 | */ 133 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 134 | return mod(a, b, "SafeMath: modulo by zero"); 135 | } 136 | 137 | /** 138 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 139 | * Reverts with custom message when dividing by zero. 140 | * 141 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 142 | * opcode (which leaves remaining gas untouched) while Solidity uses an 143 | * invalid opcode to revert (consuming all remaining gas). 144 | * 145 | * Requirements: 146 | * - The divisor cannot be zero. 147 | */ 148 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 149 | require(b != 0, errorMessage); 150 | return a % b; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("@nomiclabs/hardhat-waffle") 2 | 3 | // This is a sample Hardhat task. To learn how to create your own go to 4 | // https://hardhat.org/guides/create-task.html 5 | task("accounts", "Prints the list of accounts", async () => { 6 | const accounts = await ethers.getSigners() 7 | 8 | for (const account of accounts) { 9 | console.log(account.address) 10 | } 11 | }) 12 | 13 | // You need to export an object to set up your config 14 | // Go to https://hardhat.org/config/ to learn more 15 | 16 | /** 17 | * @type import('hardhat/config').HardhatUserConfig 18 | */ 19 | module.exports = { 20 | solidity: "0.8.0", 21 | } 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hide-protocol", 3 | "version": "0.1.0", 4 | "description": "DAO protocol for sustainable NFT rewards", 5 | "repository": "https://github.com/warashibe/hide-protocol", 6 | "license": "MIT", 7 | "devDependencies": { 8 | "@nomiclabs/hardhat-ethers": "^2.0.0", 9 | "@nomiclabs/hardhat-waffle": "^2.0.0", 10 | "@openzeppelin/contracts": "^4.1.0", 11 | "big.js": "^6.1.1", 12 | "chai": "^4.2.0", 13 | "ethereum-waffle": "^3.0.0", 14 | "ethers": "^5.0.0", 15 | "hardhat": "^2.3.3" 16 | }, 17 | "scripts": { 18 | "test": "hardhat test" 19 | }, 20 | "dependencies": { 21 | "ramda": "^0.27.1" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai") 2 | const B = require("big.js") 3 | const { waffle, ethers } = require("hardhat") 4 | const { utils, Contract } = ethers 5 | const { map } = require("ramda") 6 | const _IERC20 = require("@openzeppelin/contracts/build/contracts/IERC20.json") 7 | const { 8 | arr, 9 | isErr, 10 | to18, 11 | to32, 12 | from18, 13 | UINT_MAX, 14 | deploy, 15 | a, 16 | } = require("./utils") 17 | 18 | describe("Unit", () => { 19 | let str, cfg, utils, viewer, addr, set, mod 20 | let ac, p1, p2, p3 21 | beforeEach(async () => { 22 | ac = await ethers.getSigners() 23 | ;[p1, p2, p3] = ac 24 | }) 25 | 26 | describe("Storage", () => { 27 | beforeEach(async () => { 28 | str = await deploy("Storage") 29 | set = await deploy("Set") 30 | }) 31 | it("should allow only EDITOR", async () => { 32 | await isErr(str.connect(p2).setUint(to32("key"), 3)) 33 | await str.addEditor(a(p2)) 34 | await str.connect(p2).setUint(to32("key"), 3) 35 | expect(await str.getUint(to32("key"))).to.equal(3) 36 | await str.removeEditor(a(p2)) 37 | await isErr(str.connect(p2).setUint(to32("key"), 5)) 38 | expect(await str.getUint(to32("key"))).to.equal(3) 39 | }) 40 | it("should set UintArray", async () => { 41 | str.setUintArray(to32("key"), [1, 2, 3]) 42 | expect(arr(await str.getUintArray(to32("key")))).to.eql([1, 2, 3]) 43 | }) 44 | it("should keep uniq set", async () => { 45 | set.pushUintSet(to32("key"), 1) 46 | set.pushUintSet(to32("key"), 2) 47 | set.pushUintSet(to32("key"), 3) 48 | expect(arr(await set.getUintSet(to32("key")))).to.eql([1, 2, 3]) 49 | expect((await set.getUintSetAt(to32("key"), 0)) * 1).to.eql(1) 50 | await set.pushUintSet(to32("key"), 4) 51 | expect(arr(await set.getUintSet(to32("key")))).to.eql([1, 2, 3, 4]) 52 | await set.removeUintSet(to32("key"), 2) 53 | expect(arr(await set.getUintSet(to32("key")))).to.eql([1, 4, 3]) 54 | await set.removeUintSet(to32("key"), 3) 55 | expect(arr(await set.getUintSet(to32("key")))).to.eql([1, 4]) 56 | await set.removeUintSet(to32("key"), 1) 57 | expect(arr(await set.getUintSet(to32("key")))).to.eql([4]) 58 | expect(arr(await set.getUintSet(to32("key"))).length).to.eql(1) 59 | }) 60 | }) 61 | 62 | describe("Config", () => { 63 | beforeEach(async () => { 64 | str = await deploy("Storage") 65 | set = await deploy("Set") 66 | addr = await deploy("Addresses", a(str)) 67 | await str.addEditor(a(addr)) 68 | await addr.setSet(a(set)) 69 | utils = await deploy("Utils") 70 | addr.setUtils(a(utils)) 71 | viewer = await deploy("Viewer", a(addr)) 72 | addr.setViewer(a(viewer)) 73 | mod = await deploy("Modifiers", a(addr)) 74 | await addr.setModifiers(a(mod)) 75 | cfg = await deploy("Config", a(addr)) 76 | await str.addEditor(a(cfg)) 77 | await set.addEditor(a(cfg)) 78 | addr.setConfig(a(cfg)) 79 | }) 80 | it("should persist with Storage", async () => { 81 | await addr.setDEX(a(p1)) 82 | expect(await addr.dex()).to.equal(a(p1)) 83 | }) 84 | it("should allow only Protocol contracts", async () => { 85 | await isErr(cfg.setMinted(1, a(p1), 1)) 86 | await addr.setGovernance(a(p1)) 87 | await cfg.setMinted(1, a(p1), 1) 88 | expect(await viewer.minted(1, a(p1))).to.equal(1) 89 | }) 90 | }) 91 | }) 92 | 93 | describe("Integration", () => { 94 | let col, 95 | wpvp, 96 | token, 97 | agt, 98 | wp, 99 | gov, 100 | withdraw, 101 | vp, 102 | jpyc, 103 | doggod, 104 | market, 105 | events, 106 | nft, 107 | p, 108 | cfg, 109 | mcfg, 110 | fct, 111 | dex, 112 | topics, 113 | str, 114 | aggr, 115 | utils, 116 | viewer, 117 | addr, 118 | set, 119 | mod 120 | let ac, owner, collector, p1, p2, p3 121 | const checkEqualty = async pairs => { 122 | let total = B(from18(await viewer.getAvailable(0))) 123 | for (const v of pairs) { 124 | const pair = await viewer.getPair(0, v) 125 | const pToken = new Contract(pair, _IERC20.abi, owner) 126 | total = total 127 | .add(from18(await pToken.totalSupply())) 128 | .add(from18(await viewer.claimable(pair))) 129 | } 130 | expect(B(from18(await jpyc.balanceOf(a(withdraw)))).toFixed(0)).to.equal( 131 | total.toFixed(0) 132 | ) 133 | } 134 | 135 | beforeEach(async () => { 136 | ac = await ethers.getSigners() 137 | ;[owner, collector, p1, p2, p3] = ac 138 | 139 | // WP 140 | wp = await deploy("Token", "Warashibe Point", "WP", to18(100000000)) 141 | 142 | // JPYC 143 | jpyc = await deploy("Token", "JPYC", "JPYC", to18(100000000)) 144 | 145 | // DOGGOD 146 | doggod = await deploy("Token", "DOGGOD", "DOGGOD", to18(100000000)) 147 | 148 | // WPVP 149 | wpvp = await deploy("WPVP") 150 | 151 | // Storage 152 | str = await deploy("Storage") 153 | 154 | // Set 155 | set = await deploy("Set") 156 | 157 | // Addresses 158 | addr = await deploy("Addresses", a(str)) 159 | await str.addEditor(a(addr)) 160 | await addr.setSet(a(set)) 161 | 162 | // Events 163 | events = await deploy("Events", a(addr)) 164 | await addr.setEvents(a(events)) 165 | 166 | // Utils 167 | utils = await deploy("Utils") 168 | await addr.setUtils(a(utils)) 169 | 170 | // Viewer 171 | viewer = await deploy("Viewer", a(addr)) 172 | await addr.setViewer(a(viewer)) 173 | 174 | // Mod 175 | mod = await deploy("Modifiers", a(addr)) 176 | await addr.setModifiers(a(mod)) 177 | 178 | // Aggr 179 | aggr = await deploy("Aggregator", a(addr)) 180 | 181 | // Config 182 | cfg = await deploy("Config", a(addr)) 183 | await addr.setConfig(a(cfg)) 184 | await str.addEditor(a(cfg)) 185 | await set.addEditor(a(cfg)) 186 | await cfg.setFreigeldRate(63419584, 1000000000000000) 187 | 188 | // Config Market 189 | mcfg = await deploy("ConfigMarket", a(addr)) 190 | await addr.setConfigMarket(a(mcfg)) 191 | await str.addEditor(a(mcfg)) 192 | await set.addEditor(a(mcfg)) 193 | await mcfg.setCreatorPercentage(8000) 194 | await mcfg.setBurnLimits(a(jpyc), to18(1000)) 195 | await mcfg.setDilutionRate(63419584, 1000000000000000) 196 | 197 | // Collector 198 | col = await deploy( 199 | "Collector", 200 | [a(wp), a(jpyc)], 201 | [to18(1), to18(1)], 202 | a(collector) 203 | ) 204 | await addr.setCollector(a(col)) 205 | agt = await deploy("Agent", a(col)) 206 | await col.addAgent(a(agt)) 207 | 208 | // Withdraw 209 | withdraw = await deploy("Withdraw", a(addr)) 210 | await addr.setWithdraw(a(withdraw)) 211 | 212 | // Transfer 213 | await wp.transfer(a(p1), to18(100)) 214 | await wp.transfer(a(p2), to18(100)) 215 | await wp.transfer(a(p3), to18(100)) 216 | 217 | await jpyc.transfer(a(p1), to18(100)) 218 | await jpyc.transfer(a(p2), to18(100)) 219 | await jpyc.transfer(a(p3), to18(100)) 220 | 221 | await wp.approve(a(col), UINT_MAX) 222 | await wp.connect(p1).approve(a(col), UINT_MAX) 223 | await wp.connect(p2).approve(a(col), UINT_MAX) 224 | await wp.connect(p3).approve(a(col), UINT_MAX) 225 | 226 | // Governance 227 | gov = await deploy("Governance", a(addr)) 228 | await addr.setGovernance(a(gov)) 229 | await col.addAgent(a(gov)) 230 | await events.addEmitter(a(gov)) 231 | 232 | // Factory 233 | fct = await deploy("Factory", a(addr)) 234 | await addr.setFactory(a(fct)) 235 | await col.addAgent(a(fct)) 236 | await events.addEmitter(a(fct)) 237 | 238 | // Topics 239 | topics = await deploy( 240 | "NFT", 241 | "Hide Topics", 242 | "HIDETOPICS", 243 | "https://hide.ac/api/topics/" 244 | ) 245 | await addr.setTopics(a(topics)) 246 | await topics.addMinter(a(fct)) 247 | await fct.createFreeTopic("FREE", "free", "create") 248 | 249 | // NFT 250 | nft = await deploy( 251 | "NFT", 252 | "Hide Articles", 253 | "HIDEARTICLES", 254 | "https://hide.ac/api/items/" 255 | ) 256 | 257 | // Market 258 | market = await deploy("Market", a(nft), a(addr)) 259 | await nft.addMinter(a(market)) 260 | await addr.setMarket(a(market)) 261 | await col.addAgent(a(market)) 262 | await events.addEmitter(a(market)) 263 | 264 | // DEX 265 | dex = await deploy("DEX", a(addr)) 266 | await addr.setDEX(a(dex)) 267 | await col.addAgent(a(dex)) 268 | await events.addEmitter(a(dex)) 269 | 270 | // VP 271 | vp = await deploy("JPYCVP", a(wpvp), a(addr)) 272 | await wpvp.bulkRecordWP( 273 | [a(p1), a(p2), a(p3)], 274 | [a(p1), a(p2), a(p3)], 275 | [to18("100"), to18("100"), to18("100")], 276 | [to18("100"), to18("100"), to18("100")] 277 | ) 278 | await wpvp.setTotalWP(to18("1000")) 279 | await gov.addPool(a(vp), "JPYC") 280 | p = await viewer.getPool("JPYC") 281 | 282 | // Create Topics 283 | await fct.createTopic("TOPIC1", "topic1", "create") 284 | await fct.createTopic("TOPIC2", "topic2", "create") 285 | 286 | // Create Items 287 | await market.connect(p3).createItem("item", [1], "create") 288 | await market.connect(p3).createItem("item2", [3], "create") 289 | }) 290 | 291 | it("should deploy contracts", async () => {}) 292 | 293 | it("should collect fees", async () => { 294 | expect(await wp.balanceOf(a(collector))).to.equal(to18(5)) 295 | expect(await wp.balanceOf(a(p2))).to.equal(to18(100)) 296 | await agt.connect(p2).test() 297 | expect(await wp.balanceOf(a(collector))).to.equal(to18(6)) 298 | expect(await wp.balanceOf(a(p2))).to.equal(to18(99)) 299 | }) 300 | 301 | it("should go through the whole flow", async () => { 302 | // check setup 303 | expect(await vp.getVP(a(p1))).to.equal(to18(100)) 304 | expect(await vp.getVP(a(p2))).to.equal(to18(100)) 305 | expect(await vp.getVP(a(p3))).to.equal(to18(100)) 306 | 307 | // updateItem topics 308 | await market.connect(p3).updateItem(a(nft), 2, [2], "update") 309 | 310 | // set poll 311 | await jpyc.approve(a(gov), UINT_MAX) 312 | await gov.setPoll(p, a(jpyc), to18(1000), 30, []) 313 | 314 | // vote for topic 315 | const mintable0 = await viewer.getMintable(0, to18(10), 2) 316 | await gov.connect(p1).vote(0, to18(10), 2, "vote") 317 | 318 | // get pair token 319 | const pair2 = await viewer.getPair(0, 2) 320 | const pToken2 = new Contract(pair2, _IERC20.abi, owner) 321 | expect(await pToken2.balanceOf(a(p1))).to.equal(to18(10)) 322 | expect(await pToken2.balanceOf(a(p1))).to.equal(mintable0.mintable) 323 | 324 | // burn for item 325 | await pToken2.connect(p1).approve(a(market), UINT_MAX) 326 | await market.connect(p1).burnFor(a(nft), 2, pair2, to18(5), "ref") 327 | expect(await jpyc.balanceOf(a(p1))).to.equal(to18(101)) 328 | expect(await jpyc.balanceOf(a(p3))).to.equal(to18(104)) 329 | expect(await jpyc.balanceOf(a(withdraw))).to.equal(to18(995)) 330 | 331 | // vote for topic with shareholders 332 | const mintable = await viewer.getMintable(0, to18(30), 2) 333 | await gov.connect(p3).vote(0, to18(30), 2, "vote") 334 | expect(await pToken2.balanceOf(a(p3))).to.equal( 335 | B(mintable.mintable).minus(1).toFixed(0) 336 | ) 337 | 338 | const share = (await viewer.balanceOf(a(pToken2), a(p1))).toString() * 1 339 | const minus = B((await viewer.share_sqrt(pair2, a(p1))).toString()) 340 | .mul(B((await viewer.dilution_numerator()).toString())) 341 | .div(B((await viewer.dilution_denominator()).toString())) 342 | const convertible = ( 343 | await viewer.getConvertibleAmount(a(pToken2), share, a(p1)) 344 | ).toString() 345 | const balance = (await pToken2.balanceOf(a(p1))).toString() 346 | 347 | await dex 348 | .connect(p1) 349 | .convert(a(pToken2), B(share).minus(minus).toFixed(0), "convert") 350 | const balance2 = (await pToken2.balanceOf(a(p1))).toString() 351 | expect( 352 | B(balance2) 353 | .minus(balance * 1) 354 | .toNumber() 355 | ).to.be.gt(0) 356 | // close poll => claim period 357 | await gov.closePoll(0) 358 | await isErr(gov.connect(p3).vote(0, to18(30), 2), "vote") 359 | 360 | // check remaining amounts 361 | await checkEqualty([2]) 362 | }) 363 | 364 | it("should upgrade contracts", async () => { 365 | // Addresses 366 | addr = await deploy("Addresses", a(str)) 367 | await str.addEditor(a(addr)) 368 | await addr.setSet(a(set)) 369 | await addr.setCollector(a(col)) 370 | 371 | // Config 372 | cfg = await deploy("Config", a(addr)) 373 | await addr.setConfig(a(cfg)) 374 | await str.addEditor(a(cfg)) 375 | 376 | // Utils 377 | utils = await deploy("Utils") 378 | await addr.setUtils(a(utils)) 379 | 380 | // Viewer 381 | viewer = await deploy("Viewer", a(addr)) 382 | await addr.setViewer(a(viewer)) 383 | 384 | // Governance 385 | gov = await deploy("Governance", a(addr)) 386 | await addr.setGovernance(a(gov)) 387 | await col.addAgent(a(gov)) 388 | await events.addEmitter(a(gov)) 389 | 390 | // Factory 391 | fct = await deploy("Factory", a(addr)) 392 | await addr.setFactory(a(fct)) 393 | await col.addAgent(a(fct)) 394 | await topics.addMinter(a(fct)) 395 | await events.addEmitter(a(fct)) 396 | 397 | // NFT 398 | nft = await deploy( 399 | "NFT", 400 | "Hide Articles", 401 | "HIDEARTICLES", 402 | "https://hide.ac/api/items/" 403 | ) 404 | 405 | // Market 406 | market = await deploy("Market", a(nft), a(addr)) 407 | await nft.addMinter(a(market)) 408 | await addr.setMarket(a(market)) 409 | await col.addAgent(a(market)) 410 | await events.addEmitter(a(gov)) 411 | 412 | await fct.createTopic("TOPIC3", "topic3", "create") 413 | }) 414 | 415 | it("should add/remove fund to poll", async () => { 416 | // set poll 417 | await jpyc.approve(a(gov), UINT_MAX) 418 | await gov.setPoll(p, a(jpyc), to18(10), 30, []) 419 | let poll = await viewer.polls(0) 420 | expect(from18(B(poll.amount).sub(poll.minted).toFixed()) * 1).to.equal(10) 421 | 422 | // add fund 423 | await jpyc.approve(a(withdraw), UINT_MAX) 424 | await withdraw.addFund(0, to18(10)) 425 | poll = await viewer.polls(0) 426 | expect(from18(B(poll.amount).sub(poll.minted).toFixed()) * 1).to.equal(20) 427 | expect(from18(await jpyc.balanceOf(a(withdraw))) * 1).to.equal(20) 428 | await gov.connect(p1).vote(0, to18(30), 2, "vote") 429 | poll = await viewer.polls(0) 430 | expect(from18(B(poll.amount).sub(poll.minted).toFixed()) * 1).to.equal(19.4) 431 | 432 | // remove fund 433 | await isErr(withdraw.removeFund(0, to18(20))) 434 | await isErr(withdraw.connect(p2).removeFund(0, to18(19.4))) 435 | await withdraw.removeFund(0, to18(19.4)) 436 | await isErr(gov.connect(p1).vote(0, to18(30), 2), "vote") 437 | poll = await viewer.polls(0) 438 | expect(from18(B(poll.amount).sub(poll.minted).toFixed()) * 1).to.equal(0) 439 | }) 440 | 441 | it("should hold correct remaining fund", async () => { 442 | // set poll 443 | await jpyc.approve(a(gov), UINT_MAX) 444 | await gov.setPoll(p, a(jpyc), to18(1000), 30, []) 445 | 446 | // vote for topic 447 | await gov.connect(p1).vote(0, to18(100), 2, "vote") 448 | 449 | // update item topic 450 | await market.connect(p3).updateItem(a(nft), 2, [2], "update") 451 | 452 | // get pair token 2 453 | const pair2 = await viewer.getPair(0, 2) 454 | const pToken2 = new Contract(pair2, _IERC20.abi, owner) 455 | 456 | await checkEqualty([2]) 457 | 458 | // burn for item 459 | await pToken2.connect(p1).approve(a(market), UINT_MAX) 460 | await market.connect(p1).burnFor(a(nft), 2, pair2, to18(5), "ref") 461 | expect(await jpyc.balanceOf(a(p1))).to.equal(to18(101)) 462 | expect(await jpyc.balanceOf(a(p3))).to.equal(to18(104)) 463 | expect(await jpyc.balanceOf(a(withdraw))).to.equal(to18(995)) 464 | 465 | await checkEqualty([2]) 466 | 467 | // vote for topic with shareholders 468 | const mintable = await viewer.getMintable(0, to18(30), 2) 469 | await gov.connect(p3).vote(0, to18(30), 2, "vote") 470 | expect(await pToken2.balanceOf(a(p3))).to.equal( 471 | B(mintable.mintable).minus(1).toFixed(0) 472 | ) 473 | 474 | await checkEqualty([2]) 475 | 476 | const share = (await viewer.balanceOf(a(pToken2), a(p1))).toString() * 1 477 | const minus = B((await viewer.share_sqrt(pair2, a(p1))).toString()) 478 | .mul(B((await viewer.dilution_numerator()).toString())) 479 | .div(B((await viewer.dilution_denominator()).toString())) 480 | const convertible = ( 481 | await viewer.getConvertibleAmount(a(pToken2), share, a(p1)) 482 | ).toString() 483 | const balance = (await pToken2.balanceOf(a(p1))).toString() 484 | await dex 485 | .connect(p1) 486 | .convert(a(pToken2), B(share).minus(minus).toFixed(0), "convert") 487 | const balance2 = (await pToken2.balanceOf(a(p1))).toString() 488 | expect( 489 | B(balance2) 490 | .minus(balance * 1) 491 | .toNumber() 492 | ).to.be.gt(0) 493 | 494 | await checkEqualty([2]) 495 | 496 | // close poll => claim period 497 | await gov.closePoll(0) 498 | await isErr(gov.connect(p3).vote(0, to18(30), 2, "vote")) 499 | 500 | await checkEqualty([2]) 501 | 502 | // burn for item 503 | await pToken2.connect(p1).approve(a(market), UINT_MAX) 504 | await market.connect(p1).burnFor(a(nft), 2, pair2, to18(5), "ref") 505 | expect(await jpyc.balanceOf(a(p1))).to.equal(to18(102)) 506 | expect(await jpyc.balanceOf(a(p3))).to.equal(to18(108)) 507 | expect(await jpyc.balanceOf(a(withdraw))).to.equal(to18(990)) 508 | 509 | await checkEqualty([1, 2]) 510 | }) 511 | 512 | it("should reflext VP", async () => { 513 | // set poll 514 | await jpyc.approve(a(gov), UINT_MAX) 515 | await gov.setPoll(p, a(jpyc), to18(1000), 30, []) 516 | 517 | // vote for topic 518 | expect(from18(await vp.getVP(a(p1))) * 1).to.equal(100) 519 | expect(from18(await vp.getTotalVP()) * 1).to.equal(1000) 520 | await gov.connect(p1).vote(0, to18(10), 2, "vote") 521 | expect(from18(await vp.getVP(a(p1))) * 1).to.equal(90) 522 | expect(from18(await vp.getTotalVP()) * 1).to.equal(990) 523 | }) 524 | 525 | it("should record user/item pairs", async () => { 526 | // set poll 527 | await jpyc.approve(a(gov), UINT_MAX) 528 | await gov.setPoll(p, a(jpyc), to18(1000), 30, []) 529 | 530 | // vote for topic 531 | await gov.connect(p1).vote(0, to18(10), 2, "vote") 532 | await gov.connect(p1).vote(0, to18(10), 1, "vote") 533 | await gov.connect(p1).vote(0, to18(10), 3, "vote") 534 | 535 | // update item topic 536 | await market.connect(p3).updateItem(a(nft), 2, [1, 2, 3], "update") 537 | 538 | // get pair token 2 539 | const pair2 = await viewer.getPair(0, 2) 540 | const pair1 = await viewer.getPair(0, 1) 541 | const pair3 = await viewer.getPair(0, 3) 542 | 543 | // burn for item 544 | const pToken2 = new Contract(pair2, _IERC20.abi, owner) 545 | const pToken3 = new Contract(pair3, _IERC20.abi, owner) 546 | await pToken2.connect(p1).approve(a(market), UINT_MAX) 547 | await pToken3.connect(p1).approve(a(market), UINT_MAX) 548 | await market.connect(p1).burnFor(a(nft), 2, pair2, to18(5), "ref") 549 | await market.connect(p1).burnFor(a(nft), 2, pair3, to18(5), "ref") 550 | expect(await viewer.user_pairs(a(p1))).to.eql([pair2, pair1, pair3]) 551 | expect(await viewer.item_pairs(a(nft), 2)).to.eql([pair2, pair3]) 552 | }) 553 | 554 | it.only("should aggregate", async () => { 555 | // set poll 556 | await jpyc.approve(a(gov), UINT_MAX) 557 | await gov.setPoll(p, a(jpyc), to18(1000), 30, []) 558 | 559 | // vote for topic 560 | await gov.connect(p1).vote(0, to18(10), 2, "vote") 561 | await gov.connect(p1).vote(0, to18(10), 1, "vote") 562 | await gov.connect(p1).vote(0, to18(10), 3, "vote") 563 | 564 | // update item topic 565 | await market.connect(p3).updateItem(a(nft), 2, [1, 2, 3], "update") 566 | 567 | // get pair token 2 568 | const pair2 = await viewer.getPair(0, 2) 569 | const pair1 = await viewer.getPair(0, 1) 570 | const pair3 = await viewer.getPair(0, 3) 571 | 572 | // burn for item 573 | const pToken2 = new Contract(pair2, _IERC20.abi, owner) 574 | const pToken3 = new Contract(pair3, _IERC20.abi, owner) 575 | await pToken2.connect(p1).approve(a(market), UINT_MAX) 576 | await pToken3.connect(p1).approve(a(market), UINT_MAX) 577 | await market.connect(p1).burnFor(a(nft), 2, pair2, to18(5), "ref") 578 | await market.connect(p1).burnFor(a(nft), 2, pair3, to18(5), "ref") 579 | expect((await aggr.infoTopic("TOPIC1")).topic.toString() * 1).to.equal(2) 580 | expect(from18((await aggr.infoVote(0, to18(5), 2, a(p1))).balances[1]) * 1) 581 | .to.be.gt(7) 582 | .lt(8) 583 | expect( 584 | (await aggr.infoUser(a(p1), [a(jpyc)])).topics[0].toString() * 1 585 | ).to.equal(2) 586 | console.log(await aggr.infoItem(a(nft), 2, a(p1), [a(jpyc), a(doggod)])) 587 | expect( 588 | (await aggr.infoItem(a(nft), 2, a(p1), [a(jpyc), a(doggod)])) 589 | .votable_pairs.length 590 | ).to.equal(6) 591 | const tokens = (await aggr.infoUser(a(p1), [a(jpyc), a(doggod)])).pairs 592 | expect((await aggr.infoDEX(tokens, a(p1))).per[1].toString() * 1).to.equal( 593 | 0 594 | ) 595 | expect( 596 | (await aggr.infoBudgets([pair1, pair2, pair3])).tokens.length 597 | ).to.equal(6) 598 | }) 599 | }) 600 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | const B = require("big.js") 2 | const { expect } = require("chai") 3 | const { ethers } = require("hardhat") 4 | const { utils } = ethers 5 | 6 | module.exports.to18 = n => utils.parseEther(B(n).toFixed()) 7 | 8 | module.exports.from18 = utils.formatEther 9 | 10 | module.exports.to32 = utils.formatBytes32String 11 | 12 | module.exports.from32 = utils.parseBytes32String 13 | 14 | module.exports.UINT_MAX = B(2).pow(256).sub(1).toFixed(0) 15 | 16 | module.exports.arr = _arr => eval(`[${_arr.toString()}]`) 17 | 18 | module.exports.deploy = async (contract, ...args) => 19 | (await ethers.getContractFactory(contract)).deploy(...args) 20 | 21 | module.exports.a = obj => obj.address 22 | 23 | module.exports.isErr = async fn => { 24 | let err = false 25 | try { 26 | await fn 27 | } catch (e) { 28 | err = true 29 | } 30 | expect(err).to.be.true 31 | } 32 | --------------------------------------------------------------------------------