├── migrations └── .gitkeep ├── .gitattributes ├── .solcover.js ├── .gitignore ├── .babelrc ├── test ├── helpers │ └── parseListingTitle.js ├── mocks │ ├── MockTimelockableItemRegistry.sol │ ├── RegistryMock.sol │ ├── MockStakedRegistry.sol │ ├── TestToken.sol │ ├── MockPLCRVotingChallengeFactory.sol │ ├── MockTokenCuratedRegistry.sol │ ├── MockChallengeFactory.sol │ ├── MockChallenge.sol │ └── PLCRVotingMock.sol ├── BasicRegistry.test.js ├── OwnedItemRegistry.test.js ├── TimelockableItemRegistry.test.js ├── OwnedItemRegistry.behavior.js ├── StakedRegistry.test.js ├── TimelockableItemRegistry.behavior.js ├── BasicRegistry.behavior.js ├── TokenCuratedRegistry.test.js ├── PLCRVotingChallengeFactory.test.js ├── StakedRegistry.behavior.js ├── PLCRVotingChallenge.test.js └── TokenCuratedRegistry.behavior.js ├── contracts ├── Registry │ ├── IRegistry.sol │ ├── OwnedItemRegistry.sol │ ├── TimelockableItemRegistry.sol │ ├── BasicRegistry.sol │ ├── StakedRegistry.sol │ └── TokenCuratedRegistry.sol └── Challenge │ ├── IChallengeFactory.sol │ ├── IChallenge.sol │ ├── PLCRVotingChallengeFactory.sol │ └── PLCRVotingChallenge.sol ├── zos.json ├── truffle.js ├── package.json ├── scripts └── test.sh ├── README.md ├── zos.kovan.json ├── zos.mainnet.json ├── zos.rinkeby.json └── zos.ropsten.json /migrations/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /.solcover.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | port: 8546, 3 | copyPackages: ['zeppelin-solidity'] 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | *.log 4 | lib 5 | secrets.json 6 | 7 | .zos.session 8 | zos.dev-** 9 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0"], 3 | "env": { 4 | "commonjs": { 5 | "plugins": [ 6 | ["transform-es2015-modules-commonjs"] 7 | ] 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /test/helpers/parseListingTitle.js: -------------------------------------------------------------------------------- 1 | const web3Utils = require('web3-utils') 2 | 3 | module.exports = (listingTitle) => { 4 | return web3Utils.padRight( 5 | web3Utils.fromAscii(listingTitle), 6 | 64 7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /contracts/Registry/IRegistry.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | /** 4 | * @title IRegistry 5 | * @dev An interface for registries. 6 | */ 7 | interface IRegistry { 8 | function add(bytes32 id) public; 9 | function remove(bytes32 id) public; 10 | function exists(bytes32 id) public view returns (bool item); 11 | } 12 | -------------------------------------------------------------------------------- /contracts/Challenge/IChallengeFactory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | /** 4 | * @title IChallengeFactory 5 | * @dev An interface for factory contracts that create challenges. 6 | */ 7 | interface IChallengeFactory { 8 | function createChallenge(address registry, address challenger, address itemOwner) returns (address challenge); 9 | } 10 | -------------------------------------------------------------------------------- /test/mocks/MockTimelockableItemRegistry.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import '../../contracts/Registry/TimelockableItemRegistry.sol'; 4 | 5 | contract MockTimelockableItemRegistry is TimelockableItemRegistry { 6 | 7 | function setUnlockTime(bytes32 id, uint unlockTime) public { 8 | unlockTimes[id] = unlockTime; 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /test/BasicRegistry.test.js: -------------------------------------------------------------------------------- 1 | const { shouldBehaveLikeBasicRegistry } = require('./BasicRegistry.behavior') 2 | 3 | const BasicRegistry = artifacts.require('BasicRegistry') 4 | 5 | contract('BasicRegistry', function () { 6 | 7 | beforeEach(async function () { 8 | this.registry = await BasicRegistry.new() 9 | }) 10 | 11 | shouldBehaveLikeBasicRegistry() 12 | 13 | }) 14 | -------------------------------------------------------------------------------- /test/mocks/RegistryMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import './TestToken.sol'; 4 | 5 | contract RegistryMock { 6 | TestToken public token; 7 | 8 | constructor(address _token) public { 9 | token = TestToken(_token); 10 | } 11 | 12 | function mock_approveTokenToChallenge(address challenge, uint amount) public { 13 | token.approve(challenge, amount); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /test/mocks/MockStakedRegistry.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import '../../contracts/Registry/StakedRegistry.sol'; 4 | 5 | contract MockStakedRegistry is StakedRegistry { 6 | 7 | constructor(ERC20 _token, uint _minStake) public { 8 | StakedRegistry.initialize(_token, _minStake); 9 | } 10 | 11 | function setOwnerStake(bytes32 id, uint ownerStake) public { 12 | ownerStakes[id] = ownerStake; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /test/mocks/TestToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import 'openzeppelin-eth/contracts/token/ERC20/ERC20.sol'; 4 | 5 | contract TestToken is ERC20 { 6 | constructor (address[] _accounts, uint256 _amount) 7 | public 8 | { 9 | for (uint8 i = 0; i < _accounts.length; i++) { 10 | mint(_accounts[i], _amount); 11 | } 12 | } 13 | 14 | function mint(address to, uint256 amount) public { 15 | _mint(to, amount); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /zos.json: -------------------------------------------------------------------------------- 1 | { 2 | "zosversion": "2", 3 | "name": "registry-builder", 4 | "publish": true, 5 | "version": "0.1.0", 6 | "contracts": { 7 | "BasicRegistry": "BasicRegistry", 8 | "OwnedItemRegistry": "OwnedItemRegistry", 9 | "PLCRVotingChallengeFactory": "PLCRVotingChallengeFactory", 10 | "StakedRegistry": "StakedRegistry", 11 | "TimelockableItemRegistry": "TimelockableItemRegistry", 12 | "TokenCuratedRegistry": "TokenCuratedRegistry" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/OwnedItemRegistry.test.js: -------------------------------------------------------------------------------- 1 | const { shouldBehaveLikeOwnedItemRegistry } = require('./OwnedItemRegistry.behavior') 2 | const { shouldBehaveLikeBasicRegistry } = require('./BasicRegistry.behavior') 3 | 4 | const OwnedItemRegistry = artifacts.require('OwnedItemRegistry') 5 | 6 | contract('OwnedItemRegistry', function (accounts) { 7 | 8 | beforeEach(async function () { 9 | this.registry = await OwnedItemRegistry.new() 10 | }) 11 | 12 | shouldBehaveLikeOwnedItemRegistry(accounts) 13 | shouldBehaveLikeBasicRegistry() 14 | 15 | }) -------------------------------------------------------------------------------- /test/TimelockableItemRegistry.test.js: -------------------------------------------------------------------------------- 1 | const { shouldBehaveLikeTimelockableItemRegistry } = require('./TimelockableItemRegistry.behavior') 2 | const { shouldBehaveLikeBasicRegistry } = require('./BasicRegistry.behavior') 3 | 4 | const TimelockableItemRegistry = artifacts.require('MockTimelockableItemRegistry') 5 | 6 | contract('TimelockableItemRegistry', function () { 7 | 8 | beforeEach(async function () { 9 | this.now = (await web3.eth.getBlock('latest')).timestamp 10 | this.registry = await TimelockableItemRegistry.new() 11 | }) 12 | 13 | shouldBehaveLikeTimelockableItemRegistry() 14 | shouldBehaveLikeBasicRegistry() 15 | 16 | }) -------------------------------------------------------------------------------- /test/mocks/MockPLCRVotingChallengeFactory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import '../../contracts/Challenge/PLCRVotingChallengeFactory.sol'; 4 | 5 | contract MockPLCRVotingChallengeFactory is PLCRVotingChallengeFactory { 6 | constructor( 7 | uint challengerStake, 8 | address plcrVoting, 9 | uint commitStageLength, 10 | uint revealStageLength, 11 | uint voteQuorum, 12 | uint percentVoterReward 13 | ) public { 14 | PLCRVotingChallengeFactory.initialize( 15 | challengerStake, 16 | plcrVoting, 17 | commitStageLength, 18 | revealStageLength, 19 | voteQuorum, 20 | percentVoterReward 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/OwnedItemRegistry.behavior.js: -------------------------------------------------------------------------------- 1 | const { shouldFail } = require('lk-test-helpers')(web3) 2 | const parseListingTitle = require('./helpers/parseListingTitle') 3 | 4 | const itemId = parseListingTitle('listing 001') 5 | 6 | function shouldBehaveLikeOwnedItemRegistry (accounts) { 7 | const [owner, rando] = accounts 8 | 9 | describe('behaves like an OwnedItemRegistry', function () { 10 | 11 | describe('when remove() is not called by owner', function () { 12 | it('reverts', async function () { 13 | await this.registry.add(itemId, { from: owner }) 14 | await shouldFail.reverting(this.registry.remove(itemId, { from: rando })) 15 | }) 16 | }) 17 | 18 | }) 19 | } 20 | 21 | module.exports = { 22 | shouldBehaveLikeOwnedItemRegistry 23 | } 24 | -------------------------------------------------------------------------------- /test/mocks/MockTokenCuratedRegistry.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import '../../contracts/Registry/TokenCuratedRegistry.sol'; 4 | 5 | contract MockTokenCuratedRegistry is TokenCuratedRegistry { 6 | 7 | constructor(ERC20 _token, uint _minStake, uint _applicationPeriod, IChallengeFactory _challengeFactory) public { 8 | TokenCuratedRegistry.initialize(_token, _minStake, _applicationPeriod, _challengeFactory); 9 | } 10 | 11 | function setUnlockTime(bytes32 id, uint unlockTime) public { 12 | unlockTimes[id] = unlockTime; 13 | } 14 | 15 | function setOwnerStake(bytes32 id, uint ownerStake) public { 16 | ownerStakes[id] = ownerStake; 17 | } 18 | 19 | function setChallenge(bytes32 id, IChallenge challenge) public { 20 | challenges[id] = challenge; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /contracts/Challenge/IChallenge.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | /** 4 | * @title IChallenge 5 | * @dev An interface for challenges. 6 | */ 7 | interface IChallenge { 8 | // returns the address of the challenger. 9 | function challenger() view returns (address); 10 | 11 | // closes the challenge. 12 | function close() public; 13 | 14 | // should return `true` if close() has been called. 15 | function isClosed() public view returns (bool); 16 | 17 | // indicates whether the challenge has passed. 18 | function passed() public view returns (bool); 19 | 20 | // returns the amount of tokens the challenge needs to reward participants. 21 | function fundsRequired() public view returns (uint); 22 | 23 | // returns amount of tokens that should be allocated to challenge winner 24 | function winnerReward() public view returns (uint); 25 | } 26 | -------------------------------------------------------------------------------- /test/mocks/MockChallengeFactory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import '../../contracts/Challenge/IChallengeFactory.sol'; 4 | import './MockChallenge.sol'; 5 | 6 | contract MockChallengeFactory is IChallengeFactory { 7 | 8 | address public registry; 9 | address public challenger; 10 | address public itemOwner; 11 | uint public reward; 12 | uint public fundsRequired; 13 | 14 | constructor (uint _reward, uint _fundsRequired) public { 15 | reward = _reward; 16 | fundsRequired = _fundsRequired; 17 | } 18 | 19 | function createChallenge(address _registry, address _challenger, address _itemOwner) returns (address challenge) { 20 | registry = _registry; 21 | challenger = _challenger; 22 | itemOwner = _itemOwner; 23 | MockChallenge mockChallenge = new MockChallenge(); 24 | mockChallenge.set_mock_challenger(_challenger); 25 | mockChallenge.set_mock_winnerReward(reward); 26 | mockChallenge.set_mock_fundsRequired(fundsRequired); 27 | return address(mockChallenge); 28 | } 29 | 30 | function mock_set_fundsRequired(uint _val) public { 31 | fundsRequired = _val; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contracts/Registry/OwnedItemRegistry.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "zos-lib/contracts/Initializable.sol"; 4 | import "./BasicRegistry.sol"; 5 | 6 | /** 7 | * @title OwnedItemRegistry 8 | * @dev A registry where items are only removable by an item owner. 9 | */ 10 | contract OwnedItemRegistry is Initializable, BasicRegistry { 11 | 12 | // maps item id to owner address. 13 | mapping(bytes32 => address) public owners; 14 | 15 | /** 16 | * @dev Modifier to make function callable only by item owner. 17 | * @param id The item to require ownership for. 18 | */ 19 | modifier onlyItemOwner(bytes32 id) { 20 | require(owners[id] == msg.sender); 21 | _; 22 | } 23 | 24 | /** 25 | * @dev Overrides BasicRegistry.add(), sets msg.sender as item owner. 26 | * @param id The item to add to the registry. 27 | */ 28 | function add(bytes32 id) public { 29 | super.add(id); 30 | owners[id] = msg.sender; 31 | } 32 | 33 | /** 34 | * @dev Overrides BasicRegistry.remove(), deletes item owner state. 35 | * @param id The item to remove from the registry. 36 | */ 37 | function remove(bytes32 id) public onlyItemOwner(id) { 38 | delete owners[id]; 39 | super.remove(id); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/mocks/MockChallenge.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import 'openzeppelin-eth/contracts/token/ERC20/ERC20.sol'; 4 | import '../../contracts/Challenge/IChallenge.sol'; 5 | 6 | contract MockChallenge is IChallenge { 7 | 8 | bool mock_isClosed; 9 | 10 | bool mock_passed; 11 | uint mock_winnerReward; 12 | address mock_challenger; 13 | uint mock_fundsRequired; 14 | 15 | function set_mock_passed (bool _val) { 16 | mock_passed = _val; 17 | } 18 | 19 | function set_mock_winnerReward (uint _val) { 20 | mock_winnerReward = _val; 21 | } 22 | 23 | function set_mock_challenger (address _val) { 24 | mock_challenger = _val; 25 | } 26 | 27 | function set_mock_fundsRequired(uint _val) { 28 | mock_fundsRequired = _val; 29 | } 30 | 31 | function close() public { 32 | mock_isClosed = true; 33 | } 34 | 35 | function isClosed() public view returns (bool) { 36 | return mock_isClosed; 37 | } 38 | 39 | function passed() public view returns (bool) { 40 | return mock_passed; 41 | } 42 | 43 | function winnerReward() public view returns (uint) { 44 | return mock_winnerReward; 45 | } 46 | 47 | function challenger() view returns (address) { 48 | return mock_challenger; 49 | } 50 | 51 | function fundsRequired() view returns (uint) { 52 | return mock_fundsRequired; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | require('babel-register'); 2 | require('babel-polyfill'); 3 | 4 | const HDWalletProvider = require('truffle-hdwallet-provider'); 5 | const fs = require('fs'); 6 | 7 | // first read in the secrets.json to get our mnemonic 8 | let secrets; 9 | let mnemonic; 10 | if (fs.existsSync('secrets.json')) { 11 | secrets = JSON.parse(fs.readFileSync('secrets.json', 'utf8')); 12 | mnemonic = secrets.mnemonic; 13 | } else { 14 | console.log('no secrets.json found. You can only deploy to the testrpc.'); 15 | mnemonic = ''; 16 | } 17 | 18 | module.exports = { 19 | networks: { 20 | rinkeby: { 21 | provider: new HDWalletProvider(mnemonic, 'https://rinkeby.infura.io'), 22 | network_id: '*', 23 | gas: 6000000, 24 | gasPrice: 20 * 10 ** 9, 25 | }, 26 | ropsten: { 27 | provider: new HDWalletProvider(mnemonic, 'https://ropsten.infura.io'), 28 | network_id: '*', 29 | gas: 6000000, 30 | gasPrice: 20 * 10 ** 9, 31 | }, 32 | kovan: { 33 | provider: new HDWalletProvider(mnemonic, 'https://kovan.infura.io'), 34 | network_id: '*', 35 | gas: 6000000, 36 | gasPrice: 20 * 10 ** 9, 37 | }, 38 | development: { 39 | host: 'localhost', 40 | port: 8545, 41 | network_id: '*', 42 | gas: 6000000, 43 | gasPrice: 20 * 10 ** 9, 44 | } 45 | }, 46 | }; 47 | -------------------------------------------------------------------------------- /contracts/Registry/TimelockableItemRegistry.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "zos-lib/contracts/Initializable.sol"; 4 | import "./BasicRegistry.sol"; 5 | 6 | /** 7 | * @title TimelockableItemRegistry 8 | * @dev A registry that allows items to be locked from removal. 9 | */ 10 | contract TimelockableItemRegistry is Initializable, BasicRegistry { 11 | 12 | // maps item id to a time when the item will be unlocked. 13 | mapping(bytes32 => uint) public unlockTimes; 14 | 15 | /** 16 | * @dev Overrides BasicRegistry.remove(), deletes item owner state. 17 | * @param id The item to remove from the registry. 18 | */ 19 | function remove(bytes32 id) public { 20 | require(!isLocked(id)); 21 | delete unlockTimes[id]; 22 | super.remove(id); 23 | } 24 | 25 | /** 26 | * @dev Checks if an item is locked, reverts if the item does not exist. 27 | * @param id The item to check. 28 | * @return A bool indicating whether the item is locked. 29 | */ 30 | function isLocked(bytes32 id) public view returns (bool) { 31 | require(_exists(id)); 32 | return _isLocked(id); 33 | } 34 | 35 | /** 36 | * @dev Internal function to check if an item is locked. 37 | * @param id The item to check. 38 | * @return A bool indicating whether the item is locked. 39 | */ 40 | function _isLocked(bytes32 id) internal view returns (bool) { 41 | return unlockTimes[id] > now; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/StakedRegistry.test.js: -------------------------------------------------------------------------------- 1 | const { shouldFail, constants } = require('lk-test-helpers')(web3) 2 | const { shouldBehaveLikeStakedRegistry } = require('./StakedRegistry.behavior') 3 | const { shouldBehaveLikeOwnedItemRegistry } = require('./OwnedItemRegistry.behavior') 4 | const { shouldBehaveLikeBasicRegistry } = require('./BasicRegistry.behavior') 5 | 6 | const StakedRegistry = artifacts.require('MockStakedRegistry') 7 | const TestToken = artifacts.require('TestToken') 8 | 9 | const { ZERO_ADDRESS } = constants 10 | 11 | contract('StakedRegistry', function (accounts) { 12 | const [owner, owner2, rando] = accounts 13 | const initialBalance = 100 * 10 ** 18 14 | const minStake = 10 * 10 ** 18 15 | 16 | describe('when deployed with valid parameters', function () { 17 | beforeEach(async function () { 18 | this.token = await TestToken.new( 19 | [owner, owner2, rando], 20 | initialBalance 21 | ) 22 | this.registry = await StakedRegistry.new(this.token.address, minStake) 23 | await this.token.approve(this.registry.address, minStake, { from: owner }) 24 | }) 25 | 26 | shouldBehaveLikeStakedRegistry(minStake, initialBalance, accounts) 27 | shouldBehaveLikeOwnedItemRegistry(accounts) 28 | shouldBehaveLikeBasicRegistry() 29 | }) 30 | 31 | describe('when deployed with 0x0 token address', function () { 32 | it('reverts', async function () { 33 | await shouldFail.reverting(StakedRegistry.new(ZERO_ADDRESS, minStake)) 34 | }) 35 | }) 36 | 37 | }) 38 | -------------------------------------------------------------------------------- /contracts/Challenge/PLCRVotingChallengeFactory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "zos-lib/contracts/Initializable.sol"; 4 | import "./IChallengeFactory.sol"; 5 | import "./PLCRVotingChallenge.sol"; 6 | 7 | /** 8 | * @title PLCRVotingChallengeFactory 9 | * @dev A challenge factory for creating PLCRVotingChallenge contracts. 10 | */ 11 | contract PLCRVotingChallengeFactory is Initializable, IChallengeFactory { 12 | 13 | uint public challengerStake; 14 | address public plcrVoting; 15 | uint public commitStageLength; 16 | uint public revealStageLength; 17 | uint public voteQuorum; 18 | uint public percentVoterReward; 19 | 20 | event PLCRVotingChallengeCreated(address challenge, address registry, address challenger); 21 | 22 | function initialize( 23 | uint _challengerStake, 24 | address _plcrVoting, 25 | uint _commitStageLength, 26 | uint _revealStageLength, 27 | uint _voteQuorum, 28 | uint _percentVoterReward 29 | ) 30 | initializer 31 | public 32 | { 33 | challengerStake = _challengerStake; 34 | plcrVoting = _plcrVoting; 35 | commitStageLength = _commitStageLength; 36 | revealStageLength = _revealStageLength; 37 | voteQuorum = _voteQuorum; 38 | percentVoterReward = _percentVoterReward; 39 | } 40 | 41 | function createChallenge(address registry, address challenger, address itemOwner) public returns (address challenge) { 42 | challenge = new PLCRVotingChallenge( 43 | challenger, 44 | itemOwner, 45 | challengerStake, 46 | registry, 47 | plcrVoting, 48 | commitStageLength, 49 | revealStageLength, 50 | voteQuorum, 51 | percentVoterReward 52 | ); 53 | 54 | emit PLCRVotingChallengeCreated(challenge, registry, challenger); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "registry-builder", 3 | "description": "Open source library for generic registries and token curated registries smart contracts. You can use these contracts to deploy your own TCR or use them as an extension onto your personalized registry contract.", 4 | "version": "0.1.0", 5 | "homepage": "https://github.com/levelkdev/registry-builder", 6 | "license": "MIT", 7 | "files": [ 8 | "build", 9 | "contracts", 10 | "test", 11 | "zos.json", 12 | "zos.*.json" 13 | ], 14 | "dependencies": { 15 | "openzeppelin-eth": "^2.0.0", 16 | "plcr-voting": "^0.1.2", 17 | "zos-lib": "^2.0.0" 18 | }, 19 | "devDependencies": { 20 | "babel-cli": "^6.24.1", 21 | "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", 22 | "babel-plugin-transform-runtime": "^6.23.0", 23 | "babel-polyfill": "^6.26.0", 24 | "babel-preset-es2015": "^6.24.1", 25 | "babel-preset-stage-0": "^6.24.1", 26 | "babel-register": "^6.26.0", 27 | "chai": "^4.1.2", 28 | "chai-bignumber": "^2.0.2", 29 | "cross-env": "^5.1.4", 30 | "dotenv": "6.1.0", 31 | "ganache-cli": "6.1.8", 32 | "lk-test-helpers": "0.1.7", 33 | "moment": "^2.22.0", 34 | "snazzy": "^7.1.1", 35 | "standard": "^10.0.3", 36 | "truffle": "4.1.14", 37 | "truffle-hdwallet-provider": "^0.0.6", 38 | "web3-utils": "1.0.0-beta.36" 39 | }, 40 | "scripts": { 41 | "cleanup": "rm -rf build", 42 | "compile": "npm run cleanup && truffle compile --all", 43 | "deploy": "npm run cleanup && truffle migrate --reset", 44 | "deploy-rinkeby": "npm run cleanup && truffle migrate --reset --network rinkeby", 45 | "test": "scripts/test.sh", 46 | "test:coverage": "npm run solidity-coverage", 47 | "lint": "standard --verbose | snazzy" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/TimelockableItemRegistry.behavior.js: -------------------------------------------------------------------------------- 1 | const { shouldFail } = require('lk-test-helpers')(web3) 2 | const parseListingTitle = require('./helpers/parseListingTitle') 3 | 4 | const itemId = parseListingTitle('listing 001') 5 | 6 | function shouldBehaveLikeTimelockableItemRegistry () { 7 | 8 | describe('behaves like a TimelockableItemRegistry', function () { 9 | 10 | describe('when remove() is called on a locked item', function () { 11 | it('reverts', async function () { 12 | await this.registry.add(itemId) 13 | await this.registry.setUnlockTime(itemId, this.now + 1000) 14 | await shouldFail.reverting(this.registry.remove(itemId)) 15 | }) 16 | }) 17 | 18 | describe('isLocked()', function () { 19 | describe('when item exists', function () { 20 | beforeEach(async function () { 21 | await this.registry.add(itemId) 22 | }) 23 | 24 | describe('when item unlock time is less than `now`', function () { 25 | it('returns true', async function () { 26 | await this.registry.setUnlockTime(itemId, this.now + 1000) 27 | expect(await this.registry.isLocked(itemId)).to.be.true 28 | }) 29 | }) 30 | 31 | describe('when item unlock time is greater than `now`', function () { 32 | it('returns false', async function () { 33 | await this.registry.setUnlockTime(itemId, this.now - 1000) 34 | expect(await this.registry.isLocked(itemId)).to.be.false 35 | }) 36 | }) 37 | }) 38 | 39 | describe('when item does not exist', function () { 40 | it('reverts', async function () { 41 | await shouldFail.reverting(this.registry.isLocked(itemId)) 42 | }) 43 | }) 44 | }) 45 | }) 46 | 47 | } 48 | 49 | module.exports = { 50 | shouldBehaveLikeTimelockableItemRegistry 51 | } 52 | -------------------------------------------------------------------------------- /contracts/Registry/BasicRegistry.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "zos-lib/contracts/Initializable.sol"; 4 | import "./IRegistry.sol"; 5 | 6 | /** 7 | * @title BasicRegistry 8 | * @dev A simple implementation of IRegistry, allows any address to add/remove items 9 | */ 10 | contract BasicRegistry is Initializable, IRegistry { 11 | 12 | mapping(bytes32 => bool) items; 13 | 14 | event ItemAdded(bytes32 id); 15 | 16 | event ItemRemoved(bytes32 id); 17 | 18 | /** 19 | * @dev Adds an item to the registry. 20 | * @param id The item to add to the registry, must be unique. 21 | */ 22 | function add(bytes32 id) public { 23 | require(!_exists(id)); 24 | items[id] = true; 25 | ItemAdded(id); 26 | } 27 | 28 | /** 29 | * @dev Removes an item from the registry, reverts if the item does not exist. 30 | * @param id The item to remove from the registry. 31 | */ 32 | function remove(bytes32 id) public { 33 | require(_exists(id)); 34 | _remove(id); 35 | } 36 | 37 | /** 38 | * @dev Checks if an item exists in the registry. 39 | * @param id The item to check. 40 | * @return A bool indicating whether the item exists. 41 | */ 42 | function exists(bytes32 id) public view returns (bool) { 43 | return _exists(id); 44 | } 45 | 46 | /** 47 | * @dev Internal function to check if an item exists in the registry. 48 | * @param id The item to check. 49 | * @return A bool indicating whether the item exists. 50 | */ 51 | function _exists(bytes32 id) internal view returns (bool) { 52 | return items[id]; 53 | } 54 | 55 | /** 56 | * @dev Internal function to remove an item from the registry. 57 | * @param id The item to remove from the registry. 58 | */ 59 | function _remove(bytes32 id) internal { 60 | items[id] = false; 61 | ItemRemoved(id); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /test/mocks/PLCRVotingMock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | contract PLCRVotingMock { 4 | address public token; 5 | uint public pollNonce; 6 | bool mock_isPassed; 7 | bool mock_pollEnded; 8 | uint mock_getTotalNumberOfTokensForWinningOption; 9 | uint mock_getNumPassingTokens; 10 | 11 | constructor(address _token) public { 12 | token = _token; 13 | pollNonce = 0; 14 | } 15 | 16 | // ========================= 17 | // startPoll Mock 18 | // ========================= 19 | function startPoll (uint voteQuorum, 20 | uint commitStageLength, 21 | uint revealStageLength 22 | ) public returns (uint) { 23 | pollNonce += 1; 24 | return pollNonce; 25 | } 26 | 27 | 28 | // ========================= 29 | // pollEnded Mock 30 | // ========================= 31 | function set_mock_pollEnded(bool ended) public { 32 | mock_pollEnded = ended; 33 | } 34 | 35 | function pollEnded(uint pollId) constant public returns (bool) { 36 | return mock_pollEnded; 37 | } 38 | 39 | 40 | 41 | // ========================= 42 | // isPassed Mock 43 | // ========================= 44 | function set_mock_isPassed(bool passed) public { 45 | mock_isPassed = passed; 46 | } 47 | 48 | function isPassed(uint pollId) public view returns (bool) { 49 | return mock_isPassed; 50 | } 51 | 52 | 53 | 54 | // ============================================ 55 | // getTotalNumberOfTokensForWinningOption Mock 56 | // ============================================ 57 | function set_mock_getTotalNumberOfTokensForWinningOption(uint winningTokenAmount) public { 58 | mock_getTotalNumberOfTokensForWinningOption = winningTokenAmount; 59 | } 60 | 61 | function getTotalNumberOfTokensForWinningOption(uint pollId) public returns (uint) { 62 | return mock_getTotalNumberOfTokensForWinningOption; 63 | } 64 | 65 | 66 | 67 | // =========================== 68 | // getNumPassingTokens Mock 69 | // =========================== 70 | function set_mock_getNumPassingTokens(uint numPassingTokens) public { 71 | mock_getNumPassingTokens = numPassingTokens; 72 | } 73 | 74 | function getNumPassingTokens(address voter, uint pollId) public returns (uint) { 75 | return mock_getNumPassingTokens; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Exit script as soon as a command fails. 4 | set -o errexit 5 | 6 | # Executes cleanup function at script exit. 7 | trap cleanup EXIT 8 | 9 | cleanup() { 10 | # Kill the ganache instance that we started (if we started one and if it's still running). 11 | if [ -n "$ganache_pid" ] && ps -p $ganache_pid > /dev/null; then 12 | kill -9 $ganache_pid 13 | fi 14 | } 15 | 16 | if [ "$SOLIDITY_COVERAGE" = true ]; then 17 | ganache_port=8555 18 | else 19 | ganache_port=8545 20 | fi 21 | 22 | ganache_running() { 23 | nc -z localhost "$ganache_port" 24 | } 25 | 26 | start_ganache() { 27 | # We define 10 accounts with balance 1M ether, needed for high-value tests. 28 | local accounts=( 29 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501200,1000000000000000000000000" 30 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501201,1000000000000000000000000" 31 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501202,1000000000000000000000000" 32 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501203,1000000000000000000000000" 33 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501204,1000000000000000000000000" 34 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501205,1000000000000000000000000" 35 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501206,1000000000000000000000000" 36 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501207,1000000000000000000000000" 37 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501208,1000000000000000000000000" 38 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501209,1000000000000000000000000" 39 | ) 40 | 41 | if [ "$SOLIDITY_COVERAGE" = true ]; then 42 | node_modules/.bin/testrpc-sc --gasLimit 0xfffffffffff --port "$ganache_port" "${accounts[@]}" > /dev/null & 43 | else 44 | node_modules/.bin/ganache-cli --gasLimit 0xfffffffffff "${accounts[@]}" > /dev/null & 45 | fi 46 | 47 | ganache_pid=$! 48 | } 49 | 50 | if ganache_running; then 51 | echo "Using existing ganache instance" 52 | else 53 | echo "Starting our own ganache instance" 54 | start_ganache 55 | fi 56 | 57 | if [ "$SOLC_NIGHTLY" = true ]; then 58 | echo "Downloading solc nightly" 59 | wget -q https://raw.githubusercontent.com/ethereum/solc-bin/gh-pages/bin/soljson-nightly.js -O /tmp/soljson.js && find . -name soljson.js -exec cp /tmp/soljson.js {} \; 60 | fi 61 | 62 | truffle version 63 | 64 | if [ "$SOLIDITY_COVERAGE" = true ]; then 65 | node_modules/.bin/solidity-coverage 66 | 67 | if [ "$CONTINUOUS_INTEGRATION" = true ]; then 68 | cat coverage/lcov.info | node_modules/.bin/coveralls 69 | fi 70 | else 71 | node_modules/.bin/truffle test "$@" 72 | fi 73 | -------------------------------------------------------------------------------- /contracts/Registry/StakedRegistry.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "zos-lib/contracts/Initializable.sol"; 4 | import "openzeppelin-eth/contracts/math/SafeMath.sol"; 5 | import "openzeppelin-eth/contracts/token/ERC20/ERC20.sol"; 6 | import "./OwnedItemRegistry.sol"; 7 | 8 | /** 9 | * @title StakedRegistry 10 | * @dev A registry that lets owners stake tokens on items. 11 | */ 12 | contract StakedRegistry is Initializable, OwnedItemRegistry { 13 | using SafeMath for uint; 14 | 15 | // token used for item stake. 16 | ERC20 public token; 17 | 18 | // minimum required amount of tokens to add an item. 19 | uint public minStake; 20 | 21 | // maps item id to owner stake amount. 22 | mapping(bytes32 => uint) public ownerStakes; 23 | 24 | event NewStake(bytes32 indexed itemid, uint totalStake); 25 | 26 | event StakeIncreased(bytes32 indexed itemid, uint totalStake, uint increaseAmount); 27 | 28 | event StakeDecreased(bytes32 indexed itemid, uint totalStake, uint decreaseAmount); 29 | 30 | function initialize(ERC20 _token, uint _minStake) initializer public { 31 | require(address(_token) != 0x0); 32 | token = _token; 33 | minStake = _minStake; 34 | } 35 | 36 | /** 37 | * @dev Overrides OwnedItemRegistry.add(), transfers tokens from owner, sets stake. 38 | * @param id The item to add to the registry. 39 | */ 40 | function add(bytes32 id) public { 41 | require(token.transferFrom(msg.sender, this, minStake)); 42 | super.add(id); 43 | ownerStakes[id] = minStake; 44 | emit NewStake(id, ownerStakes[id]); 45 | } 46 | 47 | /** 48 | * @dev Overrides BasicRegistry.add(), tranfers tokens to owner, deletes stake. 49 | * @param id The item to remove from the registry. 50 | */ 51 | function remove(bytes32 id) public { 52 | require(token.transfer(msg.sender, ownerStakes[id])); 53 | delete ownerStakes[id]; 54 | super.remove(id); 55 | } 56 | 57 | /** 58 | * @dev Increases stake for an item, only callable by item owner. 59 | * @param id The item to increase stake for. 60 | * @param stakeAmount The amount of tokens to add to the current stake. 61 | */ 62 | function increaseStake(bytes32 id, uint stakeAmount) public onlyItemOwner(id) { 63 | require(token.transferFrom(msg.sender, this, stakeAmount)); 64 | ownerStakes[id] = ownerStakes[id].add(stakeAmount); 65 | emit StakeIncreased(id, ownerStakes[id], stakeAmount); 66 | } 67 | 68 | /** 69 | * @dev Decreases stake for an item, only callable by item owner. 70 | * @param id The item to decrease stake for. 71 | * @param stakeAmount The amount of tokens to remove from the current stake. 72 | */ 73 | function decreaseStake(bytes32 id, uint stakeAmount) public onlyItemOwner(id) { 74 | require(ownerStakes[id].sub(stakeAmount) > minStake); 75 | require(token.transfer(msg.sender, stakeAmount)); 76 | ownerStakes[id] = ownerStakes[id].sub(stakeAmount); 77 | emit StakeDecreased(id, ownerStakes[id], stakeAmount); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /test/BasicRegistry.behavior.js: -------------------------------------------------------------------------------- 1 | const { 2 | expectEvent, 3 | shouldFail 4 | } = require('lk-test-helpers')(web3) 5 | const parseListingTitle = require('./helpers/parseListingTitle') 6 | 7 | const itemId = parseListingTitle('listing 001') 8 | 9 | function shouldBehaveLikeBasicRegistry(supportedFunctions = [ 10 | 'add', 11 | 'remove', 12 | 'exists' 13 | ]) { 14 | describe('behaves like a BasicRegistry', function () { 15 | if (supportedFunctions.includes('add')) { 16 | describe('add()', function () { 17 | 18 | describe('when the given id is not in the items mapping', function () { 19 | beforeEach(async function () { 20 | this.logs = (await this.registry.add(itemId)).logs 21 | }) 22 | 23 | it('adds the id to the items mapping', async function () { 24 | expect(await this.registry.exists(itemId)).to.be.true 25 | }) 26 | 27 | it('emits an ItemAdded event', function () { 28 | expectEvent.inLogs(this.logs, 'ItemAdded', { id: itemId }) 29 | }) 30 | }) 31 | 32 | describe('when the given id is in the items mapping', function () { 33 | it('reverts', async function () { 34 | await this.registry.add(itemId) 35 | await shouldFail.reverting(this.registry.add(itemId)) 36 | }) 37 | }) 38 | }) 39 | } 40 | 41 | if (supportedFunctions.includes('remove')) { 42 | describe('remove()', function () { 43 | 44 | describe('when the given id is in the items mapping', function () { 45 | beforeEach(async function () { 46 | await this.registry.add(itemId) 47 | this.logs = (await this.registry.remove(itemId)).logs 48 | }) 49 | 50 | it('removes the id from the items mapping', async function () { 51 | expect(await this.registry.exists(itemId)).to.be.false 52 | }) 53 | 54 | it('emits an ItemRemoved event', function () { 55 | expectEvent.inLogs(this.logs, 'ItemRemoved', { id: itemId }) 56 | }) 57 | }) 58 | 59 | describe('when the given id is not in the items mapping', function () { 60 | it('reverts', async function () { 61 | await shouldFail.reverting(this.registry.remove(itemId)) 62 | }) 63 | }) 64 | 65 | }) 66 | } 67 | 68 | if (supportedFunctions.includes('exists')) { 69 | describe('exists()', function () { 70 | 71 | describe('when given id that exists', function () { 72 | it('returns true', async function () { 73 | await this.registry.add(itemId) 74 | expect(await this.registry.exists(itemId)).to.be.true 75 | }) 76 | }) 77 | 78 | describe('when given id that does not exist', function () { 79 | it('returns false', async function () { 80 | expect(await this.registry.exists(itemId)).to.be.false 81 | }) 82 | }) 83 | }) 84 | } 85 | }) 86 | } 87 | 88 | module.exports = { 89 | shouldBehaveLikeBasicRegistry 90 | } 91 | -------------------------------------------------------------------------------- /test/TokenCuratedRegistry.test.js: -------------------------------------------------------------------------------- 1 | const { shouldFail, constants } = require('lk-test-helpers')(web3) 2 | const { shouldBehaveLikeTokenCuratedRegistry } = require('./TokenCuratedRegistry.behavior') 3 | const { shouldBehaveLikeTimelockableItemRegistry } = require('./TimelockableItemRegistry.behavior') 4 | const { shouldBehaveLikeStakedRegistry } = require('./StakedRegistry.behavior') 5 | const { shouldBehaveLikeOwnedItemRegistry } = require('./OwnedItemRegistry.behavior') 6 | const { shouldBehaveLikeBasicRegistry } = require('./BasicRegistry.behavior') 7 | 8 | const TestToken = artifacts.require('TestToken') 9 | const ChallengeFactory = artifacts.require('MockChallengeFactory') 10 | const TokenCuratedRegistry = artifacts.require('MockTokenCuratedRegistry') 11 | 12 | const { ZERO_ADDRESS } = constants 13 | 14 | contract('TokenCuratedRegistry', function (accounts) { 15 | 16 | const [owner, challenger, rando] = accounts 17 | const initialBalance = 100 * 10 ** 18 18 | const minStake = 10 * 10 ** 18 19 | const mockChallengeReward = minStake * 2 * 75 / 100 20 | const mockRequiredFunds = minStake 21 | const applicationPeriod = 60 * 60 22 | 23 | beforeEach(async function () { 24 | this.now = (await web3.eth.getBlock('latest')).timestamp 25 | this.token = await TestToken.new( 26 | [owner, challenger, rando], 27 | initialBalance 28 | ) 29 | this.challengeFactory = await ChallengeFactory.new(mockChallengeReward, mockRequiredFunds) 30 | }) 31 | 32 | describe('when challenge factory address is zero', function () { 33 | it('contract deployment reverts', async function () { 34 | await shouldFail.reverting( 35 | TokenCuratedRegistry.new( 36 | this.token.address, 37 | minStake, 38 | applicationPeriod, 39 | ZERO_ADDRESS 40 | ) 41 | ) 42 | }) 43 | }) 44 | 45 | describe('when application period is greater than 0', function () { 46 | beforeEach(async function () { 47 | this.registry = await TokenCuratedRegistry.new( 48 | this.token.address, 49 | minStake, 50 | applicationPeriod, 51 | this.challengeFactory.address 52 | ) 53 | await this.token.approve(this.registry.address, minStake, { from: owner }) 54 | }) 55 | 56 | shouldBehaveLikeTokenCuratedRegistry({ 57 | minStake, 58 | mockChallengeReward, 59 | initialBalance, 60 | applicationPeriod, 61 | accounts 62 | }) 63 | }) 64 | 65 | describe('when application period is 0', function () { 66 | beforeEach(async function () { 67 | this.registry = await TokenCuratedRegistry.new( 68 | this.token.address, 69 | minStake, 70 | 0, // setting applicationPeriod to 0 puts added items into an unlocked state 71 | this.challengeFactory.address 72 | ) 73 | await this.token.approve(this.registry.address, minStake, { from: owner }) 74 | }) 75 | 76 | shouldBehaveLikeTimelockableItemRegistry(accounts) 77 | shouldBehaveLikeStakedRegistry(minStake, initialBalance, accounts) 78 | shouldBehaveLikeOwnedItemRegistry(accounts) 79 | shouldBehaveLikeBasicRegistry() 80 | }) 81 | 82 | }) 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # registry-builder 2 | 3 | #### *** DISCLAIMER: Current version contracts are not thoroughly tested or audited. Use at own risk *** 4 | 5 | ## About 6 | 7 | This library aims to be a readable and modular library for registries and TCR's. Ideally developers can use these contracts to deploy their TCR or use these contracts as an extension onto their personalized registry contract. 8 | 9 | ## Setup 10 | 11 | Install node modules: 12 | ``` 13 | $ npm install 14 | ``` 15 | 16 | Compile contracts: 17 | ``` 18 | $ npm run compile 19 | ``` 20 | 21 | Run tests: 22 | 23 | ``` 24 | $ npm run test 25 | ``` 26 | 27 | ## Using from ZeppelinOS 28 | 29 | You can create a TCR instance using [ZeppelinOS](http://zeppelinos.org/) by linking to this [EVM package](https://docs.zeppelinos.org/docs/linking.html). This will use the logic contracts already deployed to mainnet, kovan, ropsten, or rinkeby, reducing your gas deployment costs. 30 | 31 | As an example, to create an instance of a registry using ZeppelinOS, run the following commands: 32 | ```bash 33 | $ npm install -g zos 34 | $ zos init YourProject 35 | $ zos link registry-builder 36 | $ zos push --network rinkeby 37 | > Connecting to dependency registry-builder 0.1.0 38 | $ zos create registry-builder/OwnedItemRegistry --network rinkeby --from $SENDER 39 | > Instance created at ADDRESS 40 | ``` 41 | 42 | It is strongly suggested to [use a non-default address](https://docs.zeppelinos.org/docs/pattern.html#transparent-proxies-and-function-clashes) (this is, not the first address in your node) as `$SENDER`. 43 | 44 | Check out this [**example project**](https://github.com/levelkdev/registry-builder-example) for creating a [more interesting full TCR](https://github.com/levelkdev/registry-builder-example/blob/master/deploy/deploy.js) instead of a basic owned item registry. 45 | 46 | ## Contract Structure 47 | 48 | ### Registry Interface 49 | 50 | `IRegistry.sol ` 51 | 52 | ``` 53 | interface IRegistry { 54 | function add(bytes32 data) public; 55 | function remove(bytes32 data) public; 56 | function exists(bytes32 data) public view returns (bool item); 57 | } 58 | ``` 59 | 60 | ### Challenge Interface 61 | `IChallengeFactory.sol` 62 | 63 | ``` 64 | interface IChallengeFactory { 65 | function create(address registry, address challenger, address applicant) returns (address challenge); 66 | } 67 | ``` 68 | 69 | `IChallenge.sol` 70 | 71 | ``` 72 | interface IChallenge { 73 | // returns the address of the challenger 74 | function challenger() view returns (address); 75 | 76 | // returns true if the challenge has ended 77 | function close() public; 78 | 79 | // returns whether challenge has been officially closed 80 | function isClosed() public view returns (bool); 81 | 82 | // returns true if the challenge has passed 83 | // reverts if challenge has not been closed 84 | function passed() public view returns (bool); 85 | 86 | // @notice returns the amount of tokens the challenge must 87 | // obtain to carry out functionality 88 | function fundsRequired() public view returns (uint); 89 | 90 | // @dev returns amount to be rewarded to challenge winner 91 | function winnerReward() public view returns (uint); 92 | } 93 | ``` 94 | 95 | 96 | ## Code Review 97 | * Notes on current state of this repository: https://docs.google.com/document/d/1vjaWW7izisc2QNlZEpti4BPh8yJTOGo3Wu9GNgaRI1A/ 98 | * Feel free to create an Issue with review, questions, or concerns. 99 | -------------------------------------------------------------------------------- /test/PLCRVotingChallengeFactory.test.js: -------------------------------------------------------------------------------- 1 | import lkTestHelpers from 'lk-test-helpers' 2 | const { expectEvent } = lkTestHelpers(web3) 3 | const BigNumber = require('bignumber.js'); 4 | 5 | const RegistryMock = artifacts.require('RegistryMock.sol') 6 | const Token = artifacts.require('TestToken.sol') 7 | const PLCRVoting = artifacts.require('PLCRVotingMock.sol') 8 | const PLCRVotingChallenge = artifacts.require('PLCRVotingChallenge.sol') 9 | const PLCRVotingChallengeFactory = artifacts.require('MockPLCRVotingChallengeFactory.sol') 10 | 11 | contract('PLCRVotingChallengeFactory', (accounts) => { 12 | let plcrVoting, plcrVotingChallengeFactory, token, registry, challenger, itemOwner 13 | 14 | 15 | const mockAddresses = [ 16 | '0x4e0100882b427b3be1191c5a7c7e79171b8a24dd', 17 | '0x6512df5964f1578a8164ce93a3238f2b11485d1c', 18 | '0x687355ca7a320e5420a3db5ae59ef662e4146786' 19 | ] 20 | 21 | const CHALLENGER_STAKE = 10 * 10 ** 18 22 | const COMMIT_STAGE_LENGTH = 60 * 60 * 24 23 | const REVEAL_STAGE_LENGTH = 60 * 60 * 24 * 7 24 | const VOTE_QUORUM = 51 25 | const PERCENT_VOTER_REWARD = 15 26 | 27 | beforeEach(async () => { 28 | token = await Token.new([accounts[0], accounts[1], accounts[2]], 100 * 10 ** 18) 29 | plcrVoting = await PLCRVoting.new(token.address) 30 | registry = await RegistryMock.new(token.address) 31 | challenger = accounts[1] 32 | itemOwner = accounts[2] 33 | }) 34 | 35 | describe('when deployed with valid parameters', () => { 36 | beforeEach(async () => { 37 | plcrVotingChallengeFactory = await initializeFactory() 38 | }) 39 | 40 | it('sets the correct challengerStake', async () => { 41 | expect((await plcrVotingChallengeFactory.challengerStake()).toNumber()).to.equal(CHALLENGER_STAKE) 42 | }) 43 | 44 | it('sets the correct plcrVoting', async () => { 45 | expect(await plcrVotingChallengeFactory.plcrVoting()).to.equal(plcrVoting.address) 46 | }) 47 | 48 | it('sets the correct commitStageLength', async () => { 49 | expect((await plcrVotingChallengeFactory.commitStageLength()).toNumber()).to.equal(COMMIT_STAGE_LENGTH) 50 | }) 51 | 52 | it('sets the correct revealStageLength', async () => { 53 | expect((await plcrVotingChallengeFactory.revealStageLength()).toNumber()).to.equal(REVEAL_STAGE_LENGTH) 54 | }) 55 | 56 | it('sets the correct voteQuorum', async () => { 57 | expect((await plcrVotingChallengeFactory.voteQuorum()).toNumber()).to.equal(VOTE_QUORUM) 58 | 59 | }) 60 | it('sets the correct percentVoterReward', async () => { 61 | expect((await plcrVotingChallengeFactory.percentVoterReward()).toNumber()).to.equal(PERCENT_VOTER_REWARD) 62 | }) 63 | }) 64 | 65 | describe('createChallenge()', async () => { 66 | it('creates a PLCRVotingChallenge with all the correct parameters',async () => { 67 | plcrVotingChallengeFactory = await initializeFactory() 68 | 69 | const { logs } = await plcrVotingChallengeFactory.createChallenge(registry.address, challenger, itemOwner) 70 | const event = logs.find(e => e.event === 'PLCRVotingChallengeCreated') 71 | const challengeAddress = event.args.challenge 72 | 73 | let challenge = PLCRVotingChallenge.at(challengeAddress) 74 | expect(await challenge.registry()).to.equal(registry.address) 75 | expect(await challenge.challenger()).to.equal(challenger) 76 | expect(await challenge.itemOwner()).to.equal(itemOwner) 77 | expect((await challenge.challengerStake()).toNumber()).to.equal(CHALLENGER_STAKE) 78 | expect(await challenge.plcrVoting()).to.equal(plcrVoting.address) 79 | }) 80 | 81 | it('emits a PLCRVotingChallengeCreated event', async () => { 82 | const { logs } = await plcrVotingChallengeFactory.createChallenge(registry.address, challenger, itemOwner) 83 | await expectEvent.inLogs(logs, 'PLCRVotingChallengeCreated') 84 | }) 85 | }) 86 | 87 | async function initializeFactory() { 88 | return await PLCRVotingChallengeFactory.new( 89 | CHALLENGER_STAKE, 90 | plcrVoting.address, 91 | COMMIT_STAGE_LENGTH, 92 | REVEAL_STAGE_LENGTH, 93 | VOTE_QUORUM, 94 | PERCENT_VOTER_REWARD 95 | ) 96 | } 97 | }) 98 | -------------------------------------------------------------------------------- /contracts/Registry/TokenCuratedRegistry.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "zos-lib/contracts/Initializable.sol"; 4 | import "./TimelockableItemRegistry.sol"; 5 | import "./StakedRegistry.sol"; 6 | import "../Challenge/IChallengeFactory.sol"; 7 | import "../Challenge/IChallenge.sol"; 8 | 9 | /** 10 | * @title TokenCuratedRegistry 11 | * @dev A registry with tokenized governance of item addition and removal. 12 | * Based on https://github.com/skmgoldin/tcr 13 | */ 14 | contract TokenCuratedRegistry is Initializable, StakedRegistry, TimelockableItemRegistry { 15 | 16 | // amount of time to lock new items in the application phase. 17 | uint public applicationPeriod; 18 | 19 | // contract used to create new challenges. 20 | IChallengeFactory public challengeFactory; 21 | 22 | // maps item id to challenge contract addresses. 23 | mapping(bytes32 => IChallenge) public challenges; 24 | 25 | event Application(bytes32 indexed itemid, address indexed itemOwner, uint applicationEndDate); 26 | 27 | event ItemRejected(bytes32 indexed itemid); 28 | 29 | event ChallengeSucceeded(bytes32 indexed itemid, address challenge); 30 | 31 | event ChallengeFailed(bytes32 indexed itemid, address challenge); 32 | 33 | event ChallengeInitiated(bytes32 indexed itemid, address challenge, address challenger); 34 | 35 | function initialize( 36 | ERC20 _token, 37 | uint _minStake, 38 | uint _applicationPeriod, 39 | IChallengeFactory _challengeFactory 40 | ) 41 | initializer 42 | public 43 | { 44 | require(address(_challengeFactory) != 0x0); 45 | applicationPeriod = _applicationPeriod; 46 | challengeFactory = _challengeFactory; 47 | StakedRegistry.initialize(_token, _minStake); 48 | } 49 | 50 | /** 51 | * @dev Overrides StakedRegistry.add(), sets unlock time to end of application period. 52 | * @param id The item to add to the registry. 53 | */ 54 | function add(bytes32 id) public { 55 | super.add(id); 56 | unlockTimes[id] = now.add(applicationPeriod); 57 | emit Application(id, msg.sender, unlockTimes[id]); 58 | } 59 | 60 | /** 61 | * @dev Overrides StakedRegistry.remove(), requires that there is no challenge for the item. 62 | * @param id The item to remove from the registry. 63 | */ 64 | function remove(bytes32 id) public { 65 | require(!challengeExists(id)); 66 | super.remove(id); 67 | } 68 | 69 | /** 70 | * @dev Creates a new challenge for an item, sets msg.sender as the challenger. Requires the 71 | * challenger to match the item owner's stake. 72 | * @param id The item to challenge. 73 | */ 74 | function challenge(bytes32 id) public { 75 | require(!challengeExists(id)); 76 | require(token.transferFrom(msg.sender, this, minStake)); 77 | challenges[id] = IChallenge(challengeFactory.createChallenge(this, msg.sender, owners[id])); 78 | 79 | uint challengeFunds = challenges[id].fundsRequired(); 80 | require(challengeFunds <= minStake); 81 | require(token.approve(challenges[id], challengeFunds)); 82 | 83 | emit ChallengeInitiated(id, challenges[id], msg.sender); 84 | } 85 | 86 | /** 87 | * @dev Resolves a challenge by allocating reward tokens to the winner, closing the challenge 88 | * contract, and deleting challenge state. 89 | * @param id The item to challenge. 90 | */ 91 | function resolveChallenge(bytes32 id) public { 92 | require(challengeExists(id)); 93 | 94 | if(!challenges[id].isClosed()) { 95 | challenges[id].close(); 96 | } 97 | 98 | uint reward = challenges[id].winnerReward(); 99 | if (challenges[id].passed()) { 100 | // if the challenge passed, reward the challenger (via token.transfer), then remove 101 | // the item and all state related to it 102 | require(token.transfer(challenges[id].challenger(), reward)); 103 | emit ChallengeSucceeded(id, challenges[id]); 104 | _reject(id); 105 | } else { 106 | // if the challenge failed, reward the applicant (by adding to their staked balance) 107 | ownerStakes[id] = ownerStakes[id].add(reward).sub(minStake); 108 | emit ChallengeFailed(id, challenges[id]); 109 | delete unlockTimes[id]; 110 | delete challenges[id]; 111 | } 112 | } 113 | 114 | /** 115 | * @dev Checks if an item is in the application phase, reverts if the item does not exist. 116 | * @return A bool indicating whether the item is in the application phase. 117 | */ 118 | function inApplicationPhase(bytes32 id) public view returns (bool) { 119 | return isLocked(id); 120 | } 121 | 122 | /** 123 | * @dev Checks if a challenge exists for an item, reverts if the item does not exist. 124 | * @param id The item to check for an existing challenge. 125 | * @return A bool indicating whether a challenge exists for the item. 126 | */ 127 | function challengeExists(bytes32 id) public view returns (bool) { 128 | require(_exists(id)); 129 | return address(challenges[id]) != 0x0; 130 | } 131 | 132 | /** 133 | * @dev Overrides BasicRegistry.exists(), adds logic to check that the item is not locked in 134 | * the application phase. 135 | * @param id The item to check for existence on the registry. 136 | * @return A bool indicating whether the item exists on the registry. 137 | */ 138 | function exists(bytes32 id) public view returns (bool) { 139 | return _exists(id) && !_isLocked(id); 140 | } 141 | 142 | /** 143 | * @dev Internal function to reject an item from the registry by deleting all item state. 144 | * @param id The item to reject. 145 | */ 146 | function _reject(bytes32 id) internal { 147 | ownerStakes[id] = 0; 148 | delete owners[id]; 149 | delete unlockTimes[id]; 150 | delete challenges[id]; 151 | _remove(id); 152 | emit ItemRejected(id); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /contracts/Challenge/PLCRVotingChallenge.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "openzeppelin-eth/contracts/token/ERC20/ERC20.sol"; 4 | import "openzeppelin-eth/contracts/math/SafeMath.sol"; 5 | import "plcr-voting/contracts/PLCRVoting.sol"; 6 | import "./IChallenge.sol"; 7 | import "../Registry/TokenCuratedRegistry.sol"; 8 | 9 | /** 10 | * @title PLCRVotingChallenge 11 | * @dev A challenge that uses Partial Lock Commit Reveal (PLCR) to allow token holders to cast 12 | * secret votes which are later revealed in order to reach a decision. 13 | */ 14 | contract PLCRVotingChallenge is IChallenge { 15 | using SafeMath for uint; 16 | 17 | // address of the challenger. 18 | address public challenger; 19 | 20 | // address of the item owner. 21 | address public itemOwner; 22 | 23 | // amount of tokens staked by the challenger. 24 | uint public challengerStake; 25 | 26 | // the registry contract that initiated the challenge. 27 | TokenCuratedRegistry public registry; 28 | 29 | // contract that will handle challenge voting. 30 | PLCRVoting public plcrVoting; 31 | 32 | // ID of the PLCRVoting poll. 33 | uint public pollId; 34 | 35 | // pool of tokens to be distributed to winning voters 36 | uint public voterRewardPool; 37 | 38 | // total amount of winning tokens that have been claimed by voters. 39 | uint public voterTokensClaimed; 40 | 41 | // total amount of token rewards that have been claimed by voters. 42 | uint public voterRewardsClaimed; 43 | 44 | // maps voter address to a bool indicating if the voter has claimed their reward. 45 | mapping(address => bool) public tokenClaims; 46 | 47 | bool _isClosed; 48 | 49 | event ChallengeClosed(); 50 | 51 | event RewardClaimed(uint reward, address voterAddress); 52 | 53 | /** 54 | * @dev Constructor for the new PLCRVotingChallenge contract. 55 | * @param _challenger The creator of the challenge. 56 | * @param _itemOwner The owner of the challenged item. 57 | * @param _challengerStake The amount of tokens staked by the challenger. 58 | * @param _registry The registry contract that initiated the challenge. 59 | * @param _plcrVoting The contract that will handle the PLCR voting poll. 60 | * @param commitStageLength The length of the period to commit new votes. 61 | * @param revealStageLength The length of the period to reveal votes. 62 | * @param voteQuorum The quorum needed for an outcome to win. 63 | * @param percentVoterReward The percent of stake that will be rewarded to voters (0 - 100). 64 | */ 65 | constructor ( 66 | address _challenger, 67 | address _itemOwner, 68 | uint _challengerStake, 69 | address _registry, 70 | address _plcrVoting, 71 | uint commitStageLength, 72 | uint revealStageLength, 73 | uint voteQuorum, 74 | uint percentVoterReward 75 | ) public { 76 | require(percentVoterReward <= 100); 77 | challenger = _challenger; 78 | itemOwner = _itemOwner; 79 | challengerStake = _challengerStake; 80 | registry = TokenCuratedRegistry(_registry); 81 | plcrVoting = PLCRVoting(_plcrVoting); 82 | pollId = plcrVoting.startPoll(voteQuorum, commitStageLength, revealStageLength); 83 | voterRewardPool = (percentVoterReward.mul(challengerStake)).div(100); 84 | } 85 | 86 | /** 87 | * @dev Closes the challenge, requires PLCR voting poll to have ended. 88 | */ 89 | function close() public { 90 | require(plcrVoting.pollEnded(pollId) && !isClosed()); 91 | _isClosed = true; 92 | 93 | emit ChallengeClosed(); 94 | } 95 | 96 | /** 97 | * @dev Called by voters to claim rewards for winning votes. 98 | * @param _salt The salt of a voter's commit hash. 99 | */ 100 | function claimVoterReward(uint _salt) public { 101 | require(isClosed()); 102 | require(tokenClaims[msg.sender] == false); // Ensures the voter has not already claimed tokens 103 | 104 | uint voterTokens = plcrVoting.getNumPassingTokens(msg.sender, pollId); 105 | uint reward = voterReward(msg.sender, _salt); 106 | 107 | voterTokensClaimed = voterTokensClaimed.add(voterTokens); 108 | voterRewardsClaimed = voterRewardsClaimed.add(reward); 109 | 110 | // Ensures a voter cannot claim tokens again 111 | tokenClaims[msg.sender] = true; 112 | 113 | require(registry.token().transferFrom(registry, this, reward)); 114 | require(registry.token().transfer(msg.sender, reward)); 115 | 116 | RewardClaimed(reward, msg.sender); 117 | } 118 | 119 | /** 120 | * @return A uint amount of reward tokens to be allocted to the challenge winner. 121 | */ 122 | function winnerReward() public view returns (uint) { 123 | require(isClosed()); 124 | if (plcrVoting.getTotalNumberOfTokensForWinningOption(pollId) == 0) { 125 | return challengerStake.mul(2); 126 | } else { 127 | return (challengerStake.mul(2)).sub(voterRewardPool); 128 | } 129 | } 130 | 131 | /** 132 | * @dev Calculates a voter's token reward. 133 | * @param _voter The address of the voter whose reward balance is to be returned. 134 | * @param _salt The salt of the voter's commit hash. 135 | * @return The uint indicating the voter's reward. 136 | */ 137 | function voterReward(address _voter, uint _salt) public view returns (uint) { 138 | uint voterTokens = plcrVoting.getNumPassingTokens(_voter, pollId); 139 | uint remainingVoterRewardPool = voterRewardPool.sub(voterRewardsClaimed); 140 | uint remainingTotalTokens = plcrVoting.getTotalNumberOfTokensForWinningOption(pollId).sub(voterTokensClaimed); 141 | return (voterTokens.mul(remainingVoterRewardPool)).div(remainingTotalTokens); 142 | } 143 | 144 | /** 145 | * @dev Checks if the challenge is closed. 146 | * @return A bool indicating whether the challenge is closed. 147 | */ 148 | function isClosed() public view returns (bool) { 149 | return _isClosed; 150 | } 151 | 152 | /** 153 | * @dev Checks if the challenge has passed, reverts if the challenge has not been closed. 154 | * @return A bool indicating whether the challenge has passed. 155 | */ 156 | function passed() public view returns (bool) { 157 | require(isClosed()); 158 | 159 | // if voters do not vote in favor of item, challenge passes 160 | return !plcrVoting.isPassed(pollId); 161 | } 162 | 163 | /** 164 | * @return A uint amount of tokens the challenge needs to reward voters. 165 | */ 166 | function fundsRequired() public view returns (uint) { 167 | return voterRewardPool; 168 | } 169 | 170 | /** 171 | * @return The address of the challenger. 172 | */ 173 | function challenger() public view returns (address) { 174 | return challenger; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /test/StakedRegistry.behavior.js: -------------------------------------------------------------------------------- 1 | const { shouldFail, expectEvent } = require('lk-test-helpers')(web3) 2 | const parseListingTitle = require('./helpers/parseListingTitle') 3 | const chai = require('chai') 4 | const { expect } = chai.use(require('chai-bignumber')(web3.BigNumber)) 5 | 6 | const itemId = parseListingTitle('listing 001') 7 | 8 | function shouldBehaveLikeStakedRegistry (minStake, initialBalance, accounts) { 9 | const [owner, owner2, rando] = accounts 10 | 11 | describe('behaves like a StakedRegistry', function () { 12 | describe('add()', function () { 13 | describe('when token transfer from sender succeeds', function () { 14 | beforeEach(async function () { 15 | this.logs = (await this.registry.add(itemId, { from: owner })).logs 16 | }) 17 | 18 | it('transfers stake from the owner', async function () { 19 | expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance - minStake) 20 | }) 21 | 22 | it('transfers stake to the registry', async function () { 23 | expect(await this.token.balanceOf(this.registry.address)).to.be.bignumber.equal(minStake) 24 | }) 25 | 26 | it('emits a NewStake event', async function () { 27 | await expectEvent.inLogs(this.logs, 'NewStake') 28 | }) 29 | }) 30 | 31 | describe('when token transfer from sender fails', function () { 32 | it('reverts', async function () { 33 | await shouldFail.reverting(this.registry.add(itemId, { from: owner2 })) 34 | }) 35 | }) 36 | }) 37 | 38 | describe('remove()', function () { 39 | beforeEach(async function () { 40 | await this.registry.add(itemId, { from: owner }) 41 | }) 42 | 43 | describe('when token transfer succeeds', function () { 44 | beforeEach(async function () { 45 | await this.registry.remove(itemId, { from: owner }) 46 | }) 47 | 48 | it('transfers stake to the owner', async function () { 49 | expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance) 50 | }) 51 | 52 | it('transfers stake from the registry', async function () { 53 | expect(await this.token.balanceOf(this.registry.address)).to.be.bignumber.equal(0) 54 | }) 55 | }) 56 | 57 | describe('when owner stake is 0', function () { 58 | beforeEach(async function () { 59 | await this.registry.setOwnerStake(itemId, 0) 60 | await this.registry.remove(itemId, { from: owner }) 61 | }) 62 | 63 | it('transfers 0 stake to the owner', async function () { 64 | expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance - minStake) 65 | }) 66 | 67 | it('transfers 0 stake from the registry', async function () { 68 | expect(await this.token.balanceOf(this.registry.address)).to.be.bignumber.equal(minStake) 69 | }) 70 | }) 71 | }) 72 | 73 | describe('increaseStake()', function () { 74 | 75 | beforeEach(async function () { 76 | this.additionalStake = 5 * 10 ** 18 77 | this.totalStake = minStake + this.additionalStake 78 | this.expectedOwnerBalance = initialBalance - this.totalStake 79 | await this.registry.add(itemId, { from: owner }) 80 | }) 81 | 82 | describe('when executed by item owner', function () { 83 | 84 | describe('and token transfer is successful', function () { 85 | beforeEach(async function () { 86 | await this.token.approve(this.registry.address, this.additionalStake, { from: owner }) 87 | this.logs = (await this.registry.increaseStake(itemId, this.additionalStake, { from: owner })).logs 88 | }) 89 | 90 | it('transfers additional stake amount from the sender', async function () { 91 | expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(this.expectedOwnerBalance) 92 | }) 93 | 94 | it('transfers additional stake amount to the registry', async function () { 95 | expect(await this.token.balanceOf(this.registry.address)).to.be.bignumber.equal(this.totalStake) 96 | }) 97 | 98 | it('emits an StakeIncreased event', async function () { 99 | await expectEvent.inLogs(this.logs, 'StakeIncreased') 100 | }) 101 | }) 102 | 103 | describe('and token transfer fails', function () { 104 | it('reverts', async function () { 105 | await shouldFail.reverting(this.registry.increaseStake(itemId, 1000, { from: owner })) 106 | }) 107 | }) 108 | }) 109 | 110 | describe('when not executed by item owner', function () { 111 | it('reverts', async function () { 112 | await this.token.approve(this.registry.address, this.additionalStake, { from: rando }) 113 | await shouldFail.reverting(this.registry.increaseStake(itemId, this.additionalStake, { from: rando })) 114 | }) 115 | }) 116 | 117 | }) 118 | 119 | describe('decreaseStake()', function () { 120 | 121 | beforeEach(async function () { 122 | this.additionalStake = 5 * 10 ** 18 123 | this.decreaseAmount = 2 * 10 ** 18 124 | this.totalStake = minStake + this.additionalStake - this.decreaseAmount 125 | this.expectedOwnerBalance = initialBalance - this.totalStake 126 | await this.registry.add(itemId, { from: owner }) 127 | await this.token.approve(this.registry.address, this.additionalStake, { from: owner }) 128 | await this.registry.increaseStake(itemId, this.additionalStake, { from: owner }) 129 | }) 130 | 131 | describe('when executed by item owner', function () { 132 | describe('and decreased to a balance that would exceed the minimum stake', function () { 133 | beforeEach(async function () { 134 | this.logs = (await this.registry.decreaseStake(itemId, this.decreaseAmount, { from: owner })).logs 135 | }) 136 | 137 | it('transfers stake to the owner', async function () { 138 | expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(this.expectedOwnerBalance) 139 | }) 140 | 141 | it('transfers stake from the registry', async function () { 142 | expect(await this.token.balanceOf(this.registry.address)).to.be.bignumber.equal(this.totalStake) 143 | }) 144 | 145 | it('emits an StakeDecreased event', async function () { 146 | await expectEvent.inLogs(this.logs, 'StakeDecreased') 147 | }) 148 | }) 149 | 150 | describe('and decreased to a balance that would not exceed the minimum stake', function () { 151 | it('reverts', async function () { 152 | await shouldFail.reverting(this.registry.decreaseStake(itemId, this.additionalStake + 1 * 10 ** 18, { from: owner })) 153 | }) 154 | }) 155 | }) 156 | 157 | describe('when not exected by item owner', function () { 158 | it('reverts', async function () { 159 | await shouldFail.reverting(this.registry.decreaseStake(itemId, this.decreaseAmount, { from: rando })) 160 | }) 161 | }) 162 | }) 163 | }) 164 | } 165 | 166 | module.exports = { 167 | shouldBehaveLikeStakedRegistry 168 | } 169 | -------------------------------------------------------------------------------- /test/PLCRVotingChallenge.test.js: -------------------------------------------------------------------------------- 1 | import lkTestHelpers from 'lk-test-helpers' 2 | const { shouldFail, expectEvent } = lkTestHelpers(web3) 3 | const BigNumber = require('bignumber.js'); 4 | 5 | const RegistryMock = artifacts.require('RegistryMock.sol') 6 | const Token = artifacts.require('TestToken.sol') 7 | const PLCRVoting = artifacts.require('PLCRVotingMock.sol') 8 | const PLCRVotingChallenge = artifacts.require('PLCRVotingChallenge.sol') 9 | 10 | contract('PLCRVotingChallenge', (accounts) => { 11 | let challenge, registry, plcrVoting, token 12 | 13 | const mockAddresses = [ 14 | '0x4e0100882b427b3be1191c5a7c7e79171b8a24dd', 15 | '0x6512df5964f1578a8164ce93a3238f2b11485d1c', 16 | '0x687355ca7a320e5420a3db5ae59ef662e4146786' 17 | ] 18 | 19 | const CHALLENGER = accounts[0] 20 | const LISTING_OWNER = accounts[1] 21 | const CHALLENGER_STAKE = 10 * 10 ** 18 22 | const COMMIT_STAGE_LENGTH = 60 * 60 * 24 23 | const REVEAL_STAGE_LENGTH = 60 * 60 * 24 24 | const VOTE_QUORUM = 50 25 | const PERCENT_VOTER_REWARD = 25 26 | 27 | beforeEach(async () => { 28 | token = await Token.new([accounts[0], accounts[1], accounts[2]], 100 * 10 ** 18) 29 | registry = await RegistryMock.new(token.address) 30 | plcrVoting = await PLCRVoting.new(token.address) 31 | challenge = await initializeChallenge() 32 | }) 33 | 34 | describe('when deployed with valid parameters', async () => { 35 | it('sets the challenger address', async () => { 36 | expect(await challenge.challenger()).to.equal(CHALLENGER) 37 | }) 38 | 39 | it('sets the itemOwner address', async () => { 40 | expect(await challenge.itemOwner()).to.equal(LISTING_OWNER) 41 | }) 42 | 43 | it('sets the challengerStake', async () => { 44 | expect((await challenge.challengerStake()).toNumber()).to.equal(CHALLENGER_STAKE) 45 | }) 46 | 47 | it('sets the registry', async () => { 48 | expect(await challenge.registry()).to.equal(registry.address) 49 | }) 50 | 51 | it('sets plcrVoting to the PLCRVoting address', async () => { 52 | expect(await challenge.plcrVoting()).to.equal(plcrVoting.address) 53 | }) 54 | 55 | it('sets the correct pollId', async () => { 56 | expect((await challenge.pollId()).toNumber()).to.equal(1) 57 | }) 58 | 59 | it('sets the correct voterRewardPool', async () => { 60 | const voterRewardPool = PERCENT_VOTER_REWARD * CHALLENGER_STAKE / 100 61 | expect((await challenge.voterRewardPool()).toNumber()).to.equal(voterRewardPool) 62 | }) 63 | }) 64 | 65 | describe('when deployed with invalid parameters', async () => { 66 | it('reverts if percentVoterReward is over 100', async () => { 67 | await shouldFail.reverting(initializeChallenge({percentVoterReward: 101})) 68 | }) 69 | }) 70 | 71 | describe('close()', async () => { 72 | describe('when called under valid conditions', async () => { 73 | beforeEach(async () => { 74 | await plcrVoting.set_mock_pollEnded(true) 75 | }) 76 | 77 | it('sets isClosed to true', async () => { 78 | expect(await challenge.isClosed()).to.equal(false) 79 | await challenge.close() 80 | expect(await challenge.isClosed()).to.equal(true) 81 | }) 82 | 83 | it('emits a ChallengeClosed event', async () => { 84 | const { logs } = await challenge.close() 85 | await expectEvent.inLogs(logs, 'ChallengeClosed') 86 | }) 87 | }) 88 | 89 | describe('when called under invalid conditions', async () => { 90 | 91 | it('reverts if poll has not yet ended', async () => { 92 | await shouldFail.reverting(challenge.close()) 93 | }) 94 | 95 | it('reverts if close() has already been called successfully', async () => { 96 | await plcrVoting.set_mock_pollEnded(true) 97 | await challenge.close() 98 | shouldFail.reverting(challenge.close()) 99 | }) 100 | }) 101 | }) 102 | 103 | describe('passed()', async () => { 104 | beforeEach(async () => { 105 | await plcrVoting.set_mock_pollEnded(true) 106 | }) 107 | 108 | it('reverts if challenge is not officially closed', async () => { 109 | await shouldFail.reverting(challenge.passed()) 110 | }) 111 | 112 | it('returns true if the poll in favor of listing has failed', async () => { 113 | await plcrVoting.set_mock_isPassed(false) 114 | await challenge.close() 115 | expect(await challenge.passed()).to.equal(true) 116 | }) 117 | 118 | it('returns fales if the poll in favor of listing has succeeded', async () => { 119 | await plcrVoting.set_mock_isPassed(true) 120 | await challenge.close() 121 | expect(await challenge.passed()).to.equal(false) 122 | }) 123 | }) 124 | 125 | describe('fundsRequired()', async () => { 126 | it('returns voterRewardPool', async () => { 127 | let fundsRequired = (await challenge.fundsRequired()).toNumber() 128 | let voterRewardPool = (await challenge.voterRewardPool()).toNumber() 129 | expect(fundsRequired).to.equal(voterRewardPool) 130 | }) 131 | }) 132 | 133 | describe('winnerReward()', async () => { 134 | beforeEach(async () => { 135 | await plcrVoting.set_mock_pollEnded(true) 136 | }) 137 | 138 | it('reverts if challenge is not officially closed', async () => { 139 | await shouldFail.reverting(challenge.winnerReward()) 140 | }) 141 | 142 | it('returns challengerStake x 2 if no one voted', async () => { 143 | await challenge.close() 144 | await plcrVoting.set_mock_getTotalNumberOfTokensForWinningOption(0) 145 | expect((await challenge.winnerReward()).toNumber()).to.equal(CHALLENGER_STAKE * 2) 146 | }) 147 | 148 | it('returns challengerStake x 2 minus the voterRewardPool if there were voters', async () => { 149 | const voterRewardPool = (await challenge.voterRewardPool()).toNumber() 150 | await plcrVoting.set_mock_getTotalNumberOfTokensForWinningOption(5) 151 | await challenge.close() 152 | expect((await challenge.winnerReward()).toNumber()).to.equal(CHALLENGER_STAKE * 2 - voterRewardPool) 153 | }) 154 | }) 155 | 156 | describe('claimVoterReward()', async () => { 157 | let voterTokenAmount, voter, salt 158 | 159 | beforeEach(async () => { 160 | voterTokenAmount = 10 161 | voter = accounts[0] 162 | salt = 123 163 | await plcrVoting.set_mock_pollEnded(true) 164 | await plcrVoting.set_mock_getNumPassingTokens(voterTokenAmount) 165 | await plcrVoting.set_mock_getTotalNumberOfTokensForWinningOption(20) 166 | }) 167 | 168 | it('reverts if challenge is not officially closed', async () => { 169 | await shouldFail.reverting(challenge.claimVoterReward(salt)) 170 | }) 171 | 172 | it('reverts if the sender has already claimed reward', async () => { 173 | await challenge.close() 174 | await challenge.claimVoterReward(salt, {from: voter}) 175 | await shouldFail.reverting(challenge.claimVoterReward(salt)) 176 | }) 177 | 178 | it('increments voterTokensClaimed by the correct amount', async () => { 179 | const previousVoterTokensClaimed = (await challenge.voterTokensClaimed()).toNumber() 180 | 181 | await challenge.close() 182 | await challenge.claimVoterReward(salt, {from: voter}) 183 | 184 | const currentVoterTokensClaimed = (await challenge.voterTokensClaimed()).toNumber() 185 | expect(currentVoterTokensClaimed).to.equal(previousVoterTokensClaimed + voterTokenAmount) 186 | }) 187 | 188 | it('increments voterRewardsClaimed by the correct amount', async () => { 189 | await challenge.close() 190 | const voterReward = (await challenge.voterReward(voter, salt)).toNumber() 191 | const previousVoterRewardsClaimed = (await challenge.voterRewardsClaimed()).toNumber() 192 | 193 | await challenge.claimVoterReward(salt, {from: voter}) 194 | 195 | const currentVoterTokensClaimed = (await challenge.voterRewardsClaimed()).toNumber() 196 | 197 | expect(currentVoterTokensClaimed).to.equal(previousVoterRewardsClaimed + voterReward) 198 | }) 199 | 200 | it('tracks that the voter has claimed their tokens', async () => { 201 | await challenge.close() 202 | expect(await challenge.tokenClaims(voter)).to.equal(false) 203 | await challenge.claimVoterReward(salt) 204 | expect(await challenge.tokenClaims(voter)).to.equal(true) 205 | }) 206 | 207 | it('transfers the correct amount of tokens to the voter', async () => { 208 | await challenge.close() 209 | const voterReward = (await challenge.voterReward(voter, salt)).toNumber() 210 | const previousVoterBalance = (await token.balanceOf(voter)).toNumber() 211 | await challenge.claimVoterReward(salt, {from: voter}) 212 | const currentVoterBalance = (await token.balanceOf(voter)).toNumber() 213 | expect(currentVoterBalance).to.equal(previousVoterBalance + voterReward) 214 | }) 215 | 216 | it('emits a RewardClaimed event', async () => { 217 | await challenge.close() 218 | const { logs } = await challenge.claimVoterReward(salt, {from: voter}) 219 | await expectEvent.inLogs(logs, 'RewardClaimed') 220 | }) 221 | }) 222 | 223 | describe('voterReward()', async () => { 224 | let voter, voterTokenAmount, winningTokenAmount, voterRewardPool, voterRewardsClaimed, voterTokensClaimed 225 | beforeEach(async () => { 226 | voter = accounts[0] 227 | voterTokenAmount = 10 228 | winningTokenAmount = 20 229 | voterRewardPool = (await challenge.voterRewardPool()).toNumber() 230 | voterRewardsClaimed = (await challenge.voterRewardsClaimed()).toNumber() 231 | voterTokensClaimed = (await challenge.voterTokensClaimed()).toNumber() 232 | await plcrVoting.set_mock_pollEnded(true) 233 | await plcrVoting.set_mock_getNumPassingTokens(voterTokenAmount) 234 | await plcrVoting.set_mock_getTotalNumberOfTokensForWinningOption(winningTokenAmount) 235 | }) 236 | 237 | it('returns the correct reward amount', async () => { 238 | const correctAmount = (voterTokenAmount * (voterRewardPool - voterRewardsClaimed)) / (winningTokenAmount - voterTokensClaimed) 239 | await challenge.close() 240 | expect((await challenge.voterReward(voter, 123)).toNumber()).to.equal(correctAmount) 241 | }) 242 | }) 243 | 244 | async function initializeChallenge(customParams = {}) { 245 | 246 | const { 247 | challenger = CHALLENGER, 248 | itemOwner = LISTING_OWNER, 249 | challengerStake = CHALLENGER_STAKE, 250 | registryAddr = registry.address, 251 | plcrVotingAddr = plcrVoting.address, 252 | commitStageLength = COMMIT_STAGE_LENGTH, 253 | revealStageLength = REVEAL_STAGE_LENGTH, 254 | voteQuorum = VOTE_QUORUM, 255 | percentVoterReward = PERCENT_VOTER_REWARD 256 | } = customParams 257 | 258 | let challenge = await PLCRVotingChallenge.new( 259 | challenger, 260 | itemOwner, 261 | challengerStake, 262 | registryAddr, 263 | plcrVotingAddr, 264 | commitStageLength, 265 | revealStageLength, 266 | voteQuorum, 267 | percentVoterReward 268 | ) 269 | 270 | await token.mint(registry.address, 100 * 10 ** 18) 271 | await registry.mock_approveTokenToChallenge(challenge.address, 1000 * 18 ** 18) 272 | return challenge 273 | } 274 | }) 275 | -------------------------------------------------------------------------------- /test/TokenCuratedRegistry.behavior.js: -------------------------------------------------------------------------------- 1 | const { 2 | shouldFail, 3 | expectEvent, 4 | increaseTime, 5 | constants 6 | } = require('lk-test-helpers')(web3) 7 | const chai = require('chai') 8 | const { expect } = chai.use(require('chai-bignumber')(web3.BigNumber)) 9 | const parseListingTitle = require('./helpers/parseListingTitle') 10 | 11 | const Challenge = artifacts.require('MockChallenge') 12 | 13 | const itemId = parseListingTitle('listing 001') 14 | const { ZERO_ADDRESS } = constants 15 | 16 | function shouldBehaveLikeTokenCuratedRegistry ({ 17 | minStake, 18 | mockChallengeReward, 19 | initialBalance, 20 | applicationPeriod, 21 | accounts 22 | }) { 23 | const [owner, challenger, rando] = accounts 24 | 25 | describe('behaves like a TokenCuratedRegistry', function () { 26 | 27 | describe('add()', function () { 28 | beforeEach(async function () { 29 | this.logs = (await this.registry.add(itemId)).logs 30 | }) 31 | 32 | it('emits an Application event', async function () { 33 | await expectEvent.inLogs(this.logs, 'Application') 34 | }) 35 | 36 | describe('before applicationPeriod expires', function () { 37 | it('locks the item', async function () { 38 | expect(await this.registry.isLocked(itemId)).to.be.true 39 | }) 40 | }) 41 | 42 | describe('after applicationPeriod expires', function () { 43 | it('unlocks the item', async function () { 44 | await increaseTime(applicationPeriod + 1) 45 | expect(await this.registry.isLocked(itemId)).to.be.false 46 | }) 47 | }) 48 | 49 | }) 50 | 51 | describe('remove()', function () { 52 | beforeEach(async function () { 53 | await this.registry.add(itemId) 54 | await this.registry.setUnlockTime(itemId, 0) 55 | }) 56 | 57 | describe('when there is a challenge for the item', function () { 58 | beforeEach(async function () { 59 | this.challenge = await Challenge.new() 60 | await this.registry.setChallenge(itemId, this.challenge.address) 61 | }) 62 | 63 | it('reverts', async function () { 64 | await this.challenge.set_mock_passed(true) 65 | await shouldFail.reverting(this.registry.remove(itemId)) 66 | }) 67 | }) 68 | }) 69 | 70 | describe('exists()', function () { 71 | describe('when item is in application phase', function () { 72 | it('returns false', async function () { 73 | await this.registry.add(itemId) 74 | expect(await this.registry.exists(itemId)).to.be.false 75 | }) 76 | }) 77 | }) 78 | 79 | describe('challenge()', function () { 80 | 81 | describe('when listing item exists, there is no existing challenge for the listing, and token transfer succeeds', function () { 82 | beforeEach(async function () { 83 | await this.registry.add(itemId) 84 | await this.token.approve(this.registry.address, minStake, { from: challenger }) 85 | this.logs = (await this.registry.challenge(itemId, { from: challenger })).logs 86 | this.challengeAddress = await this.registry.challenges(itemId) 87 | this.challenge = await Challenge.at(this.challengeAddress) 88 | }) 89 | 90 | it('should transfer stake from the challenger', async function () { 91 | expect(await this.token.balanceOf(challenger)).to.be.bignumber.equal(initialBalance - minStake) 92 | }) 93 | 94 | it('should approve challenge.fundsRequired() to the challenge ', async function () { 95 | expect(await this.token.allowance(this.registry.address, this.challengeAddress)).to.be.bignumber.equal(await this.challenge.fundsRequired()) 96 | }) 97 | 98 | it('should create challenge with correct params', async function () { 99 | expect(await this.challengeFactory.registry()).to.equal(this.registry.address) 100 | expect(await this.challengeFactory.challenger()).to.equal(challenger) 101 | expect(await this.challengeFactory.itemOwner()).to.equal(owner) 102 | }) 103 | 104 | it('emits a ChallengeInitiated event', async function () { 105 | await expectEvent.inLogs(this.logs, 'ChallengeInitiated') 106 | }) 107 | }) 108 | 109 | describe('when listing item does not exist', function () { 110 | it('reverts', async function () { 111 | await this.token.approve(this.registry.address, minStake, { from: challenger }) 112 | await shouldFail.reverting(this.registry.challenge(itemId, { from: challenger })) 113 | }) 114 | }) 115 | 116 | describe('when challenge for listing item exists', function () { 117 | it('reverts', async function () { 118 | await this.registry.add(itemId) 119 | await this.token.approve(this.registry.address, minStake, { from: challenger }) 120 | await this.registry.challenge(itemId, { from: challenger }) 121 | await this.token.approve(this.registry.address, minStake, { from: rando }) 122 | await shouldFail.reverting(this.registry.challenge(itemId, { from: rando })) 123 | }) 124 | }) 125 | 126 | describe('when challenger stake token transfer fails', function () { 127 | it('reverts', async function () { 128 | await this.registry.add(itemId) 129 | await shouldFail.reverting(this.registry.challenge(itemId, { from: challenger })) 130 | }) 131 | }) 132 | 133 | describe('when challenge.fundsRequired() is greater than the challenge stake', function () { 134 | it('reverts', async function () { 135 | await this.registry.add(itemId) 136 | await this.challengeFactory.mock_set_fundsRequired(minStake * 1.5) 137 | await this.token.approve(this.registry.address, minStake, { from: challenger }) 138 | await shouldFail.reverting(this.registry.challenge(itemId, { from: challenger })) 139 | }) 140 | }) 141 | }) 142 | 143 | describe('resolveChallenge()', function () { 144 | describe('when challenge does not exist', async () => { 145 | it('reverts', async function () { 146 | await this.registry.add(itemId) 147 | await shouldFail.reverting(this.registry.resolveChallenge(itemId, { from: rando })) 148 | }) 149 | }) 150 | 151 | describe('when challenge exists', function () { 152 | beforeEach(async function () { 153 | await this.registry.add(itemId) 154 | await this.token.approve(this.registry.address, minStake, { from: challenger }) 155 | await this.registry.challenge(itemId, { from: challenger }) 156 | this.challenge = await Challenge.at(await this.registry.challenges(itemId)) 157 | }) 158 | 159 | describe('and challenge is not yet closed', async function () { 160 | it('closes the challenge', async function () { 161 | expect(await this.challenge.isClosed()).to.be.false 162 | await this.registry.resolveChallenge(itemId) 163 | expect(await this.challenge.isClosed()).to.be.true 164 | }) 165 | 166 | shouldCarryOutResolution() 167 | }) 168 | 169 | describe('and challenge is already closed', async function () { 170 | shouldCarryOutResolution() 171 | }) 172 | 173 | describe('when challenge has passed', function () { 174 | beforeEach(async function () { 175 | await this.challenge.set_mock_passed(true) 176 | this.logs = (await this.registry.resolveChallenge(itemId, { from: rando })).logs 177 | }) 178 | 179 | it('should transfer reward to the challenger', async function () { 180 | expect(await this.token.balanceOf(challenger)).to.be.bignumber.equal(initialBalance + mockChallengeReward - minStake) 181 | }) 182 | 183 | it('deletes the owner stake', async function () { 184 | expect(await this.registry.ownerStakes(itemId)).to.be.bignumber.equal(0) 185 | }) 186 | 187 | it('deletes item unlocked state', async function () { 188 | expect(await this.registry.unlockTimes(itemId)).to.be.bignumber.equal(0) 189 | }) 190 | 191 | it('deletes the item owner', async function () { 192 | expect(await this.registry.owners(itemId)).to.equal(ZERO_ADDRESS) 193 | }) 194 | 195 | it('deletes the item', async function () { 196 | expect(await this.registry.exists(itemId)).to.be.false 197 | }) 198 | 199 | it('emits a ChallengeSucceeded event', async function () { 200 | await expectEvent.inLogs(this.logs, 'ChallengeSucceeded') 201 | }) 202 | 203 | it('emits a ItemRejected event', async function () { 204 | await expectEvent.inLogs(this.logs, 'ItemRejected') 205 | }) 206 | 207 | shouldCloseChallenge() 208 | shouldDeleteChallenge() 209 | }) 210 | 211 | describe('when challenge has failed', function () { 212 | beforeEach(async function () { 213 | await this.challenge.set_mock_passed(false) 214 | this.logs = (await this.registry.resolveChallenge(itemId, { from: rando })).logs 215 | }) 216 | 217 | it('adds the reward to the item owner\'s stake', async function () { 218 | expect(await this.registry.ownerStakes(itemId)).to.be.bignumber.equal(mockChallengeReward) 219 | }) 220 | 221 | it('does not change the item owner', async function () { 222 | expect(await this.registry.owners(itemId)).to.equal(owner) 223 | }) 224 | 225 | it('does not delete the item', async function () { 226 | expect(await this.registry.exists(itemId)).to.be.true 227 | }) 228 | 229 | it('unlocks the item', async function () { 230 | expect(await this.registry.isLocked(itemId)).to.be.false 231 | }) 232 | 233 | it('emits a ChallengeFailed event', async function () { 234 | await expectEvent.inLogs(this.logs, 'ChallengeFailed') 235 | }) 236 | 237 | shouldCloseChallenge() 238 | shouldDeleteChallenge() 239 | }) 240 | 241 | function shouldCarryOutResolution() { 242 | it('carries out the resolution', async function () { 243 | const winnerReward = await this.challenge.winnerReward() 244 | const previousItemStake = await this.registry.ownerStakes(itemId) 245 | await this.challenge.set_mock_passed(false) 246 | await this.registry.resolveChallenge(itemId) 247 | const currentItemStake = await this.registry.ownerStakes(itemId) 248 | 249 | expect(previousItemStake).to.be.bignumber.equal(minStake) 250 | expect(currentItemStake).to.be.bignumber.equal(winnerReward) 251 | expect(await this.registry.challenges(itemId)).to.equal(ZERO_ADDRESS) 252 | }) 253 | } 254 | 255 | function shouldCloseChallenge () { 256 | it('closes the challenge', async function () { 257 | expect(await this.challenge.isClosed()).to.be.true 258 | }) 259 | } 260 | 261 | function shouldDeleteChallenge () { 262 | it('deletes the challenge from the registry', async function () { 263 | expect(await this.registry.challenges(itemId)).to.equal(ZERO_ADDRESS) 264 | }) 265 | } 266 | }) 267 | }) 268 | 269 | describe('inApplicationPhase()', function () { 270 | describe('when item exists', function () { 271 | beforeEach(async function () { 272 | await this.registry.add(itemId) 273 | }) 274 | 275 | describe('and item is locked', function () { 276 | it('returns true', async function () { 277 | await this.registry.setUnlockTime(itemId, this.now + 1000) 278 | expect(await this.registry.inApplicationPhase(itemId)).to.be.true 279 | }) 280 | }) 281 | 282 | describe('and item is not locked', function () { 283 | it('returns false', async function () { 284 | await this.registry.setUnlockTime(itemId, 0) 285 | expect(await this.registry.inApplicationPhase(itemId)).to.be.false 286 | }) 287 | }) 288 | }) 289 | 290 | describe('when item does not exist', function () { 291 | it('reverts', async function () { 292 | await shouldFail.reverting(this.registry.inApplicationPhase(itemId)) 293 | }) 294 | }) 295 | }) 296 | 297 | describe('challengeExists()', function () { 298 | describe('when item exists', function () { 299 | beforeEach(async function () { 300 | await this.registry.add(itemId) 301 | }) 302 | 303 | describe('and challenge exists', function () { 304 | it('returns true', async function () { 305 | await this.token.approve(this.registry.address, minStake, { from: challenger }) 306 | await this.registry.challenge(itemId, { from: challenger }) 307 | expect(await this.registry.challengeExists(itemId)).to.be.true 308 | }) 309 | }) 310 | 311 | describe('and challenge does not exist', function () { 312 | it('returns false', async function () { 313 | expect(await this.registry.challengeExists(itemId)).to.be.false 314 | }) 315 | }) 316 | }) 317 | 318 | describe('when item does not exist', function () { 319 | it('reverts', async function () { 320 | await shouldFail.reverting(this.registry.challengeExists(itemId)) 321 | }) 322 | }) 323 | }) 324 | }) 325 | } 326 | 327 | module.exports = { 328 | shouldBehaveLikeTokenCuratedRegistry 329 | } 330 | -------------------------------------------------------------------------------- /zos.kovan.json: -------------------------------------------------------------------------------- 1 | { 2 | "contracts": { 3 | "OwnedItemRegistry": { 4 | "address": "0x84ff6c68d171aab48455d5afdf9727db7aca1f8f", 5 | "constructorCode": "608060405234801561001057600080fd5b5061046e806100206000396000f300", 6 | "bodyBytecodeHash": "bbacd610fa99a625219b716e6ee4354ab784f12fbeea321369b33ce79fbf9648", 7 | "localBytecodeHash": "99d25bd908e58d83415b86085426f2f658a2e4efdfb568bcea731044c0dbebd8", 8 | "deployedBytecodeHash": "99d25bd908e58d83415b86085426f2f658a2e4efdfb568bcea731044c0dbebd8", 9 | "types": { 10 | "t_bool": { 11 | "id": "t_bool", 12 | "kind": "elementary", 13 | "label": "bool" 14 | }, 15 | "t_uint256": { 16 | "id": "t_uint256", 17 | "kind": "elementary", 18 | "label": "uint256" 19 | }, 20 | "t_array:50": { 21 | "id": "t_array:50", 22 | "valueType": "t_uint256", 23 | "length": "50", 24 | "kind": "array", 25 | "label": "uint256[50]" 26 | }, 27 | "t_mapping": { 28 | "id": "t_mapping", 29 | "valueType": "t_bool", 30 | "label": "mapping(key => bool)", 31 | "kind": "mapping" 32 | }, 33 | "t_address": { 34 | "id": "t_address", 35 | "kind": "elementary", 36 | "label": "address" 37 | }, 38 | "t_mapping": { 39 | "id": "t_mapping", 40 | "valueType": "t_address", 41 | "label": "mapping(key => address)", 42 | "kind": "mapping" 43 | } 44 | }, 45 | "storage": [ 46 | { 47 | "contract": "Initializable", 48 | "path": "zos-lib/contracts/Initializable.sol", 49 | "label": "initialized", 50 | "astId": 3575, 51 | "type": "t_bool", 52 | "src": "749:24:16" 53 | }, 54 | { 55 | "contract": "Initializable", 56 | "path": "zos-lib/contracts/Initializable.sol", 57 | "label": "initializing", 58 | "astId": 3577, 59 | "type": "t_bool", 60 | "src": "868:25:16" 61 | }, 62 | { 63 | "contract": "Initializable", 64 | "path": "zos-lib/contracts/Initializable.sol", 65 | "label": "______gap", 66 | "astId": 3626, 67 | "type": "t_array:50", 68 | "src": "1883:29:16" 69 | }, 70 | { 71 | "contract": "BasicRegistry", 72 | "path": "contracts/Registry/BasicRegistry.sol", 73 | "label": "items", 74 | "astId": 505, 75 | "type": "t_mapping", 76 | "src": "274:30:4" 77 | }, 78 | { 79 | "contract": "OwnedItemRegistry", 80 | "path": "contracts/Registry/OwnedItemRegistry.sol", 81 | "label": "owners", 82 | "astId": 625, 83 | "type": "t_mapping", 84 | "src": "307:41:6" 85 | } 86 | ], 87 | "warnings": { 88 | "hasConstructor": false, 89 | "hasSelfDestruct": false, 90 | "hasDelegateCall": false, 91 | "hasInitialValuesInDeclarations": false, 92 | "uninitializedBaseContracts": [] 93 | } 94 | }, 95 | "StakedRegistry": { 96 | "address": "0x9b708b8d40d0cdb75c74e0da9465d65a89e48104", 97 | "constructorCode": "608060405234801561001057600080fd5b50611062806100206000396000f300", 98 | "bodyBytecodeHash": "6eef5ca1332922ca41e0b55835a0216b15ae78e422aa74e680fe295e1a2dff90", 99 | "localBytecodeHash": "14e686feb65c5292073d8451a98fe3bd3ea3312e4d45e261cfc0d23cb13f23d0", 100 | "deployedBytecodeHash": "14e686feb65c5292073d8451a98fe3bd3ea3312e4d45e261cfc0d23cb13f23d0", 101 | "types": { 102 | "t_bool": { 103 | "id": "t_bool", 104 | "kind": "elementary", 105 | "label": "bool" 106 | }, 107 | "t_uint256": { 108 | "id": "t_uint256", 109 | "kind": "elementary", 110 | "label": "uint256" 111 | }, 112 | "t_array:50": { 113 | "id": "t_array:50", 114 | "valueType": "t_uint256", 115 | "length": "50", 116 | "kind": "array", 117 | "label": "uint256[50]" 118 | }, 119 | "t_mapping": { 120 | "id": "t_mapping", 121 | "valueType": "t_bool", 122 | "label": "mapping(key => bool)", 123 | "kind": "mapping" 124 | }, 125 | "t_address": { 126 | "id": "t_address", 127 | "kind": "elementary", 128 | "label": "address" 129 | }, 130 | "t_mapping": { 131 | "id": "t_mapping", 132 | "valueType": "t_address", 133 | "label": "mapping(key => address)", 134 | "kind": "mapping" 135 | }, 136 | "t_mapping": { 137 | "id": "t_mapping", 138 | "valueType": "t_uint256", 139 | "label": "mapping(key => uint256)", 140 | "kind": "mapping" 141 | } 142 | }, 143 | "storage": [ 144 | { 145 | "contract": "Initializable", 146 | "path": "zos-lib/contracts/Initializable.sol", 147 | "label": "initialized", 148 | "astId": 3575, 149 | "type": "t_bool", 150 | "src": "749:24:16" 151 | }, 152 | { 153 | "contract": "Initializable", 154 | "path": "zos-lib/contracts/Initializable.sol", 155 | "label": "initializing", 156 | "astId": 3577, 157 | "type": "t_bool", 158 | "src": "868:25:16" 159 | }, 160 | { 161 | "contract": "Initializable", 162 | "path": "zos-lib/contracts/Initializable.sol", 163 | "label": "______gap", 164 | "astId": 3626, 165 | "type": "t_array:50", 166 | "src": "1883:29:16" 167 | }, 168 | { 169 | "contract": "BasicRegistry", 170 | "path": "contracts/Registry/BasicRegistry.sol", 171 | "label": "items", 172 | "astId": 505, 173 | "type": "t_mapping", 174 | "src": "274:30:4" 175 | }, 176 | { 177 | "contract": "OwnedItemRegistry", 178 | "path": "contracts/Registry/OwnedItemRegistry.sol", 179 | "label": "owners", 180 | "astId": 625, 181 | "type": "t_mapping", 182 | "src": "307:41:6" 183 | }, 184 | { 185 | "contract": "StakedRegistry", 186 | "path": "contracts/Registry/StakedRegistry.sol", 187 | "label": "token", 188 | "astId": 695, 189 | "type": "t_address", 190 | "src": "437:18:7" 191 | }, 192 | { 193 | "contract": "StakedRegistry", 194 | "path": "contracts/Registry/StakedRegistry.sol", 195 | "label": "minStake", 196 | "astId": 697, 197 | "type": "t_uint256", 198 | "src": "515:20:7" 199 | }, 200 | { 201 | "contract": "StakedRegistry", 202 | "path": "contracts/Registry/StakedRegistry.sol", 203 | "label": "ownerStakes", 204 | "astId": 701, 205 | "type": "t_mapping", 206 | "src": "581:43:7" 207 | } 208 | ], 209 | "warnings": { 210 | "hasConstructor": false, 211 | "hasSelfDestruct": false, 212 | "hasDelegateCall": false, 213 | "hasInitialValuesInDeclarations": false, 214 | "uninitializedBaseContracts": [] 215 | } 216 | }, 217 | "TokenCuratedRegistry": { 218 | "address": "0xc39add632bdffb7761147b9ebfc02b10e387a4a2", 219 | "constructorCode": "608060405234801561001057600080fd5b5061268e806100206000396000f300", 220 | "bodyBytecodeHash": "0f8e917533622bb23545ceb52e13e61f589a894a5a96b7202647a0975c7e5c03", 221 | "localBytecodeHash": "7c02875a1f13d420997ecd6f471dd7c8fb8c5cc191e60f58f46b01d2695fa4f1", 222 | "deployedBytecodeHash": "7c02875a1f13d420997ecd6f471dd7c8fb8c5cc191e60f58f46b01d2695fa4f1", 223 | "types": { 224 | "t_bool": { 225 | "id": "t_bool", 226 | "kind": "elementary", 227 | "label": "bool" 228 | }, 229 | "t_uint256": { 230 | "id": "t_uint256", 231 | "kind": "elementary", 232 | "label": "uint256" 233 | }, 234 | "t_array:50": { 235 | "id": "t_array:50", 236 | "valueType": "t_uint256", 237 | "length": "50", 238 | "kind": "array", 239 | "label": "uint256[50]" 240 | }, 241 | "t_mapping": { 242 | "id": "t_mapping", 243 | "valueType": "t_bool", 244 | "label": "mapping(key => bool)", 245 | "kind": "mapping" 246 | }, 247 | "t_address": { 248 | "id": "t_address", 249 | "kind": "elementary", 250 | "label": "address" 251 | }, 252 | "t_mapping": { 253 | "id": "t_mapping", 254 | "valueType": "t_address", 255 | "label": "mapping(key => address)", 256 | "kind": "mapping" 257 | }, 258 | "t_mapping": { 259 | "id": "t_mapping", 260 | "valueType": "t_uint256", 261 | "label": "mapping(key => uint256)", 262 | "kind": "mapping" 263 | } 264 | }, 265 | "storage": [ 266 | { 267 | "contract": "Initializable", 268 | "path": "zos-lib/contracts/Initializable.sol", 269 | "label": "initialized", 270 | "astId": 3575, 271 | "type": "t_bool", 272 | "src": "749:24:16" 273 | }, 274 | { 275 | "contract": "Initializable", 276 | "path": "zos-lib/contracts/Initializable.sol", 277 | "label": "initializing", 278 | "astId": 3577, 279 | "type": "t_bool", 280 | "src": "868:25:16" 281 | }, 282 | { 283 | "contract": "Initializable", 284 | "path": "zos-lib/contracts/Initializable.sol", 285 | "label": "______gap", 286 | "astId": 3626, 287 | "type": "t_array:50", 288 | "src": "1883:29:16" 289 | }, 290 | { 291 | "contract": "BasicRegistry", 292 | "path": "contracts/Registry/BasicRegistry.sol", 293 | "label": "items", 294 | "astId": 505, 295 | "type": "t_mapping", 296 | "src": "274:30:4" 297 | }, 298 | { 299 | "contract": "OwnedItemRegistry", 300 | "path": "contracts/Registry/OwnedItemRegistry.sol", 301 | "label": "owners", 302 | "astId": 625, 303 | "type": "t_mapping", 304 | "src": "307:41:6" 305 | }, 306 | { 307 | "contract": "StakedRegistry", 308 | "path": "contracts/Registry/StakedRegistry.sol", 309 | "label": "token", 310 | "astId": 695, 311 | "type": "t_address", 312 | "src": "437:18:7" 313 | }, 314 | { 315 | "contract": "StakedRegistry", 316 | "path": "contracts/Registry/StakedRegistry.sol", 317 | "label": "minStake", 318 | "astId": 697, 319 | "type": "t_uint256", 320 | "src": "515:20:7" 321 | }, 322 | { 323 | "contract": "StakedRegistry", 324 | "path": "contracts/Registry/StakedRegistry.sol", 325 | "label": "ownerStakes", 326 | "astId": 701, 327 | "type": "t_mapping", 328 | "src": "581:43:7" 329 | }, 330 | { 331 | "contract": "TimelockableItemRegistry", 332 | "path": "contracts/Registry/TimelockableItemRegistry.sol", 333 | "label": "unlockTimes", 334 | "astId": 915, 335 | "type": "t_mapping", 336 | "src": "341:43:8" 337 | }, 338 | { 339 | "contract": "TokenCuratedRegistry", 340 | "path": "contracts/Registry/TokenCuratedRegistry.sol", 341 | "label": "applicationPeriod", 342 | "astId": 987, 343 | "type": "t_uint256", 344 | "src": "545:29:9" 345 | }, 346 | { 347 | "contract": "TokenCuratedRegistry", 348 | "path": "contracts/Registry/TokenCuratedRegistry.sol", 349 | "label": "challengeFactory", 350 | "astId": 989, 351 | "type": "t_address", 352 | "src": "624:41:9" 353 | }, 354 | { 355 | "contract": "TokenCuratedRegistry", 356 | "path": "contracts/Registry/TokenCuratedRegistry.sol", 357 | "label": "challenges", 358 | "astId": 993, 359 | "type": "t_mapping", 360 | "src": "721:48:9" 361 | } 362 | ], 363 | "warnings": { 364 | "hasConstructor": false, 365 | "hasSelfDestruct": false, 366 | "hasDelegateCall": false, 367 | "hasInitialValuesInDeclarations": false, 368 | "uninitializedBaseContracts": [] 369 | } 370 | }, 371 | "PLCRVotingChallengeFactory": { 372 | "address": "0xa3eea35098540fc941dd939a41ec40190b194cee", 373 | "constructorCode": "608060405234801561001057600080fd5b50611d0d806100206000396000f300", 374 | "bodyBytecodeHash": "25cd7101670194cecad9d68ac7da9641020e8acd81697c83f4f18ec87aa2ff55", 375 | "localBytecodeHash": "0d55c9174a249aae51c464df42475d958a925a58b073ba030faf7b49d064b5f5", 376 | "deployedBytecodeHash": "0d55c9174a249aae51c464df42475d958a925a58b073ba030faf7b49d064b5f5", 377 | "types": { 378 | "t_bool": { 379 | "id": "t_bool", 380 | "kind": "elementary", 381 | "label": "bool" 382 | }, 383 | "t_uint256": { 384 | "id": "t_uint256", 385 | "kind": "elementary", 386 | "label": "uint256" 387 | }, 388 | "t_array:50": { 389 | "id": "t_array:50", 390 | "valueType": "t_uint256", 391 | "length": "50", 392 | "kind": "array", 393 | "label": "uint256[50]" 394 | }, 395 | "t_address": { 396 | "id": "t_address", 397 | "kind": "elementary", 398 | "label": "address" 399 | } 400 | }, 401 | "storage": [ 402 | { 403 | "contract": "Initializable", 404 | "path": "zos-lib/contracts/Initializable.sol", 405 | "label": "initialized", 406 | "astId": 3575, 407 | "type": "t_bool", 408 | "src": "749:24:16" 409 | }, 410 | { 411 | "contract": "Initializable", 412 | "path": "zos-lib/contracts/Initializable.sol", 413 | "label": "initializing", 414 | "astId": 3577, 415 | "type": "t_bool", 416 | "src": "868:25:16" 417 | }, 418 | { 419 | "contract": "Initializable", 420 | "path": "zos-lib/contracts/Initializable.sol", 421 | "label": "______gap", 422 | "astId": 3626, 423 | "type": "t_array:50", 424 | "src": "1883:29:16" 425 | }, 426 | { 427 | "contract": "PLCRVotingChallengeFactory", 428 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 429 | "label": "challengerStake", 430 | "astId": 399, 431 | "type": "t_uint256", 432 | "src": "337:27:3" 433 | }, 434 | { 435 | "contract": "PLCRVotingChallengeFactory", 436 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 437 | "label": "plcrVoting", 438 | "astId": 401, 439 | "type": "t_address", 440 | "src": "368:25:3" 441 | }, 442 | { 443 | "contract": "PLCRVotingChallengeFactory", 444 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 445 | "label": "commitStageLength", 446 | "astId": 403, 447 | "type": "t_uint256", 448 | "src": "397:29:3" 449 | }, 450 | { 451 | "contract": "PLCRVotingChallengeFactory", 452 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 453 | "label": "revealStageLength", 454 | "astId": 405, 455 | "type": "t_uint256", 456 | "src": "430:29:3" 457 | }, 458 | { 459 | "contract": "PLCRVotingChallengeFactory", 460 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 461 | "label": "voteQuorum", 462 | "astId": 407, 463 | "type": "t_uint256", 464 | "src": "463:22:3" 465 | }, 466 | { 467 | "contract": "PLCRVotingChallengeFactory", 468 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 469 | "label": "percentVoterReward", 470 | "astId": 409, 471 | "type": "t_uint256", 472 | "src": "489:30:3" 473 | } 474 | ], 475 | "warnings": { 476 | "hasConstructor": false, 477 | "hasSelfDestruct": false, 478 | "hasDelegateCall": false, 479 | "hasInitialValuesInDeclarations": false, 480 | "uninitializedBaseContracts": [] 481 | } 482 | }, 483 | "BasicRegistry": { 484 | "address": "0x0e00945ccb6a0d406ed6c065f15e5362ffb91693", 485 | "constructorCode": "608060405234801561001057600080fd5b50610298806100206000396000f300", 486 | "bodyBytecodeHash": "2f9a209335ccce764072531a7e287df0eb22bbddad6f7cf1179a398daa3a5839", 487 | "localBytecodeHash": "4b98f4a2b8f431b011e6249051d0e3aa5fbe87bd3d7c94284a2b2f9b8aa3cb5b", 488 | "deployedBytecodeHash": "4b98f4a2b8f431b011e6249051d0e3aa5fbe87bd3d7c94284a2b2f9b8aa3cb5b", 489 | "types": { 490 | "t_bool": { 491 | "id": "t_bool", 492 | "kind": "elementary", 493 | "label": "bool" 494 | }, 495 | "t_uint256": { 496 | "id": "t_uint256", 497 | "kind": "elementary", 498 | "label": "uint256" 499 | }, 500 | "t_array:50": { 501 | "id": "t_array:50", 502 | "valueType": "t_uint256", 503 | "length": "50", 504 | "kind": "array", 505 | "label": "uint256[50]" 506 | }, 507 | "t_mapping": { 508 | "id": "t_mapping", 509 | "valueType": "t_bool", 510 | "label": "mapping(key => bool)", 511 | "kind": "mapping" 512 | } 513 | }, 514 | "storage": [ 515 | { 516 | "contract": "Initializable", 517 | "path": "zos-lib/contracts/Initializable.sol", 518 | "label": "initialized", 519 | "astId": 3575, 520 | "type": "t_bool", 521 | "src": "749:24:16" 522 | }, 523 | { 524 | "contract": "Initializable", 525 | "path": "zos-lib/contracts/Initializable.sol", 526 | "label": "initializing", 527 | "astId": 3577, 528 | "type": "t_bool", 529 | "src": "868:25:16" 530 | }, 531 | { 532 | "contract": "Initializable", 533 | "path": "zos-lib/contracts/Initializable.sol", 534 | "label": "______gap", 535 | "astId": 3626, 536 | "type": "t_array:50", 537 | "src": "1883:29:16" 538 | }, 539 | { 540 | "contract": "BasicRegistry", 541 | "path": "contracts/Registry/BasicRegistry.sol", 542 | "label": "items", 543 | "astId": 505, 544 | "type": "t_mapping", 545 | "src": "274:30:4" 546 | } 547 | ], 548 | "warnings": { 549 | "hasConstructor": false, 550 | "hasSelfDestruct": false, 551 | "hasDelegateCall": false, 552 | "hasInitialValuesInDeclarations": false, 553 | "uninitializedBaseContracts": [] 554 | } 555 | }, 556 | "TimelockableItemRegistry": { 557 | "address": "0xa8508b2736a44ec1abe11d5d90a3f2a8ff839444", 558 | "constructorCode": "608060405234801561001057600080fd5b506103e1806100206000396000f300", 559 | "bodyBytecodeHash": "27da4ce90e7aa17afef252652a2620df75d2cab14c778a348c5c461e24e29923", 560 | "localBytecodeHash": "5c96c9f1047cb34a464d450496a2399fcdac34b0af7fb295dee491743580b5da", 561 | "deployedBytecodeHash": "5c96c9f1047cb34a464d450496a2399fcdac34b0af7fb295dee491743580b5da", 562 | "types": { 563 | "t_bool": { 564 | "id": "t_bool", 565 | "kind": "elementary", 566 | "label": "bool" 567 | }, 568 | "t_uint256": { 569 | "id": "t_uint256", 570 | "kind": "elementary", 571 | "label": "uint256" 572 | }, 573 | "t_array:50": { 574 | "id": "t_array:50", 575 | "valueType": "t_uint256", 576 | "length": "50", 577 | "kind": "array", 578 | "label": "uint256[50]" 579 | }, 580 | "t_mapping": { 581 | "id": "t_mapping", 582 | "valueType": "t_bool", 583 | "label": "mapping(key => bool)", 584 | "kind": "mapping" 585 | }, 586 | "t_mapping": { 587 | "id": "t_mapping", 588 | "valueType": "t_uint256", 589 | "label": "mapping(key => uint256)", 590 | "kind": "mapping" 591 | } 592 | }, 593 | "storage": [ 594 | { 595 | "contract": "Initializable", 596 | "path": "zos-lib/contracts/Initializable.sol", 597 | "label": "initialized", 598 | "astId": 3575, 599 | "type": "t_bool", 600 | "src": "749:24:16" 601 | }, 602 | { 603 | "contract": "Initializable", 604 | "path": "zos-lib/contracts/Initializable.sol", 605 | "label": "initializing", 606 | "astId": 3577, 607 | "type": "t_bool", 608 | "src": "868:25:16" 609 | }, 610 | { 611 | "contract": "Initializable", 612 | "path": "zos-lib/contracts/Initializable.sol", 613 | "label": "______gap", 614 | "astId": 3626, 615 | "type": "t_array:50", 616 | "src": "1883:29:16" 617 | }, 618 | { 619 | "contract": "BasicRegistry", 620 | "path": "contracts/Registry/BasicRegistry.sol", 621 | "label": "items", 622 | "astId": 505, 623 | "type": "t_mapping", 624 | "src": "274:30:4" 625 | }, 626 | { 627 | "contract": "TimelockableItemRegistry", 628 | "path": "contracts/Registry/TimelockableItemRegistry.sol", 629 | "label": "unlockTimes", 630 | "astId": 915, 631 | "type": "t_mapping", 632 | "src": "341:43:8" 633 | } 634 | ], 635 | "warnings": { 636 | "hasConstructor": false, 637 | "hasSelfDestruct": false, 638 | "hasDelegateCall": false, 639 | "hasInitialValuesInDeclarations": false, 640 | "uninitializedBaseContracts": [] 641 | } 642 | } 643 | }, 644 | "solidityLibs": {}, 645 | "proxies": {}, 646 | "zosversion": "2", 647 | "frozen": false, 648 | "app": { 649 | "address": "0xcf7959fa5b478ec0145c4cd426be57ba781f56e9" 650 | }, 651 | "package": { 652 | "address": "0x3fad339b66c81ac2ad0c2c72a52f12b27644dacc" 653 | }, 654 | "provider": { 655 | "address": "0x4803ff276340f569f83d16374ac37560e3d59971" 656 | }, 657 | "version": "0.1.0" 658 | } -------------------------------------------------------------------------------- /zos.mainnet.json: -------------------------------------------------------------------------------- 1 | { 2 | "contracts": { 3 | "BasicRegistry": { 4 | "address": "0x8b067a6bf8e119e21384fb3d8ebd63899d1163d7", 5 | "constructorCode": "608060405234801561001057600080fd5b50610298806100206000396000f300", 6 | "bodyBytecodeHash": "2f9a209335ccce764072531a7e287df0eb22bbddad6f7cf1179a398daa3a5839", 7 | "localBytecodeHash": "4b98f4a2b8f431b011e6249051d0e3aa5fbe87bd3d7c94284a2b2f9b8aa3cb5b", 8 | "deployedBytecodeHash": "4b98f4a2b8f431b011e6249051d0e3aa5fbe87bd3d7c94284a2b2f9b8aa3cb5b", 9 | "types": { 10 | "t_bool": { 11 | "id": "t_bool", 12 | "kind": "elementary", 13 | "label": "bool" 14 | }, 15 | "t_uint256": { 16 | "id": "t_uint256", 17 | "kind": "elementary", 18 | "label": "uint256" 19 | }, 20 | "t_array:50": { 21 | "id": "t_array:50", 22 | "valueType": "t_uint256", 23 | "length": "50", 24 | "kind": "array", 25 | "label": "uint256[50]" 26 | }, 27 | "t_mapping": { 28 | "id": "t_mapping", 29 | "valueType": "t_bool", 30 | "label": "mapping(key => bool)", 31 | "kind": "mapping" 32 | } 33 | }, 34 | "storage": [ 35 | { 36 | "contract": "Initializable", 37 | "path": "zos-lib/contracts/Initializable.sol", 38 | "label": "initialized", 39 | "astId": 3575, 40 | "type": "t_bool", 41 | "src": "749:24:16" 42 | }, 43 | { 44 | "contract": "Initializable", 45 | "path": "zos-lib/contracts/Initializable.sol", 46 | "label": "initializing", 47 | "astId": 3577, 48 | "type": "t_bool", 49 | "src": "868:25:16" 50 | }, 51 | { 52 | "contract": "Initializable", 53 | "path": "zos-lib/contracts/Initializable.sol", 54 | "label": "______gap", 55 | "astId": 3626, 56 | "type": "t_array:50", 57 | "src": "1883:29:16" 58 | }, 59 | { 60 | "contract": "BasicRegistry", 61 | "path": "contracts/Registry/BasicRegistry.sol", 62 | "label": "items", 63 | "astId": 505, 64 | "type": "t_mapping", 65 | "src": "274:30:4" 66 | } 67 | ], 68 | "warnings": { 69 | "hasConstructor": false, 70 | "hasSelfDestruct": false, 71 | "hasDelegateCall": false, 72 | "hasInitialValuesInDeclarations": false, 73 | "uninitializedBaseContracts": [] 74 | } 75 | }, 76 | "OwnedItemRegistry": { 77 | "address": "0xe99cfd468647edb80ffcf806a400c41e81b6c8d4", 78 | "constructorCode": "608060405234801561001057600080fd5b5061046e806100206000396000f300", 79 | "bodyBytecodeHash": "bbacd610fa99a625219b716e6ee4354ab784f12fbeea321369b33ce79fbf9648", 80 | "localBytecodeHash": "99d25bd908e58d83415b86085426f2f658a2e4efdfb568bcea731044c0dbebd8", 81 | "deployedBytecodeHash": "99d25bd908e58d83415b86085426f2f658a2e4efdfb568bcea731044c0dbebd8", 82 | "types": { 83 | "t_bool": { 84 | "id": "t_bool", 85 | "kind": "elementary", 86 | "label": "bool" 87 | }, 88 | "t_uint256": { 89 | "id": "t_uint256", 90 | "kind": "elementary", 91 | "label": "uint256" 92 | }, 93 | "t_array:50": { 94 | "id": "t_array:50", 95 | "valueType": "t_uint256", 96 | "length": "50", 97 | "kind": "array", 98 | "label": "uint256[50]" 99 | }, 100 | "t_mapping": { 101 | "id": "t_mapping", 102 | "valueType": "t_bool", 103 | "label": "mapping(key => bool)", 104 | "kind": "mapping" 105 | }, 106 | "t_address": { 107 | "id": "t_address", 108 | "kind": "elementary", 109 | "label": "address" 110 | }, 111 | "t_mapping": { 112 | "id": "t_mapping", 113 | "valueType": "t_address", 114 | "label": "mapping(key => address)", 115 | "kind": "mapping" 116 | } 117 | }, 118 | "storage": [ 119 | { 120 | "contract": "Initializable", 121 | "path": "zos-lib/contracts/Initializable.sol", 122 | "label": "initialized", 123 | "astId": 3575, 124 | "type": "t_bool", 125 | "src": "749:24:16" 126 | }, 127 | { 128 | "contract": "Initializable", 129 | "path": "zos-lib/contracts/Initializable.sol", 130 | "label": "initializing", 131 | "astId": 3577, 132 | "type": "t_bool", 133 | "src": "868:25:16" 134 | }, 135 | { 136 | "contract": "Initializable", 137 | "path": "zos-lib/contracts/Initializable.sol", 138 | "label": "______gap", 139 | "astId": 3626, 140 | "type": "t_array:50", 141 | "src": "1883:29:16" 142 | }, 143 | { 144 | "contract": "BasicRegistry", 145 | "path": "contracts/Registry/BasicRegistry.sol", 146 | "label": "items", 147 | "astId": 505, 148 | "type": "t_mapping", 149 | "src": "274:30:4" 150 | }, 151 | { 152 | "contract": "OwnedItemRegistry", 153 | "path": "contracts/Registry/OwnedItemRegistry.sol", 154 | "label": "owners", 155 | "astId": 625, 156 | "type": "t_mapping", 157 | "src": "307:41:6" 158 | } 159 | ], 160 | "warnings": { 161 | "hasConstructor": false, 162 | "hasSelfDestruct": false, 163 | "hasDelegateCall": false, 164 | "hasInitialValuesInDeclarations": false, 165 | "uninitializedBaseContracts": [] 166 | } 167 | }, 168 | "TimelockableItemRegistry": { 169 | "address": "0x7230715d26721414a8d3ad3a8296cf4df1d786bf", 170 | "constructorCode": "608060405234801561001057600080fd5b506103e1806100206000396000f300", 171 | "bodyBytecodeHash": "27da4ce90e7aa17afef252652a2620df75d2cab14c778a348c5c461e24e29923", 172 | "localBytecodeHash": "5c96c9f1047cb34a464d450496a2399fcdac34b0af7fb295dee491743580b5da", 173 | "deployedBytecodeHash": "5c96c9f1047cb34a464d450496a2399fcdac34b0af7fb295dee491743580b5da", 174 | "types": { 175 | "t_bool": { 176 | "id": "t_bool", 177 | "kind": "elementary", 178 | "label": "bool" 179 | }, 180 | "t_uint256": { 181 | "id": "t_uint256", 182 | "kind": "elementary", 183 | "label": "uint256" 184 | }, 185 | "t_array:50": { 186 | "id": "t_array:50", 187 | "valueType": "t_uint256", 188 | "length": "50", 189 | "kind": "array", 190 | "label": "uint256[50]" 191 | }, 192 | "t_mapping": { 193 | "id": "t_mapping", 194 | "valueType": "t_bool", 195 | "label": "mapping(key => bool)", 196 | "kind": "mapping" 197 | }, 198 | "t_mapping": { 199 | "id": "t_mapping", 200 | "valueType": "t_uint256", 201 | "label": "mapping(key => uint256)", 202 | "kind": "mapping" 203 | } 204 | }, 205 | "storage": [ 206 | { 207 | "contract": "Initializable", 208 | "path": "zos-lib/contracts/Initializable.sol", 209 | "label": "initialized", 210 | "astId": 3575, 211 | "type": "t_bool", 212 | "src": "749:24:16" 213 | }, 214 | { 215 | "contract": "Initializable", 216 | "path": "zos-lib/contracts/Initializable.sol", 217 | "label": "initializing", 218 | "astId": 3577, 219 | "type": "t_bool", 220 | "src": "868:25:16" 221 | }, 222 | { 223 | "contract": "Initializable", 224 | "path": "zos-lib/contracts/Initializable.sol", 225 | "label": "______gap", 226 | "astId": 3626, 227 | "type": "t_array:50", 228 | "src": "1883:29:16" 229 | }, 230 | { 231 | "contract": "BasicRegistry", 232 | "path": "contracts/Registry/BasicRegistry.sol", 233 | "label": "items", 234 | "astId": 505, 235 | "type": "t_mapping", 236 | "src": "274:30:4" 237 | }, 238 | { 239 | "contract": "TimelockableItemRegistry", 240 | "path": "contracts/Registry/TimelockableItemRegistry.sol", 241 | "label": "unlockTimes", 242 | "astId": 915, 243 | "type": "t_mapping", 244 | "src": "341:43:8" 245 | } 246 | ], 247 | "warnings": { 248 | "hasConstructor": false, 249 | "hasSelfDestruct": false, 250 | "hasDelegateCall": false, 251 | "hasInitialValuesInDeclarations": false, 252 | "uninitializedBaseContracts": [] 253 | } 254 | }, 255 | "PLCRVotingChallengeFactory": { 256 | "address": "0x1f7386bfeaf313dd55b5f04abdea226b41267f1a", 257 | "constructorCode": "608060405234801561001057600080fd5b50611d0d806100206000396000f300", 258 | "bodyBytecodeHash": "25cd7101670194cecad9d68ac7da9641020e8acd81697c83f4f18ec87aa2ff55", 259 | "localBytecodeHash": "0d55c9174a249aae51c464df42475d958a925a58b073ba030faf7b49d064b5f5", 260 | "deployedBytecodeHash": "0d55c9174a249aae51c464df42475d958a925a58b073ba030faf7b49d064b5f5", 261 | "types": { 262 | "t_bool": { 263 | "id": "t_bool", 264 | "kind": "elementary", 265 | "label": "bool" 266 | }, 267 | "t_uint256": { 268 | "id": "t_uint256", 269 | "kind": "elementary", 270 | "label": "uint256" 271 | }, 272 | "t_array:50": { 273 | "id": "t_array:50", 274 | "valueType": "t_uint256", 275 | "length": "50", 276 | "kind": "array", 277 | "label": "uint256[50]" 278 | }, 279 | "t_address": { 280 | "id": "t_address", 281 | "kind": "elementary", 282 | "label": "address" 283 | } 284 | }, 285 | "storage": [ 286 | { 287 | "contract": "Initializable", 288 | "path": "zos-lib/contracts/Initializable.sol", 289 | "label": "initialized", 290 | "astId": 3575, 291 | "type": "t_bool", 292 | "src": "749:24:16" 293 | }, 294 | { 295 | "contract": "Initializable", 296 | "path": "zos-lib/contracts/Initializable.sol", 297 | "label": "initializing", 298 | "astId": 3577, 299 | "type": "t_bool", 300 | "src": "868:25:16" 301 | }, 302 | { 303 | "contract": "Initializable", 304 | "path": "zos-lib/contracts/Initializable.sol", 305 | "label": "______gap", 306 | "astId": 3626, 307 | "type": "t_array:50", 308 | "src": "1883:29:16" 309 | }, 310 | { 311 | "contract": "PLCRVotingChallengeFactory", 312 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 313 | "label": "challengerStake", 314 | "astId": 399, 315 | "type": "t_uint256", 316 | "src": "337:27:3" 317 | }, 318 | { 319 | "contract": "PLCRVotingChallengeFactory", 320 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 321 | "label": "plcrVoting", 322 | "astId": 401, 323 | "type": "t_address", 324 | "src": "368:25:3" 325 | }, 326 | { 327 | "contract": "PLCRVotingChallengeFactory", 328 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 329 | "label": "commitStageLength", 330 | "astId": 403, 331 | "type": "t_uint256", 332 | "src": "397:29:3" 333 | }, 334 | { 335 | "contract": "PLCRVotingChallengeFactory", 336 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 337 | "label": "revealStageLength", 338 | "astId": 405, 339 | "type": "t_uint256", 340 | "src": "430:29:3" 341 | }, 342 | { 343 | "contract": "PLCRVotingChallengeFactory", 344 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 345 | "label": "voteQuorum", 346 | "astId": 407, 347 | "type": "t_uint256", 348 | "src": "463:22:3" 349 | }, 350 | { 351 | "contract": "PLCRVotingChallengeFactory", 352 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 353 | "label": "percentVoterReward", 354 | "astId": 409, 355 | "type": "t_uint256", 356 | "src": "489:30:3" 357 | } 358 | ], 359 | "warnings": { 360 | "hasConstructor": false, 361 | "hasSelfDestruct": false, 362 | "hasDelegateCall": false, 363 | "hasInitialValuesInDeclarations": false, 364 | "uninitializedBaseContracts": [] 365 | } 366 | }, 367 | "TokenCuratedRegistry": { 368 | "address": "0xcadd8449da9d06c4d812b09e352fcd8212652658", 369 | "constructorCode": "608060405234801561001057600080fd5b5061268e806100206000396000f300", 370 | "bodyBytecodeHash": "0f8e917533622bb23545ceb52e13e61f589a894a5a96b7202647a0975c7e5c03", 371 | "localBytecodeHash": "7c02875a1f13d420997ecd6f471dd7c8fb8c5cc191e60f58f46b01d2695fa4f1", 372 | "deployedBytecodeHash": "7c02875a1f13d420997ecd6f471dd7c8fb8c5cc191e60f58f46b01d2695fa4f1", 373 | "types": { 374 | "t_bool": { 375 | "id": "t_bool", 376 | "kind": "elementary", 377 | "label": "bool" 378 | }, 379 | "t_uint256": { 380 | "id": "t_uint256", 381 | "kind": "elementary", 382 | "label": "uint256" 383 | }, 384 | "t_array:50": { 385 | "id": "t_array:50", 386 | "valueType": "t_uint256", 387 | "length": "50", 388 | "kind": "array", 389 | "label": "uint256[50]" 390 | }, 391 | "t_mapping": { 392 | "id": "t_mapping", 393 | "valueType": "t_bool", 394 | "label": "mapping(key => bool)", 395 | "kind": "mapping" 396 | }, 397 | "t_address": { 398 | "id": "t_address", 399 | "kind": "elementary", 400 | "label": "address" 401 | }, 402 | "t_mapping": { 403 | "id": "t_mapping", 404 | "valueType": "t_address", 405 | "label": "mapping(key => address)", 406 | "kind": "mapping" 407 | }, 408 | "t_mapping": { 409 | "id": "t_mapping", 410 | "valueType": "t_uint256", 411 | "label": "mapping(key => uint256)", 412 | "kind": "mapping" 413 | } 414 | }, 415 | "storage": [ 416 | { 417 | "contract": "Initializable", 418 | "path": "zos-lib/contracts/Initializable.sol", 419 | "label": "initialized", 420 | "astId": 3575, 421 | "type": "t_bool", 422 | "src": "749:24:16" 423 | }, 424 | { 425 | "contract": "Initializable", 426 | "path": "zos-lib/contracts/Initializable.sol", 427 | "label": "initializing", 428 | "astId": 3577, 429 | "type": "t_bool", 430 | "src": "868:25:16" 431 | }, 432 | { 433 | "contract": "Initializable", 434 | "path": "zos-lib/contracts/Initializable.sol", 435 | "label": "______gap", 436 | "astId": 3626, 437 | "type": "t_array:50", 438 | "src": "1883:29:16" 439 | }, 440 | { 441 | "contract": "BasicRegistry", 442 | "path": "contracts/Registry/BasicRegistry.sol", 443 | "label": "items", 444 | "astId": 505, 445 | "type": "t_mapping", 446 | "src": "274:30:4" 447 | }, 448 | { 449 | "contract": "OwnedItemRegistry", 450 | "path": "contracts/Registry/OwnedItemRegistry.sol", 451 | "label": "owners", 452 | "astId": 625, 453 | "type": "t_mapping", 454 | "src": "307:41:6" 455 | }, 456 | { 457 | "contract": "StakedRegistry", 458 | "path": "contracts/Registry/StakedRegistry.sol", 459 | "label": "token", 460 | "astId": 695, 461 | "type": "t_address", 462 | "src": "437:18:7" 463 | }, 464 | { 465 | "contract": "StakedRegistry", 466 | "path": "contracts/Registry/StakedRegistry.sol", 467 | "label": "minStake", 468 | "astId": 697, 469 | "type": "t_uint256", 470 | "src": "515:20:7" 471 | }, 472 | { 473 | "contract": "StakedRegistry", 474 | "path": "contracts/Registry/StakedRegistry.sol", 475 | "label": "ownerStakes", 476 | "astId": 701, 477 | "type": "t_mapping", 478 | "src": "581:43:7" 479 | }, 480 | { 481 | "contract": "TimelockableItemRegistry", 482 | "path": "contracts/Registry/TimelockableItemRegistry.sol", 483 | "label": "unlockTimes", 484 | "astId": 915, 485 | "type": "t_mapping", 486 | "src": "341:43:8" 487 | }, 488 | { 489 | "contract": "TokenCuratedRegistry", 490 | "path": "contracts/Registry/TokenCuratedRegistry.sol", 491 | "label": "applicationPeriod", 492 | "astId": 987, 493 | "type": "t_uint256", 494 | "src": "545:29:9" 495 | }, 496 | { 497 | "contract": "TokenCuratedRegistry", 498 | "path": "contracts/Registry/TokenCuratedRegistry.sol", 499 | "label": "challengeFactory", 500 | "astId": 989, 501 | "type": "t_address", 502 | "src": "624:41:9" 503 | }, 504 | { 505 | "contract": "TokenCuratedRegistry", 506 | "path": "contracts/Registry/TokenCuratedRegistry.sol", 507 | "label": "challenges", 508 | "astId": 993, 509 | "type": "t_mapping", 510 | "src": "721:48:9" 511 | } 512 | ], 513 | "warnings": { 514 | "hasConstructor": false, 515 | "hasSelfDestruct": false, 516 | "hasDelegateCall": false, 517 | "hasInitialValuesInDeclarations": false, 518 | "uninitializedBaseContracts": [] 519 | } 520 | }, 521 | "StakedRegistry": { 522 | "address": "0xcf7959fa5b478ec0145c4cd426be57ba781f56e9", 523 | "constructorCode": "608060405234801561001057600080fd5b50611062806100206000396000f300", 524 | "bodyBytecodeHash": "6eef5ca1332922ca41e0b55835a0216b15ae78e422aa74e680fe295e1a2dff90", 525 | "localBytecodeHash": "14e686feb65c5292073d8451a98fe3bd3ea3312e4d45e261cfc0d23cb13f23d0", 526 | "deployedBytecodeHash": "14e686feb65c5292073d8451a98fe3bd3ea3312e4d45e261cfc0d23cb13f23d0", 527 | "types": { 528 | "t_bool": { 529 | "id": "t_bool", 530 | "kind": "elementary", 531 | "label": "bool" 532 | }, 533 | "t_uint256": { 534 | "id": "t_uint256", 535 | "kind": "elementary", 536 | "label": "uint256" 537 | }, 538 | "t_array:50": { 539 | "id": "t_array:50", 540 | "valueType": "t_uint256", 541 | "length": "50", 542 | "kind": "array", 543 | "label": "uint256[50]" 544 | }, 545 | "t_mapping": { 546 | "id": "t_mapping", 547 | "valueType": "t_bool", 548 | "label": "mapping(key => bool)", 549 | "kind": "mapping" 550 | }, 551 | "t_address": { 552 | "id": "t_address", 553 | "kind": "elementary", 554 | "label": "address" 555 | }, 556 | "t_mapping": { 557 | "id": "t_mapping", 558 | "valueType": "t_address", 559 | "label": "mapping(key => address)", 560 | "kind": "mapping" 561 | }, 562 | "t_mapping": { 563 | "id": "t_mapping", 564 | "valueType": "t_uint256", 565 | "label": "mapping(key => uint256)", 566 | "kind": "mapping" 567 | } 568 | }, 569 | "storage": [ 570 | { 571 | "contract": "Initializable", 572 | "path": "zos-lib/contracts/Initializable.sol", 573 | "label": "initialized", 574 | "astId": 3575, 575 | "type": "t_bool", 576 | "src": "749:24:16" 577 | }, 578 | { 579 | "contract": "Initializable", 580 | "path": "zos-lib/contracts/Initializable.sol", 581 | "label": "initializing", 582 | "astId": 3577, 583 | "type": "t_bool", 584 | "src": "868:25:16" 585 | }, 586 | { 587 | "contract": "Initializable", 588 | "path": "zos-lib/contracts/Initializable.sol", 589 | "label": "______gap", 590 | "astId": 3626, 591 | "type": "t_array:50", 592 | "src": "1883:29:16" 593 | }, 594 | { 595 | "contract": "BasicRegistry", 596 | "path": "contracts/Registry/BasicRegistry.sol", 597 | "label": "items", 598 | "astId": 505, 599 | "type": "t_mapping", 600 | "src": "274:30:4" 601 | }, 602 | { 603 | "contract": "OwnedItemRegistry", 604 | "path": "contracts/Registry/OwnedItemRegistry.sol", 605 | "label": "owners", 606 | "astId": 625, 607 | "type": "t_mapping", 608 | "src": "307:41:6" 609 | }, 610 | { 611 | "contract": "StakedRegistry", 612 | "path": "contracts/Registry/StakedRegistry.sol", 613 | "label": "token", 614 | "astId": 695, 615 | "type": "t_address", 616 | "src": "437:18:7" 617 | }, 618 | { 619 | "contract": "StakedRegistry", 620 | "path": "contracts/Registry/StakedRegistry.sol", 621 | "label": "minStake", 622 | "astId": 697, 623 | "type": "t_uint256", 624 | "src": "515:20:7" 625 | }, 626 | { 627 | "contract": "StakedRegistry", 628 | "path": "contracts/Registry/StakedRegistry.sol", 629 | "label": "ownerStakes", 630 | "astId": 701, 631 | "type": "t_mapping", 632 | "src": "581:43:7" 633 | } 634 | ], 635 | "warnings": { 636 | "hasConstructor": false, 637 | "hasSelfDestruct": false, 638 | "hasDelegateCall": false, 639 | "hasInitialValuesInDeclarations": false, 640 | "uninitializedBaseContracts": [] 641 | } 642 | } 643 | }, 644 | "solidityLibs": {}, 645 | "proxies": {}, 646 | "zosversion": "2", 647 | "frozen": false, 648 | "app": { 649 | "address": "0x33f7a6835c6fdbf69eaea9d5371853a7d9b73a9d" 650 | }, 651 | "package": { 652 | "address": "0xbcc8a8f7d95e30f48e6cff652d238b12bfc5ce16" 653 | }, 654 | "provider": { 655 | "address": "0xc6bb46830a7d23548f0fafb51f34c959afc02196" 656 | }, 657 | "version": "0.1.0" 658 | } -------------------------------------------------------------------------------- /zos.rinkeby.json: -------------------------------------------------------------------------------- 1 | { 2 | "contracts": { 3 | "OwnedItemRegistry": { 4 | "address": "0x7230715d26721414a8d3ad3a8296cf4df1d786bf", 5 | "constructorCode": "608060405234801561001057600080fd5b5061046e806100206000396000f300", 6 | "bodyBytecodeHash": "bbacd610fa99a625219b716e6ee4354ab784f12fbeea321369b33ce79fbf9648", 7 | "localBytecodeHash": "99d25bd908e58d83415b86085426f2f658a2e4efdfb568bcea731044c0dbebd8", 8 | "deployedBytecodeHash": "99d25bd908e58d83415b86085426f2f658a2e4efdfb568bcea731044c0dbebd8", 9 | "types": { 10 | "t_bool": { 11 | "id": "t_bool", 12 | "kind": "elementary", 13 | "label": "bool" 14 | }, 15 | "t_uint256": { 16 | "id": "t_uint256", 17 | "kind": "elementary", 18 | "label": "uint256" 19 | }, 20 | "t_array:50": { 21 | "id": "t_array:50", 22 | "valueType": "t_uint256", 23 | "length": "50", 24 | "kind": "array", 25 | "label": "uint256[50]" 26 | }, 27 | "t_mapping": { 28 | "id": "t_mapping", 29 | "valueType": "t_bool", 30 | "label": "mapping(key => bool)", 31 | "kind": "mapping" 32 | }, 33 | "t_address": { 34 | "id": "t_address", 35 | "kind": "elementary", 36 | "label": "address" 37 | }, 38 | "t_mapping": { 39 | "id": "t_mapping", 40 | "valueType": "t_address", 41 | "label": "mapping(key => address)", 42 | "kind": "mapping" 43 | } 44 | }, 45 | "storage": [ 46 | { 47 | "contract": "Initializable", 48 | "path": "zos-lib/contracts/Initializable.sol", 49 | "label": "initialized", 50 | "astId": 3575, 51 | "type": "t_bool", 52 | "src": "749:24:16" 53 | }, 54 | { 55 | "contract": "Initializable", 56 | "path": "zos-lib/contracts/Initializable.sol", 57 | "label": "initializing", 58 | "astId": 3577, 59 | "type": "t_bool", 60 | "src": "868:25:16" 61 | }, 62 | { 63 | "contract": "Initializable", 64 | "path": "zos-lib/contracts/Initializable.sol", 65 | "label": "______gap", 66 | "astId": 3626, 67 | "type": "t_array:50", 68 | "src": "1883:29:16" 69 | }, 70 | { 71 | "contract": "BasicRegistry", 72 | "path": "contracts/Registry/BasicRegistry.sol", 73 | "label": "items", 74 | "astId": 505, 75 | "type": "t_mapping", 76 | "src": "274:30:4" 77 | }, 78 | { 79 | "contract": "OwnedItemRegistry", 80 | "path": "contracts/Registry/OwnedItemRegistry.sol", 81 | "label": "owners", 82 | "astId": 625, 83 | "type": "t_mapping", 84 | "src": "307:41:6" 85 | } 86 | ], 87 | "warnings": { 88 | "hasConstructor": false, 89 | "hasSelfDestruct": false, 90 | "hasDelegateCall": false, 91 | "hasInitialValuesInDeclarations": false, 92 | "uninitializedBaseContracts": [] 93 | } 94 | }, 95 | "StakedRegistry": { 96 | "address": "0xe99cfd468647edb80ffcf806a400c41e81b6c8d4", 97 | "constructorCode": "608060405234801561001057600080fd5b50611062806100206000396000f300", 98 | "bodyBytecodeHash": "6eef5ca1332922ca41e0b55835a0216b15ae78e422aa74e680fe295e1a2dff90", 99 | "localBytecodeHash": "14e686feb65c5292073d8451a98fe3bd3ea3312e4d45e261cfc0d23cb13f23d0", 100 | "deployedBytecodeHash": "14e686feb65c5292073d8451a98fe3bd3ea3312e4d45e261cfc0d23cb13f23d0", 101 | "types": { 102 | "t_bool": { 103 | "id": "t_bool", 104 | "kind": "elementary", 105 | "label": "bool" 106 | }, 107 | "t_uint256": { 108 | "id": "t_uint256", 109 | "kind": "elementary", 110 | "label": "uint256" 111 | }, 112 | "t_array:50": { 113 | "id": "t_array:50", 114 | "valueType": "t_uint256", 115 | "length": "50", 116 | "kind": "array", 117 | "label": "uint256[50]" 118 | }, 119 | "t_mapping": { 120 | "id": "t_mapping", 121 | "valueType": "t_bool", 122 | "label": "mapping(key => bool)", 123 | "kind": "mapping" 124 | }, 125 | "t_address": { 126 | "id": "t_address", 127 | "kind": "elementary", 128 | "label": "address" 129 | }, 130 | "t_mapping": { 131 | "id": "t_mapping", 132 | "valueType": "t_address", 133 | "label": "mapping(key => address)", 134 | "kind": "mapping" 135 | }, 136 | "t_mapping": { 137 | "id": "t_mapping", 138 | "valueType": "t_uint256", 139 | "label": "mapping(key => uint256)", 140 | "kind": "mapping" 141 | } 142 | }, 143 | "storage": [ 144 | { 145 | "contract": "Initializable", 146 | "path": "zos-lib/contracts/Initializable.sol", 147 | "label": "initialized", 148 | "astId": 3575, 149 | "type": "t_bool", 150 | "src": "749:24:16" 151 | }, 152 | { 153 | "contract": "Initializable", 154 | "path": "zos-lib/contracts/Initializable.sol", 155 | "label": "initializing", 156 | "astId": 3577, 157 | "type": "t_bool", 158 | "src": "868:25:16" 159 | }, 160 | { 161 | "contract": "Initializable", 162 | "path": "zos-lib/contracts/Initializable.sol", 163 | "label": "______gap", 164 | "astId": 3626, 165 | "type": "t_array:50", 166 | "src": "1883:29:16" 167 | }, 168 | { 169 | "contract": "BasicRegistry", 170 | "path": "contracts/Registry/BasicRegistry.sol", 171 | "label": "items", 172 | "astId": 505, 173 | "type": "t_mapping", 174 | "src": "274:30:4" 175 | }, 176 | { 177 | "contract": "OwnedItemRegistry", 178 | "path": "contracts/Registry/OwnedItemRegistry.sol", 179 | "label": "owners", 180 | "astId": 625, 181 | "type": "t_mapping", 182 | "src": "307:41:6" 183 | }, 184 | { 185 | "contract": "StakedRegistry", 186 | "path": "contracts/Registry/StakedRegistry.sol", 187 | "label": "token", 188 | "astId": 695, 189 | "type": "t_address", 190 | "src": "437:18:7" 191 | }, 192 | { 193 | "contract": "StakedRegistry", 194 | "path": "contracts/Registry/StakedRegistry.sol", 195 | "label": "minStake", 196 | "astId": 697, 197 | "type": "t_uint256", 198 | "src": "515:20:7" 199 | }, 200 | { 201 | "contract": "StakedRegistry", 202 | "path": "contracts/Registry/StakedRegistry.sol", 203 | "label": "ownerStakes", 204 | "astId": 701, 205 | "type": "t_mapping", 206 | "src": "581:43:7" 207 | } 208 | ], 209 | "warnings": { 210 | "hasConstructor": false, 211 | "hasSelfDestruct": false, 212 | "hasDelegateCall": false, 213 | "hasInitialValuesInDeclarations": false, 214 | "uninitializedBaseContracts": [] 215 | } 216 | }, 217 | "PLCRVotingChallengeFactory": { 218 | "address": "0x776f86212ad3e712dffc7c1f9eb52f57dc86e209", 219 | "constructorCode": "608060405234801561001057600080fd5b50611d0d806100206000396000f300", 220 | "bodyBytecodeHash": "25cd7101670194cecad9d68ac7da9641020e8acd81697c83f4f18ec87aa2ff55", 221 | "localBytecodeHash": "0d55c9174a249aae51c464df42475d958a925a58b073ba030faf7b49d064b5f5", 222 | "deployedBytecodeHash": "0d55c9174a249aae51c464df42475d958a925a58b073ba030faf7b49d064b5f5", 223 | "types": { 224 | "t_bool": { 225 | "id": "t_bool", 226 | "kind": "elementary", 227 | "label": "bool" 228 | }, 229 | "t_uint256": { 230 | "id": "t_uint256", 231 | "kind": "elementary", 232 | "label": "uint256" 233 | }, 234 | "t_array:50": { 235 | "id": "t_array:50", 236 | "valueType": "t_uint256", 237 | "length": "50", 238 | "kind": "array", 239 | "label": "uint256[50]" 240 | }, 241 | "t_address": { 242 | "id": "t_address", 243 | "kind": "elementary", 244 | "label": "address" 245 | } 246 | }, 247 | "storage": [ 248 | { 249 | "contract": "Initializable", 250 | "path": "zos-lib/contracts/Initializable.sol", 251 | "label": "initialized", 252 | "astId": 3575, 253 | "type": "t_bool", 254 | "src": "749:24:16" 255 | }, 256 | { 257 | "contract": "Initializable", 258 | "path": "zos-lib/contracts/Initializable.sol", 259 | "label": "initializing", 260 | "astId": 3577, 261 | "type": "t_bool", 262 | "src": "868:25:16" 263 | }, 264 | { 265 | "contract": "Initializable", 266 | "path": "zos-lib/contracts/Initializable.sol", 267 | "label": "______gap", 268 | "astId": 3626, 269 | "type": "t_array:50", 270 | "src": "1883:29:16" 271 | }, 272 | { 273 | "contract": "PLCRVotingChallengeFactory", 274 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 275 | "label": "challengerStake", 276 | "astId": 399, 277 | "type": "t_uint256", 278 | "src": "337:27:3" 279 | }, 280 | { 281 | "contract": "PLCRVotingChallengeFactory", 282 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 283 | "label": "plcrVoting", 284 | "astId": 401, 285 | "type": "t_address", 286 | "src": "368:25:3" 287 | }, 288 | { 289 | "contract": "PLCRVotingChallengeFactory", 290 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 291 | "label": "commitStageLength", 292 | "astId": 403, 293 | "type": "t_uint256", 294 | "src": "397:29:3" 295 | }, 296 | { 297 | "contract": "PLCRVotingChallengeFactory", 298 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 299 | "label": "revealStageLength", 300 | "astId": 405, 301 | "type": "t_uint256", 302 | "src": "430:29:3" 303 | }, 304 | { 305 | "contract": "PLCRVotingChallengeFactory", 306 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 307 | "label": "voteQuorum", 308 | "astId": 407, 309 | "type": "t_uint256", 310 | "src": "463:22:3" 311 | }, 312 | { 313 | "contract": "PLCRVotingChallengeFactory", 314 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 315 | "label": "percentVoterReward", 316 | "astId": 409, 317 | "type": "t_uint256", 318 | "src": "489:30:3" 319 | } 320 | ], 321 | "warnings": { 322 | "hasConstructor": false, 323 | "hasSelfDestruct": false, 324 | "hasDelegateCall": false, 325 | "hasInitialValuesInDeclarations": false, 326 | "uninitializedBaseContracts": [] 327 | } 328 | }, 329 | "BasicRegistry": { 330 | "address": "0x8b067a6bf8e119e21384fb3d8ebd63899d1163d7", 331 | "constructorCode": "608060405234801561001057600080fd5b50610298806100206000396000f300", 332 | "bodyBytecodeHash": "2f9a209335ccce764072531a7e287df0eb22bbddad6f7cf1179a398daa3a5839", 333 | "localBytecodeHash": "4b98f4a2b8f431b011e6249051d0e3aa5fbe87bd3d7c94284a2b2f9b8aa3cb5b", 334 | "deployedBytecodeHash": "4b98f4a2b8f431b011e6249051d0e3aa5fbe87bd3d7c94284a2b2f9b8aa3cb5b", 335 | "types": { 336 | "t_bool": { 337 | "id": "t_bool", 338 | "kind": "elementary", 339 | "label": "bool" 340 | }, 341 | "t_uint256": { 342 | "id": "t_uint256", 343 | "kind": "elementary", 344 | "label": "uint256" 345 | }, 346 | "t_array:50": { 347 | "id": "t_array:50", 348 | "valueType": "t_uint256", 349 | "length": "50", 350 | "kind": "array", 351 | "label": "uint256[50]" 352 | }, 353 | "t_mapping": { 354 | "id": "t_mapping", 355 | "valueType": "t_bool", 356 | "label": "mapping(key => bool)", 357 | "kind": "mapping" 358 | } 359 | }, 360 | "storage": [ 361 | { 362 | "contract": "Initializable", 363 | "path": "zos-lib/contracts/Initializable.sol", 364 | "label": "initialized", 365 | "astId": 3575, 366 | "type": "t_bool", 367 | "src": "749:24:16" 368 | }, 369 | { 370 | "contract": "Initializable", 371 | "path": "zos-lib/contracts/Initializable.sol", 372 | "label": "initializing", 373 | "astId": 3577, 374 | "type": "t_bool", 375 | "src": "868:25:16" 376 | }, 377 | { 378 | "contract": "Initializable", 379 | "path": "zos-lib/contracts/Initializable.sol", 380 | "label": "______gap", 381 | "astId": 3626, 382 | "type": "t_array:50", 383 | "src": "1883:29:16" 384 | }, 385 | { 386 | "contract": "BasicRegistry", 387 | "path": "contracts/Registry/BasicRegistry.sol", 388 | "label": "items", 389 | "astId": 505, 390 | "type": "t_mapping", 391 | "src": "274:30:4" 392 | } 393 | ], 394 | "warnings": { 395 | "hasConstructor": false, 396 | "hasSelfDestruct": false, 397 | "hasDelegateCall": false, 398 | "hasInitialValuesInDeclarations": false, 399 | "uninitializedBaseContracts": [] 400 | } 401 | }, 402 | "TimelockableItemRegistry": { 403 | "address": "0xcadd8449da9d06c4d812b09e352fcd8212652658", 404 | "constructorCode": "608060405234801561001057600080fd5b506103e1806100206000396000f300", 405 | "bodyBytecodeHash": "27da4ce90e7aa17afef252652a2620df75d2cab14c778a348c5c461e24e29923", 406 | "localBytecodeHash": "5c96c9f1047cb34a464d450496a2399fcdac34b0af7fb295dee491743580b5da", 407 | "deployedBytecodeHash": "5c96c9f1047cb34a464d450496a2399fcdac34b0af7fb295dee491743580b5da", 408 | "types": { 409 | "t_bool": { 410 | "id": "t_bool", 411 | "kind": "elementary", 412 | "label": "bool" 413 | }, 414 | "t_uint256": { 415 | "id": "t_uint256", 416 | "kind": "elementary", 417 | "label": "uint256" 418 | }, 419 | "t_array:50": { 420 | "id": "t_array:50", 421 | "valueType": "t_uint256", 422 | "length": "50", 423 | "kind": "array", 424 | "label": "uint256[50]" 425 | }, 426 | "t_mapping": { 427 | "id": "t_mapping", 428 | "valueType": "t_bool", 429 | "label": "mapping(key => bool)", 430 | "kind": "mapping" 431 | }, 432 | "t_mapping": { 433 | "id": "t_mapping", 434 | "valueType": "t_uint256", 435 | "label": "mapping(key => uint256)", 436 | "kind": "mapping" 437 | } 438 | }, 439 | "storage": [ 440 | { 441 | "contract": "Initializable", 442 | "path": "zos-lib/contracts/Initializable.sol", 443 | "label": "initialized", 444 | "astId": 3575, 445 | "type": "t_bool", 446 | "src": "749:24:16" 447 | }, 448 | { 449 | "contract": "Initializable", 450 | "path": "zos-lib/contracts/Initializable.sol", 451 | "label": "initializing", 452 | "astId": 3577, 453 | "type": "t_bool", 454 | "src": "868:25:16" 455 | }, 456 | { 457 | "contract": "Initializable", 458 | "path": "zos-lib/contracts/Initializable.sol", 459 | "label": "______gap", 460 | "astId": 3626, 461 | "type": "t_array:50", 462 | "src": "1883:29:16" 463 | }, 464 | { 465 | "contract": "BasicRegistry", 466 | "path": "contracts/Registry/BasicRegistry.sol", 467 | "label": "items", 468 | "astId": 505, 469 | "type": "t_mapping", 470 | "src": "274:30:4" 471 | }, 472 | { 473 | "contract": "TimelockableItemRegistry", 474 | "path": "contracts/Registry/TimelockableItemRegistry.sol", 475 | "label": "unlockTimes", 476 | "astId": 915, 477 | "type": "t_mapping", 478 | "src": "341:43:8" 479 | } 480 | ], 481 | "warnings": { 482 | "hasConstructor": false, 483 | "hasSelfDestruct": false, 484 | "hasDelegateCall": false, 485 | "hasInitialValuesInDeclarations": false, 486 | "uninitializedBaseContracts": [] 487 | } 488 | }, 489 | "TokenCuratedRegistry": { 490 | "address": "0x1f7386bfeaf313dd55b5f04abdea226b41267f1a", 491 | "constructorCode": "608060405234801561001057600080fd5b5061268e806100206000396000f300", 492 | "bodyBytecodeHash": "0f8e917533622bb23545ceb52e13e61f589a894a5a96b7202647a0975c7e5c03", 493 | "localBytecodeHash": "7c02875a1f13d420997ecd6f471dd7c8fb8c5cc191e60f58f46b01d2695fa4f1", 494 | "deployedBytecodeHash": "7c02875a1f13d420997ecd6f471dd7c8fb8c5cc191e60f58f46b01d2695fa4f1", 495 | "types": { 496 | "t_bool": { 497 | "id": "t_bool", 498 | "kind": "elementary", 499 | "label": "bool" 500 | }, 501 | "t_uint256": { 502 | "id": "t_uint256", 503 | "kind": "elementary", 504 | "label": "uint256" 505 | }, 506 | "t_array:50": { 507 | "id": "t_array:50", 508 | "valueType": "t_uint256", 509 | "length": "50", 510 | "kind": "array", 511 | "label": "uint256[50]" 512 | }, 513 | "t_mapping": { 514 | "id": "t_mapping", 515 | "valueType": "t_bool", 516 | "label": "mapping(key => bool)", 517 | "kind": "mapping" 518 | }, 519 | "t_address": { 520 | "id": "t_address", 521 | "kind": "elementary", 522 | "label": "address" 523 | }, 524 | "t_mapping": { 525 | "id": "t_mapping", 526 | "valueType": "t_address", 527 | "label": "mapping(key => address)", 528 | "kind": "mapping" 529 | }, 530 | "t_mapping": { 531 | "id": "t_mapping", 532 | "valueType": "t_uint256", 533 | "label": "mapping(key => uint256)", 534 | "kind": "mapping" 535 | } 536 | }, 537 | "storage": [ 538 | { 539 | "contract": "Initializable", 540 | "path": "zos-lib/contracts/Initializable.sol", 541 | "label": "initialized", 542 | "astId": 3575, 543 | "type": "t_bool", 544 | "src": "749:24:16" 545 | }, 546 | { 547 | "contract": "Initializable", 548 | "path": "zos-lib/contracts/Initializable.sol", 549 | "label": "initializing", 550 | "astId": 3577, 551 | "type": "t_bool", 552 | "src": "868:25:16" 553 | }, 554 | { 555 | "contract": "Initializable", 556 | "path": "zos-lib/contracts/Initializable.sol", 557 | "label": "______gap", 558 | "astId": 3626, 559 | "type": "t_array:50", 560 | "src": "1883:29:16" 561 | }, 562 | { 563 | "contract": "BasicRegistry", 564 | "path": "contracts/Registry/BasicRegistry.sol", 565 | "label": "items", 566 | "astId": 505, 567 | "type": "t_mapping", 568 | "src": "274:30:4" 569 | }, 570 | { 571 | "contract": "OwnedItemRegistry", 572 | "path": "contracts/Registry/OwnedItemRegistry.sol", 573 | "label": "owners", 574 | "astId": 625, 575 | "type": "t_mapping", 576 | "src": "307:41:6" 577 | }, 578 | { 579 | "contract": "StakedRegistry", 580 | "path": "contracts/Registry/StakedRegistry.sol", 581 | "label": "token", 582 | "astId": 695, 583 | "type": "t_address", 584 | "src": "437:18:7" 585 | }, 586 | { 587 | "contract": "StakedRegistry", 588 | "path": "contracts/Registry/StakedRegistry.sol", 589 | "label": "minStake", 590 | "astId": 697, 591 | "type": "t_uint256", 592 | "src": "515:20:7" 593 | }, 594 | { 595 | "contract": "StakedRegistry", 596 | "path": "contracts/Registry/StakedRegistry.sol", 597 | "label": "ownerStakes", 598 | "astId": 701, 599 | "type": "t_mapping", 600 | "src": "581:43:7" 601 | }, 602 | { 603 | "contract": "TimelockableItemRegistry", 604 | "path": "contracts/Registry/TimelockableItemRegistry.sol", 605 | "label": "unlockTimes", 606 | "astId": 915, 607 | "type": "t_mapping", 608 | "src": "341:43:8" 609 | }, 610 | { 611 | "contract": "TokenCuratedRegistry", 612 | "path": "contracts/Registry/TokenCuratedRegistry.sol", 613 | "label": "applicationPeriod", 614 | "astId": 987, 615 | "type": "t_uint256", 616 | "src": "545:29:9" 617 | }, 618 | { 619 | "contract": "TokenCuratedRegistry", 620 | "path": "contracts/Registry/TokenCuratedRegistry.sol", 621 | "label": "challengeFactory", 622 | "astId": 989, 623 | "type": "t_address", 624 | "src": "624:41:9" 625 | }, 626 | { 627 | "contract": "TokenCuratedRegistry", 628 | "path": "contracts/Registry/TokenCuratedRegistry.sol", 629 | "label": "challenges", 630 | "astId": 993, 631 | "type": "t_mapping", 632 | "src": "721:48:9" 633 | } 634 | ], 635 | "warnings": { 636 | "hasConstructor": false, 637 | "hasSelfDestruct": false, 638 | "hasDelegateCall": false, 639 | "hasInitialValuesInDeclarations": false, 640 | "uninitializedBaseContracts": [] 641 | } 642 | } 643 | }, 644 | "solidityLibs": {}, 645 | "proxies": {}, 646 | "zosversion": "2", 647 | "frozen": false, 648 | "app": { 649 | "address": "0x33f7a6835c6fdbf69eaea9d5371853a7d9b73a9d" 650 | }, 651 | "package": { 652 | "address": "0xbcc8a8f7d95e30f48e6cff652d238b12bfc5ce16" 653 | }, 654 | "provider": { 655 | "address": "0xc6bb46830a7d23548f0fafb51f34c959afc02196" 656 | }, 657 | "version": "0.1.0" 658 | } -------------------------------------------------------------------------------- /zos.ropsten.json: -------------------------------------------------------------------------------- 1 | { 2 | "contracts": { 3 | "BasicRegistry": { 4 | "address": "0x776f86212ad3e712dffc7c1f9eb52f57dc86e209", 5 | "constructorCode": "608060405234801561001057600080fd5b50610298806100206000396000f300", 6 | "bodyBytecodeHash": "2f9a209335ccce764072531a7e287df0eb22bbddad6f7cf1179a398daa3a5839", 7 | "localBytecodeHash": "4b98f4a2b8f431b011e6249051d0e3aa5fbe87bd3d7c94284a2b2f9b8aa3cb5b", 8 | "deployedBytecodeHash": "4b98f4a2b8f431b011e6249051d0e3aa5fbe87bd3d7c94284a2b2f9b8aa3cb5b", 9 | "types": { 10 | "t_bool": { 11 | "id": "t_bool", 12 | "kind": "elementary", 13 | "label": "bool" 14 | }, 15 | "t_uint256": { 16 | "id": "t_uint256", 17 | "kind": "elementary", 18 | "label": "uint256" 19 | }, 20 | "t_array:50": { 21 | "id": "t_array:50", 22 | "valueType": "t_uint256", 23 | "length": "50", 24 | "kind": "array", 25 | "label": "uint256[50]" 26 | }, 27 | "t_mapping": { 28 | "id": "t_mapping", 29 | "valueType": "t_bool", 30 | "label": "mapping(key => bool)", 31 | "kind": "mapping" 32 | } 33 | }, 34 | "storage": [ 35 | { 36 | "contract": "Initializable", 37 | "path": "zos-lib/contracts/Initializable.sol", 38 | "label": "initialized", 39 | "astId": 3575, 40 | "type": "t_bool", 41 | "src": "749:24:16" 42 | }, 43 | { 44 | "contract": "Initializable", 45 | "path": "zos-lib/contracts/Initializable.sol", 46 | "label": "initializing", 47 | "astId": 3577, 48 | "type": "t_bool", 49 | "src": "868:25:16" 50 | }, 51 | { 52 | "contract": "Initializable", 53 | "path": "zos-lib/contracts/Initializable.sol", 54 | "label": "______gap", 55 | "astId": 3626, 56 | "type": "t_array:50", 57 | "src": "1883:29:16" 58 | }, 59 | { 60 | "contract": "BasicRegistry", 61 | "path": "contracts/Registry/BasicRegistry.sol", 62 | "label": "items", 63 | "astId": 505, 64 | "type": "t_mapping", 65 | "src": "274:30:4" 66 | } 67 | ], 68 | "warnings": { 69 | "hasConstructor": false, 70 | "hasSelfDestruct": false, 71 | "hasDelegateCall": false, 72 | "hasInitialValuesInDeclarations": false, 73 | "uninitializedBaseContracts": [] 74 | } 75 | }, 76 | "TokenCuratedRegistry": { 77 | "address": "0x9507adee3f3562a924f9b7ea1694e73068c112f1", 78 | "constructorCode": "608060405234801561001057600080fd5b5061268e806100206000396000f300", 79 | "bodyBytecodeHash": "0f8e917533622bb23545ceb52e13e61f589a894a5a96b7202647a0975c7e5c03", 80 | "localBytecodeHash": "7c02875a1f13d420997ecd6f471dd7c8fb8c5cc191e60f58f46b01d2695fa4f1", 81 | "deployedBytecodeHash": "7c02875a1f13d420997ecd6f471dd7c8fb8c5cc191e60f58f46b01d2695fa4f1", 82 | "types": { 83 | "t_bool": { 84 | "id": "t_bool", 85 | "kind": "elementary", 86 | "label": "bool" 87 | }, 88 | "t_uint256": { 89 | "id": "t_uint256", 90 | "kind": "elementary", 91 | "label": "uint256" 92 | }, 93 | "t_array:50": { 94 | "id": "t_array:50", 95 | "valueType": "t_uint256", 96 | "length": "50", 97 | "kind": "array", 98 | "label": "uint256[50]" 99 | }, 100 | "t_mapping": { 101 | "id": "t_mapping", 102 | "valueType": "t_bool", 103 | "label": "mapping(key => bool)", 104 | "kind": "mapping" 105 | }, 106 | "t_address": { 107 | "id": "t_address", 108 | "kind": "elementary", 109 | "label": "address" 110 | }, 111 | "t_mapping": { 112 | "id": "t_mapping", 113 | "valueType": "t_address", 114 | "label": "mapping(key => address)", 115 | "kind": "mapping" 116 | }, 117 | "t_mapping": { 118 | "id": "t_mapping", 119 | "valueType": "t_uint256", 120 | "label": "mapping(key => uint256)", 121 | "kind": "mapping" 122 | } 123 | }, 124 | "storage": [ 125 | { 126 | "contract": "Initializable", 127 | "path": "zos-lib/contracts/Initializable.sol", 128 | "label": "initialized", 129 | "astId": 3575, 130 | "type": "t_bool", 131 | "src": "749:24:16" 132 | }, 133 | { 134 | "contract": "Initializable", 135 | "path": "zos-lib/contracts/Initializable.sol", 136 | "label": "initializing", 137 | "astId": 3577, 138 | "type": "t_bool", 139 | "src": "868:25:16" 140 | }, 141 | { 142 | "contract": "Initializable", 143 | "path": "zos-lib/contracts/Initializable.sol", 144 | "label": "______gap", 145 | "astId": 3626, 146 | "type": "t_array:50", 147 | "src": "1883:29:16" 148 | }, 149 | { 150 | "contract": "BasicRegistry", 151 | "path": "contracts/Registry/BasicRegistry.sol", 152 | "label": "items", 153 | "astId": 505, 154 | "type": "t_mapping", 155 | "src": "274:30:4" 156 | }, 157 | { 158 | "contract": "OwnedItemRegistry", 159 | "path": "contracts/Registry/OwnedItemRegistry.sol", 160 | "label": "owners", 161 | "astId": 625, 162 | "type": "t_mapping", 163 | "src": "307:41:6" 164 | }, 165 | { 166 | "contract": "StakedRegistry", 167 | "path": "contracts/Registry/StakedRegistry.sol", 168 | "label": "token", 169 | "astId": 695, 170 | "type": "t_address", 171 | "src": "437:18:7" 172 | }, 173 | { 174 | "contract": "StakedRegistry", 175 | "path": "contracts/Registry/StakedRegistry.sol", 176 | "label": "minStake", 177 | "astId": 697, 178 | "type": "t_uint256", 179 | "src": "515:20:7" 180 | }, 181 | { 182 | "contract": "StakedRegistry", 183 | "path": "contracts/Registry/StakedRegistry.sol", 184 | "label": "ownerStakes", 185 | "astId": 701, 186 | "type": "t_mapping", 187 | "src": "581:43:7" 188 | }, 189 | { 190 | "contract": "TimelockableItemRegistry", 191 | "path": "contracts/Registry/TimelockableItemRegistry.sol", 192 | "label": "unlockTimes", 193 | "astId": 915, 194 | "type": "t_mapping", 195 | "src": "341:43:8" 196 | }, 197 | { 198 | "contract": "TokenCuratedRegistry", 199 | "path": "contracts/Registry/TokenCuratedRegistry.sol", 200 | "label": "applicationPeriod", 201 | "astId": 987, 202 | "type": "t_uint256", 203 | "src": "545:29:9" 204 | }, 205 | { 206 | "contract": "TokenCuratedRegistry", 207 | "path": "contracts/Registry/TokenCuratedRegistry.sol", 208 | "label": "challengeFactory", 209 | "astId": 989, 210 | "type": "t_address", 211 | "src": "624:41:9" 212 | }, 213 | { 214 | "contract": "TokenCuratedRegistry", 215 | "path": "contracts/Registry/TokenCuratedRegistry.sol", 216 | "label": "challenges", 217 | "astId": 993, 218 | "type": "t_mapping", 219 | "src": "721:48:9" 220 | } 221 | ], 222 | "warnings": { 223 | "hasConstructor": false, 224 | "hasSelfDestruct": false, 225 | "hasDelegateCall": false, 226 | "hasInitialValuesInDeclarations": false, 227 | "uninitializedBaseContracts": [] 228 | } 229 | }, 230 | "TimelockableItemRegistry": { 231 | "address": "0xe99cfd468647edb80ffcf806a400c41e81b6c8d4", 232 | "constructorCode": "608060405234801561001057600080fd5b506103e1806100206000396000f300", 233 | "bodyBytecodeHash": "27da4ce90e7aa17afef252652a2620df75d2cab14c778a348c5c461e24e29923", 234 | "localBytecodeHash": "5c96c9f1047cb34a464d450496a2399fcdac34b0af7fb295dee491743580b5da", 235 | "deployedBytecodeHash": "5c96c9f1047cb34a464d450496a2399fcdac34b0af7fb295dee491743580b5da", 236 | "types": { 237 | "t_bool": { 238 | "id": "t_bool", 239 | "kind": "elementary", 240 | "label": "bool" 241 | }, 242 | "t_uint256": { 243 | "id": "t_uint256", 244 | "kind": "elementary", 245 | "label": "uint256" 246 | }, 247 | "t_array:50": { 248 | "id": "t_array:50", 249 | "valueType": "t_uint256", 250 | "length": "50", 251 | "kind": "array", 252 | "label": "uint256[50]" 253 | }, 254 | "t_mapping": { 255 | "id": "t_mapping", 256 | "valueType": "t_bool", 257 | "label": "mapping(key => bool)", 258 | "kind": "mapping" 259 | }, 260 | "t_mapping": { 261 | "id": "t_mapping", 262 | "valueType": "t_uint256", 263 | "label": "mapping(key => uint256)", 264 | "kind": "mapping" 265 | } 266 | }, 267 | "storage": [ 268 | { 269 | "contract": "Initializable", 270 | "path": "zos-lib/contracts/Initializable.sol", 271 | "label": "initialized", 272 | "astId": 3575, 273 | "type": "t_bool", 274 | "src": "749:24:16" 275 | }, 276 | { 277 | "contract": "Initializable", 278 | "path": "zos-lib/contracts/Initializable.sol", 279 | "label": "initializing", 280 | "astId": 3577, 281 | "type": "t_bool", 282 | "src": "868:25:16" 283 | }, 284 | { 285 | "contract": "Initializable", 286 | "path": "zos-lib/contracts/Initializable.sol", 287 | "label": "______gap", 288 | "astId": 3626, 289 | "type": "t_array:50", 290 | "src": "1883:29:16" 291 | }, 292 | { 293 | "contract": "BasicRegistry", 294 | "path": "contracts/Registry/BasicRegistry.sol", 295 | "label": "items", 296 | "astId": 505, 297 | "type": "t_mapping", 298 | "src": "274:30:4" 299 | }, 300 | { 301 | "contract": "TimelockableItemRegistry", 302 | "path": "contracts/Registry/TimelockableItemRegistry.sol", 303 | "label": "unlockTimes", 304 | "astId": 915, 305 | "type": "t_mapping", 306 | "src": "341:43:8" 307 | } 308 | ], 309 | "warnings": { 310 | "hasConstructor": false, 311 | "hasSelfDestruct": false, 312 | "hasDelegateCall": false, 313 | "hasInitialValuesInDeclarations": false, 314 | "uninitializedBaseContracts": [] 315 | } 316 | }, 317 | "StakedRegistry": { 318 | "address": "0xcadd8449da9d06c4d812b09e352fcd8212652658", 319 | "constructorCode": "608060405234801561001057600080fd5b50611062806100206000396000f300", 320 | "bodyBytecodeHash": "6eef5ca1332922ca41e0b55835a0216b15ae78e422aa74e680fe295e1a2dff90", 321 | "localBytecodeHash": "14e686feb65c5292073d8451a98fe3bd3ea3312e4d45e261cfc0d23cb13f23d0", 322 | "deployedBytecodeHash": "14e686feb65c5292073d8451a98fe3bd3ea3312e4d45e261cfc0d23cb13f23d0", 323 | "types": { 324 | "t_bool": { 325 | "id": "t_bool", 326 | "kind": "elementary", 327 | "label": "bool" 328 | }, 329 | "t_uint256": { 330 | "id": "t_uint256", 331 | "kind": "elementary", 332 | "label": "uint256" 333 | }, 334 | "t_array:50": { 335 | "id": "t_array:50", 336 | "valueType": "t_uint256", 337 | "length": "50", 338 | "kind": "array", 339 | "label": "uint256[50]" 340 | }, 341 | "t_mapping": { 342 | "id": "t_mapping", 343 | "valueType": "t_bool", 344 | "label": "mapping(key => bool)", 345 | "kind": "mapping" 346 | }, 347 | "t_address": { 348 | "id": "t_address", 349 | "kind": "elementary", 350 | "label": "address" 351 | }, 352 | "t_mapping": { 353 | "id": "t_mapping", 354 | "valueType": "t_address", 355 | "label": "mapping(key => address)", 356 | "kind": "mapping" 357 | }, 358 | "t_mapping": { 359 | "id": "t_mapping", 360 | "valueType": "t_uint256", 361 | "label": "mapping(key => uint256)", 362 | "kind": "mapping" 363 | } 364 | }, 365 | "storage": [ 366 | { 367 | "contract": "Initializable", 368 | "path": "zos-lib/contracts/Initializable.sol", 369 | "label": "initialized", 370 | "astId": 3575, 371 | "type": "t_bool", 372 | "src": "749:24:16" 373 | }, 374 | { 375 | "contract": "Initializable", 376 | "path": "zos-lib/contracts/Initializable.sol", 377 | "label": "initializing", 378 | "astId": 3577, 379 | "type": "t_bool", 380 | "src": "868:25:16" 381 | }, 382 | { 383 | "contract": "Initializable", 384 | "path": "zos-lib/contracts/Initializable.sol", 385 | "label": "______gap", 386 | "astId": 3626, 387 | "type": "t_array:50", 388 | "src": "1883:29:16" 389 | }, 390 | { 391 | "contract": "BasicRegistry", 392 | "path": "contracts/Registry/BasicRegistry.sol", 393 | "label": "items", 394 | "astId": 505, 395 | "type": "t_mapping", 396 | "src": "274:30:4" 397 | }, 398 | { 399 | "contract": "OwnedItemRegistry", 400 | "path": "contracts/Registry/OwnedItemRegistry.sol", 401 | "label": "owners", 402 | "astId": 625, 403 | "type": "t_mapping", 404 | "src": "307:41:6" 405 | }, 406 | { 407 | "contract": "StakedRegistry", 408 | "path": "contracts/Registry/StakedRegistry.sol", 409 | "label": "token", 410 | "astId": 695, 411 | "type": "t_address", 412 | "src": "437:18:7" 413 | }, 414 | { 415 | "contract": "StakedRegistry", 416 | "path": "contracts/Registry/StakedRegistry.sol", 417 | "label": "minStake", 418 | "astId": 697, 419 | "type": "t_uint256", 420 | "src": "515:20:7" 421 | }, 422 | { 423 | "contract": "StakedRegistry", 424 | "path": "contracts/Registry/StakedRegistry.sol", 425 | "label": "ownerStakes", 426 | "astId": 701, 427 | "type": "t_mapping", 428 | "src": "581:43:7" 429 | } 430 | ], 431 | "warnings": { 432 | "hasConstructor": false, 433 | "hasSelfDestruct": false, 434 | "hasDelegateCall": false, 435 | "hasInitialValuesInDeclarations": false, 436 | "uninitializedBaseContracts": [] 437 | } 438 | }, 439 | "OwnedItemRegistry": { 440 | "address": "0x1f7386bfeaf313dd55b5f04abdea226b41267f1a", 441 | "constructorCode": "608060405234801561001057600080fd5b5061046e806100206000396000f300", 442 | "bodyBytecodeHash": "bbacd610fa99a625219b716e6ee4354ab784f12fbeea321369b33ce79fbf9648", 443 | "localBytecodeHash": "99d25bd908e58d83415b86085426f2f658a2e4efdfb568bcea731044c0dbebd8", 444 | "deployedBytecodeHash": "99d25bd908e58d83415b86085426f2f658a2e4efdfb568bcea731044c0dbebd8", 445 | "types": { 446 | "t_bool": { 447 | "id": "t_bool", 448 | "kind": "elementary", 449 | "label": "bool" 450 | }, 451 | "t_uint256": { 452 | "id": "t_uint256", 453 | "kind": "elementary", 454 | "label": "uint256" 455 | }, 456 | "t_array:50": { 457 | "id": "t_array:50", 458 | "valueType": "t_uint256", 459 | "length": "50", 460 | "kind": "array", 461 | "label": "uint256[50]" 462 | }, 463 | "t_mapping": { 464 | "id": "t_mapping", 465 | "valueType": "t_bool", 466 | "label": "mapping(key => bool)", 467 | "kind": "mapping" 468 | }, 469 | "t_address": { 470 | "id": "t_address", 471 | "kind": "elementary", 472 | "label": "address" 473 | }, 474 | "t_mapping": { 475 | "id": "t_mapping", 476 | "valueType": "t_address", 477 | "label": "mapping(key => address)", 478 | "kind": "mapping" 479 | } 480 | }, 481 | "storage": [ 482 | { 483 | "contract": "Initializable", 484 | "path": "zos-lib/contracts/Initializable.sol", 485 | "label": "initialized", 486 | "astId": 3575, 487 | "type": "t_bool", 488 | "src": "749:24:16" 489 | }, 490 | { 491 | "contract": "Initializable", 492 | "path": "zos-lib/contracts/Initializable.sol", 493 | "label": "initializing", 494 | "astId": 3577, 495 | "type": "t_bool", 496 | "src": "868:25:16" 497 | }, 498 | { 499 | "contract": "Initializable", 500 | "path": "zos-lib/contracts/Initializable.sol", 501 | "label": "______gap", 502 | "astId": 3626, 503 | "type": "t_array:50", 504 | "src": "1883:29:16" 505 | }, 506 | { 507 | "contract": "BasicRegistry", 508 | "path": "contracts/Registry/BasicRegistry.sol", 509 | "label": "items", 510 | "astId": 505, 511 | "type": "t_mapping", 512 | "src": "274:30:4" 513 | }, 514 | { 515 | "contract": "OwnedItemRegistry", 516 | "path": "contracts/Registry/OwnedItemRegistry.sol", 517 | "label": "owners", 518 | "astId": 625, 519 | "type": "t_mapping", 520 | "src": "307:41:6" 521 | } 522 | ], 523 | "warnings": { 524 | "hasConstructor": false, 525 | "hasSelfDestruct": false, 526 | "hasDelegateCall": false, 527 | "hasInitialValuesInDeclarations": false, 528 | "uninitializedBaseContracts": [] 529 | } 530 | }, 531 | "PLCRVotingChallengeFactory": { 532 | "address": "0x0ebc09a3e1e192ddaaa9472bcd01197c245cfc2d", 533 | "constructorCode": "608060405234801561001057600080fd5b50611d0d806100206000396000f300", 534 | "bodyBytecodeHash": "25cd7101670194cecad9d68ac7da9641020e8acd81697c83f4f18ec87aa2ff55", 535 | "localBytecodeHash": "0d55c9174a249aae51c464df42475d958a925a58b073ba030faf7b49d064b5f5", 536 | "deployedBytecodeHash": "0d55c9174a249aae51c464df42475d958a925a58b073ba030faf7b49d064b5f5", 537 | "types": { 538 | "t_bool": { 539 | "id": "t_bool", 540 | "kind": "elementary", 541 | "label": "bool" 542 | }, 543 | "t_uint256": { 544 | "id": "t_uint256", 545 | "kind": "elementary", 546 | "label": "uint256" 547 | }, 548 | "t_array:50": { 549 | "id": "t_array:50", 550 | "valueType": "t_uint256", 551 | "length": "50", 552 | "kind": "array", 553 | "label": "uint256[50]" 554 | }, 555 | "t_address": { 556 | "id": "t_address", 557 | "kind": "elementary", 558 | "label": "address" 559 | } 560 | }, 561 | "storage": [ 562 | { 563 | "contract": "Initializable", 564 | "path": "zos-lib/contracts/Initializable.sol", 565 | "label": "initialized", 566 | "astId": 3575, 567 | "type": "t_bool", 568 | "src": "749:24:16" 569 | }, 570 | { 571 | "contract": "Initializable", 572 | "path": "zos-lib/contracts/Initializable.sol", 573 | "label": "initializing", 574 | "astId": 3577, 575 | "type": "t_bool", 576 | "src": "868:25:16" 577 | }, 578 | { 579 | "contract": "Initializable", 580 | "path": "zos-lib/contracts/Initializable.sol", 581 | "label": "______gap", 582 | "astId": 3626, 583 | "type": "t_array:50", 584 | "src": "1883:29:16" 585 | }, 586 | { 587 | "contract": "PLCRVotingChallengeFactory", 588 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 589 | "label": "challengerStake", 590 | "astId": 399, 591 | "type": "t_uint256", 592 | "src": "337:27:3" 593 | }, 594 | { 595 | "contract": "PLCRVotingChallengeFactory", 596 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 597 | "label": "plcrVoting", 598 | "astId": 401, 599 | "type": "t_address", 600 | "src": "368:25:3" 601 | }, 602 | { 603 | "contract": "PLCRVotingChallengeFactory", 604 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 605 | "label": "commitStageLength", 606 | "astId": 403, 607 | "type": "t_uint256", 608 | "src": "397:29:3" 609 | }, 610 | { 611 | "contract": "PLCRVotingChallengeFactory", 612 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 613 | "label": "revealStageLength", 614 | "astId": 405, 615 | "type": "t_uint256", 616 | "src": "430:29:3" 617 | }, 618 | { 619 | "contract": "PLCRVotingChallengeFactory", 620 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 621 | "label": "voteQuorum", 622 | "astId": 407, 623 | "type": "t_uint256", 624 | "src": "463:22:3" 625 | }, 626 | { 627 | "contract": "PLCRVotingChallengeFactory", 628 | "path": "contracts/Challenge/PLCRVotingChallengeFactory.sol", 629 | "label": "percentVoterReward", 630 | "astId": 409, 631 | "type": "t_uint256", 632 | "src": "489:30:3" 633 | } 634 | ], 635 | "warnings": { 636 | "hasConstructor": false, 637 | "hasSelfDestruct": false, 638 | "hasDelegateCall": false, 639 | "hasInitialValuesInDeclarations": false, 640 | "uninitializedBaseContracts": [] 641 | } 642 | } 643 | }, 644 | "solidityLibs": {}, 645 | "proxies": {}, 646 | "zosversion": "2", 647 | "frozen": false, 648 | "app": { 649 | "address": "0xc6bb46830a7d23548f0fafb51f34c959afc02196" 650 | }, 651 | "package": { 652 | "address": "0x2e453916db835b7891f60ea8e81cd1c31f730fd8" 653 | }, 654 | "provider": { 655 | "address": "0x4ff1a9cee9b38fb8609f041e3859300a170c6922" 656 | }, 657 | "version": "0.1.0" 658 | } --------------------------------------------------------------------------------