Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 1,523 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw DGD | 14499041 | 1047 days ago | IN | 0 ETH | 0.00720057 | ||||
Withdraw DGD | 14499026 | 1047 days ago | IN | 0 ETH | 0.00720057 | ||||
Withdraw DGD | 11459477 | 1518 days ago | IN | 0 ETH | 0.00280133 | ||||
Withdraw DGD | 11459468 | 1518 days ago | IN | 0 ETH | 0.00257265 | ||||
Withdraw DGD | 11391834 | 1529 days ago | IN | 0 ETH | 0.0006 | ||||
Withdraw DGD | 10424344 | 1678 days ago | IN | 0 ETH | 0.0011434 | ||||
Withdraw DGD | 10316803 | 1694 days ago | IN | 0 ETH | 0.00788946 | ||||
Withdraw DGD | 10316791 | 1694 days ago | IN | 0 ETH | 0.00943305 | ||||
Withdraw DGD | 10316206 | 1694 days ago | IN | 0 ETH | 0.00943305 | ||||
Withdraw DGD | 10315958 | 1694 days ago | IN | 0 ETH | 0.00788946 | ||||
Withdraw DGD | 10236146 | 1707 days ago | IN | 0 ETH | 0.116 | ||||
Withdraw DGD | 10236146 | 1707 days ago | IN | 0 ETH | 0.1 | ||||
Withdraw DGD | 10236146 | 1707 days ago | IN | 0 ETH | 0.08 | ||||
Withdraw DGD | 10184694 | 1715 days ago | IN | 0 ETH | 0.022 | ||||
Withdraw DGD | 10178400 | 1716 days ago | IN | 0 ETH | 0.044 | ||||
Withdraw DGD | 10178398 | 1716 days ago | IN | 0 ETH | 0.04 | ||||
Withdraw DGD | 10178393 | 1716 days ago | IN | 0 ETH | 0.03 | ||||
Withdraw DGD | 10178393 | 1716 days ago | IN | 0 ETH | 0.028 | ||||
Withdraw DGD | 10158954 | 1719 days ago | IN | 0 ETH | 0.034 | ||||
Withdraw DGD | 10158954 | 1719 days ago | IN | 0 ETH | 0.03 | ||||
Withdraw DGD | 10158954 | 1719 days ago | IN | 0 ETH | 0.03 | ||||
Withdraw DGD | 10118434 | 1725 days ago | IN | 0 ETH | 0.024 | ||||
Withdraw DGD | 10117967 | 1725 days ago | IN | 0 ETH | 0.03 | ||||
Withdraw DGD | 10107321 | 1727 days ago | IN | 0 ETH | 0.02203883 | ||||
Withdraw DGD | 10097796 | 1728 days ago | IN | 0 ETH | 0.01292761 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
DaoStakeLocking
Compiler Version
v0.4.25+commit.59dbf8f1
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2019-03-30 */ // Full Contract Sources : https://github.com/DigixGlobal/dao-contracts // File: @digix/cacp-contracts-dao/contracts/ACOwned.sol pragma solidity ^0.4.25; /// @title Owner based access control /// @author DigixGlobal contract ACOwned { address public owner; address public new_owner; bool is_ac_owned_init; /// @dev Modifier to check if msg.sender is the contract owner modifier if_owner() { require(is_owner()); _; } function init_ac_owned() internal returns (bool _success) { if (is_ac_owned_init == false) { owner = msg.sender; is_ac_owned_init = true; } _success = true; } function is_owner() private constant returns (bool _is_owner) { _is_owner = (msg.sender == owner); } function change_owner(address _new_owner) if_owner() public returns (bool _success) { new_owner = _new_owner; _success = true; } function claim_ownership() public returns (bool _success) { require(msg.sender == new_owner); owner = new_owner; _success = true; } } // File: @digix/cacp-contracts-dao/contracts/Constants.sol pragma solidity ^0.4.25; /// @title Some useful constants /// @author DigixGlobal contract Constants { address constant NULL_ADDRESS = address(0x0); uint256 constant ZERO = uint256(0); bytes32 constant EMPTY = bytes32(0x0); } // File: @digix/cacp-contracts-dao/contracts/ContractResolver.sol pragma solidity ^0.4.25; /// @title Contract Name Registry /// @author DigixGlobal contract ContractResolver is ACOwned, Constants { mapping (bytes32 => address) contracts; bool public locked_forever; modifier unless_registered(bytes32 _key) { require(contracts[_key] == NULL_ADDRESS); _; } modifier if_owner_origin() { require(tx.origin == owner); _; } /// Function modifier to check if msg.sender corresponds to the resolved address of a given key /// @param _contract The resolver key modifier if_sender_is(bytes32 _contract) { require(msg.sender == get_contract(_contract)); _; } modifier if_not_locked() { require(locked_forever == false); _; } /// @dev ContractResolver constructor will perform the following: 1. Set msg.sender as the contract owner. constructor() public { require(init_ac_owned()); locked_forever = false; } /// @dev Called at contract initialization /// @param _key bytestring for CACP name /// @param _contract_address The address of the contract to be registered /// @return _success if the operation is successful function init_register_contract(bytes32 _key, address _contract_address) if_owner_origin() if_not_locked() unless_registered(_key) public returns (bool _success) { require(_contract_address != NULL_ADDRESS); contracts[_key] = _contract_address; _success = true; } /// @dev Lock the resolver from any further modifications. This can only be called from the owner /// @return _success if the operation is successful function lock_resolver_forever() if_owner public returns (bool _success) { locked_forever = true; _success = true; } /// @dev Get address of a contract /// @param _key the bytestring name of the contract to look up /// @return _contract the address of the contract function get_contract(bytes32 _key) public view returns (address _contract) { require(contracts[_key] != NULL_ADDRESS); _contract = contracts[_key]; } } // File: @digix/cacp-contracts-dao/contracts/ResolverClient.sol pragma solidity ^0.4.25; /// @title Contract Resolver Interface /// @author DigixGlobal contract ResolverClient { /// The address of the resolver contract for this project address public resolver; bytes32 public key; /// Make our own address available to us as a constant address public CONTRACT_ADDRESS; /// Function modifier to check if msg.sender corresponds to the resolved address of a given key /// @param _contract The resolver key modifier if_sender_is(bytes32 _contract) { require(sender_is(_contract)); _; } function sender_is(bytes32 _contract) internal view returns (bool _isFrom) { _isFrom = msg.sender == ContractResolver(resolver).get_contract(_contract); } modifier if_sender_is_from(bytes32[3] _contracts) { require(sender_is_from(_contracts)); _; } function sender_is_from(bytes32[3] _contracts) internal view returns (bool _isFrom) { uint256 _n = _contracts.length; for (uint256 i = 0; i < _n; i++) { if (_contracts[i] == bytes32(0x0)) continue; if (msg.sender == ContractResolver(resolver).get_contract(_contracts[i])) { _isFrom = true; break; } } } /// Function modifier to check resolver's locking status. modifier unless_resolver_is_locked() { require(is_locked() == false); _; } /// @dev Initialize new contract /// @param _key the resolver key for this contract /// @return _success if the initialization is successful function init(bytes32 _key, address _resolver) internal returns (bool _success) { bool _is_locked = ContractResolver(_resolver).locked_forever(); if (_is_locked == false) { CONTRACT_ADDRESS = address(this); resolver = _resolver; key = _key; require(ContractResolver(resolver).init_register_contract(key, CONTRACT_ADDRESS)); _success = true; } else { _success = false; } } /// @dev Check if resolver is locked /// @return _locked if the resolver is currently locked function is_locked() private view returns (bool _locked) { _locked = ContractResolver(resolver).locked_forever(); } /// @dev Get the address of a contract /// @param _key the resolver key to look up /// @return _contract the address of the contract function get_contract(bytes32 _key) public view returns (address _contract) { _contract = ContractResolver(resolver).get_contract(_key); } } // File: openzeppelin-solidity/contracts/math/SafeMath.sol pragma solidity ^0.4.24; /** * @title SafeMath * @dev Math operations with safety checks that throw on error */ library SafeMath { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) { // Gas optimization: this is cheaper than asserting 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (_a == 0) { return 0; } c = _a * _b; assert(c / _a == _b); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 _a, uint256 _b) internal pure returns (uint256) { // assert(_b > 0); // Solidity automatically throws when dividing by 0 // uint256 c = _a / _b; // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold return _a / _b; } /** * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 _a, uint256 _b) internal pure returns (uint256) { assert(_b <= _a); return _a - _b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) { c = _a + _b; assert(c >= _a); return c; } } // File: contracts/lib/MathHelper.sol pragma solidity ^0.4.25; library MathHelper { using SafeMath for uint256; function max(uint256 a, uint256 b) internal pure returns (uint256 _max){ _max = b; if (a > b) { _max = a; } } function min(uint256 a, uint256 b) internal pure returns (uint256 _min){ _min = b; if (a < b) { _min = a; } } function sumNumbers(uint256[] _numbers) internal pure returns (uint256 _sum) { for (uint256 i=0;i<_numbers.length;i++) { _sum = _sum.add(_numbers[i]); } } } // File: @digix/solidity-collections/contracts/abstract/AddressIteratorInteractive.sol pragma solidity ^0.4.19; /** @title Address Iterator Interactive @author DigixGlobal Pte Ltd */ contract AddressIteratorInteractive { /** @notice Lists a Address collection from start or end @param _count Total number of Address items to return @param _function_first Function that returns the First Address item in the list @param _function_last Function that returns the last Address item in the list @param _function_next Function that returns the Next Address item in the list @param _function_previous Function that returns previous Address item in the list @param _from_start whether to read from start (or end) of the list @return {"_address_items" : "Collection of reversed Address list"} */ function list_addresses(uint256 _count, function () external constant returns (address) _function_first, function () external constant returns (address) _function_last, function (address) external constant returns (address) _function_next, function (address) external constant returns (address) _function_previous, bool _from_start) internal constant returns (address[] _address_items) { if (_from_start) { _address_items = private_list_addresses_from_address(_function_first(), _count, true, _function_last, _function_next); } else { _address_items = private_list_addresses_from_address(_function_last(), _count, true, _function_first, _function_previous); } } /** @notice Lists a Address collection from some `_current_item`, going forwards or backwards depending on `_from_start` @param _current_item The current Item @param _count Total number of Address items to return @param _function_first Function that returns the First Address item in the list @param _function_last Function that returns the last Address item in the list @param _function_next Function that returns the Next Address item in the list @param _function_previous Function that returns previous Address item in the list @param _from_start whether to read in the forwards ( or backwards) direction @return {"_address_items" :"Collection/list of Address"} */ function list_addresses_from(address _current_item, uint256 _count, function () external constant returns (address) _function_first, function () external constant returns (address) _function_last, function (address) external constant returns (address) _function_next, function (address) external constant returns (address) _function_previous, bool _from_start) internal constant returns (address[] _address_items) { if (_from_start) { _address_items = private_list_addresses_from_address(_current_item, _count, false, _function_last, _function_next); } else { _address_items = private_list_addresses_from_address(_current_item, _count, false, _function_first, _function_previous); } } /** @notice a private function to lists a Address collection starting from some `_current_item` (which could be included or excluded), in the forwards or backwards direction @param _current_item The current Item @param _count Total number of Address items to return @param _including_current Whether the `_current_item` should be included in the result @param _function_last Function that returns the address where we stop reading more address @param _function_next Function that returns the next address to read after some address (could be backwards or forwards in the physical collection) @return {"_address_items" :"Collection/list of Address"} */ function private_list_addresses_from_address(address _current_item, uint256 _count, bool _including_current, function () external constant returns (address) _function_last, function (address) external constant returns (address) _function_next) private constant returns (address[] _address_items) { uint256 _i; uint256 _real_count = 0; address _last_item; _last_item = _function_last(); if (_count == 0 || _last_item == address(0x0)) { _address_items = new address[](0); } else { address[] memory _items_temp = new address[](_count); address _this_item; if (_including_current == true) { _items_temp[0] = _current_item; _real_count = 1; } _this_item = _current_item; for (_i = _real_count; (_i < _count) && (_this_item != _last_item);_i++) { _this_item = _function_next(_this_item); if (_this_item != address(0x0)) { _real_count++; _items_temp[_i] = _this_item; } } _address_items = new address[](_real_count); for(_i = 0;_i < _real_count;_i++) { _address_items[_i] = _items_temp[_i]; } } } /** DEPRECATED @notice private function to list a Address collection starting from the start or end of the list @param _count Total number of Address item to return @param _function_total Function that returns the Total number of Address item in the list @param _function_first Function that returns the First Address item in the list @param _function_next Function that returns the Next Address item in the list @return {"_address_items" :"Collection/list of Address"} */ /*function list_addresses_from_start_or_end(uint256 _count, function () external constant returns (uint256) _function_total, function () external constant returns (address) _function_first, function (address) external constant returns (address) _function_next) private constant returns (address[] _address_items) { uint256 _i; address _current_item; uint256 _real_count = _function_total(); if (_count > _real_count) { _count = _real_count; } address[] memory _items_tmp = new address[](_count); if (_count > 0) { _current_item = _function_first(); _items_tmp[0] = _current_item; for(_i = 1;_i <= (_count - 1);_i++) { _current_item = _function_next(_current_item); if (_current_item != address(0x0)) { _items_tmp[_i] = _current_item; } } _address_items = _items_tmp; } else { _address_items = new address[](0); } }*/ /** DEPRECATED @notice a private function to lists a Address collection starting from some `_current_item`, could be forwards or backwards @param _current_item The current Item @param _count Total number of Address items to return @param _function_last Function that returns the bytes where we stop reading more bytes @param _function_next Function that returns the next bytes to read after some bytes (could be backwards or forwards in the physical collection) @return {"_address_items" :"Collection/list of Address"} */ /*function list_addresses_from_byte(address _current_item, uint256 _count, function () external constant returns (address) _function_last, function (address) external constant returns (address) _function_next) private constant returns (address[] _address_items) { uint256 _i; uint256 _real_count = 0; if (_count == 0) { _address_items = new address[](0); } else { address[] memory _items_temp = new address[](_count); address _start_item; address _last_item; _last_item = _function_last(); if (_last_item != _current_item) { _start_item = _function_next(_current_item); if (_start_item != address(0x0)) { _items_temp[0] = _start_item; _real_count = 1; for(_i = 1;(_i <= (_count - 1)) && (_start_item != _last_item);_i++) { _start_item = _function_next(_start_item); if (_start_item != address(0x0)) { _real_count++; _items_temp[_i] = _start_item; } } _address_items = new address[](_real_count); for(_i = 0;_i <= (_real_count - 1);_i++) { _address_items[_i] = _items_temp[_i]; } } else { _address_items = new address[](0); } } else { _address_items = new address[](0); } } }*/ } // File: @digix/solidity-collections/contracts/abstract/BytesIteratorInteractive.sol pragma solidity ^0.4.19; /** @title Bytes Iterator Interactive @author DigixGlobal Pte Ltd */ contract BytesIteratorInteractive { /** @notice Lists a Bytes collection from start or end @param _count Total number of Bytes items to return @param _function_first Function that returns the First Bytes item in the list @param _function_last Function that returns the last Bytes item in the list @param _function_next Function that returns the Next Bytes item in the list @param _function_previous Function that returns previous Bytes item in the list @param _from_start whether to read from start (or end) of the list @return {"_bytes_items" : "Collection of reversed Bytes list"} */ function list_bytesarray(uint256 _count, function () external constant returns (bytes32) _function_first, function () external constant returns (bytes32) _function_last, function (bytes32) external constant returns (bytes32) _function_next, function (bytes32) external constant returns (bytes32) _function_previous, bool _from_start) internal constant returns (bytes32[] _bytes_items) { if (_from_start) { _bytes_items = private_list_bytes_from_bytes(_function_first(), _count, true, _function_last, _function_next); } else { _bytes_items = private_list_bytes_from_bytes(_function_last(), _count, true, _function_first, _function_previous); } } /** @notice Lists a Bytes collection from some `_current_item`, going forwards or backwards depending on `_from_start` @param _current_item The current Item @param _count Total number of Bytes items to return @param _function_first Function that returns the First Bytes item in the list @param _function_last Function that returns the last Bytes item in the list @param _function_next Function that returns the Next Bytes item in the list @param _function_previous Function that returns previous Bytes item in the list @param _from_start whether to read in the forwards ( or backwards) direction @return {"_bytes_items" :"Collection/list of Bytes"} */ function list_bytesarray_from(bytes32 _current_item, uint256 _count, function () external constant returns (bytes32) _function_first, function () external constant returns (bytes32) _function_last, function (bytes32) external constant returns (bytes32) _function_next, function (bytes32) external constant returns (bytes32) _function_previous, bool _from_start) internal constant returns (bytes32[] _bytes_items) { if (_from_start) { _bytes_items = private_list_bytes_from_bytes(_current_item, _count, false, _function_last, _function_next); } else { _bytes_items = private_list_bytes_from_bytes(_current_item, _count, false, _function_first, _function_previous); } } /** @notice A private function to lists a Bytes collection starting from some `_current_item` (which could be included or excluded), in the forwards or backwards direction @param _current_item The current Item @param _count Total number of Bytes items to return @param _including_current Whether the `_current_item` should be included in the result @param _function_last Function that returns the bytes where we stop reading more bytes @param _function_next Function that returns the next bytes to read after some bytes (could be backwards or forwards in the physical collection) @return {"_address_items" :"Collection/list of Bytes"} */ function private_list_bytes_from_bytes(bytes32 _current_item, uint256 _count, bool _including_current, function () external constant returns (bytes32) _function_last, function (bytes32) external constant returns (bytes32) _function_next) private constant returns (bytes32[] _bytes32_items) { uint256 _i; uint256 _real_count = 0; bytes32 _last_item; _last_item = _function_last(); if (_count == 0 || _last_item == bytes32(0x0)) { _bytes32_items = new bytes32[](0); } else { bytes32[] memory _items_temp = new bytes32[](_count); bytes32 _this_item; if (_including_current == true) { _items_temp[0] = _current_item; _real_count = 1; } _this_item = _current_item; for (_i = _real_count; (_i < _count) && (_this_item != _last_item);_i++) { _this_item = _function_next(_this_item); if (_this_item != bytes32(0x0)) { _real_count++; _items_temp[_i] = _this_item; } } _bytes32_items = new bytes32[](_real_count); for(_i = 0;_i < _real_count;_i++) { _bytes32_items[_i] = _items_temp[_i]; } } } ////// DEPRECATED FUNCTIONS (old versions) /** @notice a private function to lists a Bytes collection starting from some `_current_item`, could be forwards or backwards @param _current_item The current Item @param _count Total number of Bytes items to return @param _function_last Function that returns the bytes where we stop reading more bytes @param _function_next Function that returns the next bytes to read after some bytes (could be backwards or forwards in the physical collection) @return {"_bytes_items" :"Collection/list of Bytes"} */ /*function list_bytes_from_bytes(bytes32 _current_item, uint256 _count, function () external constant returns (bytes32) _function_last, function (bytes32) external constant returns (bytes32) _function_next) private constant returns (bytes32[] _bytes_items) { uint256 _i; uint256 _real_count = 0; if (_count == 0) { _bytes_items = new bytes32[](0); } else { bytes32[] memory _items_temp = new bytes32[](_count); bytes32 _start_item; bytes32 _last_item; _last_item = _function_last(); if (_last_item != _current_item) { _start_item = _function_next(_current_item); if (_start_item != bytes32(0x0)) { _items_temp[0] = _start_item; _real_count = 1; for(_i = 1;(_i <= (_count - 1)) && (_start_item != _last_item);_i++) { _start_item = _function_next(_start_item); if (_start_item != bytes32(0x0)) { _real_count++; _items_temp[_i] = _start_item; } } _bytes_items = new bytes32[](_real_count); for(_i = 0;_i <= (_real_count - 1);_i++) { _bytes_items[_i] = _items_temp[_i]; } } else { _bytes_items = new bytes32[](0); } } else { _bytes_items = new bytes32[](0); } } }*/ /** @notice private function to list a Bytes collection starting from the start or end of the list @param _count Total number of Bytes item to return @param _function_total Function that returns the Total number of Bytes item in the list @param _function_first Function that returns the First Bytes item in the list @param _function_next Function that returns the Next Bytes item in the list @return {"_bytes_items" :"Collection/list of Bytes"} */ /*function list_bytes_from_start_or_end(uint256 _count, function () external constant returns (uint256) _function_total, function () external constant returns (bytes32) _function_first, function (bytes32) external constant returns (bytes32) _function_next) private constant returns (bytes32[] _bytes_items) { uint256 _i; bytes32 _current_item; uint256 _real_count = _function_total(); if (_count > _real_count) { _count = _real_count; } bytes32[] memory _items_tmp = new bytes32[](_count); if (_count > 0) { _current_item = _function_first(); _items_tmp[0] = _current_item; for(_i = 1;_i <= (_count - 1);_i++) { _current_item = _function_next(_current_item); if (_current_item != bytes32(0x0)) { _items_tmp[_i] = _current_item; } } _bytes_items = _items_tmp; } else { _bytes_items = new bytes32[](0); } }*/ } // File: @digix/solidity-collections/contracts/abstract/IndexedBytesIteratorInteractive.sol pragma solidity ^0.4.19; /** @title Indexed Bytes Iterator Interactive @author DigixGlobal Pte Ltd */ contract IndexedBytesIteratorInteractive { /** @notice Lists an indexed Bytes collection from start or end @param _collection_index Index of the Collection to list @param _count Total number of Bytes items to return @param _function_first Function that returns the First Bytes item in the list @param _function_last Function that returns the last Bytes item in the list @param _function_next Function that returns the Next Bytes item in the list @param _function_previous Function that returns previous Bytes item in the list @param _from_start whether to read from start (or end) of the list @return {"_bytes_items" : "Collection of reversed Bytes list"} */ function list_indexed_bytesarray(bytes32 _collection_index, uint256 _count, function (bytes32) external constant returns (bytes32) _function_first, function (bytes32) external constant returns (bytes32) _function_last, function (bytes32, bytes32) external constant returns (bytes32) _function_next, function (bytes32, bytes32) external constant returns (bytes32) _function_previous, bool _from_start) internal constant returns (bytes32[] _indexed_bytes_items) { if (_from_start) { _indexed_bytes_items = private_list_indexed_bytes_from_bytes(_collection_index, _function_first(_collection_index), _count, true, _function_last, _function_next); } else { _indexed_bytes_items = private_list_indexed_bytes_from_bytes(_collection_index, _function_last(_collection_index), _count, true, _function_first, _function_previous); } } /** @notice Lists an indexed Bytes collection from some `_current_item`, going forwards or backwards depending on `_from_start` @param _collection_index Index of the Collection to list @param _current_item The current Item @param _count Total number of Bytes items to return @param _function_first Function that returns the First Bytes item in the list @param _function_last Function that returns the last Bytes item in the list @param _function_next Function that returns the Next Bytes item in the list @param _function_previous Function that returns previous Bytes item in the list @param _from_start whether to read in the forwards ( or backwards) direction @return {"_bytes_items" :"Collection/list of Bytes"} */ function list_indexed_bytesarray_from(bytes32 _collection_index, bytes32 _current_item, uint256 _count, function (bytes32) external constant returns (bytes32) _function_first, function (bytes32) external constant returns (bytes32) _function_last, function (bytes32, bytes32) external constant returns (bytes32) _function_next, function (bytes32, bytes32) external constant returns (bytes32) _function_previous, bool _from_start) internal constant returns (bytes32[] _indexed_bytes_items) { if (_from_start) { _indexed_bytes_items = private_list_indexed_bytes_from_bytes(_collection_index, _current_item, _count, false, _function_last, _function_next); } else { _indexed_bytes_items = private_list_indexed_bytes_from_bytes(_collection_index, _current_item, _count, false, _function_first, _function_previous); } } /** @notice a private function to lists an indexed Bytes collection starting from some `_current_item` (which could be included or excluded), in the forwards or backwards direction @param _collection_index Index of the Collection to list @param _current_item The item where we start reading from the list @param _count Total number of Bytes items to return @param _including_current Whether the `_current_item` should be included in the result @param _function_last Function that returns the bytes where we stop reading more bytes @param _function_next Function that returns the next bytes to read after another bytes (could be backwards or forwards in the physical collection) @return {"_bytes_items" :"Collection/list of Bytes"} */ function private_list_indexed_bytes_from_bytes(bytes32 _collection_index, bytes32 _current_item, uint256 _count, bool _including_current, function (bytes32) external constant returns (bytes32) _function_last, function (bytes32, bytes32) external constant returns (bytes32) _function_next) private constant returns (bytes32[] _indexed_bytes_items) { uint256 _i; uint256 _real_count = 0; bytes32 _last_item; _last_item = _function_last(_collection_index); if (_count == 0 || _last_item == bytes32(0x0)) { // if count is 0 or the collection is empty, returns empty array _indexed_bytes_items = new bytes32[](0); } else { bytes32[] memory _items_temp = new bytes32[](_count); bytes32 _this_item; if (_including_current) { _items_temp[0] = _current_item; _real_count = 1; } _this_item = _current_item; for (_i = _real_count; (_i < _count) && (_this_item != _last_item);_i++) { _this_item = _function_next(_collection_index, _this_item); if (_this_item != bytes32(0x0)) { _real_count++; _items_temp[_i] = _this_item; } } _indexed_bytes_items = new bytes32[](_real_count); for(_i = 0;_i < _real_count;_i++) { _indexed_bytes_items[_i] = _items_temp[_i]; } } } // old function, DEPRECATED /*function list_indexed_bytes_from_bytes(bytes32 _collection_index, bytes32 _current_item, uint256 _count, function (bytes32) external constant returns (bytes32) _function_last, function (bytes32, bytes32) external constant returns (bytes32) _function_next) private constant returns (bytes32[] _indexed_bytes_items) { uint256 _i; uint256 _real_count = 0; if (_count == 0) { _indexed_bytes_items = new bytes32[](0); } else { bytes32[] memory _items_temp = new bytes32[](_count); bytes32 _start_item; bytes32 _last_item; _last_item = _function_last(_collection_index); if (_last_item != _current_item) { _start_item = _function_next(_collection_index, _current_item); if (_start_item != bytes32(0x0)) { _items_temp[0] = _start_item; _real_count = 1; for(_i = 1;(_i <= (_count - 1)) && (_start_item != _last_item);_i++) { _start_item = _function_next(_collection_index, _start_item); if (_start_item != bytes32(0x0)) { _real_count++; _items_temp[_i] = _start_item; } } _indexed_bytes_items = new bytes32[](_real_count); for(_i = 0;_i <= (_real_count - 1);_i++) { _indexed_bytes_items[_i] = _items_temp[_i]; } } else { _indexed_bytes_items = new bytes32[](0); } } else { _indexed_bytes_items = new bytes32[](0); } } }*/ } // File: @digix/solidity-collections/contracts/lib/DoublyLinkedList.sol pragma solidity ^0.4.19; library DoublyLinkedList { struct Item { bytes32 item; uint256 previous_index; uint256 next_index; } struct Data { uint256 first_index; uint256 last_index; uint256 count; mapping(bytes32 => uint256) item_index; mapping(uint256 => bool) valid_indexes; Item[] collection; } struct IndexedUint { mapping(bytes32 => Data) data; } struct IndexedAddress { mapping(bytes32 => Data) data; } struct IndexedBytes { mapping(bytes32 => Data) data; } struct Address { Data data; } struct Bytes { Data data; } struct Uint { Data data; } uint256 constant NONE = uint256(0); bytes32 constant EMPTY_BYTES = bytes32(0x0); address constant NULL_ADDRESS = address(0x0); function find(Data storage self, bytes32 _item) public constant returns (uint256 _item_index) { if ((self.item_index[_item] == NONE) && (self.count == NONE)) { _item_index = NONE; } else { _item_index = self.item_index[_item]; } } function get(Data storage self, uint256 _item_index) public constant returns (bytes32 _item) { if (self.valid_indexes[_item_index] == true) { _item = self.collection[_item_index - 1].item; } else { _item = EMPTY_BYTES; } } function append(Data storage self, bytes32 _data) internal returns (bool _success) { if (find(self, _data) != NONE || _data == bytes32("")) { // rejects addition of empty values _success = false; } else { uint256 _index = uint256(self.collection.push(Item({item: _data, previous_index: self.last_index, next_index: NONE}))); if (self.last_index == NONE) { if ((self.first_index != NONE) || (self.count != NONE)) { revert(); } else { self.first_index = self.last_index = _index; self.count = 1; } } else { self.collection[self.last_index - 1].next_index = _index; self.last_index = _index; self.count++; } self.valid_indexes[_index] = true; self.item_index[_data] = _index; _success = true; } } function remove(Data storage self, uint256 _index) internal returns (bool _success) { if (self.valid_indexes[_index] == true) { Item memory item = self.collection[_index - 1]; if (item.previous_index == NONE) { self.first_index = item.next_index; } else { self.collection[item.previous_index - 1].next_index = item.next_index; } if (item.next_index == NONE) { self.last_index = item.previous_index; } else { self.collection[item.next_index - 1].previous_index = item.previous_index; } delete self.collection[_index - 1]; self.valid_indexes[_index] = false; delete self.item_index[item.item]; self.count--; _success = true; } else { _success = false; } } function remove_item(Data storage self, bytes32 _item) internal returns (bool _success) { uint256 _item_index = find(self, _item); if (_item_index != NONE) { require(remove(self, _item_index)); _success = true; } else { _success = false; } return _success; } function total(Data storage self) public constant returns (uint256 _total_count) { _total_count = self.count; } function start(Data storage self) public constant returns (uint256 _item_index) { _item_index = self.first_index; return _item_index; } function start_item(Data storage self) public constant returns (bytes32 _item) { uint256 _item_index = start(self); if (_item_index != NONE) { _item = get(self, _item_index); } else { _item = EMPTY_BYTES; } } function end(Data storage self) public constant returns (uint256 _item_index) { _item_index = self.last_index; return _item_index; } function end_item(Data storage self) public constant returns (bytes32 _item) { uint256 _item_index = end(self); if (_item_index != NONE) { _item = get(self, _item_index); } else { _item = EMPTY_BYTES; } } function valid(Data storage self, uint256 _item_index) public constant returns (bool _yes) { _yes = self.valid_indexes[_item_index]; //_yes = ((_item_index - 1) < self.collection.length); } function valid_item(Data storage self, bytes32 _item) public constant returns (bool _yes) { uint256 _item_index = self.item_index[_item]; _yes = self.valid_indexes[_item_index]; } function previous(Data storage self, uint256 _current_index) public constant returns (uint256 _previous_index) { if (self.valid_indexes[_current_index] == true) { _previous_index = self.collection[_current_index - 1].previous_index; } else { _previous_index = NONE; } } function previous_item(Data storage self, bytes32 _current_item) public constant returns (bytes32 _previous_item) { uint256 _current_index = find(self, _current_item); if (_current_index != NONE) { uint256 _previous_index = previous(self, _current_index); _previous_item = get(self, _previous_index); } else { _previous_item = EMPTY_BYTES; } } function next(Data storage self, uint256 _current_index) public constant returns (uint256 _next_index) { if (self.valid_indexes[_current_index] == true) { _next_index = self.collection[_current_index - 1].next_index; } else { _next_index = NONE; } } function next_item(Data storage self, bytes32 _current_item) public constant returns (bytes32 _next_item) { uint256 _current_index = find(self, _current_item); if (_current_index != NONE) { uint256 _next_index = next(self, _current_index); _next_item = get(self, _next_index); } else { _next_item = EMPTY_BYTES; } } function find(Uint storage self, uint256 _item) public constant returns (uint256 _item_index) { _item_index = find(self.data, bytes32(_item)); } function get(Uint storage self, uint256 _item_index) public constant returns (uint256 _item) { _item = uint256(get(self.data, _item_index)); } function append(Uint storage self, uint256 _data) public returns (bool _success) { _success = append(self.data, bytes32(_data)); } function remove(Uint storage self, uint256 _index) internal returns (bool _success) { _success = remove(self.data, _index); } function remove_item(Uint storage self, uint256 _item) public returns (bool _success) { _success = remove_item(self.data, bytes32(_item)); } function total(Uint storage self) public constant returns (uint256 _total_count) { _total_count = total(self.data); } function start(Uint storage self) public constant returns (uint256 _index) { _index = start(self.data); } function start_item(Uint storage self) public constant returns (uint256 _start_item) { _start_item = uint256(start_item(self.data)); } function end(Uint storage self) public constant returns (uint256 _index) { _index = end(self.data); } function end_item(Uint storage self) public constant returns (uint256 _end_item) { _end_item = uint256(end_item(self.data)); } function valid(Uint storage self, uint256 _item_index) public constant returns (bool _yes) { _yes = valid(self.data, _item_index); } function valid_item(Uint storage self, uint256 _item) public constant returns (bool _yes) { _yes = valid_item(self.data, bytes32(_item)); } function previous(Uint storage self, uint256 _current_index) public constant returns (uint256 _previous_index) { _previous_index = previous(self.data, _current_index); } function previous_item(Uint storage self, uint256 _current_item) public constant returns (uint256 _previous_item) { _previous_item = uint256(previous_item(self.data, bytes32(_current_item))); } function next(Uint storage self, uint256 _current_index) public constant returns (uint256 _next_index) { _next_index = next(self.data, _current_index); } function next_item(Uint storage self, uint256 _current_item) public constant returns (uint256 _next_item) { _next_item = uint256(next_item(self.data, bytes32(_current_item))); } function find(Address storage self, address _item) public constant returns (uint256 _item_index) { _item_index = find(self.data, bytes32(_item)); } function get(Address storage self, uint256 _item_index) public constant returns (address _item) { _item = address(get(self.data, _item_index)); } function find(IndexedUint storage self, bytes32 _collection_index, uint256 _item) public constant returns (uint256 _item_index) { _item_index = find(self.data[_collection_index], bytes32(_item)); } function get(IndexedUint storage self, bytes32 _collection_index, uint256 _item_index) public constant returns (uint256 _item) { _item = uint256(get(self.data[_collection_index], _item_index)); } function append(IndexedUint storage self, bytes32 _collection_index, uint256 _data) public returns (bool _success) { _success = append(self.data[_collection_index], bytes32(_data)); } function remove(IndexedUint storage self, bytes32 _collection_index, uint256 _index) internal returns (bool _success) { _success = remove(self.data[_collection_index], _index); } function remove_item(IndexedUint storage self, bytes32 _collection_index, uint256 _item) public returns (bool _success) { _success = remove_item(self.data[_collection_index], bytes32(_item)); } function total(IndexedUint storage self, bytes32 _collection_index) public constant returns (uint256 _total_count) { _total_count = total(self.data[_collection_index]); } function start(IndexedUint storage self, bytes32 _collection_index) public constant returns (uint256 _index) { _index = start(self.data[_collection_index]); } function start_item(IndexedUint storage self, bytes32 _collection_index) public constant returns (uint256 _start_item) { _start_item = uint256(start_item(self.data[_collection_index])); } function end(IndexedUint storage self, bytes32 _collection_index) public constant returns (uint256 _index) { _index = end(self.data[_collection_index]); } function end_item(IndexedUint storage self, bytes32 _collection_index) public constant returns (uint256 _end_item) { _end_item = uint256(end_item(self.data[_collection_index])); } function valid(IndexedUint storage self, bytes32 _collection_index, uint256 _item_index) public constant returns (bool _yes) { _yes = valid(self.data[_collection_index], _item_index); } function valid_item(IndexedUint storage self, bytes32 _collection_index, uint256 _item) public constant returns (bool _yes) { _yes = valid_item(self.data[_collection_index], bytes32(_item)); } function previous(IndexedUint storage self, bytes32 _collection_index, uint256 _current_index) public constant returns (uint256 _previous_index) { _previous_index = previous(self.data[_collection_index], _current_index); } function previous_item(IndexedUint storage self, bytes32 _collection_index, uint256 _current_item) public constant returns (uint256 _previous_item) { _previous_item = uint256(previous_item(self.data[_collection_index], bytes32(_current_item))); } function next(IndexedUint storage self, bytes32 _collection_index, uint256 _current_index) public constant returns (uint256 _next_index) { _next_index = next(self.data[_collection_index], _current_index); } function next_item(IndexedUint storage self, bytes32 _collection_index, uint256 _current_item) public constant returns (uint256 _next_item) { _next_item = uint256(next_item(self.data[_collection_index], bytes32(_current_item))); } function append(Address storage self, address _data) public returns (bool _success) { _success = append(self.data, bytes32(_data)); } function remove(Address storage self, uint256 _index) internal returns (bool _success) { _success = remove(self.data, _index); } function remove_item(Address storage self, address _item) public returns (bool _success) { _success = remove_item(self.data, bytes32(_item)); } function total(Address storage self) public constant returns (uint256 _total_count) { _total_count = total(self.data); } function start(Address storage self) public constant returns (uint256 _index) { _index = start(self.data); } function start_item(Address storage self) public constant returns (address _start_item) { _start_item = address(start_item(self.data)); } function end(Address storage self) public constant returns (uint256 _index) { _index = end(self.data); } function end_item(Address storage self) public constant returns (address _end_item) { _end_item = address(end_item(self.data)); } function valid(Address storage self, uint256 _item_index) public constant returns (bool _yes) { _yes = valid(self.data, _item_index); } function valid_item(Address storage self, address _item) public constant returns (bool _yes) { _yes = valid_item(self.data, bytes32(_item)); } function previous(Address storage self, uint256 _current_index) public constant returns (uint256 _previous_index) { _previous_index = previous(self.data, _current_index); } function previous_item(Address storage self, address _current_item) public constant returns (address _previous_item) { _previous_item = address(previous_item(self.data, bytes32(_current_item))); } function next(Address storage self, uint256 _current_index) public constant returns (uint256 _next_index) { _next_index = next(self.data, _current_index); } function next_item(Address storage self, address _current_item) public constant returns (address _next_item) { _next_item = address(next_item(self.data, bytes32(_current_item))); } function append(IndexedAddress storage self, bytes32 _collection_index, address _data) public returns (bool _success) { _success = append(self.data[_collection_index], bytes32(_data)); } function remove(IndexedAddress storage self, bytes32 _collection_index, uint256 _index) internal returns (bool _success) { _success = remove(self.data[_collection_index], _index); } function remove_item(IndexedAddress storage self, bytes32 _collection_index, address _item) public returns (bool _success) { _success = remove_item(self.data[_collection_index], bytes32(_item)); } function total(IndexedAddress storage self, bytes32 _collection_index) public constant returns (uint256 _total_count) { _total_count = total(self.data[_collection_index]); } function start(IndexedAddress storage self, bytes32 _collection_index) public constant returns (uint256 _index) { _index = start(self.data[_collection_index]); } function start_item(IndexedAddress storage self, bytes32 _collection_index) public constant returns (address _start_item) { _start_item = address(start_item(self.data[_collection_index])); } function end(IndexedAddress storage self, bytes32 _collection_index) public constant returns (uint256 _index) { _index = end(self.data[_collection_index]); } function end_item(IndexedAddress storage self, bytes32 _collection_index) public constant returns (address _end_item) { _end_item = address(end_item(self.data[_collection_index])); } function valid(IndexedAddress storage self, bytes32 _collection_index, uint256 _item_index) public constant returns (bool _yes) { _yes = valid(self.data[_collection_index], _item_index); } function valid_item(IndexedAddress storage self, bytes32 _collection_index, address _item) public constant returns (bool _yes) { _yes = valid_item(self.data[_collection_index], bytes32(_item)); } function previous(IndexedAddress storage self, bytes32 _collection_index, uint256 _current_index) public constant returns (uint256 _previous_index) { _previous_index = previous(self.data[_collection_index], _current_index); } function previous_item(IndexedAddress storage self, bytes32 _collection_index, address _current_item) public constant returns (address _previous_item) { _previous_item = address(previous_item(self.data[_collection_index], bytes32(_current_item))); } function next(IndexedAddress storage self, bytes32 _collection_index, uint256 _current_index) public constant returns (uint256 _next_index) { _next_index = next(self.data[_collection_index], _current_index); } function next_item(IndexedAddress storage self, bytes32 _collection_index, address _current_item) public constant returns (address _next_item) { _next_item = address(next_item(self.data[_collection_index], bytes32(_current_item))); } function find(Bytes storage self, bytes32 _item) public constant returns (uint256 _item_index) { _item_index = find(self.data, _item); } function get(Bytes storage self, uint256 _item_index) public constant returns (bytes32 _item) { _item = get(self.data, _item_index); } function append(Bytes storage self, bytes32 _data) public returns (bool _success) { _success = append(self.data, _data); } function remove(Bytes storage self, uint256 _index) internal returns (bool _success) { _success = remove(self.data, _index); } function remove_item(Bytes storage self, bytes32 _item) public returns (bool _success) { _success = remove_item(self.data, _item); } function total(Bytes storage self) public constant returns (uint256 _total_count) { _total_count = total(self.data); } function start(Bytes storage self) public constant returns (uint256 _index) { _index = start(self.data); } function start_item(Bytes storage self) public constant returns (bytes32 _start_item) { _start_item = start_item(self.data); } function end(Bytes storage self) public constant returns (uint256 _index) { _index = end(self.data); } function end_item(Bytes storage self) public constant returns (bytes32 _end_item) { _end_item = end_item(self.data); } function valid(Bytes storage self, uint256 _item_index) public constant returns (bool _yes) { _yes = valid(self.data, _item_index); } function valid_item(Bytes storage self, bytes32 _item) public constant returns (bool _yes) { _yes = valid_item(self.data, _item); } function previous(Bytes storage self, uint256 _current_index) public constant returns (uint256 _previous_index) { _previous_index = previous(self.data, _current_index); } function previous_item(Bytes storage self, bytes32 _current_item) public constant returns (bytes32 _previous_item) { _previous_item = previous_item(self.data, _current_item); } function next(Bytes storage self, uint256 _current_index) public constant returns (uint256 _next_index) { _next_index = next(self.data, _current_index); } function next_item(Bytes storage self, bytes32 _current_item) public constant returns (bytes32 _next_item) { _next_item = next_item(self.data, _current_item); } function append(IndexedBytes storage self, bytes32 _collection_index, bytes32 _data) public returns (bool _success) { _success = append(self.data[_collection_index], bytes32(_data)); } function remove(IndexedBytes storage self, bytes32 _collection_index, uint256 _index) internal returns (bool _success) { _success = remove(self.data[_collection_index], _index); } function remove_item(IndexedBytes storage self, bytes32 _collection_index, bytes32 _item) public returns (bool _success) { _success = remove_item(self.data[_collection_index], bytes32(_item)); } function total(IndexedBytes storage self, bytes32 _collection_index) public constant returns (uint256 _total_count) { _total_count = total(self.data[_collection_index]); } function start(IndexedBytes storage self, bytes32 _collection_index) public constant returns (uint256 _index) { _index = start(self.data[_collection_index]); } function start_item(IndexedBytes storage self, bytes32 _collection_index) public constant returns (bytes32 _start_item) { _start_item = bytes32(start_item(self.data[_collection_index])); } function end(IndexedBytes storage self, bytes32 _collection_index) public constant returns (uint256 _index) { _index = end(self.data[_collection_index]); } function end_item(IndexedBytes storage self, bytes32 _collection_index) public constant returns (bytes32 _end_item) { _end_item = bytes32(end_item(self.data[_collection_index])); } function valid(IndexedBytes storage self, bytes32 _collection_index, uint256 _item_index) public constant returns (bool _yes) { _yes = valid(self.data[_collection_index], _item_index); } function valid_item(IndexedBytes storage self, bytes32 _collection_index, bytes32 _item) public constant returns (bool _yes) { _yes = valid_item(self.data[_collection_index], bytes32(_item)); } function previous(IndexedBytes storage self, bytes32 _collection_index, uint256 _current_index) public constant returns (uint256 _previous_index) { _previous_index = previous(self.data[_collection_index], _current_index); } function previous_item(IndexedBytes storage self, bytes32 _collection_index, bytes32 _current_item) public constant returns (bytes32 _previous_item) { _previous_item = bytes32(previous_item(self.data[_collection_index], bytes32(_current_item))); } function next(IndexedBytes storage self, bytes32 _collection_index, uint256 _current_index) public constant returns (uint256 _next_index) { _next_index = next(self.data[_collection_index], _current_index); } function next_item(IndexedBytes storage self, bytes32 _collection_index, bytes32 _current_item) public constant returns (bytes32 _next_item) { _next_item = bytes32(next_item(self.data[_collection_index], bytes32(_current_item))); } } // File: @digix/solidity-collections/contracts/abstract/BytesIteratorStorage.sol pragma solidity ^0.4.19; /** @title Bytes Iterator Storage @author DigixGlobal Pte Ltd */ contract BytesIteratorStorage { // Initialize Doubly Linked List of Bytes using DoublyLinkedList for DoublyLinkedList.Bytes; /** @notice Reads the first item from the list of Bytes @param _list The source list @return {"_item": "The first item from the list"} */ function read_first_from_bytesarray(DoublyLinkedList.Bytes storage _list) internal constant returns (bytes32 _item) { _item = _list.start_item(); } /** @notice Reads the last item from the list of Bytes @param _list The source list @return {"_item": "The last item from the list"} */ function read_last_from_bytesarray(DoublyLinkedList.Bytes storage _list) internal constant returns (bytes32 _item) { _item = _list.end_item(); } /** @notice Reads the next item on the list of Bytes @param _list The source list @param _current_item The current item to be used as base line @return {"_item": "The next item from the list based on the specieid `_current_item`"} TODO: Need to verify what happens if the specified `_current_item` is the last item from the list */ function read_next_from_bytesarray(DoublyLinkedList.Bytes storage _list, bytes32 _current_item) internal constant returns (bytes32 _item) { _item = _list.next_item(_current_item); } /** @notice Reads the previous item on the list of Bytes @param _list The source list @param _current_item The current item to be used as base line @return {"_item": "The previous item from the list based on the spcified `_current_item`"} TODO: Need to verify what happens if the specified `_current_item` is the first item from the list */ function read_previous_from_bytesarray(DoublyLinkedList.Bytes storage _list, bytes32 _current_item) internal constant returns (bytes32 _item) { _item = _list.previous_item(_current_item); } /** @notice Reads the list of Bytes and returns the length of the list @param _list The source list @return {"count": "`uint256` The lenght of the list"} */ function read_total_bytesarray(DoublyLinkedList.Bytes storage _list) internal constant returns (uint256 _count) { _count = _list.total(); } } // File: contracts/common/DaoConstants.sol pragma solidity ^0.4.25; contract DaoConstants { using SafeMath for uint256; bytes32 EMPTY_BYTES = bytes32(0x0); address EMPTY_ADDRESS = address(0x0); bytes32 PROPOSAL_STATE_PREPROPOSAL = "proposal_state_preproposal"; bytes32 PROPOSAL_STATE_DRAFT = "proposal_state_draft"; bytes32 PROPOSAL_STATE_MODERATED = "proposal_state_moderated"; bytes32 PROPOSAL_STATE_ONGOING = "proposal_state_ongoing"; bytes32 PROPOSAL_STATE_CLOSED = "proposal_state_closed"; bytes32 PROPOSAL_STATE_ARCHIVED = "proposal_state_archived"; uint256 PRL_ACTION_STOP = 1; uint256 PRL_ACTION_PAUSE = 2; uint256 PRL_ACTION_UNPAUSE = 3; uint256 COLLATERAL_STATUS_UNLOCKED = 1; uint256 COLLATERAL_STATUS_LOCKED = 2; uint256 COLLATERAL_STATUS_CLAIMED = 3; bytes32 INTERMEDIATE_DGD_IDENTIFIER = "inter_dgd_id"; bytes32 INTERMEDIATE_MODERATOR_DGD_IDENTIFIER = "inter_mod_dgd_id"; bytes32 INTERMEDIATE_BONUS_CALCULATION_IDENTIFIER = "inter_bonus_calculation_id"; // interactive contracts bytes32 CONTRACT_DAO = "dao"; bytes32 CONTRACT_DAO_SPECIAL_PROPOSAL = "dao:special:proposal"; bytes32 CONTRACT_DAO_STAKE_LOCKING = "dao:stake-locking"; bytes32 CONTRACT_DAO_VOTING = "dao:voting"; bytes32 CONTRACT_DAO_VOTING_CLAIMS = "dao:voting:claims"; bytes32 CONTRACT_DAO_SPECIAL_VOTING_CLAIMS = "dao:svoting:claims"; bytes32 CONTRACT_DAO_IDENTITY = "dao:identity"; bytes32 CONTRACT_DAO_REWARDS_MANAGER = "dao:rewards-manager"; bytes32 CONTRACT_DAO_REWARDS_MANAGER_EXTRAS = "dao:rewards-extras"; bytes32 CONTRACT_DAO_ROLES = "dao:roles"; bytes32 CONTRACT_DAO_FUNDING_MANAGER = "dao:funding-manager"; bytes32 CONTRACT_DAO_WHITELISTING = "dao:whitelisting"; bytes32 CONTRACT_DAO_INFORMATION = "dao:information"; // service contracts bytes32 CONTRACT_SERVICE_ROLE = "service:role"; bytes32 CONTRACT_SERVICE_DAO_INFO = "service:dao:info"; bytes32 CONTRACT_SERVICE_DAO_LISTING = "service:dao:listing"; bytes32 CONTRACT_SERVICE_DAO_CALCULATOR = "service:dao:calculator"; // storage contracts bytes32 CONTRACT_STORAGE_DAO = "storage:dao"; bytes32 CONTRACT_STORAGE_DAO_COUNTER = "storage:dao:counter"; bytes32 CONTRACT_STORAGE_DAO_UPGRADE = "storage:dao:upgrade"; bytes32 CONTRACT_STORAGE_DAO_IDENTITY = "storage:dao:identity"; bytes32 CONTRACT_STORAGE_DAO_POINTS = "storage:dao:points"; bytes32 CONTRACT_STORAGE_DAO_SPECIAL = "storage:dao:special"; bytes32 CONTRACT_STORAGE_DAO_CONFIG = "storage:dao:config"; bytes32 CONTRACT_STORAGE_DAO_STAKE = "storage:dao:stake"; bytes32 CONTRACT_STORAGE_DAO_REWARDS = "storage:dao:rewards"; bytes32 CONTRACT_STORAGE_DAO_WHITELISTING = "storage:dao:whitelisting"; bytes32 CONTRACT_STORAGE_INTERMEDIATE_RESULTS = "storage:intermediate:results"; bytes32 CONTRACT_DGD_TOKEN = "t:dgd"; bytes32 CONTRACT_DGX_TOKEN = "t:dgx"; bytes32 CONTRACT_BADGE_TOKEN = "t:badge"; uint8 ROLES_ROOT = 1; uint8 ROLES_FOUNDERS = 2; uint8 ROLES_PRLS = 3; uint8 ROLES_KYC_ADMINS = 4; uint256 QUARTER_DURATION = 90 days; bytes32 CONFIG_MINIMUM_LOCKED_DGD = "min_dgd_participant"; bytes32 CONFIG_MINIMUM_DGD_FOR_MODERATOR = "min_dgd_moderator"; bytes32 CONFIG_MINIMUM_REPUTATION_FOR_MODERATOR = "min_reputation_moderator"; bytes32 CONFIG_LOCKING_PHASE_DURATION = "locking_phase_duration"; bytes32 CONFIG_QUARTER_DURATION = "quarter_duration"; bytes32 CONFIG_VOTING_COMMIT_PHASE = "voting_commit_phase"; bytes32 CONFIG_VOTING_PHASE_TOTAL = "voting_phase_total"; bytes32 CONFIG_INTERIM_COMMIT_PHASE = "interim_voting_commit_phase"; bytes32 CONFIG_INTERIM_PHASE_TOTAL = "interim_voting_phase_total"; bytes32 CONFIG_DRAFT_QUORUM_FIXED_PORTION_NUMERATOR = "draft_quorum_fixed_numerator"; bytes32 CONFIG_DRAFT_QUORUM_FIXED_PORTION_DENOMINATOR = "draft_quorum_fixed_denominator"; bytes32 CONFIG_DRAFT_QUORUM_SCALING_FACTOR_NUMERATOR = "draft_quorum_sfactor_numerator"; bytes32 CONFIG_DRAFT_QUORUM_SCALING_FACTOR_DENOMINATOR = "draft_quorum_sfactor_denominator"; bytes32 CONFIG_VOTING_QUORUM_FIXED_PORTION_NUMERATOR = "vote_quorum_fixed_numerator"; bytes32 CONFIG_VOTING_QUORUM_FIXED_PORTION_DENOMINATOR = "vote_quorum_fixed_denominator"; bytes32 CONFIG_VOTING_QUORUM_SCALING_FACTOR_NUMERATOR = "vote_quorum_sfactor_numerator"; bytes32 CONFIG_VOTING_QUORUM_SCALING_FACTOR_DENOMINATOR = "vote_quorum_sfactor_denominator"; bytes32 CONFIG_FINAL_REWARD_SCALING_FACTOR_NUMERATOR = "final_reward_sfactor_numerator"; bytes32 CONFIG_FINAL_REWARD_SCALING_FACTOR_DENOMINATOR = "final_reward_sfactor_denominator"; bytes32 CONFIG_DRAFT_QUOTA_NUMERATOR = "draft_quota_numerator"; bytes32 CONFIG_DRAFT_QUOTA_DENOMINATOR = "draft_quota_denominator"; bytes32 CONFIG_VOTING_QUOTA_NUMERATOR = "voting_quota_numerator"; bytes32 CONFIG_VOTING_QUOTA_DENOMINATOR = "voting_quota_denominator"; bytes32 CONFIG_MINIMAL_QUARTER_POINT = "minimal_qp"; bytes32 CONFIG_QUARTER_POINT_SCALING_FACTOR = "quarter_point_scaling_factor"; bytes32 CONFIG_REPUTATION_POINT_SCALING_FACTOR = "rep_point_scaling_factor"; bytes32 CONFIG_MODERATOR_MINIMAL_QUARTER_POINT = "minimal_mod_qp"; bytes32 CONFIG_MODERATOR_QUARTER_POINT_SCALING_FACTOR = "mod_qp_scaling_factor"; bytes32 CONFIG_MODERATOR_REPUTATION_POINT_SCALING_FACTOR = "mod_rep_point_scaling_factor"; bytes32 CONFIG_QUARTER_POINT_DRAFT_VOTE = "quarter_point_draft_vote"; bytes32 CONFIG_QUARTER_POINT_VOTE = "quarter_point_vote"; bytes32 CONFIG_QUARTER_POINT_INTERIM_VOTE = "quarter_point_interim_vote"; /// this is per 10000 ETHs bytes32 CONFIG_QUARTER_POINT_MILESTONE_COMPLETION_PER_10000ETH = "q_p_milestone_completion"; bytes32 CONFIG_BONUS_REPUTATION_NUMERATOR = "bonus_reputation_numerator"; bytes32 CONFIG_BONUS_REPUTATION_DENOMINATOR = "bonus_reputation_denominator"; bytes32 CONFIG_SPECIAL_PROPOSAL_COMMIT_PHASE = "special_proposal_commit_phase"; bytes32 CONFIG_SPECIAL_PROPOSAL_PHASE_TOTAL = "special_proposal_phase_total"; bytes32 CONFIG_SPECIAL_QUOTA_NUMERATOR = "config_special_quota_numerator"; bytes32 CONFIG_SPECIAL_QUOTA_DENOMINATOR = "config_special_quota_denominator"; bytes32 CONFIG_SPECIAL_PROPOSAL_QUORUM_NUMERATOR = "special_quorum_numerator"; bytes32 CONFIG_SPECIAL_PROPOSAL_QUORUM_DENOMINATOR = "special_quorum_denominator"; bytes32 CONFIG_MAXIMUM_REPUTATION_DEDUCTION = "config_max_reputation_deduction"; bytes32 CONFIG_PUNISHMENT_FOR_NOT_LOCKING = "config_punishment_not_locking"; bytes32 CONFIG_REPUTATION_PER_EXTRA_QP_NUM = "config_rep_per_extra_qp_num"; bytes32 CONFIG_REPUTATION_PER_EXTRA_QP_DEN = "config_rep_per_extra_qp_den"; bytes32 CONFIG_MAXIMUM_MODERATOR_REPUTATION_DEDUCTION = "config_max_m_rp_deduction"; bytes32 CONFIG_REPUTATION_PER_EXTRA_MODERATOR_QP_NUM = "config_rep_per_extra_m_qp_num"; bytes32 CONFIG_REPUTATION_PER_EXTRA_MODERATOR_QP_DEN = "config_rep_per_extra_m_qp_den"; bytes32 CONFIG_PORTION_TO_MODERATORS_NUM = "config_mod_portion_num"; bytes32 CONFIG_PORTION_TO_MODERATORS_DEN = "config_mod_portion_den"; bytes32 CONFIG_DRAFT_VOTING_PHASE = "config_draft_voting_phase"; bytes32 CONFIG_REPUTATION_POINT_BOOST_FOR_BADGE = "config_rp_boost_per_badge"; bytes32 CONFIG_VOTE_CLAIMING_DEADLINE = "config_claiming_deadline"; bytes32 CONFIG_PREPROPOSAL_COLLATERAL = "config_preproposal_collateral"; bytes32 CONFIG_MAX_FUNDING_FOR_NON_DIGIX = "config_max_funding_nonDigix"; bytes32 CONFIG_MAX_MILESTONES_FOR_NON_DIGIX = "config_max_milestones_nonDigix"; bytes32 CONFIG_NON_DIGIX_PROPOSAL_CAP_PER_QUARTER = "config_nonDigix_proposal_cap"; bytes32 CONFIG_PROPOSAL_DEAD_DURATION = "config_dead_duration"; bytes32 CONFIG_CARBON_VOTE_REPUTATION_BONUS = "config_cv_reputation"; } // File: contracts/storage/DaoWhitelistingStorage.sol pragma solidity ^0.4.25; // This contract is basically created to restrict read access to // ethereum accounts, and whitelisted contracts contract DaoWhitelistingStorage is ResolverClient, DaoConstants { // we want to avoid the scenario in which an on-chain bribing contract // can be deployed to distribute funds in a trustless way by verifying // on-chain votes. This mapping marks whether a contract address is whitelisted // to read from the read functions in DaoStorage, DaoSpecialStorage, etc. mapping (address => bool) public whitelist; constructor(address _resolver) public { require(init(CONTRACT_STORAGE_DAO_WHITELISTING, _resolver)); } function setWhitelisted(address _contractAddress, bool _senderIsAllowedToRead) public { require(sender_is(CONTRACT_DAO_WHITELISTING)); whitelist[_contractAddress] = _senderIsAllowedToRead; } } // File: contracts/common/DaoWhitelistingCommon.sol pragma solidity ^0.4.25; contract DaoWhitelistingCommon is ResolverClient, DaoConstants { function daoWhitelistingStorage() internal view returns (DaoWhitelistingStorage _contract) { _contract = DaoWhitelistingStorage(get_contract(CONTRACT_STORAGE_DAO_WHITELISTING)); } /** @notice Check if a certain address is whitelisted to read sensitive information in the storage layer @dev if the address is an account, it is allowed to read. If the address is a contract, it has to be in the whitelist */ function senderIsAllowedToRead() internal view returns (bool _senderIsAllowedToRead) { // msg.sender is allowed to read only if its an EOA or a whitelisted contract _senderIsAllowedToRead = (msg.sender == tx.origin) || daoWhitelistingStorage().whitelist(msg.sender); } } // File: contracts/lib/DaoStructs.sol pragma solidity ^0.4.25; library DaoStructs { using DoublyLinkedList for DoublyLinkedList.Bytes; using SafeMath for uint256; bytes32 constant EMPTY_BYTES = bytes32(0x0); struct PrlAction { // UTC timestamp at which the PRL action was done uint256 at; // IPFS hash of the document summarizing the action bytes32 doc; // Type of action // check PRL_ACTION_* in "./../common/DaoConstants.sol" uint256 actionId; } struct Voting { // UTC timestamp at which the voting round starts uint256 startTime; // Mapping of whether a commit was used in this voting round mapping (bytes32 => bool) usedCommits; // Mapping of commits by address. These are the commits during the commit phase in a voting round // This only stores the most recent commit in the voting round // In case a vote is edited, the previous commit is overwritten by the new commit // Only this new commit is verified at the reveal phase mapping (address => bytes32) commits; // This mapping is updated after the reveal phase, when votes are revealed // It is a mapping of address to weight of vote // Weight implies the lockedDGDStake of the address, at the time of revealing // If the address voted "NO", or didn't vote, this would be 0 mapping (address => uint256) yesVotes; // This mapping is updated after the reveal phase, when votes are revealed // It is a mapping of address to weight of vote // Weight implies the lockedDGDStake of the address, at the time of revealing // If the address voted "YES", or didn't vote, this would be 0 mapping (address => uint256) noVotes; // Boolean whether the voting round passed or not bool passed; // Boolean whether the voting round results were claimed or not // refer the claimProposalVotingResult function in "./../interative/DaoVotingClaims.sol" bool claimed; // Boolean whether the milestone following this voting round was funded or not // The milestone is funded when the proposer calls claimFunding in "./../interactive/DaoFundingManager.sol" bool funded; } struct ProposalVersion { // IPFS doc hash of this version of the proposal bytes32 docIpfsHash; // UTC timestamp at which this version was created uint256 created; // The number of milestones in the proposal as per this version uint256 milestoneCount; // The final reward asked by the proposer for completion of the entire proposal uint256 finalReward; // List of fundings required by the proposal as per this version // The numbers are in wei uint256[] milestoneFundings; // When a proposal is finalized (calling Dao.finalizeProposal), the proposer can no longer add proposal versions // However, they can still add more details to this final proposal version, in the form of IPFS docs. // These IPFS docs are stored in this array bytes32[] moreDocs; } struct Proposal { // ID of the proposal. Also the IPFS hash of the first ProposalVersion bytes32 proposalId; // current state of the proposal // refer PROPOSAL_STATE_* in "./../common/DaoConstants.sol" bytes32 currentState; // UTC timestamp at which the proposal was created uint256 timeCreated; // DoublyLinkedList of IPFS doc hashes of the various versions of the proposal DoublyLinkedList.Bytes proposalVersionDocs; // Mapping of version (IPFS doc hash) to ProposalVersion struct mapping (bytes32 => ProposalVersion) proposalVersions; // Voting struct for the draft voting round Voting draftVoting; // Mapping of voting round index (starts from 0) to Voting struct // votingRounds[0] is the Voting round of the proposal, which lasts for get_uint_config(CONFIG_VOTING_PHASE_TOTAL) // votingRounds[i] for i>0 are the Interim Voting rounds of the proposal, which lasts for get_uint_config(CONFIG_INTERIM_PHASE_TOTAL) mapping (uint256 => Voting) votingRounds; // Every proposal has a collateral tied to it with a value of // get_uint_config(CONFIG_PREPROPOSAL_COLLATERAL) (refer "./../storage/DaoConfigsStorage.sol") // Collateral can be in different states // refer COLLATERAL_STATUS_* in "./../common/DaoConstants.sol" uint256 collateralStatus; uint256 collateralAmount; // The final version of the proposal // Every proposal needs to be finalized before it can be voted on // This is the IPFS doc hash of the final version bytes32 finalVersion; // List of PrlAction structs // These are all the actions done by the PRL on the proposal PrlAction[] prlActions; // Address of the user who created the proposal address proposer; // Address of the moderator who endorsed the proposal address endorser; // Boolean whether the proposal is paused/stopped at the moment bool isPausedOrStopped; // Boolean whether the proposal was created by a founder role bool isDigix; } function countVotes(Voting storage _voting, address[] _allUsers) external view returns (uint256 _for, uint256 _against) { uint256 _n = _allUsers.length; for (uint256 i = 0; i < _n; i++) { if (_voting.yesVotes[_allUsers[i]] > 0) { _for = _for.add(_voting.yesVotes[_allUsers[i]]); } else if (_voting.noVotes[_allUsers[i]] > 0) { _against = _against.add(_voting.noVotes[_allUsers[i]]); } } } // get the list of voters who voted _vote (true-yes/false-no) function listVotes(Voting storage _voting, address[] _allUsers, bool _vote) external view returns (address[] memory _voters, uint256 _length) { uint256 _n = _allUsers.length; uint256 i; _length = 0; _voters = new address[](_n); if (_vote == true) { for (i = 0; i < _n; i++) { if (_voting.yesVotes[_allUsers[i]] > 0) { _voters[_length] = _allUsers[i]; _length++; } } } else { for (i = 0; i < _n; i++) { if (_voting.noVotes[_allUsers[i]] > 0) { _voters[_length] = _allUsers[i]; _length++; } } } } function readVote(Voting storage _voting, address _voter) public view returns (bool _vote, uint256 _weight) { if (_voting.yesVotes[_voter] > 0) { _weight = _voting.yesVotes[_voter]; _vote = true; } else { _weight = _voting.noVotes[_voter]; // if _voter didnt vote at all, the weight will be 0 anyway _vote = false; } } function revealVote( Voting storage _voting, address _voter, bool _vote, uint256 _weight ) public { if (_vote) { _voting.yesVotes[_voter] = _weight; } else { _voting.noVotes[_voter] = _weight; } } function readVersion(ProposalVersion storage _version) public view returns ( bytes32 _doc, uint256 _created, uint256[] _milestoneFundings, uint256 _finalReward ) { _doc = _version.docIpfsHash; _created = _version.created; _milestoneFundings = _version.milestoneFundings; _finalReward = _version.finalReward; } // read the funding for a particular milestone of a finalized proposal // if _milestoneId is the same as _milestoneCount, it returns the final reward function readProposalMilestone(Proposal storage _proposal, uint256 _milestoneIndex) public view returns (uint256 _funding) { bytes32 _finalVersion = _proposal.finalVersion; uint256 _milestoneCount = _proposal.proposalVersions[_finalVersion].milestoneFundings.length; require(_milestoneIndex <= _milestoneCount); require(_finalVersion != EMPTY_BYTES); // the proposal must have been finalized if (_milestoneIndex < _milestoneCount) { _funding = _proposal.proposalVersions[_finalVersion].milestoneFundings[_milestoneIndex]; } else { _funding = _proposal.proposalVersions[_finalVersion].finalReward; } } function addProposalVersion( Proposal storage _proposal, bytes32 _newDoc, uint256[] _newMilestoneFundings, uint256 _finalReward ) public { _proposal.proposalVersionDocs.append(_newDoc); _proposal.proposalVersions[_newDoc].docIpfsHash = _newDoc; _proposal.proposalVersions[_newDoc].created = now; _proposal.proposalVersions[_newDoc].milestoneCount = _newMilestoneFundings.length; _proposal.proposalVersions[_newDoc].milestoneFundings = _newMilestoneFundings; _proposal.proposalVersions[_newDoc].finalReward = _finalReward; } struct SpecialProposal { // ID of the special proposal // This is the IPFS doc hash of the proposal bytes32 proposalId; // UTC timestamp at which the proposal was created uint256 timeCreated; // Voting struct for the special proposal Voting voting; // List of the new uint256 configs as per the special proposal uint256[] uintConfigs; // List of the new address configs as per the special proposal address[] addressConfigs; // List of the new bytes32 configs as per the special proposal bytes32[] bytesConfigs; // Address of the user who created the special proposal // This address should also be in the ROLES_FOUNDERS group // refer "./../storage/DaoIdentityStorage.sol" address proposer; } // All configs are as per the DaoConfigsStorage values at the time when // calculateGlobalRewardsBeforeNewQuarter is called by founder in that quarter struct DaoQuarterInfo { // The minimum quarter points required // below this, reputation will be deducted uint256 minimalParticipationPoint; // The scaling factor for quarter point uint256 quarterPointScalingFactor; // The scaling factor for reputation point uint256 reputationPointScalingFactor; // The summation of effectiveDGDs in the previous quarter // The effectiveDGDs represents the effective participation in DigixDAO in a quarter // Which depends on lockedDGDStake, quarter point and reputation point // This value is the summation of all participant effectiveDGDs // It will be used to calculate the fraction of effectiveDGD a user has, // which will determine his portion of DGX rewards for that quarter uint256 totalEffectiveDGDPreviousQuarter; // The minimum moderator quarter point required // below this, reputation will be deducted for moderators uint256 moderatorMinimalParticipationPoint; // the scaling factor for moderator quarter point uint256 moderatorQuarterPointScalingFactor; // the scaling factor for moderator reputation point uint256 moderatorReputationPointScalingFactor; // The summation of effectiveDGDs (only specific to moderators) uint256 totalEffectiveModeratorDGDLastQuarter; // UTC timestamp from which the DGX rewards for the previous quarter are distributable to Holders uint256 dgxDistributionDay; // This is the rewards pool for the previous quarter. This is the sum of the DGX fees coming in from the collector, and the demurrage that has incurred // when user call claimRewards() in the previous quarter. // more graphical explanation: https://ipfs.io/ipfs/QmZDgFFMbyF3dvuuDfoXv5F6orq4kaDPo7m3QvnseUguzo uint256 dgxRewardsPoolLastQuarter; // The summation of all dgxRewardsPoolLastQuarter up until this quarter uint256 sumRewardsFromBeginning; } // There are many function calls where all calculations/summations cannot be done in one transaction // and require multiple transactions. // This struct stores the intermediate results in between the calculating transactions // These intermediate results are stored in IntermediateResultsStorage struct IntermediateResults { // weight of "FOR" votes counted up until the current calculation step uint256 currentForCount; // weight of "AGAINST" votes counted up until the current calculation step uint256 currentAgainstCount; // summation of effectiveDGDs up until the iteration of calculation uint256 currentSumOfEffectiveBalance; // Address of user until which the calculation has been done address countedUntil; } } // File: contracts/storage/DaoStorage.sol pragma solidity ^0.4.25; contract DaoStorage is DaoWhitelistingCommon, BytesIteratorStorage { using DoublyLinkedList for DoublyLinkedList.Bytes; using DaoStructs for DaoStructs.Voting; using DaoStructs for DaoStructs.Proposal; using DaoStructs for DaoStructs.ProposalVersion; // List of all the proposals ever created in DigixDAO DoublyLinkedList.Bytes allProposals; // mapping of Proposal struct by its ID // ID is also the IPFS doc hash of the first ever version of this proposal mapping (bytes32 => DaoStructs.Proposal) proposalsById; // mapping from state of a proposal to list of all proposals in that state // proposals are added/removed from the state's list as their states change // eg. when proposal is endorsed, when proposal is funded, etc mapping (bytes32 => DoublyLinkedList.Bytes) proposalsByState; constructor(address _resolver) public { require(init(CONTRACT_STORAGE_DAO, _resolver)); } /////////////////////////////// READ FUNCTIONS ////////////////////////////// /// @notice read all information and details of proposal /// @param _proposalId Proposal ID, i.e. hash of IPFS doc Proposal ID, i.e. hash of IPFS doc /// return { /// "_doc": "Original IPFS doc of proposal, also ID of proposal", /// "_proposer": "Address of the proposer", /// "_endorser": "Address of the moderator that endorsed the proposal", /// "_state": "Current state of the proposal", /// "_timeCreated": "UTC timestamp at which proposal was created", /// "_nVersions": "Number of versions of the proposal", /// "_latestVersionDoc": "IPFS doc hash of the latest version of this proposal", /// "_finalVersion": "If finalized, the version of the final proposal", /// "_pausedOrStopped": "If the proposal is paused/stopped at the moment", /// "_isDigixProposal": "If the proposal has been created by founder or not" /// } function readProposal(bytes32 _proposalId) public view returns ( bytes32 _doc, address _proposer, address _endorser, bytes32 _state, uint256 _timeCreated, uint256 _nVersions, bytes32 _latestVersionDoc, bytes32 _finalVersion, bool _pausedOrStopped, bool _isDigixProposal ) { require(senderIsAllowedToRead()); DaoStructs.Proposal storage _proposal = proposalsById[_proposalId]; _doc = _proposal.proposalId; _proposer = _proposal.proposer; _endorser = _proposal.endorser; _state = _proposal.currentState; _timeCreated = _proposal.timeCreated; _nVersions = read_total_bytesarray(_proposal.proposalVersionDocs); _latestVersionDoc = read_last_from_bytesarray(_proposal.proposalVersionDocs); _finalVersion = _proposal.finalVersion; _pausedOrStopped = _proposal.isPausedOrStopped; _isDigixProposal = _proposal.isDigix; } function readProposalProposer(bytes32 _proposalId) public view returns (address _proposer) { _proposer = proposalsById[_proposalId].proposer; } function readTotalPrlActions(bytes32 _proposalId) public view returns (uint256 _length) { _length = proposalsById[_proposalId].prlActions.length; } function readPrlAction(bytes32 _proposalId, uint256 _index) public view returns (uint256 _actionId, uint256 _time, bytes32 _doc) { DaoStructs.PrlAction[] memory _actions = proposalsById[_proposalId].prlActions; require(_index < _actions.length); _actionId = _actions[_index].actionId; _time = _actions[_index].at; _doc = _actions[_index].doc; } function readProposalDraftVotingResult(bytes32 _proposalId) public view returns (bool _result) { require(senderIsAllowedToRead()); _result = proposalsById[_proposalId].draftVoting.passed; } function readProposalVotingResult(bytes32 _proposalId, uint256 _index) public view returns (bool _result) { require(senderIsAllowedToRead()); _result = proposalsById[_proposalId].votingRounds[_index].passed; } function readProposalDraftVotingTime(bytes32 _proposalId) public view returns (uint256 _start) { require(senderIsAllowedToRead()); _start = proposalsById[_proposalId].draftVoting.startTime; } function readProposalVotingTime(bytes32 _proposalId, uint256 _index) public view returns (uint256 _start) { require(senderIsAllowedToRead()); _start = proposalsById[_proposalId].votingRounds[_index].startTime; } function readDraftVotingCount(bytes32 _proposalId, address[] _allUsers) external view returns (uint256 _for, uint256 _against) { require(senderIsAllowedToRead()); return proposalsById[_proposalId].draftVoting.countVotes(_allUsers); } function readVotingCount(bytes32 _proposalId, uint256 _index, address[] _allUsers) external view returns (uint256 _for, uint256 _against) { require(senderIsAllowedToRead()); return proposalsById[_proposalId].votingRounds[_index].countVotes(_allUsers); } function readVotingRoundVotes(bytes32 _proposalId, uint256 _index, address[] _allUsers, bool _vote) external view returns (address[] memory _voters, uint256 _length) { require(senderIsAllowedToRead()); return proposalsById[_proposalId].votingRounds[_index].listVotes(_allUsers, _vote); } function readDraftVote(bytes32 _proposalId, address _voter) public view returns (bool _vote, uint256 _weight) { require(senderIsAllowedToRead()); return proposalsById[_proposalId].draftVoting.readVote(_voter); } /// @notice returns the latest committed vote by a voter on a proposal /// @param _proposalId proposal ID /// @param _voter address of the voter /// @return { /// "_commitHash": "" /// } function readComittedVote(bytes32 _proposalId, uint256 _index, address _voter) public view returns (bytes32 _commitHash) { require(senderIsAllowedToRead()); _commitHash = proposalsById[_proposalId].votingRounds[_index].commits[_voter]; } function readVote(bytes32 _proposalId, uint256 _index, address _voter) public view returns (bool _vote, uint256 _weight) { require(senderIsAllowedToRead()); return proposalsById[_proposalId].votingRounds[_index].readVote(_voter); } /// @notice get all information and details of the first proposal /// return { /// "_id": "" /// } function getFirstProposal() public view returns (bytes32 _id) { _id = read_first_from_bytesarray(allProposals); } /// @notice get all information and details of the last proposal /// return { /// "_id": "" /// } function getLastProposal() public view returns (bytes32 _id) { _id = read_last_from_bytesarray(allProposals); } /// @notice get all information and details of proposal next to _proposalId /// @param _proposalId Proposal ID, i.e. hash of IPFS doc /// return { /// "_id": "" /// } function getNextProposal(bytes32 _proposalId) public view returns (bytes32 _id) { _id = read_next_from_bytesarray( allProposals, _proposalId ); } /// @notice get all information and details of proposal previous to _proposalId /// @param _proposalId Proposal ID, i.e. hash of IPFS doc /// return { /// "_id": "" /// } function getPreviousProposal(bytes32 _proposalId) public view returns (bytes32 _id) { _id = read_previous_from_bytesarray( allProposals, _proposalId ); } /// @notice get all information and details of the first proposal in state _stateId /// @param _stateId State ID of the proposal /// return { /// "_id": "" /// } function getFirstProposalInState(bytes32 _stateId) public view returns (bytes32 _id) { require(senderIsAllowedToRead()); _id = read_first_from_bytesarray(proposalsByState[_stateId]); } /// @notice get all information and details of the last proposal in state _stateId /// @param _stateId State ID of the proposal /// return { /// "_id": "" /// } function getLastProposalInState(bytes32 _stateId) public view returns (bytes32 _id) { require(senderIsAllowedToRead()); _id = read_last_from_bytesarray(proposalsByState[_stateId]); } /// @notice get all information and details of the next proposal to _proposalId in state _stateId /// @param _stateId State ID of the proposal /// return { /// "_id": "" /// } function getNextProposalInState(bytes32 _stateId, bytes32 _proposalId) public view returns (bytes32 _id) { require(senderIsAllowedToRead()); _id = read_next_from_bytesarray( proposalsByState[_stateId], _proposalId ); } /// @notice get all information and details of the previous proposal to _proposalId in state _stateId /// @param _stateId State ID of the proposal /// return { /// "_id": "" /// } function getPreviousProposalInState(bytes32 _stateId, bytes32 _proposalId) public view returns (bytes32 _id) { require(senderIsAllowedToRead()); _id = read_previous_from_bytesarray( proposalsByState[_stateId], _proposalId ); } /// @notice read proposal version details for a specific version /// @param _proposalId Proposal ID, i.e. hash of IPFS doc /// @param _version Version of proposal, i.e. hash of IPFS doc for specific version /// return { /// "_doc": "", /// "_created": "", /// "_milestoneFundings": "" /// } function readProposalVersion(bytes32 _proposalId, bytes32 _version) public view returns ( bytes32 _doc, uint256 _created, uint256[] _milestoneFundings, uint256 _finalReward ) { return proposalsById[_proposalId].proposalVersions[_version].readVersion(); } /** @notice Read the fundings of a finalized proposal @return { "_fundings": "fundings for the milestones", "_finalReward": "the final reward" } */ function readProposalFunding(bytes32 _proposalId) public view returns (uint256[] memory _fundings, uint256 _finalReward) { require(senderIsAllowedToRead()); bytes32 _finalVersion = proposalsById[_proposalId].finalVersion; require(_finalVersion != EMPTY_BYTES); _fundings = proposalsById[_proposalId].proposalVersions[_finalVersion].milestoneFundings; _finalReward = proposalsById[_proposalId].proposalVersions[_finalVersion].finalReward; } function readProposalMilestone(bytes32 _proposalId, uint256 _index) public view returns (uint256 _funding) { require(senderIsAllowedToRead()); _funding = proposalsById[_proposalId].readProposalMilestone(_index); } /// @notice get proposal version details for the first version /// @param _proposalId Proposal ID, i.e. hash of IPFS doc /// return { /// "_version": "" /// } function getFirstProposalVersion(bytes32 _proposalId) public view returns (bytes32 _version) { DaoStructs.Proposal storage _proposal = proposalsById[_proposalId]; _version = read_first_from_bytesarray(_proposal.proposalVersionDocs); } /// @notice get proposal version details for the last version /// @param _proposalId Proposal ID, i.e. hash of IPFS doc /// return { /// "_version": "" /// } function getLastProposalVersion(bytes32 _proposalId) public view returns (bytes32 _version) { DaoStructs.Proposal storage _proposal = proposalsById[_proposalId]; _version = read_last_from_bytesarray(_proposal.proposalVersionDocs); } /// @notice get proposal version details for the next version to _version /// @param _proposalId Proposal ID, i.e. hash of IPFS doc /// @param _version Version of proposal /// return { /// "_nextVersion": "" /// } function getNextProposalVersion(bytes32 _proposalId, bytes32 _version) public view returns (bytes32 _nextVersion) { DaoStructs.Proposal storage _proposal = proposalsById[_proposalId]; _nextVersion = read_next_from_bytesarray( _proposal.proposalVersionDocs, _version ); } /// @notice get proposal version details for the previous version to _version /// @param _proposalId Proposal ID, i.e. hash of IPFS doc /// @param _version Version of proposal /// return { /// "_previousVersion": "" /// } function getPreviousProposalVersion(bytes32 _proposalId, bytes32 _version) public view returns (bytes32 _previousVersion) { DaoStructs.Proposal storage _proposal = proposalsById[_proposalId]; _previousVersion = read_previous_from_bytesarray( _proposal.proposalVersionDocs, _version ); } function isDraftClaimed(bytes32 _proposalId) public view returns (bool _claimed) { _claimed = proposalsById[_proposalId].draftVoting.claimed; } function isClaimed(bytes32 _proposalId, uint256 _index) public view returns (bool _claimed) { _claimed = proposalsById[_proposalId].votingRounds[_index].claimed; } function readProposalCollateralStatus(bytes32 _proposalId) public view returns (uint256 _status) { require(senderIsAllowedToRead()); _status = proposalsById[_proposalId].collateralStatus; } function readProposalCollateralAmount(bytes32 _proposalId) public view returns (uint256 _amount) { _amount = proposalsById[_proposalId].collateralAmount; } /// @notice Read the additional docs that are added after the proposal is finalized /// @dev Will throw if the propsal is not finalized yet function readProposalDocs(bytes32 _proposalId) public view returns (bytes32[] _moreDocs) { bytes32 _finalVersion = proposalsById[_proposalId].finalVersion; require(_finalVersion != EMPTY_BYTES); _moreDocs = proposalsById[_proposalId].proposalVersions[_finalVersion].moreDocs; } function readIfMilestoneFunded(bytes32 _proposalId, uint256 _milestoneId) public view returns (bool _funded) { require(senderIsAllowedToRead()); _funded = proposalsById[_proposalId].votingRounds[_milestoneId].funded; } ////////////////////////////// WRITE FUNCTIONS ////////////////////////////// function addProposal( bytes32 _doc, address _proposer, uint256[] _milestoneFundings, uint256 _finalReward, bool _isFounder ) external { require(sender_is(CONTRACT_DAO)); require( (proposalsById[_doc].proposalId == EMPTY_BYTES) && (_doc != EMPTY_BYTES) ); allProposals.append(_doc); proposalsByState[PROPOSAL_STATE_PREPROPOSAL].append(_doc); proposalsById[_doc].proposalId = _doc; proposalsById[_doc].proposer = _proposer; proposalsById[_doc].currentState = PROPOSAL_STATE_PREPROPOSAL; proposalsById[_doc].timeCreated = now; proposalsById[_doc].isDigix = _isFounder; proposalsById[_doc].addProposalVersion(_doc, _milestoneFundings, _finalReward); } function editProposal( bytes32 _proposalId, bytes32 _newDoc, uint256[] _newMilestoneFundings, uint256 _finalReward ) external { require(sender_is(CONTRACT_DAO)); proposalsById[_proposalId].addProposalVersion(_newDoc, _newMilestoneFundings, _finalReward); } /// @notice change fundings of a proposal /// @dev Will throw if the proposal is not finalized yet function changeFundings(bytes32 _proposalId, uint256[] _newMilestoneFundings, uint256 _finalReward) external { require(sender_is(CONTRACT_DAO)); bytes32 _finalVersion = proposalsById[_proposalId].finalVersion; require(_finalVersion != EMPTY_BYTES); proposalsById[_proposalId].proposalVersions[_finalVersion].milestoneFundings = _newMilestoneFundings; proposalsById[_proposalId].proposalVersions[_finalVersion].finalReward = _finalReward; } /// @dev Will throw if the proposal is not finalized yet function addProposalDoc(bytes32 _proposalId, bytes32 _newDoc) public { require(sender_is(CONTRACT_DAO)); bytes32 _finalVersion = proposalsById[_proposalId].finalVersion; require(_finalVersion != EMPTY_BYTES); //already checked in interactive layer, but why not proposalsById[_proposalId].proposalVersions[_finalVersion].moreDocs.push(_newDoc); } function finalizeProposal(bytes32 _proposalId) public { require(sender_is(CONTRACT_DAO)); proposalsById[_proposalId].finalVersion = getLastProposalVersion(_proposalId); } function updateProposalEndorse( bytes32 _proposalId, address _endorser ) public { require(sender_is(CONTRACT_DAO)); DaoStructs.Proposal storage _proposal = proposalsById[_proposalId]; _proposal.endorser = _endorser; _proposal.currentState = PROPOSAL_STATE_DRAFT; proposalsByState[PROPOSAL_STATE_PREPROPOSAL].remove_item(_proposalId); proposalsByState[PROPOSAL_STATE_DRAFT].append(_proposalId); } function setProposalDraftPass(bytes32 _proposalId, bool _result) public { require(sender_is(CONTRACT_DAO_VOTING_CLAIMS)); proposalsById[_proposalId].draftVoting.passed = _result; if (_result) { proposalsByState[PROPOSAL_STATE_DRAFT].remove_item(_proposalId); proposalsByState[PROPOSAL_STATE_MODERATED].append(_proposalId); proposalsById[_proposalId].currentState = PROPOSAL_STATE_MODERATED; } else { closeProposalInternal(_proposalId); } } function setProposalPass(bytes32 _proposalId, uint256 _index, bool _result) public { require(sender_is(CONTRACT_DAO_VOTING_CLAIMS)); if (!_result) { closeProposalInternal(_proposalId); } else if (_index == 0) { proposalsByState[PROPOSAL_STATE_MODERATED].remove_item(_proposalId); proposalsByState[PROPOSAL_STATE_ONGOING].append(_proposalId); proposalsById[_proposalId].currentState = PROPOSAL_STATE_ONGOING; } proposalsById[_proposalId].votingRounds[_index].passed = _result; } function setProposalDraftVotingTime( bytes32 _proposalId, uint256 _time ) public { require(sender_is(CONTRACT_DAO)); proposalsById[_proposalId].draftVoting.startTime = _time; } function setProposalVotingTime( bytes32 _proposalId, uint256 _index, uint256 _time ) public { require(sender_is_from([CONTRACT_DAO, CONTRACT_DAO_VOTING_CLAIMS, EMPTY_BYTES])); proposalsById[_proposalId].votingRounds[_index].startTime = _time; } function setDraftVotingClaim(bytes32 _proposalId, bool _claimed) public { require(sender_is(CONTRACT_DAO_VOTING_CLAIMS)); proposalsById[_proposalId].draftVoting.claimed = _claimed; } function setVotingClaim(bytes32 _proposalId, uint256 _index, bool _claimed) public { require(sender_is(CONTRACT_DAO_VOTING_CLAIMS)); proposalsById[_proposalId].votingRounds[_index].claimed = _claimed; } function setProposalCollateralStatus(bytes32 _proposalId, uint256 _status) public { require(sender_is_from([CONTRACT_DAO_VOTING_CLAIMS, CONTRACT_DAO_FUNDING_MANAGER, CONTRACT_DAO])); proposalsById[_proposalId].collateralStatus = _status; } function setProposalCollateralAmount(bytes32 _proposalId, uint256 _amount) public { require(sender_is(CONTRACT_DAO)); proposalsById[_proposalId].collateralAmount = _amount; } function updateProposalPRL( bytes32 _proposalId, uint256 _action, bytes32 _doc, uint256 _time ) public { require(sender_is(CONTRACT_DAO)); require(proposalsById[_proposalId].currentState != PROPOSAL_STATE_CLOSED); DaoStructs.PrlAction memory prlAction; prlAction.at = _time; prlAction.doc = _doc; prlAction.actionId = _action; proposalsById[_proposalId].prlActions.push(prlAction); if (_action == PRL_ACTION_PAUSE) { proposalsById[_proposalId].isPausedOrStopped = true; } else if (_action == PRL_ACTION_UNPAUSE) { proposalsById[_proposalId].isPausedOrStopped = false; } else { // STOP proposalsById[_proposalId].isPausedOrStopped = true; closeProposalInternal(_proposalId); } } function closeProposalInternal(bytes32 _proposalId) internal { bytes32 _currentState = proposalsById[_proposalId].currentState; proposalsByState[_currentState].remove_item(_proposalId); proposalsByState[PROPOSAL_STATE_CLOSED].append(_proposalId); proposalsById[_proposalId].currentState = PROPOSAL_STATE_CLOSED; } function addDraftVote( bytes32 _proposalId, address _voter, bool _vote, uint256 _weight ) public { require(sender_is(CONTRACT_DAO_VOTING)); DaoStructs.Proposal storage _proposal = proposalsById[_proposalId]; if (_vote) { _proposal.draftVoting.yesVotes[_voter] = _weight; if (_proposal.draftVoting.noVotes[_voter] > 0) { // minimize number of writes to storage, since EIP-1087 is not implemented yet _proposal.draftVoting.noVotes[_voter] = 0; } } else { _proposal.draftVoting.noVotes[_voter] = _weight; if (_proposal.draftVoting.yesVotes[_voter] > 0) { _proposal.draftVoting.yesVotes[_voter] = 0; } } } function commitVote( bytes32 _proposalId, bytes32 _hash, address _voter, uint256 _index ) public { require(sender_is(CONTRACT_DAO_VOTING)); proposalsById[_proposalId].votingRounds[_index].commits[_voter] = _hash; } function revealVote( bytes32 _proposalId, address _voter, bool _vote, uint256 _weight, uint256 _index ) public { require(sender_is(CONTRACT_DAO_VOTING)); proposalsById[_proposalId].votingRounds[_index].revealVote(_voter, _vote, _weight); } function closeProposal(bytes32 _proposalId) public { require(sender_is(CONTRACT_DAO)); closeProposalInternal(_proposalId); } function archiveProposal(bytes32 _proposalId) public { require(sender_is(CONTRACT_DAO_VOTING_CLAIMS)); bytes32 _currentState = proposalsById[_proposalId].currentState; proposalsByState[_currentState].remove_item(_proposalId); proposalsByState[PROPOSAL_STATE_ARCHIVED].append(_proposalId); proposalsById[_proposalId].currentState = PROPOSAL_STATE_ARCHIVED; } function setMilestoneFunded(bytes32 _proposalId, uint256 _milestoneId) public { require(sender_is(CONTRACT_DAO_FUNDING_MANAGER)); proposalsById[_proposalId].votingRounds[_milestoneId].funded = true; } } // File: @digix/solidity-collections/contracts/abstract/AddressIteratorStorage.sol pragma solidity ^0.4.19; /** @title Address Iterator Storage @author DigixGlobal Pte Ltd @notice See: [Doubly Linked List](/DoublyLinkedList) */ contract AddressIteratorStorage { // Initialize Doubly Linked List of Address using DoublyLinkedList for DoublyLinkedList.Address; /** @notice Reads the first item from the list of Address @param _list The source list @return {"_item" : "The first item from the list"} */ function read_first_from_addresses(DoublyLinkedList.Address storage _list) internal constant returns (address _item) { _item = _list.start_item(); } /** @notice Reads the last item from the list of Address @param _list The source list @return {"_item" : "The last item from the list"} */ function read_last_from_addresses(DoublyLinkedList.Address storage _list) internal constant returns (address _item) { _item = _list.end_item(); } /** @notice Reads the next item on the list of Address @param _list The source list @param _current_item The current item to be used as base line @return {"_item" : "The next item from the list based on the specieid `_current_item`"} */ function read_next_from_addresses(DoublyLinkedList.Address storage _list, address _current_item) internal constant returns (address _item) { _item = _list.next_item(_current_item); } /** @notice Reads the previous item on the list of Address @param _list The source list @param _current_item The current item to be used as base line @return {"_item" : "The previous item from the list based on the spcified `_current_item`"} */ function read_previous_from_addresses(DoublyLinkedList.Address storage _list, address _current_item) internal constant returns (address _item) { _item = _list.previous_item(_current_item); } /** @notice Reads the list of Address and returns the length of the list @param _list The source list @return {"_count": "The lenght of the list"} */ function read_total_addresses(DoublyLinkedList.Address storage _list) internal constant returns (uint256 _count) { _count = _list.total(); } } // File: contracts/storage/DaoStakeStorage.sol pragma solidity ^0.4.25; contract DaoStakeStorage is ResolverClient, DaoConstants, AddressIteratorStorage { using DoublyLinkedList for DoublyLinkedList.Address; // This is the DGD stake of a user (one that is considered in the DAO) mapping (address => uint256) public lockedDGDStake; // This is the actual number of DGDs locked by user // may be more than the lockedDGDStake // in case they locked during the main phase mapping (address => uint256) public actualLockedDGD; // The total locked DGDs in the DAO (summation of lockedDGDStake) uint256 public totalLockedDGDStake; // The total locked DGDs by moderators uint256 public totalModeratorLockedDGDStake; // The list of participants in DAO // actual participants will be subset of this list DoublyLinkedList.Address allParticipants; // The list of moderators in DAO // actual moderators will be subset of this list DoublyLinkedList.Address allModerators; // Boolean to mark if an address has redeemed // reputation points for their DGD Badge mapping (address => bool) public redeemedBadge; // mapping to note whether an address has claimed their // reputation bonus for carbon vote participation mapping (address => bool) public carbonVoteBonusClaimed; constructor(address _resolver) public { require(init(CONTRACT_STORAGE_DAO_STAKE, _resolver)); } function redeemBadge(address _user) public { require(sender_is(CONTRACT_DAO_STAKE_LOCKING)); redeemedBadge[_user] = true; } function setCarbonVoteBonusClaimed(address _user) public { require(sender_is(CONTRACT_DAO_STAKE_LOCKING)); carbonVoteBonusClaimed[_user] = true; } function updateTotalLockedDGDStake(uint256 _totalLockedDGDStake) public { require(sender_is_from([CONTRACT_DAO_STAKE_LOCKING, CONTRACT_DAO_REWARDS_MANAGER, EMPTY_BYTES])); totalLockedDGDStake = _totalLockedDGDStake; } function updateTotalModeratorLockedDGDs(uint256 _totalLockedDGDStake) public { require(sender_is_from([CONTRACT_DAO_STAKE_LOCKING, CONTRACT_DAO_REWARDS_MANAGER, EMPTY_BYTES])); totalModeratorLockedDGDStake = _totalLockedDGDStake; } function updateUserDGDStake(address _user, uint256 _actualLockedDGD, uint256 _lockedDGDStake) public { require(sender_is(CONTRACT_DAO_STAKE_LOCKING)); actualLockedDGD[_user] = _actualLockedDGD; lockedDGDStake[_user] = _lockedDGDStake; } function readUserDGDStake(address _user) public view returns ( uint256 _actualLockedDGD, uint256 _lockedDGDStake ) { _actualLockedDGD = actualLockedDGD[_user]; _lockedDGDStake = lockedDGDStake[_user]; } function addToParticipantList(address _user) public returns (bool _success) { require(sender_is(CONTRACT_DAO_STAKE_LOCKING)); _success = allParticipants.append(_user); } function removeFromParticipantList(address _user) public returns (bool _success) { require(sender_is(CONTRACT_DAO_STAKE_LOCKING)); _success = allParticipants.remove_item(_user); } function addToModeratorList(address _user) public returns (bool _success) { require(sender_is(CONTRACT_DAO_STAKE_LOCKING)); _success = allModerators.append(_user); } function removeFromModeratorList(address _user) public returns (bool _success) { require(sender_is(CONTRACT_DAO_STAKE_LOCKING)); _success = allModerators.remove_item(_user); } function isInParticipantList(address _user) public view returns (bool _is) { _is = allParticipants.find(_user) != 0; } function isInModeratorsList(address _user) public view returns (bool _is) { _is = allModerators.find(_user) != 0; } function readFirstModerator() public view returns (address _item) { _item = read_first_from_addresses(allModerators); } function readLastModerator() public view returns (address _item) { _item = read_last_from_addresses(allModerators); } function readNextModerator(address _current_item) public view returns (address _item) { _item = read_next_from_addresses(allModerators, _current_item); } function readPreviousModerator(address _current_item) public view returns (address _item) { _item = read_previous_from_addresses(allModerators, _current_item); } function readTotalModerators() public view returns (uint256 _total_count) { _total_count = read_total_addresses(allModerators); } function readFirstParticipant() public view returns (address _item) { _item = read_first_from_addresses(allParticipants); } function readLastParticipant() public view returns (address _item) { _item = read_last_from_addresses(allParticipants); } function readNextParticipant(address _current_item) public view returns (address _item) { _item = read_next_from_addresses(allParticipants, _current_item); } function readPreviousParticipant(address _current_item) public view returns (address _item) { _item = read_previous_from_addresses(allParticipants, _current_item); } function readTotalParticipant() public view returns (uint256 _total_count) { _total_count = read_total_addresses(allParticipants); } } // File: contracts/service/DaoListingService.sol pragma solidity ^0.4.25; /** @title Contract to list various storage states from DigixDAO @author Digix Holdings */ contract DaoListingService is AddressIteratorInteractive, BytesIteratorInteractive, IndexedBytesIteratorInteractive, DaoWhitelistingCommon { /** @notice Constructor @param _resolver address of contract resolver */ constructor(address _resolver) public { require(init(CONTRACT_SERVICE_DAO_LISTING, _resolver)); } function daoStakeStorage() internal view returns (DaoStakeStorage _contract) { _contract = DaoStakeStorage(get_contract(CONTRACT_STORAGE_DAO_STAKE)); } function daoStorage() internal view returns (DaoStorage _contract) { _contract = DaoStorage(get_contract(CONTRACT_STORAGE_DAO)); } /** @notice function to list moderators @dev note that this list may include some additional entries that are not moderators in the current quarter. This may happen if they were moderators in the previous quarter, but have not confirmed their participation in the current quarter. For a single address, a better way to know if moderator or not is: Dao.isModerator(_user) @param _count number of addresses to list @param _from_start boolean, whether to list from start or end @return { "_moderators": "list of moderator addresses" } */ function listModerators(uint256 _count, bool _from_start) public view returns (address[] _moderators) { _moderators = list_addresses( _count, daoStakeStorage().readFirstModerator, daoStakeStorage().readLastModerator, daoStakeStorage().readNextModerator, daoStakeStorage().readPreviousModerator, _from_start ); } /** @notice function to list moderators from a particular moderator @dev note that this list may include some additional entries that are not moderators in the current quarter. This may happen if they were moderators in the previous quarter, but have not confirmed their participation in the current quarter. For a single address, a better way to know if moderator or not is: Dao.isModerator(_user) Another note: this function will start listing AFTER the _currentModerator For example: we have [address1, address2, address3, address4]. listModeratorsFrom(address1, 2, true) = [address2, address3] @param _currentModerator start the list after this moderator address @param _count number of addresses to list @param _from_start boolean, whether to list from start or end @return { "_moderators": "list of moderator addresses" } */ function listModeratorsFrom( address _currentModerator, uint256 _count, bool _from_start ) public view returns (address[] _moderators) { _moderators = list_addresses_from( _currentModerator, _count, daoStakeStorage().readFirstModerator, daoStakeStorage().readLastModerator, daoStakeStorage().readNextModerator, daoStakeStorage().readPreviousModerator, _from_start ); } /** @notice function to list participants @dev note that this list may include some additional entries that are not participants in the current quarter. This may happen if they were participants in the previous quarter, but have not confirmed their participation in the current quarter. For a single address, a better way to know if participant or not is: Dao.isParticipant(_user) @param _count number of addresses to list @param _from_start boolean, whether to list from start or end @return { "_participants": "list of participant addresses" } */ function listParticipants(uint256 _count, bool _from_start) public view returns (address[] _participants) { _participants = list_addresses( _count, daoStakeStorage().readFirstParticipant, daoStakeStorage().readLastParticipant, daoStakeStorage().readNextParticipant, daoStakeStorage().readPreviousParticipant, _from_start ); } /** @notice function to list participants from a particular participant @dev note that this list may include some additional entries that are not participants in the current quarter. This may happen if they were participants in the previous quarter, but have not confirmed their participation in the current quarter. For a single address, a better way to know if participant or not is: contracts.dao.isParticipant(_user) Another note: this function will start listing AFTER the _currentParticipant For example: we have [address1, address2, address3, address4]. listParticipantsFrom(address1, 2, true) = [address2, address3] @param _currentParticipant list from AFTER this participant address @param _count number of addresses to list @param _from_start boolean, whether to list from start or end @return { "_participants": "list of participant addresses" } */ function listParticipantsFrom( address _currentParticipant, uint256 _count, bool _from_start ) public view returns (address[] _participants) { _participants = list_addresses_from( _currentParticipant, _count, daoStakeStorage().readFirstParticipant, daoStakeStorage().readLastParticipant, daoStakeStorage().readNextParticipant, daoStakeStorage().readPreviousParticipant, _from_start ); } /** @notice function to list _count no. of proposals @param _count number of proposals to list @param _from_start boolean value, true if count from start, false if count from end @return { "_proposals": "the list of proposal IDs" } */ function listProposals( uint256 _count, bool _from_start ) public view returns (bytes32[] _proposals) { _proposals = list_bytesarray( _count, daoStorage().getFirstProposal, daoStorage().getLastProposal, daoStorage().getNextProposal, daoStorage().getPreviousProposal, _from_start ); } /** @notice function to list _count no. of proposals from AFTER _currentProposal @param _currentProposal ID of proposal to list proposals from @param _count number of proposals to list @param _from_start boolean value, true if count forwards, false if count backwards @return { "_proposals": "the list of proposal IDs" } */ function listProposalsFrom( bytes32 _currentProposal, uint256 _count, bool _from_start ) public view returns (bytes32[] _proposals) { _proposals = list_bytesarray_from( _currentProposal, _count, daoStorage().getFirstProposal, daoStorage().getLastProposal, daoStorage().getNextProposal, daoStorage().getPreviousProposal, _from_start ); } /** @notice function to list _count no. of proposals in state _stateId @param _stateId state of proposal @param _count number of proposals to list @param _from_start boolean value, true if count from start, false if count from end @return { "_proposals": "the list of proposal IDs" } */ function listProposalsInState( bytes32 _stateId, uint256 _count, bool _from_start ) public view returns (bytes32[] _proposals) { require(senderIsAllowedToRead()); _proposals = list_indexed_bytesarray( _stateId, _count, daoStorage().getFirstProposalInState, daoStorage().getLastProposalInState, daoStorage().getNextProposalInState, daoStorage().getPreviousProposalInState, _from_start ); } /** @notice function to list _count no. of proposals in state _stateId from AFTER _currentProposal @param _stateId state of proposal @param _currentProposal ID of proposal to list proposals from @param _count number of proposals to list @param _from_start boolean value, true if count forwards, false if count backwards @return { "_proposals": "the list of proposal IDs" } */ function listProposalsInStateFrom( bytes32 _stateId, bytes32 _currentProposal, uint256 _count, bool _from_start ) public view returns (bytes32[] _proposals) { require(senderIsAllowedToRead()); _proposals = list_indexed_bytesarray_from( _stateId, _currentProposal, _count, daoStorage().getFirstProposalInState, daoStorage().getLastProposalInState, daoStorage().getNextProposalInState, daoStorage().getPreviousProposalInState, _from_start ); } /** @notice function to list proposal versions @param _proposalId ID of the proposal @param _count number of proposal versions to list @param _from_start boolean, true to list from start, false to list from end @return { "_versions": "list of proposal versions" } */ function listProposalVersions( bytes32 _proposalId, uint256 _count, bool _from_start ) public view returns (bytes32[] _versions) { _versions = list_indexed_bytesarray( _proposalId, _count, daoStorage().getFirstProposalVersion, daoStorage().getLastProposalVersion, daoStorage().getNextProposalVersion, daoStorage().getPreviousProposalVersion, _from_start ); } /** @notice function to list proposal versions from AFTER a particular version @param _proposalId ID of the proposal @param _currentVersion version to list _count versions from @param _count number of proposal versions to list @param _from_start boolean, true to list from start, false to list from end @return { "_versions": "list of proposal versions" } */ function listProposalVersionsFrom( bytes32 _proposalId, bytes32 _currentVersion, uint256 _count, bool _from_start ) public view returns (bytes32[] _versions) { _versions = list_indexed_bytesarray_from( _proposalId, _currentVersion, _count, daoStorage().getFirstProposalVersion, daoStorage().getLastProposalVersion, daoStorage().getNextProposalVersion, daoStorage().getPreviousProposalVersion, _from_start ); } } // File: @digix/solidity-collections/contracts/abstract/IndexedAddressIteratorStorage.sol pragma solidity ^0.4.19; /** @title Indexed Address IteratorStorage @author DigixGlobal Pte Ltd @notice This contract utilizes: [Doubly Linked List](/DoublyLinkedList) */ contract IndexedAddressIteratorStorage { using DoublyLinkedList for DoublyLinkedList.IndexedAddress; /** @notice Reads the first item from an Indexed Address Doubly Linked List @param _list The source list @param _collection_index Index of the Collection to evaluate @return {"_item" : "First item on the list"} */ function read_first_from_indexed_addresses(DoublyLinkedList.IndexedAddress storage _list, bytes32 _collection_index) internal constant returns (address _item) { _item = _list.start_item(_collection_index); } /** @notice Reads the last item from an Indexed Address Doubly Linked list @param _list The source list @param _collection_index Index of the Collection to evaluate @return {"_item" : "First item on the list"} */ function read_last_from_indexed_addresses(DoublyLinkedList.IndexedAddress storage _list, bytes32 _collection_index) internal constant returns (address _item) { _item = _list.end_item(_collection_index); } /** @notice Reads the next item from an Indexed Address Doubly Linked List based on the specified `_current_item` @param _list The source list @param _collection_index Index of the Collection to evaluate @param _current_item The current item to use as base line @return {"_item": "The next item on the list"} */ function read_next_from_indexed_addresses(DoublyLinkedList.IndexedAddress storage _list, bytes32 _collection_index, address _current_item) internal constant returns (address _item) { _item = _list.next_item(_collection_index, _current_item); } /** @notice Reads the previous item from an Index Address Doubly Linked List based on the specified `_current_item` @param _list The source list @param _collection_index Index of the Collection to evaluate @param _current_item The current item to use as base line @return {"_item" : "The previous item on the list"} */ function read_previous_from_indexed_addresses(DoublyLinkedList.IndexedAddress storage _list, bytes32 _collection_index, address _current_item) internal constant returns (address _item) { _item = _list.previous_item(_collection_index, _current_item); } /** @notice Reads the total number of items in an Indexed Address Doubly Linked List @param _list The source list @param _collection_index Index of the Collection to evaluate @return {"_count": "Length of the Doubly Linked list"} */ function read_total_indexed_addresses(DoublyLinkedList.IndexedAddress storage _list, bytes32 _collection_index) internal constant returns (uint256 _count) { _count = _list.total(_collection_index); } } // File: @digix/solidity-collections/contracts/abstract/UintIteratorStorage.sol pragma solidity ^0.4.19; /** @title Uint Iterator Storage @author DigixGlobal Pte Ltd */ contract UintIteratorStorage { using DoublyLinkedList for DoublyLinkedList.Uint; /** @notice Returns the first item from a `DoublyLinkedList.Uint` list @param _list The DoublyLinkedList.Uint list @return {"_item": "The first item"} */ function read_first_from_uints(DoublyLinkedList.Uint storage _list) internal constant returns (uint256 _item) { _item = _list.start_item(); } /** @notice Returns the last item from a `DoublyLinkedList.Uint` list @param _list The DoublyLinkedList.Uint list @return {"_item": "The last item"} */ function read_last_from_uints(DoublyLinkedList.Uint storage _list) internal constant returns (uint256 _item) { _item = _list.end_item(); } /** @notice Returns the next item from a `DoublyLinkedList.Uint` list based on the specified `_current_item` @param _list The DoublyLinkedList.Uint list @param _current_item The current item @return {"_item": "The next item"} */ function read_next_from_uints(DoublyLinkedList.Uint storage _list, uint256 _current_item) internal constant returns (uint256 _item) { _item = _list.next_item(_current_item); } /** @notice Returns the previous item from a `DoublyLinkedList.Uint` list based on the specified `_current_item` @param _list The DoublyLinkedList.Uint list @param _current_item The current item @return {"_item": "The previous item"} */ function read_previous_from_uints(DoublyLinkedList.Uint storage _list, uint256 _current_item) internal constant returns (uint256 _item) { _item = _list.previous_item(_current_item); } /** @notice Returns the total count of itemsfrom a `DoublyLinkedList.Uint` list @param _list The DoublyLinkedList.Uint list @return {"_count": "The total count of items"} */ function read_total_uints(DoublyLinkedList.Uint storage _list) internal constant returns (uint256 _count) { _count = _list.total(); } } // File: @digix/cdap/contracts/storage/DirectoryStorage.sol pragma solidity ^0.4.16; /** @title Directory Storage contains information of a directory @author DigixGlobal */ contract DirectoryStorage is IndexedAddressIteratorStorage, UintIteratorStorage { using DoublyLinkedList for DoublyLinkedList.IndexedAddress; using DoublyLinkedList for DoublyLinkedList.Uint; struct User { bytes32 document; bool active; } struct Group { bytes32 name; bytes32 document; uint256 role_id; mapping(address => User) members_by_address; } struct System { DoublyLinkedList.Uint groups; DoublyLinkedList.IndexedAddress groups_collection; mapping (uint256 => Group) groups_by_id; mapping (address => uint256) group_ids_by_address; mapping (uint256 => bytes32) roles_by_id; bool initialized; uint256 total_groups; } System system; /** @notice Initializes directory settings @return _success If directory initialization is successful */ function initialize_directory() internal returns (bool _success) { require(system.initialized == false); system.total_groups = 0; system.initialized = true; internal_create_role(1, "root"); internal_create_group(1, "root", ""); _success = internal_update_add_user_to_group(1, tx.origin, ""); } /** @notice Creates a new role with the given information @param _role_id Id of the new role @param _name Name of the new role @return {"_success": "If creation of new role is successful"} */ function internal_create_role(uint256 _role_id, bytes32 _name) internal returns (bool _success) { require(_role_id > 0); require(_name != bytes32(0x0)); system.roles_by_id[_role_id] = _name; _success = true; } /** @notice Returns the role's name of a role id @param _role_id Id of the role @return {"_name": "Name of the role"} */ function read_role(uint256 _role_id) public constant returns (bytes32 _name) { _name = system.roles_by_id[_role_id]; } /** @notice Creates a new group with the given information @param _role_id Role id of the new group @param _name Name of the new group @param _document Document of the new group @return { "_success": "If creation of the new group is successful", "_group_id: "Id of the new group" } */ function internal_create_group(uint256 _role_id, bytes32 _name, bytes32 _document) internal returns (bool _success, uint256 _group_id) { require(_role_id > 0); require(read_role(_role_id) != bytes32(0x0)); _group_id = ++system.total_groups; system.groups.append(_group_id); system.groups_by_id[_group_id].role_id = _role_id; system.groups_by_id[_group_id].name = _name; system.groups_by_id[_group_id].document = _document; _success = true; } /** @notice Returns the group's information @param _group_id Id of the group @return { "_role_id": "Role id of the group", "_name: "Name of the group", "_document: "Document of the group" } */ function read_group(uint256 _group_id) public constant returns (uint256 _role_id, bytes32 _name, bytes32 _document, uint256 _members_count) { if (system.groups.valid_item(_group_id)) { _role_id = system.groups_by_id[_group_id].role_id; _name = system.groups_by_id[_group_id].name; _document = system.groups_by_id[_group_id].document; _members_count = read_total_indexed_addresses(system.groups_collection, bytes32(_group_id)); } else { _role_id = 0; _name = "invalid"; _document = ""; _members_count = 0; } } /** @notice Adds new user with the given information to a group @param _group_id Id of the group @param _user Address of the new user @param _document Information of the new user @return {"_success": "If adding new user to a group is successful"} */ function internal_update_add_user_to_group(uint256 _group_id, address _user, bytes32 _document) internal returns (bool _success) { if (system.groups_by_id[_group_id].members_by_address[_user].active == false && system.group_ids_by_address[_user] == 0 && system.groups_by_id[_group_id].role_id != 0) { system.groups_by_id[_group_id].members_by_address[_user].active = true; system.group_ids_by_address[_user] = _group_id; system.groups_collection.append(bytes32(_group_id), _user); system.groups_by_id[_group_id].members_by_address[_user].document = _document; _success = true; } else { _success = false; } } /** @notice Removes user from its group @param _user Address of the user @return {"_success": "If removing of user is successful"} */ function internal_destroy_group_user(address _user) internal returns (bool _success) { uint256 _group_id = system.group_ids_by_address[_user]; if ((_group_id == 1) && (system.groups_collection.total(bytes32(_group_id)) == 1)) { _success = false; } else { system.groups_by_id[_group_id].members_by_address[_user].active = false; system.group_ids_by_address[_user] = 0; delete system.groups_by_id[_group_id].members_by_address[_user]; _success = system.groups_collection.remove_item(bytes32(_group_id), _user); } } /** @notice Returns the role id of a user @param _user Address of a user @return {"_role_id": "Role id of the user"} */ function read_user_role_id(address _user) constant public returns (uint256 _role_id) { uint256 _group_id = system.group_ids_by_address[_user]; _role_id = system.groups_by_id[_group_id].role_id; } /** @notice Returns the user's information @param _user Address of the user @return { "_group_id": "Group id of the user", "_role_id": "Role id of the user", "_document": "Information of the user" } */ function read_user(address _user) public constant returns (uint256 _group_id, uint256 _role_id, bytes32 _document) { _group_id = system.group_ids_by_address[_user]; _role_id = system.groups_by_id[_group_id].role_id; _document = system.groups_by_id[_group_id].members_by_address[_user].document; } /** @notice Returns the id of the first group @return {"_group_id": "Id of the first group"} */ function read_first_group() view external returns (uint256 _group_id) { _group_id = read_first_from_uints(system.groups); } /** @notice Returns the id of the last group @return {"_group_id": "Id of the last group"} */ function read_last_group() view external returns (uint256 _group_id) { _group_id = read_last_from_uints(system.groups); } /** @notice Returns the id of the previous group depending on the given current group @param _current_group_id Id of the current group @return {"_group_id": "Id of the previous group"} */ function read_previous_group_from_group(uint256 _current_group_id) view external returns (uint256 _group_id) { _group_id = read_previous_from_uints(system.groups, _current_group_id); } /** @notice Returns the id of the next group depending on the given current group @param _current_group_id Id of the current group @return {"_group_id": "Id of the next group"} */ function read_next_group_from_group(uint256 _current_group_id) view external returns (uint256 _group_id) { _group_id = read_next_from_uints(system.groups, _current_group_id); } /** @notice Returns the total number of groups @return {"_total_groups": "Total number of groups"} */ function read_total_groups() view external returns (uint256 _total_groups) { _total_groups = read_total_uints(system.groups); } /** @notice Returns the first user of a group @param _group_id Id of the group @return {"_user": "Address of the user"} */ function read_first_user_in_group(bytes32 _group_id) view external returns (address _user) { _user = read_first_from_indexed_addresses(system.groups_collection, bytes32(_group_id)); } /** @notice Returns the last user of a group @param _group_id Id of the group @return {"_user": "Address of the user"} */ function read_last_user_in_group(bytes32 _group_id) view external returns (address _user) { _user = read_last_from_indexed_addresses(system.groups_collection, bytes32(_group_id)); } /** @notice Returns the next user of a group depending on the given current user @param _group_id Id of the group @param _current_user Address of the current user @return {"_user": "Address of the next user"} */ function read_next_user_in_group(bytes32 _group_id, address _current_user) view external returns (address _user) { _user = read_next_from_indexed_addresses(system.groups_collection, bytes32(_group_id), _current_user); } /** @notice Returns the previous user of a group depending on the given current user @param _group_id Id of the group @param _current_user Address of the current user @return {"_user": "Address of the last user"} */ function read_previous_user_in_group(bytes32 _group_id, address _current_user) view external returns (address _user) { _user = read_previous_from_indexed_addresses(system.groups_collection, bytes32(_group_id), _current_user); } /** @notice Returns the total number of users of a group @param _group_id Id of the group @return {"_total_users": "Total number of users"} */ function read_total_users_in_group(bytes32 _group_id) view external returns (uint256 _total_users) { _total_users = read_total_indexed_addresses(system.groups_collection, bytes32(_group_id)); } } // File: contracts/storage/DaoIdentityStorage.sol pragma solidity ^0.4.25; contract DaoIdentityStorage is ResolverClient, DaoConstants, DirectoryStorage { // struct for KYC details // doc is the IPFS doc hash for any information regarding this KYC // id_expiration is the UTC timestamp at which this KYC will expire // at any time after this, the user's KYC is invalid, and that user // MUST re-KYC before doing any proposer related operation in DigixDAO struct KycDetails { bytes32 doc; uint256 id_expiration; } // a mapping of address to the KYC details mapping (address => KycDetails) kycInfo; constructor(address _resolver) public { require(init(CONTRACT_STORAGE_DAO_IDENTITY, _resolver)); require(initialize_directory()); } function create_group(uint256 _role_id, bytes32 _name, bytes32 _document) public returns (bool _success, uint256 _group_id) { require(sender_is(CONTRACT_DAO_IDENTITY)); (_success, _group_id) = internal_create_group(_role_id, _name, _document); require(_success); } function create_role(uint256 _role_id, bytes32 _name) public returns (bool _success) { require(sender_is(CONTRACT_DAO_IDENTITY)); _success = internal_create_role(_role_id, _name); require(_success); } function update_add_user_to_group(uint256 _group_id, address _user, bytes32 _document) public returns (bool _success) { require(sender_is(CONTRACT_DAO_IDENTITY)); _success = internal_update_add_user_to_group(_group_id, _user, _document); require(_success); } function update_remove_group_user(address _user) public returns (bool _success) { require(sender_is(CONTRACT_DAO_IDENTITY)); _success = internal_destroy_group_user(_user); require(_success); } function update_kyc(address _user, bytes32 _doc, uint256 _id_expiration) public { require(sender_is(CONTRACT_DAO_IDENTITY)); kycInfo[_user].doc = _doc; kycInfo[_user].id_expiration = _id_expiration; } function read_kyc_info(address _user) public view returns (bytes32 _doc, uint256 _id_expiration) { _doc = kycInfo[_user].doc; _id_expiration = kycInfo[_user].id_expiration; } function is_kyc_approved(address _user) public view returns (bool _approved) { uint256 _id_expiration; (,_id_expiration) = read_kyc_info(_user); _approved = _id_expiration > now; } } // File: contracts/common/IdentityCommon.sol pragma solidity ^0.4.25; contract IdentityCommon is DaoWhitelistingCommon { modifier if_root() { require(identity_storage().read_user_role_id(msg.sender) == ROLES_ROOT); _; } modifier if_founder() { require(is_founder()); _; } function is_founder() internal view returns (bool _isFounder) { _isFounder = identity_storage().read_user_role_id(msg.sender) == ROLES_FOUNDERS; } modifier if_prl() { require(identity_storage().read_user_role_id(msg.sender) == ROLES_PRLS); _; } modifier if_kyc_admin() { require(identity_storage().read_user_role_id(msg.sender) == ROLES_KYC_ADMINS); _; } function identity_storage() internal view returns (DaoIdentityStorage _contract) { _contract = DaoIdentityStorage(get_contract(CONTRACT_STORAGE_DAO_IDENTITY)); } } // File: contracts/storage/DaoConfigsStorage.sol pragma solidity ^0.4.25; contract DaoConfigsStorage is ResolverClient, DaoConstants { // mapping of config name to config value // config names can be found in DaoConstants contract mapping (bytes32 => uint256) public uintConfigs; // mapping of config name to config value // config names can be found in DaoConstants contract mapping (bytes32 => address) public addressConfigs; // mapping of config name to config value // config names can be found in DaoConstants contract mapping (bytes32 => bytes32) public bytesConfigs; uint256 ONE_BILLION = 1000000000; uint256 ONE_MILLION = 1000000; constructor(address _resolver) public { require(init(CONTRACT_STORAGE_DAO_CONFIG, _resolver)); uintConfigs[CONFIG_LOCKING_PHASE_DURATION] = 10 days; uintConfigs[CONFIG_QUARTER_DURATION] = QUARTER_DURATION; uintConfigs[CONFIG_VOTING_COMMIT_PHASE] = 14 days; uintConfigs[CONFIG_VOTING_PHASE_TOTAL] = 21 days; uintConfigs[CONFIG_INTERIM_COMMIT_PHASE] = 7 days; uintConfigs[CONFIG_INTERIM_PHASE_TOTAL] = 14 days; uintConfigs[CONFIG_DRAFT_QUORUM_FIXED_PORTION_NUMERATOR] = 5; // 5% uintConfigs[CONFIG_DRAFT_QUORUM_FIXED_PORTION_DENOMINATOR] = 100; // 5% uintConfigs[CONFIG_DRAFT_QUORUM_SCALING_FACTOR_NUMERATOR] = 35; // 35% uintConfigs[CONFIG_DRAFT_QUORUM_SCALING_FACTOR_DENOMINATOR] = 100; // 35% uintConfigs[CONFIG_VOTING_QUORUM_FIXED_PORTION_NUMERATOR] = 5; // 5% uintConfigs[CONFIG_VOTING_QUORUM_FIXED_PORTION_DENOMINATOR] = 100; // 5% uintConfigs[CONFIG_VOTING_QUORUM_SCALING_FACTOR_NUMERATOR] = 25; // 25% uintConfigs[CONFIG_VOTING_QUORUM_SCALING_FACTOR_DENOMINATOR] = 100; // 25% uintConfigs[CONFIG_DRAFT_QUOTA_NUMERATOR] = 1; // >50% uintConfigs[CONFIG_DRAFT_QUOTA_DENOMINATOR] = 2; // >50% uintConfigs[CONFIG_VOTING_QUOTA_NUMERATOR] = 1; // >50% uintConfigs[CONFIG_VOTING_QUOTA_DENOMINATOR] = 2; // >50% uintConfigs[CONFIG_QUARTER_POINT_DRAFT_VOTE] = ONE_BILLION; uintConfigs[CONFIG_QUARTER_POINT_VOTE] = ONE_BILLION; uintConfigs[CONFIG_QUARTER_POINT_INTERIM_VOTE] = ONE_BILLION; uintConfigs[CONFIG_QUARTER_POINT_MILESTONE_COMPLETION_PER_10000ETH] = 20000 * ONE_BILLION; uintConfigs[CONFIG_BONUS_REPUTATION_NUMERATOR] = 15; // 15% bonus for consistent votes uintConfigs[CONFIG_BONUS_REPUTATION_DENOMINATOR] = 100; // 15% bonus for consistent votes uintConfigs[CONFIG_SPECIAL_PROPOSAL_COMMIT_PHASE] = 28 days; uintConfigs[CONFIG_SPECIAL_PROPOSAL_PHASE_TOTAL] = 35 days; uintConfigs[CONFIG_SPECIAL_QUOTA_NUMERATOR] = 1; // >50% uintConfigs[CONFIG_SPECIAL_QUOTA_DENOMINATOR] = 2; // >50% uintConfigs[CONFIG_SPECIAL_PROPOSAL_QUORUM_NUMERATOR] = 40; // 40% uintConfigs[CONFIG_SPECIAL_PROPOSAL_QUORUM_DENOMINATOR] = 100; // 40% uintConfigs[CONFIG_MAXIMUM_REPUTATION_DEDUCTION] = 8334 * ONE_MILLION; uintConfigs[CONFIG_PUNISHMENT_FOR_NOT_LOCKING] = 1666 * ONE_MILLION; uintConfigs[CONFIG_REPUTATION_PER_EXTRA_QP_NUM] = 1; // 1 extra QP gains 1/1 RP uintConfigs[CONFIG_REPUTATION_PER_EXTRA_QP_DEN] = 1; uintConfigs[CONFIG_MINIMAL_QUARTER_POINT] = 2 * ONE_BILLION; uintConfigs[CONFIG_QUARTER_POINT_SCALING_FACTOR] = 400 * ONE_BILLION; uintConfigs[CONFIG_REPUTATION_POINT_SCALING_FACTOR] = 2000 * ONE_BILLION; uintConfigs[CONFIG_MODERATOR_MINIMAL_QUARTER_POINT] = 4 * ONE_BILLION; uintConfigs[CONFIG_MODERATOR_QUARTER_POINT_SCALING_FACTOR] = 400 * ONE_BILLION; uintConfigs[CONFIG_MODERATOR_REPUTATION_POINT_SCALING_FACTOR] = 2000 * ONE_BILLION; uintConfigs[CONFIG_PORTION_TO_MODERATORS_NUM] = 42; //4.2% of DGX to moderator voting activity uintConfigs[CONFIG_PORTION_TO_MODERATORS_DEN] = 1000; uintConfigs[CONFIG_DRAFT_VOTING_PHASE] = 10 days; uintConfigs[CONFIG_REPUTATION_POINT_BOOST_FOR_BADGE] = 412500 * ONE_MILLION; uintConfigs[CONFIG_FINAL_REWARD_SCALING_FACTOR_NUMERATOR] = 7; // 7% uintConfigs[CONFIG_FINAL_REWARD_SCALING_FACTOR_DENOMINATOR] = 100; // 7% uintConfigs[CONFIG_MAXIMUM_MODERATOR_REPUTATION_DEDUCTION] = 12500 * ONE_MILLION; uintConfigs[CONFIG_REPUTATION_PER_EXTRA_MODERATOR_QP_NUM] = 1; uintConfigs[CONFIG_REPUTATION_PER_EXTRA_MODERATOR_QP_DEN] = 1; uintConfigs[CONFIG_VOTE_CLAIMING_DEADLINE] = 10 days; uintConfigs[CONFIG_MINIMUM_LOCKED_DGD] = 10 * ONE_BILLION; uintConfigs[CONFIG_MINIMUM_DGD_FOR_MODERATOR] = 842 * ONE_BILLION; uintConfigs[CONFIG_MINIMUM_REPUTATION_FOR_MODERATOR] = 400 * ONE_BILLION; uintConfigs[CONFIG_PREPROPOSAL_COLLATERAL] = 2 ether; uintConfigs[CONFIG_MAX_FUNDING_FOR_NON_DIGIX] = 100 ether; uintConfigs[CONFIG_MAX_MILESTONES_FOR_NON_DIGIX] = 5; uintConfigs[CONFIG_NON_DIGIX_PROPOSAL_CAP_PER_QUARTER] = 80; uintConfigs[CONFIG_PROPOSAL_DEAD_DURATION] = 90 days; uintConfigs[CONFIG_CARBON_VOTE_REPUTATION_BONUS] = 10 * ONE_BILLION; } function updateUintConfigs(uint256[] _uintConfigs) external { require(sender_is(CONTRACT_DAO_SPECIAL_VOTING_CLAIMS)); uintConfigs[CONFIG_LOCKING_PHASE_DURATION] = _uintConfigs[0]; /* This used to be a config that can be changed. Now, _uintConfigs[1] is just a dummy config that doesnt do anything uintConfigs[CONFIG_QUARTER_DURATION] = _uintConfigs[1]; */ uintConfigs[CONFIG_VOTING_COMMIT_PHASE] = _uintConfigs[2]; uintConfigs[CONFIG_VOTING_PHASE_TOTAL] = _uintConfigs[3]; uintConfigs[CONFIG_INTERIM_COMMIT_PHASE] = _uintConfigs[4]; uintConfigs[CONFIG_INTERIM_PHASE_TOTAL] = _uintConfigs[5]; uintConfigs[CONFIG_DRAFT_QUORUM_FIXED_PORTION_NUMERATOR] = _uintConfigs[6]; uintConfigs[CONFIG_DRAFT_QUORUM_FIXED_PORTION_DENOMINATOR] = _uintConfigs[7]; uintConfigs[CONFIG_DRAFT_QUORUM_SCALING_FACTOR_NUMERATOR] = _uintConfigs[8]; uintConfigs[CONFIG_DRAFT_QUORUM_SCALING_FACTOR_DENOMINATOR] = _uintConfigs[9]; uintConfigs[CONFIG_VOTING_QUORUM_FIXED_PORTION_NUMERATOR] = _uintConfigs[10]; uintConfigs[CONFIG_VOTING_QUORUM_FIXED_PORTION_DENOMINATOR] = _uintConfigs[11]; uintConfigs[CONFIG_VOTING_QUORUM_SCALING_FACTOR_NUMERATOR] = _uintConfigs[12]; uintConfigs[CONFIG_VOTING_QUORUM_SCALING_FACTOR_DENOMINATOR] = _uintConfigs[13]; uintConfigs[CONFIG_DRAFT_QUOTA_NUMERATOR] = _uintConfigs[14]; uintConfigs[CONFIG_DRAFT_QUOTA_DENOMINATOR] = _uintConfigs[15]; uintConfigs[CONFIG_VOTING_QUOTA_NUMERATOR] = _uintConfigs[16]; uintConfigs[CONFIG_VOTING_QUOTA_DENOMINATOR] = _uintConfigs[17]; uintConfigs[CONFIG_QUARTER_POINT_DRAFT_VOTE] = _uintConfigs[18]; uintConfigs[CONFIG_QUARTER_POINT_VOTE] = _uintConfigs[19]; uintConfigs[CONFIG_QUARTER_POINT_INTERIM_VOTE] = _uintConfigs[20]; uintConfigs[CONFIG_MINIMAL_QUARTER_POINT] = _uintConfigs[21]; uintConfigs[CONFIG_QUARTER_POINT_MILESTONE_COMPLETION_PER_10000ETH] = _uintConfigs[22]; uintConfigs[CONFIG_BONUS_REPUTATION_NUMERATOR] = _uintConfigs[23]; uintConfigs[CONFIG_BONUS_REPUTATION_DENOMINATOR] = _uintConfigs[24]; uintConfigs[CONFIG_SPECIAL_PROPOSAL_COMMIT_PHASE] = _uintConfigs[25]; uintConfigs[CONFIG_SPECIAL_PROPOSAL_PHASE_TOTAL] = _uintConfigs[26]; uintConfigs[CONFIG_SPECIAL_QUOTA_NUMERATOR] = _uintConfigs[27]; uintConfigs[CONFIG_SPECIAL_QUOTA_DENOMINATOR] = _uintConfigs[28]; uintConfigs[CONFIG_SPECIAL_PROPOSAL_QUORUM_NUMERATOR] = _uintConfigs[29]; uintConfigs[CONFIG_SPECIAL_PROPOSAL_QUORUM_DENOMINATOR] = _uintConfigs[30]; uintConfigs[CONFIG_MAXIMUM_REPUTATION_DEDUCTION] = _uintConfigs[31]; uintConfigs[CONFIG_PUNISHMENT_FOR_NOT_LOCKING] = _uintConfigs[32]; uintConfigs[CONFIG_REPUTATION_PER_EXTRA_QP_NUM] = _uintConfigs[33]; uintConfigs[CONFIG_REPUTATION_PER_EXTRA_QP_DEN] = _uintConfigs[34]; uintConfigs[CONFIG_QUARTER_POINT_SCALING_FACTOR] = _uintConfigs[35]; uintConfigs[CONFIG_REPUTATION_POINT_SCALING_FACTOR] = _uintConfigs[36]; uintConfigs[CONFIG_MODERATOR_MINIMAL_QUARTER_POINT] = _uintConfigs[37]; uintConfigs[CONFIG_MODERATOR_QUARTER_POINT_SCALING_FACTOR] = _uintConfigs[38]; uintConfigs[CONFIG_MODERATOR_REPUTATION_POINT_SCALING_FACTOR] = _uintConfigs[39]; uintConfigs[CONFIG_PORTION_TO_MODERATORS_NUM] = _uintConfigs[40]; uintConfigs[CONFIG_PORTION_TO_MODERATORS_DEN] = _uintConfigs[41]; uintConfigs[CONFIG_DRAFT_VOTING_PHASE] = _uintConfigs[42]; uintConfigs[CONFIG_REPUTATION_POINT_BOOST_FOR_BADGE] = _uintConfigs[43]; uintConfigs[CONFIG_FINAL_REWARD_SCALING_FACTOR_NUMERATOR] = _uintConfigs[44]; uintConfigs[CONFIG_FINAL_REWARD_SCALING_FACTOR_DENOMINATOR] = _uintConfigs[45]; uintConfigs[CONFIG_MAXIMUM_MODERATOR_REPUTATION_DEDUCTION] = _uintConfigs[46]; uintConfigs[CONFIG_REPUTATION_PER_EXTRA_MODERATOR_QP_NUM] = _uintConfigs[47]; uintConfigs[CONFIG_REPUTATION_PER_EXTRA_MODERATOR_QP_DEN] = _uintConfigs[48]; uintConfigs[CONFIG_VOTE_CLAIMING_DEADLINE] = _uintConfigs[49]; uintConfigs[CONFIG_MINIMUM_LOCKED_DGD] = _uintConfigs[50]; uintConfigs[CONFIG_MINIMUM_DGD_FOR_MODERATOR] = _uintConfigs[51]; uintConfigs[CONFIG_MINIMUM_REPUTATION_FOR_MODERATOR] = _uintConfigs[52]; uintConfigs[CONFIG_PREPROPOSAL_COLLATERAL] = _uintConfigs[53]; uintConfigs[CONFIG_MAX_FUNDING_FOR_NON_DIGIX] = _uintConfigs[54]; uintConfigs[CONFIG_MAX_MILESTONES_FOR_NON_DIGIX] = _uintConfigs[55]; uintConfigs[CONFIG_NON_DIGIX_PROPOSAL_CAP_PER_QUARTER] = _uintConfigs[56]; uintConfigs[CONFIG_PROPOSAL_DEAD_DURATION] = _uintConfigs[57]; uintConfigs[CONFIG_CARBON_VOTE_REPUTATION_BONUS] = _uintConfigs[58]; } function readUintConfigs() public view returns (uint256[]) { uint256[] memory _uintConfigs = new uint256[](59); _uintConfigs[0] = uintConfigs[CONFIG_LOCKING_PHASE_DURATION]; _uintConfigs[1] = uintConfigs[CONFIG_QUARTER_DURATION]; _uintConfigs[2] = uintConfigs[CONFIG_VOTING_COMMIT_PHASE]; _uintConfigs[3] = uintConfigs[CONFIG_VOTING_PHASE_TOTAL]; _uintConfigs[4] = uintConfigs[CONFIG_INTERIM_COMMIT_PHASE]; _uintConfigs[5] = uintConfigs[CONFIG_INTERIM_PHASE_TOTAL]; _uintConfigs[6] = uintConfigs[CONFIG_DRAFT_QUORUM_FIXED_PORTION_NUMERATOR]; _uintConfigs[7] = uintConfigs[CONFIG_DRAFT_QUORUM_FIXED_PORTION_DENOMINATOR]; _uintConfigs[8] = uintConfigs[CONFIG_DRAFT_QUORUM_SCALING_FACTOR_NUMERATOR]; _uintConfigs[9] = uintConfigs[CONFIG_DRAFT_QUORUM_SCALING_FACTOR_DENOMINATOR]; _uintConfigs[10] = uintConfigs[CONFIG_VOTING_QUORUM_FIXED_PORTION_NUMERATOR]; _uintConfigs[11] = uintConfigs[CONFIG_VOTING_QUORUM_FIXED_PORTION_DENOMINATOR]; _uintConfigs[12] = uintConfigs[CONFIG_VOTING_QUORUM_SCALING_FACTOR_NUMERATOR]; _uintConfigs[13] = uintConfigs[CONFIG_VOTING_QUORUM_SCALING_FACTOR_DENOMINATOR]; _uintConfigs[14] = uintConfigs[CONFIG_DRAFT_QUOTA_NUMERATOR]; _uintConfigs[15] = uintConfigs[CONFIG_DRAFT_QUOTA_DENOMINATOR]; _uintConfigs[16] = uintConfigs[CONFIG_VOTING_QUOTA_NUMERATOR]; _uintConfigs[17] = uintConfigs[CONFIG_VOTING_QUOTA_DENOMINATOR]; _uintConfigs[18] = uintConfigs[CONFIG_QUARTER_POINT_DRAFT_VOTE]; _uintConfigs[19] = uintConfigs[CONFIG_QUARTER_POINT_VOTE]; _uintConfigs[20] = uintConfigs[CONFIG_QUARTER_POINT_INTERIM_VOTE]; _uintConfigs[21] = uintConfigs[CONFIG_MINIMAL_QUARTER_POINT]; _uintConfigs[22] = uintConfigs[CONFIG_QUARTER_POINT_MILESTONE_COMPLETION_PER_10000ETH]; _uintConfigs[23] = uintConfigs[CONFIG_BONUS_REPUTATION_NUMERATOR]; _uintConfigs[24] = uintConfigs[CONFIG_BONUS_REPUTATION_DENOMINATOR]; _uintConfigs[25] = uintConfigs[CONFIG_SPECIAL_PROPOSAL_COMMIT_PHASE]; _uintConfigs[26] = uintConfigs[CONFIG_SPECIAL_PROPOSAL_PHASE_TOTAL]; _uintConfigs[27] = uintConfigs[CONFIG_SPECIAL_QUOTA_NUMERATOR]; _uintConfigs[28] = uintConfigs[CONFIG_SPECIAL_QUOTA_DENOMINATOR]; _uintConfigs[29] = uintConfigs[CONFIG_SPECIAL_PROPOSAL_QUORUM_NUMERATOR]; _uintConfigs[30] = uintConfigs[CONFIG_SPECIAL_PROPOSAL_QUORUM_DENOMINATOR]; _uintConfigs[31] = uintConfigs[CONFIG_MAXIMUM_REPUTATION_DEDUCTION]; _uintConfigs[32] = uintConfigs[CONFIG_PUNISHMENT_FOR_NOT_LOCKING]; _uintConfigs[33] = uintConfigs[CONFIG_REPUTATION_PER_EXTRA_QP_NUM]; _uintConfigs[34] = uintConfigs[CONFIG_REPUTATION_PER_EXTRA_QP_DEN]; _uintConfigs[35] = uintConfigs[CONFIG_QUARTER_POINT_SCALING_FACTOR]; _uintConfigs[36] = uintConfigs[CONFIG_REPUTATION_POINT_SCALING_FACTOR]; _uintConfigs[37] = uintConfigs[CONFIG_MODERATOR_MINIMAL_QUARTER_POINT]; _uintConfigs[38] = uintConfigs[CONFIG_MODERATOR_QUARTER_POINT_SCALING_FACTOR]; _uintConfigs[39] = uintConfigs[CONFIG_MODERATOR_REPUTATION_POINT_SCALING_FACTOR]; _uintConfigs[40] = uintConfigs[CONFIG_PORTION_TO_MODERATORS_NUM]; _uintConfigs[41] = uintConfigs[CONFIG_PORTION_TO_MODERATORS_DEN]; _uintConfigs[42] = uintConfigs[CONFIG_DRAFT_VOTING_PHASE]; _uintConfigs[43] = uintConfigs[CONFIG_REPUTATION_POINT_BOOST_FOR_BADGE]; _uintConfigs[44] = uintConfigs[CONFIG_FINAL_REWARD_SCALING_FACTOR_NUMERATOR]; _uintConfigs[45] = uintConfigs[CONFIG_FINAL_REWARD_SCALING_FACTOR_DENOMINATOR]; _uintConfigs[46] = uintConfigs[CONFIG_MAXIMUM_MODERATOR_REPUTATION_DEDUCTION]; _uintConfigs[47] = uintConfigs[CONFIG_REPUTATION_PER_EXTRA_MODERATOR_QP_NUM]; _uintConfigs[48] = uintConfigs[CONFIG_REPUTATION_PER_EXTRA_MODERATOR_QP_DEN]; _uintConfigs[49] = uintConfigs[CONFIG_VOTE_CLAIMING_DEADLINE]; _uintConfigs[50] = uintConfigs[CONFIG_MINIMUM_LOCKED_DGD]; _uintConfigs[51] = uintConfigs[CONFIG_MINIMUM_DGD_FOR_MODERATOR]; _uintConfigs[52] = uintConfigs[CONFIG_MINIMUM_REPUTATION_FOR_MODERATOR]; _uintConfigs[53] = uintConfigs[CONFIG_PREPROPOSAL_COLLATERAL]; _uintConfigs[54] = uintConfigs[CONFIG_MAX_FUNDING_FOR_NON_DIGIX]; _uintConfigs[55] = uintConfigs[CONFIG_MAX_MILESTONES_FOR_NON_DIGIX]; _uintConfigs[56] = uintConfigs[CONFIG_NON_DIGIX_PROPOSAL_CAP_PER_QUARTER]; _uintConfigs[57] = uintConfigs[CONFIG_PROPOSAL_DEAD_DURATION]; _uintConfigs[58] = uintConfigs[CONFIG_CARBON_VOTE_REPUTATION_BONUS]; return _uintConfigs; } } // File: contracts/storage/DaoProposalCounterStorage.sol pragma solidity ^0.4.25; contract DaoProposalCounterStorage is ResolverClient, DaoConstants { constructor(address _resolver) public { require(init(CONTRACT_STORAGE_DAO_COUNTER, _resolver)); } // This is to mark the number of proposals that have been funded in a specific quarter // this is to take care of the cap on the number of funded proposals in a quarter mapping (uint256 => uint256) public proposalCountByQuarter; function addNonDigixProposalCountInQuarter(uint256 _quarterNumber) public { require(sender_is(CONTRACT_DAO_VOTING_CLAIMS)); proposalCountByQuarter[_quarterNumber] = proposalCountByQuarter[_quarterNumber].add(1); } } // File: contracts/storage/DaoUpgradeStorage.sol pragma solidity ^0.4.25; contract DaoUpgradeStorage is ResolverClient, DaoConstants { // this UTC timestamp marks the start of the first quarter // of DigixDAO. All time related calculations in DaoCommon // depend on this value uint256 public startOfFirstQuarter; // this boolean marks whether the DAO contracts have been replaced // by newer versions or not. The process of migration is done by deploying // a new set of contracts, transferring funds from these contracts to the new ones // migrating some state variables, and finally setting this boolean to true // All operations in these contracts that may transfer tokens, claim ether, // boost one's reputation, etc. SHOULD fail if this is true bool public isReplacedByNewDao; // this is the address of the new Dao contract address public newDaoContract; // this is the address of the new DaoFundingManager contract // ether funds will be moved from the current version's contract to this // new contract address public newDaoFundingManager; // this is the address of the new DaoRewardsManager contract // DGX funds will be moved from the current version of contract to this // new contract address public newDaoRewardsManager; constructor(address _resolver) public { require(init(CONTRACT_STORAGE_DAO_UPGRADE, _resolver)); } function setStartOfFirstQuarter(uint256 _start) public { require(sender_is(CONTRACT_DAO)); startOfFirstQuarter = _start; } function setNewContractAddresses( address _newDaoContract, address _newDaoFundingManager, address _newDaoRewardsManager ) public { require(sender_is(CONTRACT_DAO)); newDaoContract = _newDaoContract; newDaoFundingManager = _newDaoFundingManager; newDaoRewardsManager = _newDaoRewardsManager; } function updateForDaoMigration() public { require(sender_is(CONTRACT_DAO)); isReplacedByNewDao = true; } } // File: contracts/storage/DaoSpecialStorage.sol pragma solidity ^0.4.25; contract DaoSpecialStorage is DaoWhitelistingCommon { using DoublyLinkedList for DoublyLinkedList.Bytes; using DaoStructs for DaoStructs.SpecialProposal; using DaoStructs for DaoStructs.Voting; // List of all the special proposals ever created in DigixDAO DoublyLinkedList.Bytes proposals; // mapping of the SpecialProposal struct by its ID // ID is also the IPFS doc hash of the proposal mapping (bytes32 => DaoStructs.SpecialProposal) proposalsById; constructor(address _resolver) public { require(init(CONTRACT_STORAGE_DAO_SPECIAL, _resolver)); } function addSpecialProposal( bytes32 _proposalId, address _proposer, uint256[] _uintConfigs, address[] _addressConfigs, bytes32[] _bytesConfigs ) public { require(sender_is(CONTRACT_DAO_SPECIAL_PROPOSAL)); require( (proposalsById[_proposalId].proposalId == EMPTY_BYTES) && (_proposalId != EMPTY_BYTES) ); proposals.append(_proposalId); proposalsById[_proposalId].proposalId = _proposalId; proposalsById[_proposalId].proposer = _proposer; proposalsById[_proposalId].timeCreated = now; proposalsById[_proposalId].uintConfigs = _uintConfigs; proposalsById[_proposalId].addressConfigs = _addressConfigs; proposalsById[_proposalId].bytesConfigs = _bytesConfigs; } function readProposal(bytes32 _proposalId) public view returns ( bytes32 _id, address _proposer, uint256 _timeCreated, uint256 _timeVotingStarted ) { _id = proposalsById[_proposalId].proposalId; _proposer = proposalsById[_proposalId].proposer; _timeCreated = proposalsById[_proposalId].timeCreated; _timeVotingStarted = proposalsById[_proposalId].voting.startTime; } function readProposalProposer(bytes32 _proposalId) public view returns (address _proposer) { _proposer = proposalsById[_proposalId].proposer; } function readConfigs(bytes32 _proposalId) public view returns ( uint256[] memory _uintConfigs, address[] memory _addressConfigs, bytes32[] memory _bytesConfigs ) { _uintConfigs = proposalsById[_proposalId].uintConfigs; _addressConfigs = proposalsById[_proposalId].addressConfigs; _bytesConfigs = proposalsById[_proposalId].bytesConfigs; } function readVotingCount(bytes32 _proposalId, address[] _allUsers) external view returns (uint256 _for, uint256 _against) { require(senderIsAllowedToRead()); return proposalsById[_proposalId].voting.countVotes(_allUsers); } function readVotingTime(bytes32 _proposalId) public view returns (uint256 _start) { require(senderIsAllowedToRead()); _start = proposalsById[_proposalId].voting.startTime; } function commitVote( bytes32 _proposalId, bytes32 _hash, address _voter ) public { require(sender_is(CONTRACT_DAO_VOTING)); proposalsById[_proposalId].voting.commits[_voter] = _hash; } function readComittedVote(bytes32 _proposalId, address _voter) public view returns (bytes32 _commitHash) { require(senderIsAllowedToRead()); _commitHash = proposalsById[_proposalId].voting.commits[_voter]; } function setVotingTime(bytes32 _proposalId, uint256 _time) public { require(sender_is(CONTRACT_DAO_SPECIAL_PROPOSAL)); proposalsById[_proposalId].voting.startTime = _time; } function readVotingResult(bytes32 _proposalId) public view returns (bool _result) { require(senderIsAllowedToRead()); _result = proposalsById[_proposalId].voting.passed; } function setPass(bytes32 _proposalId, bool _result) public { require(sender_is(CONTRACT_DAO_SPECIAL_VOTING_CLAIMS)); proposalsById[_proposalId].voting.passed = _result; } function setVotingClaim(bytes32 _proposalId, bool _claimed) public { require(sender_is(CONTRACT_DAO_SPECIAL_VOTING_CLAIMS)); DaoStructs.SpecialProposal storage _proposal = proposalsById[_proposalId]; _proposal.voting.claimed = _claimed; } function isClaimed(bytes32 _proposalId) public view returns (bool _claimed) { require(senderIsAllowedToRead()); _claimed = proposalsById[_proposalId].voting.claimed; } function readVote(bytes32 _proposalId, address _voter) public view returns (bool _vote, uint256 _weight) { require(senderIsAllowedToRead()); return proposalsById[_proposalId].voting.readVote(_voter); } function revealVote( bytes32 _proposalId, address _voter, bool _vote, uint256 _weight ) public { require(sender_is(CONTRACT_DAO_VOTING)); proposalsById[_proposalId].voting.revealVote(_voter, _vote, _weight); } } // File: contracts/storage/DaoPointsStorage.sol pragma solidity ^0.4.25; contract DaoPointsStorage is ResolverClient, DaoConstants { // struct for a non-transferrable token struct Token { uint256 totalSupply; mapping (address => uint256) balance; } // the reputation point token // since reputation is cumulative, we only need to store one value Token reputationPoint; // since quarter points are specific to quarters, we need a mapping from // quarter number to the quarter point token for that quarter mapping (uint256 => Token) quarterPoint; // the same is the case with quarter moderator points // these are specific to quarters mapping (uint256 => Token) quarterModeratorPoint; constructor(address _resolver) public { require(init(CONTRACT_STORAGE_DAO_POINTS, _resolver)); } /// @notice add quarter points for a _participant for a _quarterNumber function addQuarterPoint(address _participant, uint256 _point, uint256 _quarterNumber) public returns (uint256 _newPoint, uint256 _newTotalPoint) { require(sender_is_from([CONTRACT_DAO_VOTING, CONTRACT_DAO_VOTING_CLAIMS, EMPTY_BYTES])); quarterPoint[_quarterNumber].totalSupply = quarterPoint[_quarterNumber].totalSupply.add(_point); quarterPoint[_quarterNumber].balance[_participant] = quarterPoint[_quarterNumber].balance[_participant].add(_point); _newPoint = quarterPoint[_quarterNumber].balance[_participant]; _newTotalPoint = quarterPoint[_quarterNumber].totalSupply; } function addModeratorQuarterPoint(address _participant, uint256 _point, uint256 _quarterNumber) public returns (uint256 _newPoint, uint256 _newTotalPoint) { require(sender_is_from([CONTRACT_DAO_VOTING, CONTRACT_DAO_VOTING_CLAIMS, EMPTY_BYTES])); quarterModeratorPoint[_quarterNumber].totalSupply = quarterModeratorPoint[_quarterNumber].totalSupply.add(_point); quarterModeratorPoint[_quarterNumber].balance[_participant] = quarterModeratorPoint[_quarterNumber].balance[_participant].add(_point); _newPoint = quarterModeratorPoint[_quarterNumber].balance[_participant]; _newTotalPoint = quarterModeratorPoint[_quarterNumber].totalSupply; } /// @notice get quarter points for a _participant in a _quarterNumber function getQuarterPoint(address _participant, uint256 _quarterNumber) public view returns (uint256 _point) { _point = quarterPoint[_quarterNumber].balance[_participant]; } function getQuarterModeratorPoint(address _participant, uint256 _quarterNumber) public view returns (uint256 _point) { _point = quarterModeratorPoint[_quarterNumber].balance[_participant]; } /// @notice get total quarter points for a particular _quarterNumber function getTotalQuarterPoint(uint256 _quarterNumber) public view returns (uint256 _totalPoint) { _totalPoint = quarterPoint[_quarterNumber].totalSupply; } function getTotalQuarterModeratorPoint(uint256 _quarterNumber) public view returns (uint256 _totalPoint) { _totalPoint = quarterModeratorPoint[_quarterNumber].totalSupply; } /// @notice add reputation points for a _participant function increaseReputation(address _participant, uint256 _point) public returns (uint256 _newPoint, uint256 _totalPoint) { require(sender_is_from([CONTRACT_DAO_VOTING_CLAIMS, CONTRACT_DAO_REWARDS_MANAGER, CONTRACT_DAO_STAKE_LOCKING])); reputationPoint.totalSupply = reputationPoint.totalSupply.add(_point); reputationPoint.balance[_participant] = reputationPoint.balance[_participant].add(_point); _newPoint = reputationPoint.balance[_participant]; _totalPoint = reputationPoint.totalSupply; } /// @notice subtract reputation points for a _participant function reduceReputation(address _participant, uint256 _point) public returns (uint256 _newPoint, uint256 _totalPoint) { require(sender_is_from([CONTRACT_DAO_VOTING_CLAIMS, CONTRACT_DAO_REWARDS_MANAGER, EMPTY_BYTES])); uint256 _toDeduct = _point; if (reputationPoint.balance[_participant] > _point) { reputationPoint.balance[_participant] = reputationPoint.balance[_participant].sub(_point); } else { _toDeduct = reputationPoint.balance[_participant]; reputationPoint.balance[_participant] = 0; } reputationPoint.totalSupply = reputationPoint.totalSupply.sub(_toDeduct); _newPoint = reputationPoint.balance[_participant]; _totalPoint = reputationPoint.totalSupply; } /// @notice get reputation points for a _participant function getReputation(address _participant) public view returns (uint256 _point) { _point = reputationPoint.balance[_participant]; } /// @notice get total reputation points distributed in the dao function getTotalReputation() public view returns (uint256 _totalPoint) { _totalPoint = reputationPoint.totalSupply; } } // File: contracts/storage/DaoRewardsStorage.sol pragma solidity ^0.4.25; // this contract will receive DGXs fees from the DGX fees distributors contract DaoRewardsStorage is ResolverClient, DaoConstants { using DaoStructs for DaoStructs.DaoQuarterInfo; // DaoQuarterInfo is a struct that stores the quarter specific information // regarding totalEffectiveDGDs, DGX distribution day, etc. pls check // docs in lib/DaoStructs mapping(uint256 => DaoStructs.DaoQuarterInfo) public allQuartersInfo; // Mapping that stores the DGX that can be claimed as rewards by // an address (a participant of DigixDAO) mapping(address => uint256) public claimableDGXs; // This stores the total DGX value that has been claimed by participants // this can be done by calling the DaoRewardsManager.claimRewards method // Note that this value is the only outgoing DGX from DaoRewardsManager contract // Note that this value also takes into account the demurrage that has been paid // by participants for simply holding their DGXs in the DaoRewardsManager contract uint256 public totalDGXsClaimed; // The Quarter ID in which the user last participated in // To participate means they had locked more than CONFIG_MINIMUM_LOCKED_DGD // DGD tokens. In addition, they should not have withdrawn those tokens in the same // quarter. Basically, in the main phase of the quarter, if DaoCommon.isParticipant(_user) // was true, they were participants. And that quarter was their lastParticipatedQuarter mapping (address => uint256) public lastParticipatedQuarter; // This mapping is only used to update the lastParticipatedQuarter to the // previousLastParticipatedQuarter in case users lock and withdraw DGDs // within the same quarter's locking phase mapping (address => uint256) public previousLastParticipatedQuarter; // This number marks the Quarter in which the rewards were last updated for that user // Since the rewards calculation for a specific quarter is only done once that // quarter is completed, we need this value to note the last quarter when the rewards were updated // We then start adding the rewards for all quarters after that quarter, until the current quarter mapping (address => uint256) public lastQuarterThatRewardsWasUpdated; // Similar as the lastQuarterThatRewardsWasUpdated, but this is for reputation updates // Note that reputation can also be deducted for no participation (not locking DGDs) // This value is used to update the reputation based on all quarters from the lastQuarterThatReputationWasUpdated // to the current quarter mapping (address => uint256) public lastQuarterThatReputationWasUpdated; constructor(address _resolver) public { require(init(CONTRACT_STORAGE_DAO_REWARDS, _resolver)); } function updateQuarterInfo( uint256 _quarterNumber, uint256 _minimalParticipationPoint, uint256 _quarterPointScalingFactor, uint256 _reputationPointScalingFactor, uint256 _totalEffectiveDGDPreviousQuarter, uint256 _moderatorMinimalQuarterPoint, uint256 _moderatorQuarterPointScalingFactor, uint256 _moderatorReputationPointScalingFactor, uint256 _totalEffectiveModeratorDGDLastQuarter, uint256 _dgxDistributionDay, uint256 _dgxRewardsPoolLastQuarter, uint256 _sumRewardsFromBeginning ) public { require(sender_is(CONTRACT_DAO_REWARDS_MANAGER)); allQuartersInfo[_quarterNumber].minimalParticipationPoint = _minimalParticipationPoint; allQuartersInfo[_quarterNumber].quarterPointScalingFactor = _quarterPointScalingFactor; allQuartersInfo[_quarterNumber].reputationPointScalingFactor = _reputationPointScalingFactor; allQuartersInfo[_quarterNumber].totalEffectiveDGDPreviousQuarter = _totalEffectiveDGDPreviousQuarter; allQuartersInfo[_quarterNumber].moderatorMinimalParticipationPoint = _moderatorMinimalQuarterPoint; allQuartersInfo[_quarterNumber].moderatorQuarterPointScalingFactor = _moderatorQuarterPointScalingFactor; allQuartersInfo[_quarterNumber].moderatorReputationPointScalingFactor = _moderatorReputationPointScalingFactor; allQuartersInfo[_quarterNumber].totalEffectiveModeratorDGDLastQuarter = _totalEffectiveModeratorDGDLastQuarter; allQuartersInfo[_quarterNumber].dgxDistributionDay = _dgxDistributionDay; allQuartersInfo[_quarterNumber].dgxRewardsPoolLastQuarter = _dgxRewardsPoolLastQuarter; allQuartersInfo[_quarterNumber].sumRewardsFromBeginning = _sumRewardsFromBeginning; } function updateClaimableDGX(address _user, uint256 _newClaimableDGX) public { require(sender_is(CONTRACT_DAO_REWARDS_MANAGER)); claimableDGXs[_user] = _newClaimableDGX; } function updateLastParticipatedQuarter(address _user, uint256 _lastQuarter) public { require(sender_is(CONTRACT_DAO_STAKE_LOCKING)); lastParticipatedQuarter[_user] = _lastQuarter; } function updatePreviousLastParticipatedQuarter(address _user, uint256 _lastQuarter) public { require(sender_is(CONTRACT_DAO_STAKE_LOCKING)); previousLastParticipatedQuarter[_user] = _lastQuarter; } function updateLastQuarterThatRewardsWasUpdated(address _user, uint256 _lastQuarter) public { require(sender_is_from([CONTRACT_DAO_REWARDS_MANAGER, CONTRACT_DAO_STAKE_LOCKING, EMPTY_BYTES])); lastQuarterThatRewardsWasUpdated[_user] = _lastQuarter; } function updateLastQuarterThatReputationWasUpdated(address _user, uint256 _lastQuarter) public { require(sender_is_from([CONTRACT_DAO_REWARDS_MANAGER, CONTRACT_DAO_STAKE_LOCKING, EMPTY_BYTES])); lastQuarterThatReputationWasUpdated[_user] = _lastQuarter; } function addToTotalDgxClaimed(uint256 _dgxClaimed) public { require(sender_is(CONTRACT_DAO_REWARDS_MANAGER)); totalDGXsClaimed = totalDGXsClaimed.add(_dgxClaimed); } function readQuarterInfo(uint256 _quarterNumber) public view returns ( uint256 _minimalParticipationPoint, uint256 _quarterPointScalingFactor, uint256 _reputationPointScalingFactor, uint256 _totalEffectiveDGDPreviousQuarter, uint256 _moderatorMinimalQuarterPoint, uint256 _moderatorQuarterPointScalingFactor, uint256 _moderatorReputationPointScalingFactor, uint256 _totalEffectiveModeratorDGDLastQuarter, uint256 _dgxDistributionDay, uint256 _dgxRewardsPoolLastQuarter, uint256 _sumRewardsFromBeginning ) { _minimalParticipationPoint = allQuartersInfo[_quarterNumber].minimalParticipationPoint; _quarterPointScalingFactor = allQuartersInfo[_quarterNumber].quarterPointScalingFactor; _reputationPointScalingFactor = allQuartersInfo[_quarterNumber].reputationPointScalingFactor; _totalEffectiveDGDPreviousQuarter = allQuartersInfo[_quarterNumber].totalEffectiveDGDPreviousQuarter; _moderatorMinimalQuarterPoint = allQuartersInfo[_quarterNumber].moderatorMinimalParticipationPoint; _moderatorQuarterPointScalingFactor = allQuartersInfo[_quarterNumber].moderatorQuarterPointScalingFactor; _moderatorReputationPointScalingFactor = allQuartersInfo[_quarterNumber].moderatorReputationPointScalingFactor; _totalEffectiveModeratorDGDLastQuarter = allQuartersInfo[_quarterNumber].totalEffectiveModeratorDGDLastQuarter; _dgxDistributionDay = allQuartersInfo[_quarterNumber].dgxDistributionDay; _dgxRewardsPoolLastQuarter = allQuartersInfo[_quarterNumber].dgxRewardsPoolLastQuarter; _sumRewardsFromBeginning = allQuartersInfo[_quarterNumber].sumRewardsFromBeginning; } function readQuarterGeneralInfo(uint256 _quarterNumber) public view returns ( uint256 _dgxDistributionDay, uint256 _dgxRewardsPoolLastQuarter, uint256 _sumRewardsFromBeginning ) { _dgxDistributionDay = allQuartersInfo[_quarterNumber].dgxDistributionDay; _dgxRewardsPoolLastQuarter = allQuartersInfo[_quarterNumber].dgxRewardsPoolLastQuarter; _sumRewardsFromBeginning = allQuartersInfo[_quarterNumber].sumRewardsFromBeginning; } function readQuarterModeratorInfo(uint256 _quarterNumber) public view returns ( uint256 _moderatorMinimalQuarterPoint, uint256 _moderatorQuarterPointScalingFactor, uint256 _moderatorReputationPointScalingFactor, uint256 _totalEffectiveModeratorDGDLastQuarter ) { _moderatorMinimalQuarterPoint = allQuartersInfo[_quarterNumber].moderatorMinimalParticipationPoint; _moderatorQuarterPointScalingFactor = allQuartersInfo[_quarterNumber].moderatorQuarterPointScalingFactor; _moderatorReputationPointScalingFactor = allQuartersInfo[_quarterNumber].moderatorReputationPointScalingFactor; _totalEffectiveModeratorDGDLastQuarter = allQuartersInfo[_quarterNumber].totalEffectiveModeratorDGDLastQuarter; } function readQuarterParticipantInfo(uint256 _quarterNumber) public view returns ( uint256 _minimalParticipationPoint, uint256 _quarterPointScalingFactor, uint256 _reputationPointScalingFactor, uint256 _totalEffectiveDGDPreviousQuarter ) { _minimalParticipationPoint = allQuartersInfo[_quarterNumber].minimalParticipationPoint; _quarterPointScalingFactor = allQuartersInfo[_quarterNumber].quarterPointScalingFactor; _reputationPointScalingFactor = allQuartersInfo[_quarterNumber].reputationPointScalingFactor; _totalEffectiveDGDPreviousQuarter = allQuartersInfo[_quarterNumber].totalEffectiveDGDPreviousQuarter; } function readDgxDistributionDay(uint256 _quarterNumber) public view returns (uint256 _distributionDay) { _distributionDay = allQuartersInfo[_quarterNumber].dgxDistributionDay; } function readTotalEffectiveDGDLastQuarter(uint256 _quarterNumber) public view returns (uint256 _totalEffectiveDGDPreviousQuarter) { _totalEffectiveDGDPreviousQuarter = allQuartersInfo[_quarterNumber].totalEffectiveDGDPreviousQuarter; } function readTotalEffectiveModeratorDGDLastQuarter(uint256 _quarterNumber) public view returns (uint256 _totalEffectiveModeratorDGDLastQuarter) { _totalEffectiveModeratorDGDLastQuarter = allQuartersInfo[_quarterNumber].totalEffectiveModeratorDGDLastQuarter; } function readRewardsPoolOfLastQuarter(uint256 _quarterNumber) public view returns (uint256 _rewardsPool) { _rewardsPool = allQuartersInfo[_quarterNumber].dgxRewardsPoolLastQuarter; } } // File: contracts/storage/IntermediateResultsStorage.sol pragma solidity ^0.4.25; contract IntermediateResultsStorage is ResolverClient, DaoConstants { using DaoStructs for DaoStructs.IntermediateResults; constructor(address _resolver) public { require(init(CONTRACT_STORAGE_INTERMEDIATE_RESULTS, _resolver)); } // There are scenarios in which we must loop across all participants/moderators // in a function call. For a big number of operations, the function call may be short of gas // To tackle this, we use an IntermediateResults struct to store the intermediate results // The same function is then called multiple times until all operations are completed // If the operations cannot be done in that iteration, the intermediate results are stored // else, the final outcome is returned // Please check the lib/DaoStructs for docs on this struct mapping (bytes32 => DaoStructs.IntermediateResults) allIntermediateResults; function getIntermediateResults(bytes32 _key) public view returns ( address _countedUntil, uint256 _currentForCount, uint256 _currentAgainstCount, uint256 _currentSumOfEffectiveBalance ) { _countedUntil = allIntermediateResults[_key].countedUntil; _currentForCount = allIntermediateResults[_key].currentForCount; _currentAgainstCount = allIntermediateResults[_key].currentAgainstCount; _currentSumOfEffectiveBalance = allIntermediateResults[_key].currentSumOfEffectiveBalance; } function resetIntermediateResults(bytes32 _key) public { require(sender_is_from([CONTRACT_DAO_REWARDS_MANAGER, CONTRACT_DAO_VOTING_CLAIMS, CONTRACT_DAO_SPECIAL_VOTING_CLAIMS])); allIntermediateResults[_key].countedUntil = address(0x0); } function setIntermediateResults( bytes32 _key, address _countedUntil, uint256 _currentForCount, uint256 _currentAgainstCount, uint256 _currentSumOfEffectiveBalance ) public { require(sender_is_from([CONTRACT_DAO_REWARDS_MANAGER, CONTRACT_DAO_VOTING_CLAIMS, CONTRACT_DAO_SPECIAL_VOTING_CLAIMS])); allIntermediateResults[_key].countedUntil = _countedUntil; allIntermediateResults[_key].currentForCount = _currentForCount; allIntermediateResults[_key].currentAgainstCount = _currentAgainstCount; allIntermediateResults[_key].currentSumOfEffectiveBalance = _currentSumOfEffectiveBalance; } } // File: contracts/common/DaoCommonMini.sol pragma solidity ^0.4.25; contract DaoCommonMini is IdentityCommon { using MathHelper for MathHelper; /** @notice Check if the DAO contracts have been replaced by a new set of contracts @return _isNotReplaced true if it is not replaced, false if it has already been replaced */ function isDaoNotReplaced() public view returns (bool _isNotReplaced) { _isNotReplaced = !daoUpgradeStorage().isReplacedByNewDao(); } /** @notice Check if it is currently in the locking phase @dev No governance activities can happen in the locking phase. The locking phase is from t=0 to t=CONFIG_LOCKING_PHASE_DURATION-1 @return _isLockingPhase true if it is in the locking phase */ function isLockingPhase() public view returns (bool _isLockingPhase) { _isLockingPhase = currentTimeInQuarter() < getUintConfig(CONFIG_LOCKING_PHASE_DURATION); } /** @notice Check if it is currently in a main phase. @dev The main phase is where all the governance activities could take plase. If the DAO is replaced, there can never be any more main phase. @return _isMainPhase true if it is in a main phase */ function isMainPhase() public view returns (bool _isMainPhase) { _isMainPhase = isDaoNotReplaced() && currentTimeInQuarter() >= getUintConfig(CONFIG_LOCKING_PHASE_DURATION); } /** @notice Check if the calculateGlobalRewardsBeforeNewQuarter function has been done for a certain quarter @dev However, there is no need to run calculateGlobalRewardsBeforeNewQuarter for the first quarter */ modifier ifGlobalRewardsSet(uint256 _quarterNumber) { if (_quarterNumber > 1) { require(daoRewardsStorage().readDgxDistributionDay(_quarterNumber) > 0); } _; } /** @notice require that it is currently during a phase, which is within _relativePhaseStart and _relativePhaseEnd seconds, after the _startingPoint */ function requireInPhase(uint256 _startingPoint, uint256 _relativePhaseStart, uint256 _relativePhaseEnd) internal view { require(_startingPoint > 0); require(now < _startingPoint.add(_relativePhaseEnd)); require(now >= _startingPoint.add(_relativePhaseStart)); } /** @notice Get the current quarter index @dev Quarter indexes starts from 1 @return _quarterNumber the current quarter index */ function currentQuarterNumber() public view returns(uint256 _quarterNumber) { _quarterNumber = getQuarterNumber(now); } /** @notice Get the quarter index of a timestamp @dev Quarter indexes starts from 1 @return _index the quarter index */ function getQuarterNumber(uint256 _time) internal view returns (uint256 _index) { require(startOfFirstQuarterIsSet()); _index = _time.sub(daoUpgradeStorage().startOfFirstQuarter()) .div(getUintConfig(CONFIG_QUARTER_DURATION)) .add(1); } /** @notice Get the relative time in quarter of a timestamp @dev For example, the timeInQuarter of the first second of any quarter n-th is always 1 */ function timeInQuarter(uint256 _time) internal view returns (uint256 _timeInQuarter) { require(startOfFirstQuarterIsSet()); // must be already set _timeInQuarter = _time.sub(daoUpgradeStorage().startOfFirstQuarter()) % getUintConfig(CONFIG_QUARTER_DURATION); } /** @notice Check if the start of first quarter is already set @return _isSet true if start of first quarter is already set */ function startOfFirstQuarterIsSet() internal view returns (bool _isSet) { _isSet = daoUpgradeStorage().startOfFirstQuarter() != 0; } /** @notice Get the current relative time in the quarter @dev For example: the currentTimeInQuarter of the first second of any quarter is 1 @return _currentT the current relative time in the quarter */ function currentTimeInQuarter() public view returns (uint256 _currentT) { _currentT = timeInQuarter(now); } /** @notice Get the time remaining in the quarter */ function getTimeLeftInQuarter(uint256 _time) internal view returns (uint256 _timeLeftInQuarter) { _timeLeftInQuarter = getUintConfig(CONFIG_QUARTER_DURATION).sub(timeInQuarter(_time)); } function daoListingService() internal view returns (DaoListingService _contract) { _contract = DaoListingService(get_contract(CONTRACT_SERVICE_DAO_LISTING)); } function daoConfigsStorage() internal view returns (DaoConfigsStorage _contract) { _contract = DaoConfigsStorage(get_contract(CONTRACT_STORAGE_DAO_CONFIG)); } function daoStakeStorage() internal view returns (DaoStakeStorage _contract) { _contract = DaoStakeStorage(get_contract(CONTRACT_STORAGE_DAO_STAKE)); } function daoStorage() internal view returns (DaoStorage _contract) { _contract = DaoStorage(get_contract(CONTRACT_STORAGE_DAO)); } function daoProposalCounterStorage() internal view returns (DaoProposalCounterStorage _contract) { _contract = DaoProposalCounterStorage(get_contract(CONTRACT_STORAGE_DAO_COUNTER)); } function daoUpgradeStorage() internal view returns (DaoUpgradeStorage _contract) { _contract = DaoUpgradeStorage(get_contract(CONTRACT_STORAGE_DAO_UPGRADE)); } function daoSpecialStorage() internal view returns (DaoSpecialStorage _contract) { _contract = DaoSpecialStorage(get_contract(CONTRACT_STORAGE_DAO_SPECIAL)); } function daoPointsStorage() internal view returns (DaoPointsStorage _contract) { _contract = DaoPointsStorage(get_contract(CONTRACT_STORAGE_DAO_POINTS)); } function daoRewardsStorage() internal view returns (DaoRewardsStorage _contract) { _contract = DaoRewardsStorage(get_contract(CONTRACT_STORAGE_DAO_REWARDS)); } function intermediateResultsStorage() internal view returns (IntermediateResultsStorage _contract) { _contract = IntermediateResultsStorage(get_contract(CONTRACT_STORAGE_INTERMEDIATE_RESULTS)); } function getUintConfig(bytes32 _configKey) public view returns (uint256 _configValue) { _configValue = daoConfigsStorage().uintConfigs(_configKey); } } // File: contracts/common/DaoCommon.sol pragma solidity ^0.4.25; contract DaoCommon is DaoCommonMini { using MathHelper for MathHelper; /** @notice Check if the transaction is called by the proposer of a proposal @return _isFromProposer true if the caller is the proposer */ function isFromProposer(bytes32 _proposalId) internal view returns (bool _isFromProposer) { _isFromProposer = msg.sender == daoStorage().readProposalProposer(_proposalId); } /** @notice Check if the proposal can still be "editted", or in other words, added more versions @dev Once the proposal is finalized, it can no longer be editted. The proposer will still be able to add docs and change fundings though. @return _isEditable true if the proposal is editable */ function isEditable(bytes32 _proposalId) internal view returns (bool _isEditable) { bytes32 _finalVersion; (,,,,,,,_finalVersion,,) = daoStorage().readProposal(_proposalId); _isEditable = _finalVersion == EMPTY_BYTES; } /** @notice returns the balance of DaoFundingManager, which is the wei in DigixDAO */ function weiInDao() internal view returns (uint256 _wei) { _wei = get_contract(CONTRACT_DAO_FUNDING_MANAGER).balance; } /** @notice Check if it is after the draft voting phase of the proposal */ modifier ifAfterDraftVotingPhase(bytes32 _proposalId) { uint256 _start = daoStorage().readProposalDraftVotingTime(_proposalId); require(_start > 0); // Draft voting must have started. In other words, proposer must have finalized the proposal require(now >= _start.add(getUintConfig(CONFIG_DRAFT_VOTING_PHASE))); _; } modifier ifCommitPhase(bytes32 _proposalId, uint8 _index) { requireInPhase( daoStorage().readProposalVotingTime(_proposalId, _index), 0, getUintConfig(_index == 0 ? CONFIG_VOTING_COMMIT_PHASE : CONFIG_INTERIM_COMMIT_PHASE) ); _; } modifier ifRevealPhase(bytes32 _proposalId, uint256 _index) { requireInPhase( daoStorage().readProposalVotingTime(_proposalId, _index), getUintConfig(_index == 0 ? CONFIG_VOTING_COMMIT_PHASE : CONFIG_INTERIM_COMMIT_PHASE), getUintConfig(_index == 0 ? CONFIG_VOTING_PHASE_TOTAL : CONFIG_INTERIM_PHASE_TOTAL) ); _; } modifier ifAfterProposalRevealPhase(bytes32 _proposalId, uint256 _index) { uint256 _start = daoStorage().readProposalVotingTime(_proposalId, _index); require(_start > 0); require(now >= _start.add(getUintConfig(_index == 0 ? CONFIG_VOTING_PHASE_TOTAL : CONFIG_INTERIM_PHASE_TOTAL))); _; } modifier ifDraftVotingPhase(bytes32 _proposalId) { requireInPhase( daoStorage().readProposalDraftVotingTime(_proposalId), 0, getUintConfig(CONFIG_DRAFT_VOTING_PHASE) ); _; } modifier isProposalState(bytes32 _proposalId, bytes32 _STATE) { bytes32 _currentState; (,,,_currentState,,,,,,) = daoStorage().readProposal(_proposalId); require(_currentState == _STATE); _; } /** @notice Check if the DAO has enough ETHs for a particular funding request */ modifier ifFundingPossible(uint256[] _fundings, uint256 _finalReward) { require(MathHelper.sumNumbers(_fundings).add(_finalReward) <= weiInDao()); _; } modifier ifDraftNotClaimed(bytes32 _proposalId) { require(daoStorage().isDraftClaimed(_proposalId) == false); _; } modifier ifNotClaimed(bytes32 _proposalId, uint256 _index) { require(daoStorage().isClaimed(_proposalId, _index) == false); _; } modifier ifNotClaimedSpecial(bytes32 _proposalId) { require(daoSpecialStorage().isClaimed(_proposalId) == false); _; } modifier hasNotRevealed(bytes32 _proposalId, uint256 _index) { uint256 _voteWeight; (, _voteWeight) = daoStorage().readVote(_proposalId, _index, msg.sender); require(_voteWeight == uint(0)); _; } modifier hasNotRevealedSpecial(bytes32 _proposalId) { uint256 _weight; (,_weight) = daoSpecialStorage().readVote(_proposalId, msg.sender); require(_weight == uint256(0)); _; } modifier ifAfterRevealPhaseSpecial(bytes32 _proposalId) { uint256 _start = daoSpecialStorage().readVotingTime(_proposalId); require(_start > 0); require(now.sub(_start) >= getUintConfig(CONFIG_SPECIAL_PROPOSAL_PHASE_TOTAL)); _; } modifier ifCommitPhaseSpecial(bytes32 _proposalId) { requireInPhase( daoSpecialStorage().readVotingTime(_proposalId), 0, getUintConfig(CONFIG_SPECIAL_PROPOSAL_COMMIT_PHASE) ); _; } modifier ifRevealPhaseSpecial(bytes32 _proposalId) { requireInPhase( daoSpecialStorage().readVotingTime(_proposalId), getUintConfig(CONFIG_SPECIAL_PROPOSAL_COMMIT_PHASE), getUintConfig(CONFIG_SPECIAL_PROPOSAL_PHASE_TOTAL) ); _; } function daoWhitelistingStorage() internal view returns (DaoWhitelistingStorage _contract) { _contract = DaoWhitelistingStorage(get_contract(CONTRACT_STORAGE_DAO_WHITELISTING)); } function getAddressConfig(bytes32 _configKey) public view returns (address _configValue) { _configValue = daoConfigsStorage().addressConfigs(_configKey); } function getBytesConfig(bytes32 _configKey) public view returns (bytes32 _configValue) { _configValue = daoConfigsStorage().bytesConfigs(_configKey); } /** @notice Check if a user is a participant in the current quarter */ function isParticipant(address _user) public view returns (bool _is) { _is = (daoRewardsStorage().lastParticipatedQuarter(_user) == currentQuarterNumber()) && (daoStakeStorage().lockedDGDStake(_user) >= getUintConfig(CONFIG_MINIMUM_LOCKED_DGD)); } /** @notice Check if a user is a moderator in the current quarter */ function isModerator(address _user) public view returns (bool _is) { _is = (daoRewardsStorage().lastParticipatedQuarter(_user) == currentQuarterNumber()) && (daoStakeStorage().lockedDGDStake(_user) >= getUintConfig(CONFIG_MINIMUM_DGD_FOR_MODERATOR)) && (daoPointsStorage().getReputation(_user) >= getUintConfig(CONFIG_MINIMUM_REPUTATION_FOR_MODERATOR)); } /** @notice Calculate the start of a specific milestone of a specific proposal. @dev This is calculated from the voting start of the voting round preceding the milestone This would throw if the voting start is 0 (the voting round has not started yet) Note that if the milestoneIndex is exactly the same as the number of milestones, This will just return the end of the last voting round. */ function startOfMilestone(bytes32 _proposalId, uint256 _milestoneIndex) internal view returns (uint256 _milestoneStart) { uint256 _startOfPrecedingVotingRound = daoStorage().readProposalVotingTime(_proposalId, _milestoneIndex); require(_startOfPrecedingVotingRound > 0); // the preceding voting round must have started if (_milestoneIndex == 0) { // This is the 1st milestone, which starts after voting round 0 _milestoneStart = _startOfPrecedingVotingRound .add(getUintConfig(CONFIG_VOTING_PHASE_TOTAL)); } else { // if its the n-th milestone, it starts after voting round n-th _milestoneStart = _startOfPrecedingVotingRound .add(getUintConfig(CONFIG_INTERIM_PHASE_TOTAL)); } } /** @notice Calculate the actual voting start for a voting round, given the tentative start @dev The tentative start is the ideal start. For example, when a proposer finish a milestone, it should be now However, sometimes the tentative start is too close to the end of the quarter, hence, the actual voting start should be pushed to the next quarter */ function getTimelineForNextVote( uint256 _index, uint256 _tentativeVotingStart ) internal view returns (uint256 _actualVotingStart) { uint256 _timeLeftInQuarter = getTimeLeftInQuarter(_tentativeVotingStart); uint256 _votingDuration = getUintConfig(_index == 0 ? CONFIG_VOTING_PHASE_TOTAL : CONFIG_INTERIM_PHASE_TOTAL); _actualVotingStart = _tentativeVotingStart; if (timeInQuarter(_tentativeVotingStart) < getUintConfig(CONFIG_LOCKING_PHASE_DURATION)) { // if the tentative start is during a locking phase _actualVotingStart = _tentativeVotingStart.add( getUintConfig(CONFIG_LOCKING_PHASE_DURATION).sub(timeInQuarter(_tentativeVotingStart)) ); } else if (_timeLeftInQuarter < _votingDuration.add(getUintConfig(CONFIG_VOTE_CLAIMING_DEADLINE))) { // if the time left in quarter is not enough to vote and claim voting _actualVotingStart = _tentativeVotingStart.add( _timeLeftInQuarter.add(getUintConfig(CONFIG_LOCKING_PHASE_DURATION)).add(1) ); } } /** @notice Check if we can add another non-Digix proposal in this quarter @dev There is a max cap to the number of non-Digix proposals CONFIG_NON_DIGIX_PROPOSAL_CAP_PER_QUARTER */ function checkNonDigixProposalLimit(bytes32 _proposalId) internal view { require(isNonDigixProposalsWithinLimit(_proposalId)); } function isNonDigixProposalsWithinLimit(bytes32 _proposalId) internal view returns (bool _withinLimit) { bool _isDigixProposal; (,,,,,,,,,_isDigixProposal) = daoStorage().readProposal(_proposalId); _withinLimit = true; if (!_isDigixProposal) { _withinLimit = daoProposalCounterStorage().proposalCountByQuarter(currentQuarterNumber()) < getUintConfig(CONFIG_NON_DIGIX_PROPOSAL_CAP_PER_QUARTER); } } /** @notice If its a non-Digix proposal, check if the fundings are within limit @dev There is a max cap to the fundings and number of milestones for non-Digix proposals */ function checkNonDigixFundings(uint256[] _milestonesFundings, uint256 _finalReward) internal view { if (!is_founder()) { require(_milestonesFundings.length <= getUintConfig(CONFIG_MAX_MILESTONES_FOR_NON_DIGIX)); require(MathHelper.sumNumbers(_milestonesFundings).add(_finalReward) <= getUintConfig(CONFIG_MAX_FUNDING_FOR_NON_DIGIX)); } } /** @notice Check if msg.sender can do operations as a proposer @dev Note that this function does not check if he is the proposer of the proposal */ function senderCanDoProposerOperations() internal view { require(isMainPhase()); require(isParticipant(msg.sender)); require(identity_storage().is_kyc_approved(msg.sender)); } } // File: contracts/interface/DgxDemurrageCalculator.sol pragma solidity ^0.4.25; /// @title Digix Gold Token Demurrage Calculator /// @author Digix Holdings Pte Ltd /// @notice This contract is meant to be used by exchanges/other parties who want to calculate the DGX demurrage fees, provided an initial balance and the days elapsed contract DgxDemurrageCalculator { function calculateDemurrage(uint256 _initial_balance, uint256 _days_elapsed) public view returns (uint256 _demurrage_fees, bool _no_demurrage_fees); } // File: contracts/service/DaoCalculatorService.sol pragma solidity ^0.4.25; contract DaoCalculatorService is DaoCommon { address public dgxDemurrageCalculatorAddress; using MathHelper for MathHelper; constructor(address _resolver, address _dgxDemurrageCalculatorAddress) public { require(init(CONTRACT_SERVICE_DAO_CALCULATOR, _resolver)); dgxDemurrageCalculatorAddress = _dgxDemurrageCalculatorAddress; } /** @notice Calculate the additional lockedDGDStake, given the DGDs that the user has just locked in @dev The earlier the locking happens, the more lockedDGDStake the user will get The formula is: additionalLockedDGDStake = (90 - t)/80 * additionalDGD if t is more than 10. If t<=10, additionalLockedDGDStake = additionalDGD */ function calculateAdditionalLockedDGDStake(uint256 _additionalDgd) public view returns (uint256 _additionalLockedDGDStake) { _additionalLockedDGDStake = _additionalDgd.mul( getUintConfig(CONFIG_QUARTER_DURATION) .sub( MathHelper.max( currentTimeInQuarter(), getUintConfig(CONFIG_LOCKING_PHASE_DURATION) ) ) ) .div( getUintConfig(CONFIG_QUARTER_DURATION) .sub(getUintConfig(CONFIG_LOCKING_PHASE_DURATION)) ); } // Quorum is in terms of lockedDGDStake function minimumDraftQuorum(bytes32 _proposalId) public view returns (uint256 _minQuorum) { uint256[] memory _fundings; (_fundings,) = daoStorage().readProposalFunding(_proposalId); _minQuorum = calculateMinQuorum( daoStakeStorage().totalModeratorLockedDGDStake(), getUintConfig(CONFIG_DRAFT_QUORUM_FIXED_PORTION_NUMERATOR), getUintConfig(CONFIG_DRAFT_QUORUM_FIXED_PORTION_DENOMINATOR), getUintConfig(CONFIG_DRAFT_QUORUM_SCALING_FACTOR_NUMERATOR), getUintConfig(CONFIG_DRAFT_QUORUM_SCALING_FACTOR_DENOMINATOR), _fundings[0] ); } function draftQuotaPass(uint256 _for, uint256 _against) public view returns (bool _passed) { _passed = _for.mul(getUintConfig(CONFIG_DRAFT_QUOTA_DENOMINATOR)) > getUintConfig(CONFIG_DRAFT_QUOTA_NUMERATOR).mul(_for.add(_against)); } // Quorum is in terms of lockedDGDStake function minimumVotingQuorum(bytes32 _proposalId, uint256 _milestone_id) public view returns (uint256 _minQuorum) { require(senderIsAllowedToRead()); uint256[] memory _weiAskedPerMilestone; uint256 _finalReward; (_weiAskedPerMilestone,_finalReward) = daoStorage().readProposalFunding(_proposalId); require(_milestone_id <= _weiAskedPerMilestone.length); if (_milestone_id == _weiAskedPerMilestone.length) { // calculate quorum for the final voting round _minQuorum = calculateMinQuorum( daoStakeStorage().totalLockedDGDStake(), getUintConfig(CONFIG_VOTING_QUORUM_FIXED_PORTION_NUMERATOR), getUintConfig(CONFIG_VOTING_QUORUM_FIXED_PORTION_DENOMINATOR), getUintConfig(CONFIG_FINAL_REWARD_SCALING_FACTOR_NUMERATOR), getUintConfig(CONFIG_FINAL_REWARD_SCALING_FACTOR_DENOMINATOR), _finalReward ); } else { // calculate quorum for a voting round _minQuorum = calculateMinQuorum( daoStakeStorage().totalLockedDGDStake(), getUintConfig(CONFIG_VOTING_QUORUM_FIXED_PORTION_NUMERATOR), getUintConfig(CONFIG_VOTING_QUORUM_FIXED_PORTION_DENOMINATOR), getUintConfig(CONFIG_VOTING_QUORUM_SCALING_FACTOR_NUMERATOR), getUintConfig(CONFIG_VOTING_QUORUM_SCALING_FACTOR_DENOMINATOR), _weiAskedPerMilestone[_milestone_id] ); } } // Quorum is in terms of lockedDGDStake function minimumVotingQuorumForSpecial() public view returns (uint256 _minQuorum) { _minQuorum = getUintConfig(CONFIG_SPECIAL_PROPOSAL_QUORUM_NUMERATOR).mul( daoStakeStorage().totalLockedDGDStake() ).div( getUintConfig(CONFIG_SPECIAL_PROPOSAL_QUORUM_DENOMINATOR) ); } function votingQuotaPass(uint256 _for, uint256 _against) public view returns (bool _passed) { _passed = _for.mul(getUintConfig(CONFIG_VOTING_QUOTA_DENOMINATOR)) > getUintConfig(CONFIG_VOTING_QUOTA_NUMERATOR).mul(_for.add(_against)); } function votingQuotaForSpecialPass(uint256 _for, uint256 _against) public view returns (bool _passed) { _passed =_for.mul(getUintConfig(CONFIG_SPECIAL_QUOTA_DENOMINATOR)) > getUintConfig(CONFIG_SPECIAL_QUOTA_NUMERATOR).mul(_for.add(_against)); } function calculateMinQuorum( uint256 _totalStake, uint256 _fixedQuorumPortionNumerator, uint256 _fixedQuorumPortionDenominator, uint256 _scalingFactorNumerator, uint256 _scalingFactorDenominator, uint256 _weiAsked ) internal view returns (uint256 _minimumQuorum) { uint256 _weiInDao = weiInDao(); // add the fixed portion of the quorum _minimumQuorum = (_totalStake.mul(_fixedQuorumPortionNumerator)).div(_fixedQuorumPortionDenominator); // add the dynamic portion of the quorum _minimumQuorum = _minimumQuorum.add(_totalStake.mul(_weiAsked.mul(_scalingFactorNumerator)).div(_weiInDao.mul(_scalingFactorDenominator))); } function calculateUserEffectiveBalance( uint256 _minimalParticipationPoint, uint256 _quarterPointScalingFactor, uint256 _reputationPointScalingFactor, uint256 _quarterPoint, uint256 _reputationPoint, uint256 _lockedDGDStake ) public pure returns (uint256 _effectiveDGDBalance) { uint256 _baseDGDBalance = MathHelper.min(_quarterPoint, _minimalParticipationPoint).mul(_lockedDGDStake).div(_minimalParticipationPoint); _effectiveDGDBalance = _baseDGDBalance .mul(_quarterPointScalingFactor.add(_quarterPoint).sub(_minimalParticipationPoint)) .mul(_reputationPointScalingFactor.add(_reputationPoint)) .div(_quarterPointScalingFactor.mul(_reputationPointScalingFactor)); } function calculateDemurrage(uint256 _balance, uint256 _daysElapsed) public view returns (uint256 _demurrageFees) { (_demurrageFees,) = DgxDemurrageCalculator(dgxDemurrageCalculatorAddress).calculateDemurrage(_balance, _daysElapsed); } } // File: contracts/common/DaoRewardsManagerCommon.sol pragma solidity ^0.4.25; contract DaoRewardsManagerCommon is DaoCommonMini { using DaoStructs for DaoStructs.DaoQuarterInfo; // this is a struct that store information relevant for calculating the user rewards // for the last participating quarter struct UserRewards { uint256 lastParticipatedQuarter; uint256 lastQuarterThatRewardsWasUpdated; uint256 effectiveDGDBalance; uint256 effectiveModeratorDGDBalance; DaoStructs.DaoQuarterInfo qInfo; } // struct to store variables needed in the execution of calculateGlobalRewardsBeforeNewQuarter struct QuarterRewardsInfo { uint256 previousQuarter; uint256 totalEffectiveDGDPreviousQuarter; uint256 totalEffectiveModeratorDGDLastQuarter; uint256 dgxRewardsPoolLastQuarter; uint256 userCount; uint256 i; DaoStructs.DaoQuarterInfo qInfo; address currentUser; address[] users; bool doneCalculatingEffectiveBalance; bool doneCalculatingModeratorEffectiveBalance; } // get the struct for the relevant information for calculating a user's DGX rewards for the last participated quarter function getUserRewardsStruct(address _user) internal view returns (UserRewards memory _data) { _data.lastParticipatedQuarter = daoRewardsStorage().lastParticipatedQuarter(_user); _data.lastQuarterThatRewardsWasUpdated = daoRewardsStorage().lastQuarterThatRewardsWasUpdated(_user); _data.qInfo = readQuarterInfo(_data.lastParticipatedQuarter); } // read the DaoQuarterInfo struct of a certain quarter function readQuarterInfo(uint256 _quarterNumber) internal view returns (DaoStructs.DaoQuarterInfo _qInfo) { ( _qInfo.minimalParticipationPoint, _qInfo.quarterPointScalingFactor, _qInfo.reputationPointScalingFactor, _qInfo.totalEffectiveDGDPreviousQuarter ) = daoRewardsStorage().readQuarterParticipantInfo(_quarterNumber); ( _qInfo.moderatorMinimalParticipationPoint, _qInfo.moderatorQuarterPointScalingFactor, _qInfo.moderatorReputationPointScalingFactor, _qInfo.totalEffectiveModeratorDGDLastQuarter ) = daoRewardsStorage().readQuarterModeratorInfo(_quarterNumber); ( _qInfo.dgxDistributionDay, _qInfo.dgxRewardsPoolLastQuarter, _qInfo.sumRewardsFromBeginning ) = daoRewardsStorage().readQuarterGeneralInfo(_quarterNumber); } } // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol pragma solidity ^0.4.24; /** * @title ERC20Basic * @dev Simpler version of ERC20 interface * See https://github.com/ethereum/EIPs/issues/179 */ contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address _who) public view returns (uint256); function transfer(address _to, uint256 _value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol pragma solidity ^0.4.24; /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 is ERC20Basic { function allowance(address _owner, address _spender) public view returns (uint256); function transferFrom(address _from, address _to, uint256 _value) public returns (bool); function approve(address _spender, uint256 _value) public returns (bool); event Approval( address indexed owner, address indexed spender, uint256 value ); } // File: contracts/interactive/DaoRewardsManagerExtras.sol pragma solidity ^0.4.25; contract DaoRewardsManagerExtras is DaoRewardsManagerCommon { constructor(address _resolver) public { require(init(CONTRACT_DAO_REWARDS_MANAGER_EXTRAS, _resolver)); } function daoCalculatorService() internal view returns (DaoCalculatorService _contract) { _contract = DaoCalculatorService(get_contract(CONTRACT_SERVICE_DAO_CALCULATOR)); } // done // calculate dgx rewards; This is basically the DGXs that user has earned from participating in lastParticipatedQuarter, and can be withdrawn on the dgxDistributionDay of the (lastParticipatedQuarter + 1) // when user actually withdraw some time after that, he will be deducted demurrage. function calculateUserRewardsForLastParticipatingQuarter(address _user) public view returns (uint256 _dgxRewardsAsParticipant, uint256 _dgxRewardsAsModerator) { UserRewards memory data = getUserRewardsStruct(_user); data.effectiveDGDBalance = daoCalculatorService().calculateUserEffectiveBalance( data.qInfo.minimalParticipationPoint, data.qInfo.quarterPointScalingFactor, data.qInfo.reputationPointScalingFactor, daoPointsStorage().getQuarterPoint(_user, data.lastParticipatedQuarter), // RP has been updated at the beginning of the lastParticipatedQuarter in // a call to updateRewardsAndReputationBeforeNewQuarter(); It should not have changed since then daoPointsStorage().getReputation(_user), // lockedDGDStake should have stayed the same throughout since the lastParticipatedQuarter // if this participant has done anything (lock/unlock/continue) to change the lockedDGDStake, // updateUserRewardsForLastParticipatingQuarter, and hence this function, would have been called first before the lockedDGDStake is changed daoStakeStorage().lockedDGDStake(_user) ); data.effectiveModeratorDGDBalance = daoCalculatorService().calculateUserEffectiveBalance( data.qInfo.moderatorMinimalParticipationPoint, data.qInfo.moderatorQuarterPointScalingFactor, data.qInfo.moderatorReputationPointScalingFactor, daoPointsStorage().getQuarterModeratorPoint(_user, data.lastParticipatedQuarter), // RP has been updated at the beginning of the lastParticipatedQuarter in // a call to updateRewardsAndReputationBeforeNewQuarter(); daoPointsStorage().getReputation(_user), // lockedDGDStake should have stayed the same throughout since the lastParticipatedQuarter // if this participant has done anything (lock/unlock/continue) to change the lockedDGDStake, // updateUserRewardsForLastParticipatingQuarter would have been called first before the lockedDGDStake is changed daoStakeStorage().lockedDGDStake(_user) ); // will not need to calculate if the totalEffectiveDGDLastQuarter is 0 (no one participated) if (daoRewardsStorage().readTotalEffectiveDGDLastQuarter(data.lastParticipatedQuarter.add(1)) > 0) { _dgxRewardsAsParticipant = data.effectiveDGDBalance .mul(daoRewardsStorage().readRewardsPoolOfLastQuarter( data.lastParticipatedQuarter.add(1) )) .mul( getUintConfig(CONFIG_PORTION_TO_MODERATORS_DEN) .sub(getUintConfig(CONFIG_PORTION_TO_MODERATORS_NUM)) ) .div(daoRewardsStorage().readTotalEffectiveDGDLastQuarter( data.lastParticipatedQuarter.add(1) )) .div(getUintConfig(CONFIG_PORTION_TO_MODERATORS_DEN)); } // will not need to calculate if the totalEffectiveModeratorDGDLastQuarter is 0 (no one participated) if (daoRewardsStorage().readTotalEffectiveModeratorDGDLastQuarter(data.lastParticipatedQuarter.add(1)) > 0) { _dgxRewardsAsModerator = data.effectiveModeratorDGDBalance .mul(daoRewardsStorage().readRewardsPoolOfLastQuarter( data.lastParticipatedQuarter.add(1) )) .mul( getUintConfig(CONFIG_PORTION_TO_MODERATORS_NUM) ) .div(daoRewardsStorage().readTotalEffectiveModeratorDGDLastQuarter( data.lastParticipatedQuarter.add(1) )) .div(getUintConfig(CONFIG_PORTION_TO_MODERATORS_DEN)); } } } // File: contracts/interactive/DaoRewardsManager.sol pragma solidity ^0.4.25; /** @title Contract to manage DGX rewards @author Digix Holdings */ contract DaoRewardsManager is DaoRewardsManagerCommon { using MathHelper for MathHelper; using DaoStructs for DaoStructs.DaoQuarterInfo; using DaoStructs for DaoStructs.IntermediateResults; // is emitted when calculateGlobalRewardsBeforeNewQuarter has been done in the beginning of the quarter // after which, all the other DAO activities could happen event StartNewQuarter(uint256 indexed _quarterNumber); address public ADDRESS_DGX_TOKEN; function daoCalculatorService() internal view returns (DaoCalculatorService _contract) { _contract = DaoCalculatorService(get_contract(CONTRACT_SERVICE_DAO_CALCULATOR)); } function daoRewardsManagerExtras() internal view returns (DaoRewardsManagerExtras _contract) { _contract = DaoRewardsManagerExtras(get_contract(CONTRACT_DAO_REWARDS_MANAGER_EXTRAS)); } /** @notice Constructor (set the DaoQuarterInfo struct for the first quarter) @param _resolver Address of the Contract Resolver contract @param _dgxAddress Address of the Digix Gold Token contract */ constructor(address _resolver, address _dgxAddress) public { require(init(CONTRACT_DAO_REWARDS_MANAGER, _resolver)); ADDRESS_DGX_TOKEN = _dgxAddress; // set the DaoQuarterInfo for the first quarter daoRewardsStorage().updateQuarterInfo( 1, getUintConfig(CONFIG_MINIMAL_QUARTER_POINT), getUintConfig(CONFIG_QUARTER_POINT_SCALING_FACTOR), getUintConfig(CONFIG_REPUTATION_POINT_SCALING_FACTOR), 0, // totalEffectiveDGDPreviousQuarter, Not Applicable, this value should not be used ever getUintConfig(CONFIG_MODERATOR_MINIMAL_QUARTER_POINT), getUintConfig(CONFIG_MODERATOR_QUARTER_POINT_SCALING_FACTOR), getUintConfig(CONFIG_MODERATOR_REPUTATION_POINT_SCALING_FACTOR), 0, // _totalEffectiveModeratorDGDLastQuarter , Not applicable, this value should not be used ever // _dgxDistributionDay, Not applicable, there shouldnt be any DGX rewards in the DAO now. The actual DGX fees that have been collected // before the deployment of DigixDAO contracts would be counted as part of the DGX fees incurred in the first quarter // this value should not be used ever now, 0, // _dgxRewardsPoolLastQuarter, not applicable, this value should not be used ever 0 // sumRewardsFromBeginning, which is 0 ); } /** @notice Function to transfer the claimableDGXs to the new DaoRewardsManager @dev This is done during the migrateToNewDao procedure @param _newDaoRewardsManager Address of the new daoRewardsManager contract */ function moveDGXsToNewDao(address _newDaoRewardsManager) public { require(sender_is(CONTRACT_DAO)); uint256 _dgxBalance = ERC20(ADDRESS_DGX_TOKEN).balanceOf(address(this)); ERC20(ADDRESS_DGX_TOKEN).transfer(_newDaoRewardsManager, _dgxBalance); } /** @notice Function for users to claim the claimable DGX rewards @dev Will revert if _claimableDGX < MINIMUM_TRANSFER_AMOUNT of DGX. Can only be called after calculateGlobalRewardsBeforeNewQuarter() has been called in the current quarter This cannot be called once the current version of Dao contracts have been migrated to newer version */ function claimRewards() public ifGlobalRewardsSet(currentQuarterNumber()) { require(isDaoNotReplaced()); address _user = msg.sender; uint256 _claimableDGX; // update rewards for the quarter that he last participated in (, _claimableDGX) = updateUserRewardsForLastParticipatingQuarter(_user); // withdraw from his claimableDGXs // This has to take into account demurrage // Basically, the value of claimableDGXs in the contract is for the dgxDistributionDay of (lastParticipatedQuarter + 1) // if now is after that, we need to deduct demurrage uint256 _days_elapsed = now .sub( daoRewardsStorage().readDgxDistributionDay( daoRewardsStorage().lastQuarterThatRewardsWasUpdated(_user).add(1) // lastQuarterThatRewardsWasUpdated should be the same as lastParticipatedQuarter now ) ) .div(1 days); // similar logic as in the similar step in updateUserRewardsForLastParticipatingQuarter. // it is as if the user has withdrawn all _claimableDGX, and the demurrage is paid back into the DAO immediately daoRewardsStorage().addToTotalDgxClaimed(_claimableDGX); _claimableDGX = _claimableDGX.sub( daoCalculatorService().calculateDemurrage( _claimableDGX, _days_elapsed )); daoRewardsStorage().updateClaimableDGX(_user, 0); ERC20(ADDRESS_DGX_TOKEN).transfer(_user, _claimableDGX); // the _demurrageFees is implicitly "transfered" back into the DAO, and would be counted in the dgxRewardsPool of this quarter (in other words, dgxRewardsPoolLastQuarter of next quarter) } /** @notice Function to update DGX rewards of user. This is only called during locking/withdrawing DGDs, or continuing participation for new quarter @param _user Address of the DAO participant */ function updateRewardsAndReputationBeforeNewQuarter(address _user) public { require(sender_is(CONTRACT_DAO_STAKE_LOCKING)); updateUserRewardsForLastParticipatingQuarter(_user); updateUserReputationUntilPreviousQuarter(_user); } // This function would ALWAYS make sure that the user's Reputation Point is updated for ALL activities that has happened // BEFORE this current quarter. These activities include: // - Reputation bonus/penalty due to participation in all of the previous quarters // - Reputation penalty for not participating for a few quarters, up until and including the previous quarter // - Badges redemption and carbon vote reputation redemption (that happens in the first time locking) // As such, after this function is called on quarter N, the updated reputation point of the user would tentatively be used to calculate the rewards for quarter N // Its tentative because the user can also redeem a badge during the period of quarter N to add to his reputation point. function updateUserReputationUntilPreviousQuarter (address _user) private { uint256 _lastParticipatedQuarter = daoRewardsStorage().lastParticipatedQuarter(_user); uint256 _lastQuarterThatReputationWasUpdated = daoRewardsStorage().lastQuarterThatReputationWasUpdated(_user); uint256 _reputationDeduction; // If the reputation was already updated until the previous quarter // nothing needs to be done if ( _lastQuarterThatReputationWasUpdated.add(1) >= currentQuarterNumber() ) { return; } // first, we calculate and update the reputation change due to the user's governance activities in lastParticipatedQuarter, if it is not already updated. // reputation is not updated for lastParticipatedQuarter yet is equivalent to _lastQuarterThatReputationWasUpdated == _lastParticipatedQuarter - 1 if ( (_lastQuarterThatReputationWasUpdated.add(1) == _lastParticipatedQuarter) ) { updateRPfromQP( _user, daoPointsStorage().getQuarterPoint(_user, _lastParticipatedQuarter), getUintConfig(CONFIG_MINIMAL_QUARTER_POINT), getUintConfig(CONFIG_MAXIMUM_REPUTATION_DEDUCTION), getUintConfig(CONFIG_REPUTATION_PER_EXTRA_QP_NUM), getUintConfig(CONFIG_REPUTATION_PER_EXTRA_QP_DEN) ); // this user is not a Moderator for current quarter // coz this step is done before updating the refreshModerator. // But may have been a Moderator before, and if was moderator in their // lastParticipatedQuarter, we will find them in the DoublyLinkedList. if (daoStakeStorage().isInModeratorsList(_user)) { updateRPfromQP( _user, daoPointsStorage().getQuarterModeratorPoint(_user, _lastParticipatedQuarter), getUintConfig(CONFIG_MODERATOR_MINIMAL_QUARTER_POINT), getUintConfig(CONFIG_MAXIMUM_MODERATOR_REPUTATION_DEDUCTION), getUintConfig(CONFIG_REPUTATION_PER_EXTRA_MODERATOR_QP_NUM), getUintConfig(CONFIG_REPUTATION_PER_EXTRA_MODERATOR_QP_DEN) ); } _lastQuarterThatReputationWasUpdated = _lastParticipatedQuarter; } // at this point, the _lastQuarterThatReputationWasUpdated MUST be at least the _lastParticipatedQuarter already // Hence, any quarters between the _lastQuarterThatReputationWasUpdated and now must be a non-participating quarter, // and this participant should be penalized for those. // If this is their first ever participation, It is fine as well, as the reputation would be still be 0 after this step. // note that the carbon vote's reputation bonus will be added after this, so its fine _reputationDeduction = (currentQuarterNumber().sub(1).sub(_lastQuarterThatReputationWasUpdated)) .mul( getUintConfig(CONFIG_MAXIMUM_REPUTATION_DEDUCTION) .add(getUintConfig(CONFIG_PUNISHMENT_FOR_NOT_LOCKING)) ); if (_reputationDeduction > 0) daoPointsStorage().reduceReputation(_user, _reputationDeduction); daoRewardsStorage().updateLastQuarterThatReputationWasUpdated(_user, currentQuarterNumber().sub(1)); } // update ReputationPoint of a participant based on QuarterPoint/ModeratorQuarterPoint in a quarter function updateRPfromQP ( address _user, uint256 _userQP, uint256 _minimalQP, uint256 _maxRPDeduction, uint256 _rpPerExtraQP_num, uint256 _rpPerExtraQP_den ) internal { uint256 _reputationDeduction; uint256 _reputationAddition; if (_userQP < _minimalQP) { _reputationDeduction = _minimalQP.sub(_userQP) .mul(_maxRPDeduction) .div(_minimalQP); daoPointsStorage().reduceReputation(_user, _reputationDeduction); } else { _reputationAddition = _userQP.sub(_minimalQP) .mul(_rpPerExtraQP_num) .div(_rpPerExtraQP_den); daoPointsStorage().increaseReputation(_user, _reputationAddition); } } // if the DGX rewards has not been calculated for the user's lastParticipatedQuarter, calculate and update it function updateUserRewardsForLastParticipatingQuarter(address _user) internal returns (bool _valid, uint256 _userClaimableDgx) { UserRewards memory data = getUserRewardsStruct(_user); _userClaimableDgx = daoRewardsStorage().claimableDGXs(_user); // There is nothing to do if: // - The participant is already participating this quarter and hence this function has been called in this quarter // - We have updated the rewards to the lastParticipatedQuarter // In ANY other cases: it means that the lastParticipatedQuarter is NOT this quarter, and its greater than lastQuarterThatRewardsWasUpdated, hence // This also means that this participant has ALREADY PARTICIPATED at least once IN THE PAST, and we have not calculated for this quarter // Thus, we need to calculate the Rewards for the lastParticipatedQuarter if ( (currentQuarterNumber() == data.lastParticipatedQuarter) || (data.lastParticipatedQuarter <= data.lastQuarterThatRewardsWasUpdated) ) { return (false, _userClaimableDgx); } // now we will calculate the user rewards based on info of the data.lastParticipatedQuarter // first we "deduct the demurrage" for the existing claimable DGXs for time period from // dgxDistributionDay of (lastQuarterThatRewardsWasUpdated + 1) to dgxDistributionDay of (lastParticipatedQuarter + 1) // (note that, when people participate in quarter n, the DGX rewards for quarter n is only released at the dgxDistributionDay of (n+1)th quarter) uint256 _days_elapsed = daoRewardsStorage().readDgxDistributionDay(data.lastParticipatedQuarter.add(1)) .sub(daoRewardsStorage().readDgxDistributionDay(data.lastQuarterThatRewardsWasUpdated.add(1))) .div(1 days); uint256 _demurrageFees = daoCalculatorService().calculateDemurrage( _userClaimableDgx, _days_elapsed ); _userClaimableDgx = _userClaimableDgx.sub(_demurrageFees); // this demurrage fees will not be accurate to the hours, but we will leave it as this. // this deducted demurrage is then added to the totalDGXsClaimed // This is as if, the user claims exactly _demurrageFees DGXs, which would be used immediately to pay for the demurrage on his claimableDGXs, // from dgxDistributionDay of (lastQuarterThatRewardsWasUpdated + 1) to dgxDistributionDay of (lastParticipatedQuarter + 1) // This is done as such, so that this _demurrageFees would "flow back into the DAO" and be counted in the dgxRewardsPool of this current quarter (in other words, dgxRewardsPoolLastQuarter of the next quarter, as will be calculated in calculateGlobalRewardsBeforeNewQuarter of the next quarter) // this is not 100% techinally correct as a demurrage concept, because this demurrage fees could have been incurred for the duration of the quarters in the past, but we will account them this way, as if its demurrage fees for this quarter, for simplicity. daoRewardsStorage().addToTotalDgxClaimed(_demurrageFees); uint256 _dgxRewardsAsParticipant; uint256 _dgxRewardsAsModerator; (_dgxRewardsAsParticipant, _dgxRewardsAsModerator) = daoRewardsManagerExtras().calculateUserRewardsForLastParticipatingQuarter(_user); _userClaimableDgx = _userClaimableDgx.add(_dgxRewardsAsParticipant).add(_dgxRewardsAsModerator); // update claimableDGXs. The calculation just now should have taken into account demurrage // such that the demurrage has been paid until dgxDistributionDay of (lastParticipatedQuarter + 1) daoRewardsStorage().updateClaimableDGX(_user, _userClaimableDgx); // update lastQuarterThatRewardsWasUpdated daoRewardsStorage().updateLastQuarterThatRewardsWasUpdated(_user, data.lastParticipatedQuarter); _valid = true; } /** @notice Function called by the founder after transfering the DGX fees into the DAO at the beginning of the quarter @dev This function needs to do lots of calculation, so it might not fit into one transaction As such, it could be done in multiple transactions, each time passing _operations which is the number of operations we want to calculate. When the value of _done is finally true, that's when the calculation is done. Only after this function runs, any other activities in the DAO could happen. Basically, if there were M participants and N moderators in the previous quarter, it takes M+N "operations". In summary, the function populates the DaoQuarterInfo of this quarter. The bulk of the calculation is to go through every participant in the previous quarter to calculate their effectiveDGDBalance and sum them to get the totalEffectiveDGDLastQuarter */ function calculateGlobalRewardsBeforeNewQuarter(uint256 _operations) public if_founder() returns (bool _done) { require(isDaoNotReplaced()); require(daoUpgradeStorage().startOfFirstQuarter() != 0); // start of first quarter must have been set already require(isLockingPhase()); require(daoRewardsStorage().readDgxDistributionDay(currentQuarterNumber()) == 0); // throw if this function has already finished running this quarter QuarterRewardsInfo memory info; info.previousQuarter = currentQuarterNumber().sub(1); require(info.previousQuarter > 0); // throw if this is the first quarter info.qInfo = readQuarterInfo(info.previousQuarter); DaoStructs.IntermediateResults memory interResults; ( interResults.countedUntil,,, info.totalEffectiveDGDPreviousQuarter ) = intermediateResultsStorage().getIntermediateResults( getIntermediateResultsIdForGlobalRewards(info.previousQuarter, false) ); uint256 _operationsLeft = sumEffectiveBalance(info, false, _operations, interResults); // now we are left with _operationsLeft operations // the results is saved in interResults // if we have not done with calculating the effective balance, quit. if (!info.doneCalculatingEffectiveBalance) { return false; } ( interResults.countedUntil,,, info.totalEffectiveModeratorDGDLastQuarter ) = intermediateResultsStorage().getIntermediateResults( getIntermediateResultsIdForGlobalRewards(info.previousQuarter, true) ); sumEffectiveBalance(info, true, _operationsLeft, interResults); // if we have not done with calculating the moderator effective balance, quit. if (!info.doneCalculatingModeratorEffectiveBalance) { return false; } // we have done the heavey calculation, now save the quarter info processGlobalRewardsUpdate(info); _done = true; emit StartNewQuarter(currentQuarterNumber()); } // get the Id for the intermediateResult for a quarter's global rewards calculation function getIntermediateResultsIdForGlobalRewards(uint256 _quarterNumber, bool _forModerator) internal view returns (bytes32 _id) { _id = keccak256(abi.encodePacked( _forModerator ? INTERMEDIATE_MODERATOR_DGD_IDENTIFIER : INTERMEDIATE_DGD_IDENTIFIER, _quarterNumber )); } // final step in calculateGlobalRewardsBeforeNewQuarter, which is to save the DaoQuarterInfo struct for this quarter function processGlobalRewardsUpdate(QuarterRewardsInfo memory info) internal { // calculate how much DGX rewards we got for this quarter info.dgxRewardsPoolLastQuarter = ERC20(ADDRESS_DGX_TOKEN).balanceOf(address(this)) .add(daoRewardsStorage().totalDGXsClaimed()) .sub(info.qInfo.sumRewardsFromBeginning); // starting new quarter, no one locked in DGDs yet daoStakeStorage().updateTotalLockedDGDStake(0); daoStakeStorage().updateTotalModeratorLockedDGDs(0); daoRewardsStorage().updateQuarterInfo( info.previousQuarter.add(1), getUintConfig(CONFIG_MINIMAL_QUARTER_POINT), getUintConfig(CONFIG_QUARTER_POINT_SCALING_FACTOR), getUintConfig(CONFIG_REPUTATION_POINT_SCALING_FACTOR), info.totalEffectiveDGDPreviousQuarter, getUintConfig(CONFIG_MODERATOR_MINIMAL_QUARTER_POINT), getUintConfig(CONFIG_MODERATOR_QUARTER_POINT_SCALING_FACTOR), getUintConfig(CONFIG_MODERATOR_REPUTATION_POINT_SCALING_FACTOR), info.totalEffectiveModeratorDGDLastQuarter, now, info.dgxRewardsPoolLastQuarter, info.qInfo.sumRewardsFromBeginning.add(info.dgxRewardsPoolLastQuarter) ); } // Sum the effective balance (could be effectiveDGDBalance or effectiveModeratorDGDBalance), given that we have _operations left function sumEffectiveBalance ( QuarterRewardsInfo memory info, bool _badgeCalculation, // false if this is the first step, true if its the second step uint256 _operations, DaoStructs.IntermediateResults memory _interResults ) internal returns (uint _operationsLeft) { if (_operations == 0) return _operations; // no more operations left, quit if (_interResults.countedUntil == EMPTY_ADDRESS) { // if this is the first time we are doing this calculation, we need to // get the list of the participants to calculate by querying the first _operations participants info.users = _badgeCalculation ? daoListingService().listModerators(_operations, true) : daoListingService().listParticipants(_operations, true); } else { info.users = _badgeCalculation ? daoListingService().listModeratorsFrom(_interResults.countedUntil, _operations, true) : daoListingService().listParticipantsFrom(_interResults.countedUntil, _operations, true); // if this list is the already empty, it means this is the first step (calculating effective balance), and its already done; if (info.users.length == 0) { info.doneCalculatingEffectiveBalance = true; return _operations; } } address _lastAddress; _lastAddress = info.users[info.users.length - 1]; info.userCount = info.users.length; for (info.i=0;info.i<info.userCount;info.i++) { info.currentUser = info.users[info.i]; // check if this participant really did participate in the previous quarter if (daoRewardsStorage().lastParticipatedQuarter(info.currentUser) != info.previousQuarter) { continue; } if (_badgeCalculation) { info.totalEffectiveModeratorDGDLastQuarter = info.totalEffectiveModeratorDGDLastQuarter.add(daoCalculatorService().calculateUserEffectiveBalance( info.qInfo.moderatorMinimalParticipationPoint, info.qInfo.moderatorQuarterPointScalingFactor, info.qInfo.moderatorReputationPointScalingFactor, daoPointsStorage().getQuarterModeratorPoint(info.currentUser, info.previousQuarter), daoPointsStorage().getReputation(info.currentUser), daoStakeStorage().lockedDGDStake(info.currentUser) )); } else { info.totalEffectiveDGDPreviousQuarter = info.totalEffectiveDGDPreviousQuarter.add(daoCalculatorService().calculateUserEffectiveBalance( info.qInfo.minimalParticipationPoint, info.qInfo.quarterPointScalingFactor, info.qInfo.reputationPointScalingFactor, daoPointsStorage().getQuarterPoint(info.currentUser, info.previousQuarter), daoPointsStorage().getReputation(info.currentUser), daoStakeStorage().lockedDGDStake(info.currentUser) )); } } // check if we have reached the last guy in the current list if (_lastAddress == daoStakeStorage().readLastModerator() && _badgeCalculation) { info.doneCalculatingModeratorEffectiveBalance = true; } if (_lastAddress == daoStakeStorage().readLastParticipant() && !_badgeCalculation) { info.doneCalculatingEffectiveBalance = true; } // save to the intermediateResult storage intermediateResultsStorage().setIntermediateResults( getIntermediateResultsIdForGlobalRewards(info.previousQuarter, _badgeCalculation), _lastAddress, 0,0, _badgeCalculation ? info.totalEffectiveModeratorDGDLastQuarter : info.totalEffectiveDGDPreviousQuarter ); _operationsLeft = _operations.sub(info.userCount); } } // File: contracts/interface/NumberCarbonVoting.sol pragma solidity ^0.4.25; contract NumberCarbonVoting { function voted(address _voter) public view returns (bool); } // File: contracts/interactive/DaoStakeLocking.sol pragma solidity ^0.4.25; /** @title Contract to handle staking/withdrawing of DGDs for participation in DAO @author Digix Holdings */ contract DaoStakeLocking is DaoCommon { event RedeemBadge(address indexed _user); event LockDGD(address indexed _user, uint256 _amount, uint256 _currentLockedDGDStake); event WithdrawDGD(address indexed _user, uint256 _amount, uint256 _currentLockedDGDStake); address public dgdToken; address public dgdBadgeToken; // carbonVoting1 refers to this carbon vote: https://digix.global/carbonvote/1/#/ // the contract is at: https://etherscan.io/address/0x9f56f330bceb9d4e756be94581298673e94ed592#code address public carbonVoting1; // carbonVoting2 refers to this carbon vote: https://digix.global/carbonvote/2/#/ // the contract is at: https://etherscan.io/address/0xdec6c0dc7004ba23940c9ee7cb4a0528ec4c0580#code address public carbonVoting2; // The two carbon votes implement the NumberCarbonVoting interface, which has a voted(address) function to find out // whether an address has voted in the carbon vote. // Addresses will be awarded a fixed amount of Reputation Point (CONFIG_CARBON_VOTE_REPUTATION_BONUS) for every carbon votes that they participated in struct StakeInformation { // this is the amount of DGDs that a user has actualy locked up uint256 userActualLockedDGD; // this is the DGDStake that the user get from locking up their DGDs. // this amount might be smaller than the userActualLockedDGD, because the user has locked some DGDs in the middle of the quarter // and those DGDs will not fetch as much DGDStake uint256 userLockedDGDStake; // this is the sum of everyone's DGD Stake uint256 totalLockedDGDStake; } constructor( address _resolver, address _dgdToken, address _dgdBadgeToken, address _carbonVoting1, address _carbonVoting2 ) public { require(init(CONTRACT_DAO_STAKE_LOCKING, _resolver)); dgdToken = _dgdToken; dgdBadgeToken = _dgdBadgeToken; carbonVoting1 = _carbonVoting1; carbonVoting2 = _carbonVoting2; } function daoCalculatorService() internal view returns (DaoCalculatorService _contract) { _contract = DaoCalculatorService(get_contract(CONTRACT_SERVICE_DAO_CALCULATOR)); } function daoRewardsManager() internal view returns (DaoRewardsManager _contract) { _contract = DaoRewardsManager(get_contract(CONTRACT_DAO_REWARDS_MANAGER)); } /** @notice Function to convert a DGD Badge to Reputation Points @dev The Badge holder can redeem the Badge anytime in the first quarter, or Otherwise, the participant must either lock/withdraw/continue in the current quarter first, before he can redeem a badge Only 1 DGD Badge is accepted from an address, so holders with multiple badges should either sell their other badges or redeem reputation to another address */ function redeemBadge() public { // should not have redeemed a badge require(!daoStakeStorage().redeemedBadge(msg.sender)); // Can only redeem a badge if the reputation has been updated to the previous quarter. // In other words, this holder must have called either lockDGD/withdrawDGD/confirmContinuedParticipation in this quarter (hence, rewards for last quarter was already calculated) // This is to prevent users from changing the Reputation point that would be used to calculate their rewards for the previous quarter. // Note that after lockDGD/withdrawDGD/confirmContinuedParticipation is called, the reputation is always updated to the previous quarter require( daoRewardsStorage().lastQuarterThatReputationWasUpdated(msg.sender) == (currentQuarterNumber() - 1) ); daoStakeStorage().redeemBadge(msg.sender); daoPointsStorage().increaseReputation(msg.sender, getUintConfig(CONFIG_REPUTATION_POINT_BOOST_FOR_BADGE)); // update moderator status StakeInformation memory _info = getStakeInformation(msg.sender); refreshModeratorStatus(msg.sender, _info, _info); // transfer the badge to this contract require(ERC20(dgdBadgeToken).transferFrom(msg.sender, address(this), 1)); emit RedeemBadge(msg.sender); } function lockDGD(uint256 _amount) public { require(_amount > 0); lockDGDInternal(_amount); } /** @notice Function to lock DGD tokens to participate in the DAO @dev Users must `approve` the DaoStakeLocking contract to transfer DGDs from them Contracts are not allowed to participate in DigixDAO @param _amount Amount of DGDs to lock */ function lockDGDInternal(uint256 _amount) internal ifGlobalRewardsSet(currentQuarterNumber()) { // msg.sender must be an EOA. Disallows any contract from participating in the DAO. require(msg.sender == tx.origin); StakeInformation memory _info = getStakeInformation(msg.sender); StakeInformation memory _newInfo = refreshDGDStake(msg.sender, _info); uint256 _additionalStake = 0; if (_amount > 0) _additionalStake = daoCalculatorService().calculateAdditionalLockedDGDStake(_amount); _newInfo.userActualLockedDGD = _newInfo.userActualLockedDGD.add(_amount); _newInfo.userLockedDGDStake = _newInfo.userLockedDGDStake.add(_additionalStake); _newInfo.totalLockedDGDStake = _newInfo.totalLockedDGDStake.add(_additionalStake); // This has to happen at least once before user can participate in next quarter daoRewardsManager().updateRewardsAndReputationBeforeNewQuarter(msg.sender); daoStakeStorage().updateUserDGDStake(msg.sender, _newInfo.userActualLockedDGD, _newInfo.userLockedDGDStake); //since Reputation is updated, we need to refresh moderator status refreshModeratorStatus(msg.sender, _info, _newInfo); uint256 _lastParticipatedQuarter = daoRewardsStorage().lastParticipatedQuarter(msg.sender); uint256 _currentQuarter = currentQuarterNumber(); // Note: there might be a case when user locked in very small amount A that is less than Minimum locked DGD // then, lock again in the middle of the quarter. This will not take into account that A was staked in earlier. Its as if A is only staked in now. // Its not ideal, but we will keep it this way. if (_newInfo.userLockedDGDStake >= getUintConfig(CONFIG_MINIMUM_LOCKED_DGD)) { daoStakeStorage().addToParticipantList(msg.sender); // this will not add a second duplicate of the address if its already there // if this is the first time we lock/unlock/continue in this quarter, save the previous lastParticipatedQuarter // the purpose of the previousLastParticipatedQuarter is so that, if this participant withdraw all his DGD after locking in, // we will revert his lastParticipatedQuarter to the previousLastParticipatedQuarter, so as to not screw up any calculation // that uses the lastParticipatedQuarter (for example, for calculating the Reputation penalty for not participating in a number of quarters) if (_lastParticipatedQuarter < _currentQuarter) { daoRewardsStorage().updatePreviousLastParticipatedQuarter(msg.sender, _lastParticipatedQuarter); daoRewardsStorage().updateLastParticipatedQuarter(msg.sender, _currentQuarter); } // if this is the first time they're locking tokens, ever, // reward them with bonus for carbon voting activity if (_lastParticipatedQuarter == 0) { rewardCarbonVotingBonus(msg.sender); } } else { // this participant doesnt have enough DGD to be a participant // Absolute: The lastParticipatedQuarter of this participant WILL NEVER be the current quarter // Otherwise, his lockedDGDStake must be above the CONFIG_MINIMUM_LOCKED_DGDd // Hence, the refreshDGDStake() function must have added _newInfo.userLockedDGDStake to _newInfo.totalLockedDGDStake // Since this participant is not counted as a participant, we need to deduct _newInfo.userLockedDGDStake from _newInfo.totalLockedDGDStake _newInfo.totalLockedDGDStake = _newInfo.totalLockedDGDStake.sub(_newInfo.userLockedDGDStake); daoStakeStorage().removeFromParticipantList(msg.sender); } daoStakeStorage().updateTotalLockedDGDStake(_newInfo.totalLockedDGDStake); // interaction happens last require(ERC20(dgdToken).transferFrom(msg.sender, address(this), _amount)); emit LockDGD(msg.sender, _amount, _newInfo.userLockedDGDStake); } /** @notice Function to withdraw DGD tokens from this contract (can only be withdrawn in the locking phase of quarter) @param _amount Number of DGD tokens to withdraw @return { "_success": "Boolean, true if the withdrawal was successful, revert otherwise" } */ function withdrawDGD(uint256 _amount) public ifGlobalRewardsSet(currentQuarterNumber()) { require(isLockingPhase() || daoUpgradeStorage().isReplacedByNewDao()); // If the DAO is already replaced, everyone is free to withdraw their DGDs anytime StakeInformation memory _info = getStakeInformation(msg.sender); StakeInformation memory _newInfo = refreshDGDStake(msg.sender, _info); // This address must have at least some DGDs locked in, to withdraw // Otherwise, its meaningless anw // This also makes sure that the first participation ever must be a lockDGD() call, to avoid unnecessary complications require(_info.userActualLockedDGD > 0); require(_info.userActualLockedDGD >= _amount); _newInfo.userActualLockedDGD = _newInfo.userActualLockedDGD.sub(_amount); _newInfo.userLockedDGDStake = _newInfo.userLockedDGDStake.sub(_amount); _newInfo.totalLockedDGDStake = _newInfo.totalLockedDGDStake.sub(_amount); //_newInfo.totalLockedDGDStake = _newInfo.totalLockedDGDStake.sub(_amount); // This has to happen at least once before user can participate in next quarter daoRewardsManager().updateRewardsAndReputationBeforeNewQuarter(msg.sender); //since Reputation is updated, we need to refresh moderator status refreshModeratorStatus(msg.sender, _info, _newInfo); uint256 _lastParticipatedQuarter = daoRewardsStorage().lastParticipatedQuarter(msg.sender); uint256 _currentQuarter = currentQuarterNumber(); if (_newInfo.userLockedDGDStake < getUintConfig(CONFIG_MINIMUM_LOCKED_DGD)) { // this participant doesnt have enough DGD to be a participant // if this participant has lock/unlock/continue in this quarter before, we need to revert the lastParticipatedQuarter to the previousLastParticipatedQuarter if (_lastParticipatedQuarter == _currentQuarter) { daoRewardsStorage().updateLastParticipatedQuarter(msg.sender, daoRewardsStorage().previousLastParticipatedQuarter(msg.sender)); } // if this participant is not counted as a participant, the totalLockedDGDStake should not take into account the userLockedDGDStake at all _newInfo.totalLockedDGDStake = _newInfo.totalLockedDGDStake.sub(_newInfo.userLockedDGDStake); daoStakeStorage().removeFromParticipantList(msg.sender); } else { // This participant still remains as a participant // if this is the first time we lock/unlock/continue in this quarter, save the previous lastParticipatedQuarter if (_lastParticipatedQuarter < _currentQuarter) { daoRewardsStorage().updatePreviousLastParticipatedQuarter(msg.sender, _lastParticipatedQuarter); daoRewardsStorage().updateLastParticipatedQuarter(msg.sender, _currentQuarter); } // the totalLockedDGDStake after refreshDGDStake() should decrease by _amount, since this guy withdraws _amount } daoStakeStorage().updateUserDGDStake(msg.sender, _newInfo.userActualLockedDGD, _newInfo.userLockedDGDStake); daoStakeStorage().updateTotalLockedDGDStake(_newInfo.totalLockedDGDStake); require(ERC20(dgdToken).transfer(msg.sender, _amount)); emit WithdrawDGD(msg.sender, _amount, _newInfo.userLockedDGDStake); } /** @notice Function to be called by someone who doesnt change their DGDStake for the next quarter to confirm that they're participating @dev This can be done in the middle of the quarter as well. If someone just lets their DGDs sit in the DAO, and don't call this function, they are not counted as a participant in the quarter. */ function confirmContinuedParticipation() public { lockDGDInternal(0); } /** @notice This function refreshes the DGD stake of a user before doing any staking action(locking/withdrawing/continuing) in a new quarter @dev We need to do this because sometimes, the user locked DGDs in the middle of the previous quarter. Hence, his DGDStake in the record now is not correct. Note that this function might be called in the middle of the current quarter as well. This has no effect if the user has already done some staking action in the current quarter _infoBefore has the user's current stake information _infoAfter will be the user's stake information after refreshing This function updates the totalLockedDGDStake as if, the _user is participating in this quarter Therefore, if the _user actually will not qualify as a participant, the caller of this function needs to deduct _infoAfter.userLockedDGDStake from _infoAfter.totalLockedDGDStake */ function refreshDGDStake(address _user, StakeInformation _infoBefore) internal view returns (StakeInformation memory _infoAfter) { _infoAfter.userLockedDGDStake = _infoBefore.userLockedDGDStake; _infoAfter.userActualLockedDGD = _infoBefore.userActualLockedDGD; _infoAfter.totalLockedDGDStake = _infoBefore.totalLockedDGDStake; // only need to refresh if this is the first refresh in this new quarter; uint256 _currentQuarter = currentQuarterNumber(); if (daoRewardsStorage().lastParticipatedQuarter(_user) < _currentQuarter) { _infoAfter.userLockedDGDStake = daoCalculatorService().calculateAdditionalLockedDGDStake(_infoBefore.userActualLockedDGD); _infoAfter.totalLockedDGDStake = _infoAfter.totalLockedDGDStake.add( _infoAfter.userLockedDGDStake ); } } /** @notice This function refreshes the Moderator status of a user, to be done right after ANY STEP where a user's reputation or DGDStake is changed @dev _infoBefore is the stake information of the user before this transaction, _infoAfter is the stake information after this transaction This function needs to: - add/remove addresses from the moderator list accordingly - adjust the totalModeratorLockedDGDStake accordingly as well */ function refreshModeratorStatus(address _user, StakeInformation _infoBefore, StakeInformation _infoAfter) internal { bool _alreadyParticipatedInThisQuarter = daoRewardsStorage().lastParticipatedQuarter(_user) == currentQuarterNumber(); uint256 _currentTotalModeratorLockedDGDs = daoStakeStorage().totalModeratorLockedDGDStake(); if (daoStakeStorage().isInModeratorsList(_user) == true) { // this participant was already in the moderator list if (_infoAfter.userLockedDGDStake < getUintConfig(CONFIG_MINIMUM_DGD_FOR_MODERATOR) || daoPointsStorage().getReputation(_user) < getUintConfig(CONFIG_MINIMUM_REPUTATION_FOR_MODERATOR)) { // this participant is no longer a moderator this quarter, should be removed // Throw if this is the last moderator. There must be at least one moderator in the moderator list. Otherwise calculateGlobalRewardsBeforeNewQuarter() will fail. // after replacing DAO, we will want all moderators to withdraw their DGDs, hence the check require( (daoStakeStorage().readTotalModerators() > 1) || (!isDaoNotReplaced()) ); daoStakeStorage().removeFromModeratorList(_user); // only need to deduct the dgdStake from the totalModeratorLockedDGDStake if this participant has participated in this quarter before this transaction if (_alreadyParticipatedInThisQuarter) { daoStakeStorage().updateTotalModeratorLockedDGDs( _currentTotalModeratorLockedDGDs.sub(_infoBefore.userLockedDGDStake) ); } } else { // this moderator was in the moderator list and still remains a moderator now if (_alreadyParticipatedInThisQuarter) { // if already participated in this quarter, just account for the difference in dgdStake daoStakeStorage().updateTotalModeratorLockedDGDs( _currentTotalModeratorLockedDGDs.sub(_infoBefore.userLockedDGDStake).add(_infoAfter.userLockedDGDStake) ); } else { // has not participated in this quarter before this transaction daoStakeStorage().updateTotalModeratorLockedDGDs( _currentTotalModeratorLockedDGDs.add(_infoAfter.userLockedDGDStake) ); } } } else { // was not in moderator list if (_infoAfter.userLockedDGDStake >= getUintConfig(CONFIG_MINIMUM_DGD_FOR_MODERATOR) && daoPointsStorage().getReputation(_user) >= getUintConfig(CONFIG_MINIMUM_REPUTATION_FOR_MODERATOR)) { daoStakeStorage().addToModeratorList(_user); daoStakeStorage().updateTotalModeratorLockedDGDs( _currentTotalModeratorLockedDGDs.add(_infoAfter.userLockedDGDStake) ); } } } /** @notice Get the actualLockedDGD and lockedDGDStake of a user, as well as the totalLockedDGDStake of all users */ function getStakeInformation(address _user) internal view returns (StakeInformation _info) { (_info.userActualLockedDGD, _info.userLockedDGDStake) = daoStakeStorage().readUserDGDStake(_user); _info.totalLockedDGDStake = daoStakeStorage().totalLockedDGDStake(); } /** @notice Reward the voters of carbon voting rounds with initial bonus reputation @dev This is only called when they're locking tokens for the first time, enough tokens to be a participant */ function rewardCarbonVotingBonus(address _user) internal { // if the bonus has already been given out once to this user, return if (daoStakeStorage().carbonVoteBonusClaimed(_user)) return; // for carbon voting 1, if voted, give out a bonus if (NumberCarbonVoting(carbonVoting1).voted(_user)) { daoPointsStorage().increaseReputation(_user, getUintConfig(CONFIG_CARBON_VOTE_REPUTATION_BONUS)); } // for carbon voting 2, if voted, give out a bonus if (NumberCarbonVoting(carbonVoting2).voted(_user)) { daoPointsStorage().increaseReputation(_user, getUintConfig(CONFIG_CARBON_VOTE_REPUTATION_BONUS)); } // we changed reputation, so we need to update the last quarter that reputation was updated // This is to take care of this situation: // Holder A locks DGD for the first time in quarter 5, gets some bonus RP for the carbon votes // Then, A withdraw all his DGDs right away. Essentially, he's not participating in quarter 5 anymore // Now, when he comes back at quarter 10, he should be deducted reputation for 5 quarters that he didnt participated in: from quarter 5 to quarter 9 daoRewardsStorage().updateLastQuarterThatReputationWasUpdated(msg.sender, currentQuarterNumber().sub(1)); // set that this user's carbon voting bonus has been given out daoStakeStorage().setCarbonVoteBonusClaimed(_user); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"constant":true,"inputs":[],"name":"resolver","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"lockDGD","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"dgdBadgeToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_configKey","type":"bytes32"}],"name":"getAddressConfig","outputs":[{"name":"_configValue","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"key","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_key","type":"bytes32"}],"name":"get_contract","outputs":[{"name":"_contract","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentTimeInQuarter","outputs":[{"name":"_currentT","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isMainPhase","outputs":[{"name":"_isMainPhase","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"confirmContinuedParticipation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isLockingPhase","outputs":[{"name":"_isLockingPhase","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentQuarterNumber","outputs":[{"name":"_quarterNumber","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_user","type":"address"}],"name":"isParticipant","outputs":[{"name":"_is","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_configKey","type":"bytes32"}],"name":"getBytesConfig","outputs":[{"name":"_configValue","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"withdrawDGD","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"carbonVoting1","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_configKey","type":"bytes32"}],"name":"getUintConfig","outputs":[{"name":"_configValue","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"dgdToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isDaoNotReplaced","outputs":[{"name":"_isNotReplaced","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CONTRACT_ADDRESS","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"redeemBadge","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_user","type":"address"}],"name":"isModerator","outputs":[{"name":"_is","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"carbonVoting2","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_resolver","type":"address"},{"name":"_dgdToken","type":"address"},{"name":"_dgdBadgeToken","type":"address"},{"name":"_carbonVoting1","type":"address"},{"name":"_carbonVoting2","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_user","type":"address"}],"name":"RedeemBadge","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_user","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"},{"indexed":false,"name":"_currentLockedDGDStake","type":"uint256"}],"name":"LockDGD","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_user","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"},{"indexed":false,"name":"_currentLockedDGDStake","type":"uint256"}],"name":"WithdrawDGD","type":"event"}]
Contract Creation Code
608060405260006001026003906000191690556000600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f70726f706f73616c5f73746174655f70726570726f706f73616c0000000000006005906000191690557f70726f706f73616c5f73746174655f64726166740000000000000000000000006006906000191690557f70726f706f73616c5f73746174655f6d6f6465726174656400000000000000006007906000191690557f70726f706f73616c5f73746174655f6f6e676f696e67000000000000000000006008906000191690557f70726f706f73616c5f73746174655f636c6f73656400000000000000000000006009906000191690557f70726f706f73616c5f73746174655f6172636869766564000000000000000000600a906000191690556001600b556002600c556003600d556001600e556002600f5560036010557f696e7465725f6467645f696400000000000000000000000000000000000000006011906000191690557f696e7465725f6d6f645f6467645f6964000000000000000000000000000000006012906000191690557f696e7465725f626f6e75735f63616c63756c6174696f6e5f69640000000000006013906000191690557f64616f00000000000000000000000000000000000000000000000000000000006014906000191690557f64616f3a7370656369616c3a70726f706f73616c0000000000000000000000006015906000191690557f64616f3a7374616b652d6c6f636b696e670000000000000000000000000000006016906000191690557f64616f3a766f74696e67000000000000000000000000000000000000000000006017906000191690557f64616f3a766f74696e673a636c61696d730000000000000000000000000000006018906000191690557f64616f3a73766f74696e673a636c61696d7300000000000000000000000000006019906000191690557f64616f3a6964656e746974790000000000000000000000000000000000000000601a906000191690557f64616f3a726577617264732d6d616e6167657200000000000000000000000000601b906000191690557f64616f3a726577617264732d6578747261730000000000000000000000000000601c906000191690557f64616f3a726f6c65730000000000000000000000000000000000000000000000601d906000191690557f64616f3a66756e64696e672d6d616e6167657200000000000000000000000000601e906000191690557f64616f3a77686974656c697374696e6700000000000000000000000000000000601f906000191690557f64616f3a696e666f726d6174696f6e00000000000000000000000000000000006020906000191690557f736572766963653a726f6c6500000000000000000000000000000000000000006021906000191690557f736572766963653a64616f3a696e666f000000000000000000000000000000006022906000191690557f736572766963653a64616f3a6c697374696e67000000000000000000000000006023906000191690557f736572766963653a64616f3a63616c63756c61746f72000000000000000000006024906000191690557f73746f726167653a64616f0000000000000000000000000000000000000000006025906000191690557f73746f726167653a64616f3a636f756e746572000000000000000000000000006026906000191690557f73746f726167653a64616f3a75706772616465000000000000000000000000006027906000191690557f73746f726167653a64616f3a6964656e746974790000000000000000000000006028906000191690557f73746f726167653a64616f3a706f696e747300000000000000000000000000006029906000191690557f73746f726167653a64616f3a7370656369616c00000000000000000000000000602a906000191690557f73746f726167653a64616f3a636f6e6669670000000000000000000000000000602b906000191690557f73746f726167653a64616f3a7374616b65000000000000000000000000000000602c906000191690557f73746f726167653a64616f3a7265776172647300000000000000000000000000602d906000191690557f73746f726167653a64616f3a77686974656c697374696e670000000000000000602e906000191690557f73746f726167653a696e7465726d6564696174653a726573756c747300000000602f906000191690557f743a6467640000000000000000000000000000000000000000000000000000006030906000191690557f743a6467780000000000000000000000000000000000000000000000000000006031906000191690557f743a6261646765000000000000000000000000000000000000000000000000006032906000191690556001603360006101000a81548160ff021916908360ff1602179055506002603360016101000a81548160ff021916908360ff1602179055506003603360026101000a81548160ff021916908360ff1602179055506004603360036101000a81548160ff021916908360ff1602179055506276a7006034557f6d696e5f6467645f7061727469636970616e74000000000000000000000000006035906000191690557f6d696e5f6467645f6d6f64657261746f720000000000000000000000000000006036906000191690557f6d696e5f72657075746174696f6e5f6d6f64657261746f7200000000000000006037906000191690557f6c6f636b696e675f70686173655f6475726174696f6e000000000000000000006038906000191690557f717561727465725f6475726174696f6e000000000000000000000000000000006039906000191690557f766f74696e675f636f6d6d69745f706861736500000000000000000000000000603a906000191690557f766f74696e675f70686173655f746f74616c0000000000000000000000000000603b906000191690557f696e746572696d5f766f74696e675f636f6d6d69745f70686173650000000000603c906000191690557f696e746572696d5f766f74696e675f70686173655f746f74616c000000000000603d906000191690557f64726166745f71756f72756d5f66697865645f6e756d657261746f7200000000603e906000191690557f64726166745f71756f72756d5f66697865645f64656e6f6d696e61746f720000603f906000191690557f64726166745f71756f72756d5f73666163746f725f6e756d657261746f7200006040906000191690557f64726166745f71756f72756d5f73666163746f725f64656e6f6d696e61746f726041906000191690557f766f74655f71756f72756d5f66697865645f6e756d657261746f7200000000006042906000191690557f766f74655f71756f72756d5f66697865645f64656e6f6d696e61746f720000006043906000191690557f766f74655f71756f72756d5f73666163746f725f6e756d657261746f720000006044906000191690557f766f74655f71756f72756d5f73666163746f725f64656e6f6d696e61746f72006045906000191690557f66696e616c5f7265776172645f73666163746f725f6e756d657261746f7200006046906000191690557f66696e616c5f7265776172645f73666163746f725f64656e6f6d696e61746f726047906000191690557f64726166745f71756f74615f6e756d657261746f7200000000000000000000006048906000191690557f64726166745f71756f74615f64656e6f6d696e61746f720000000000000000006049906000191690557f766f74696e675f71756f74615f6e756d657261746f7200000000000000000000604a906000191690557f766f74696e675f71756f74615f64656e6f6d696e61746f720000000000000000604b906000191690557f6d696e696d616c5f717000000000000000000000000000000000000000000000604c906000191690557f717561727465725f706f696e745f7363616c696e675f666163746f7200000000604d906000191690557f7265705f706f696e745f7363616c696e675f666163746f720000000000000000604e906000191690557f6d696e696d616c5f6d6f645f7170000000000000000000000000000000000000604f906000191690557f6d6f645f71705f7363616c696e675f666163746f7200000000000000000000006050906000191690557f6d6f645f7265705f706f696e745f7363616c696e675f666163746f72000000006051906000191690557f717561727465725f706f696e745f64726166745f766f746500000000000000006052906000191690557f717561727465725f706f696e745f766f746500000000000000000000000000006053906000191690557f717561727465725f706f696e745f696e746572696d5f766f74650000000000006054906000191690557f715f705f6d696c6573746f6e655f636f6d706c6574696f6e00000000000000006055906000191690557f626f6e75735f72657075746174696f6e5f6e756d657261746f720000000000006056906000191690557f626f6e75735f72657075746174696f6e5f64656e6f6d696e61746f72000000006057906000191690557f7370656369616c5f70726f706f73616c5f636f6d6d69745f70686173650000006058906000191690557f7370656369616c5f70726f706f73616c5f70686173655f746f74616c000000006059906000191690557f636f6e6669675f7370656369616c5f71756f74615f6e756d657261746f720000605a906000191690557f636f6e6669675f7370656369616c5f71756f74615f64656e6f6d696e61746f72605b906000191690557f7370656369616c5f71756f72756d5f6e756d657261746f720000000000000000605c906000191690557f7370656369616c5f71756f72756d5f64656e6f6d696e61746f72000000000000605d906000191690557f636f6e6669675f6d61785f72657075746174696f6e5f646564756374696f6e00605e906000191690557f636f6e6669675f70756e6973686d656e745f6e6f745f6c6f636b696e67000000605f906000191690557f636f6e6669675f7265705f7065725f65787472615f71705f6e756d00000000006060906000191690557f636f6e6669675f7265705f7065725f65787472615f71705f64656e00000000006061906000191690557f636f6e6669675f6d61785f6d5f72705f646564756374696f6e000000000000006062906000191690557f636f6e6669675f7265705f7065725f65787472615f6d5f71705f6e756d0000006063906000191690557f636f6e6669675f7265705f7065725f65787472615f6d5f71705f64656e0000006064906000191690557f636f6e6669675f6d6f645f706f7274696f6e5f6e756d000000000000000000006065906000191690557f636f6e6669675f6d6f645f706f7274696f6e5f64656e000000000000000000006066906000191690557f636f6e6669675f64726166745f766f74696e675f7068617365000000000000006067906000191690557f636f6e6669675f72705f626f6f73745f7065725f6261646765000000000000006068906000191690557f636f6e6669675f636c61696d696e675f646561646c696e6500000000000000006069906000191690557f636f6e6669675f70726570726f706f73616c5f636f6c6c61746572616c000000606a906000191690557f636f6e6669675f6d61785f66756e64696e675f6e6f6e44696769780000000000606b906000191690557f636f6e6669675f6d61785f6d696c6573746f6e65735f6e6f6e44696769780000606c906000191690557f636f6e6669675f6e6f6e44696769785f70726f706f73616c5f63617000000000606d906000191690557f636f6e6669675f646561645f6475726174696f6e000000000000000000000000606e906000191690557f636f6e6669675f63765f72657075746174696f6e000000000000000000000000606f906000191690553480156200113457600080fd5b5060405160a080620058ff83398101806040528101908080519060200190929190805190602001909291908051906020019092919080519060200190929190805190602001909291905050506200119d60165486620012b8640100000000026401000000009004565b1515620011a957600080fd5b83607060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082607160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081607260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080607360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505050505062001549565b6000808273ffffffffffffffffffffffffffffffffffffffff16636d19a8826040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156200132057600080fd5b505af115801562001335573d6000803e3d6000fd5b505050506040513d60208110156200134c57600080fd5b810190808051906020019092919050505090506000151581151514156200153d5730600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550826000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555083600181600019169055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c0f6ef4a600154600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083600019166000191681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b158015620014ea57600080fd5b505af1158015620014ff573d6000803e3d6000fd5b505050506040513d60208110156200151657600080fd5b810190808051906020019092919050505015156200153357600080fd5b6001915062001542565b600091505b5092915050565b6143a680620015596000396000f300608060405260043610610128576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806304f3bcec1461012d57806314efcd3c146101845780631b1e53ef146101b15780631d8ccd04146102085780633943380c146102795780633f83acff146102ac578063560a25ea1461031d578063685330601461034857806374cd7f6d146103775780637d6fed801461038e5780637f6a26b6146103bd578063929066f5146103e857806393ddad0814610443578063963cdbfd146104905780639bd71354146104bd578063b1e2b9dd14610514578063be6999c414610559578063d70d9358146105b0578063db4ecbc1146105df578063dda249f514610636578063fa6f39361461064d578063fbc28462146106a8575b600080fd5b34801561013957600080fd5b506101426106ff565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561019057600080fd5b506101af60048036038101908080359060200190929190505050610724565b005b3480156101bd57600080fd5b506101c661073f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561021457600080fd5b506102376004803603810190808035600019169060200190929190505050610765565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561028557600080fd5b5061028e610827565b60405180826000191660001916815260200191505060405180910390f35b3480156102b857600080fd5b506102db600480360381019080803560001916906020019092919050505061082d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561032957600080fd5b50610332610909565b6040518082815260200191505060405180910390f35b34801561035457600080fd5b5061035d610919565b604051808215151515815260200191505060405180910390f35b34801561038357600080fd5b5061038c610945565b005b34801561039a57600080fd5b506103a3610951565b604051808215151515815260200191505060405180910390f35b3480156103c957600080fd5b506103d261096c565b6040518082815260200191505060405180910390f35b3480156103f457600080fd5b50610429600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061097c565b604051808215151515815260200191505060405180910390f35b34801561044f57600080fd5b506104726004803603810190808035600019169060200190929190505050610b5d565b60405180826000191660001916815260200191505060405180910390f35b34801561049c57600080fd5b506104bb60048036038101908080359060200190929190505050610c1f565b005b3480156104c957600080fd5b506104d2611731565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561052057600080fd5b506105436004803603810190808035600019169060200190929190505050611757565b6040518082815260200191505060405180910390f35b34801561056557600080fd5b5061056e611819565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156105bc57600080fd5b506105c561183f565b604051808215151515815260200191505060405180910390f35b3480156105eb57600080fd5b506105f46118ed565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561064257600080fd5b5061064b611913565b005b34801561065957600080fd5b5061068e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611e48565b604051808215151515815260200191505060405180910390f35b3480156106b457600080fd5b506106bd61211b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008111151561073357600080fd5b61073c81612141565b50565b607160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600061076f612bea565b73ffffffffffffffffffffffffffffffffffffffff1663e6b39eab836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050602060405180830381600087803b1580156107e557600080fd5b505af11580156107f9573d6000803e3d6000fd5b505050506040513d602081101561080f57600080fd5b81019080805190602001909291905050509050919050565b60015481565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633f83acff836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050602060405180830381600087803b1580156108c757600080fd5b505af11580156108db573d6000803e3d6000fd5b505050506040513d60208110156108f157600080fd5b81019080805190602001909291905050509050919050565b600061091442612bfc565b905090565b600061092361183f565b80156109405750610935603854611757565b61093d610909565b10155b905090565b61094f6000612141565b565b600061095e603854611757565b610966610909565b10905090565b600061097742612ce5565b905090565b600061098661096c565b61098e612de8565b73ffffffffffffffffffffffffffffffffffffffff1663cefc2bff846040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015610a2857600080fd5b505af1158015610a3c573d6000803e3d6000fd5b505050506040513d6020811015610a5257600080fd5b8101908080519060200190929190505050148015610b565750610a76603554611757565b610a7e612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663cd094a27846040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015610b1857600080fd5b505af1158015610b2c573d6000803e3d6000fd5b505050506040513d6020811015610b4257600080fd5b810190808051906020019092919050505010155b9050919050565b6000610b67612bea565b73ffffffffffffffffffffffffffffffffffffffff1663c0a8405d836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050602060405180830381600087803b158015610bdd57600080fd5b505af1158015610bf1573d6000803e3d6000fd5b505050506040513d6020811015610c0757600080fd5b81019080805190602001909291905050509050919050565b610c27614358565b610c2f614358565b600080610c3a61096c565b6001811115610d03576000610c4d612de8565b73ffffffffffffffffffffffffffffffffffffffff1663a78e00d6836040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b158015610cbb57600080fd5b505af1158015610ccf573d6000803e3d6000fd5b505050506040513d6020811015610ce557600080fd5b8101908080519060200190929190505050111515610d0257600080fd5b5b610d0b610951565b80610db85750610d19612e0c565b73ffffffffffffffffffffffffffffffffffffffff16638bc865fd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015610d7c57600080fd5b505af1158015610d90573d6000803e3d6000fd5b505050506040513d6020811015610da657600080fd5b81019080805190602001909291905050505b1515610dc357600080fd5b610dcc33612e1e565b9450610dd83386612fd2565b935060008560000151111515610ded57600080fd5b85856000015110151515610e0057600080fd5b610e178685600001516131de90919063ffffffff16565b846000018181525050610e378685602001516131de90919063ffffffff16565b846020018181525050610e578685604001516131de90919063ffffffff16565b846040018181525050610e686131f7565b73ffffffffffffffffffffffffffffffffffffffff166349da49bc336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b158015610f0257600080fd5b505af1158015610f16573d6000803e3d6000fd5b50505050610f25338686613209565b610f2d612de8565b73ffffffffffffffffffffffffffffffffffffffff1663cefc2bff336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015610fc757600080fd5b505af1158015610fdb573d6000803e3d6000fd5b505050506040513d6020811015610ff157600080fd5b8101908080519060200190929190505050925061100c61096c565b9150611019603554611757565b846020015110156112d257818314156111cb57611034612de8565b73ffffffffffffffffffffffffffffffffffffffff1663927bb66833611058612de8565b73ffffffffffffffffffffffffffffffffffffffff1663bcda6424336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156110f257600080fd5b505af1158015611106573d6000803e3d6000fd5b505050506040513d602081101561111c57600080fd5b81019080805190602001909291905050506040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b1580156111b257600080fd5b505af11580156111c6573d6000803e3d6000fd5b505050505b6111e6846020015185604001516131de90919063ffffffff16565b8460400181815250506111f7612dfa565b73ffffffffffffffffffffffffffffffffffffffff166344d9bfe6336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561129157600080fd5b505af11580156112a5573d6000803e3d6000fd5b505050506040513d60208110156112bb57600080fd5b810190808051906020019092919050505050611460565b8183101561145f576112e2612de8565b73ffffffffffffffffffffffffffffffffffffffff1663863eb74a33856040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561138457600080fd5b505af1158015611398573d6000803e3d6000fd5b505050506113a4612de8565b73ffffffffffffffffffffffffffffffffffffffff1663927bb66833846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561144657600080fd5b505af115801561145a573d6000803e3d6000fd5b505050505b5b611468612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663ad5c464733866000015187602001516040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018381526020018281526020019350505050600060405180830381600087803b15801561151a57600080fd5b505af115801561152e573d6000803e3d6000fd5b5050505061153a612dfa565b73ffffffffffffffffffffffffffffffffffffffff16631538e68c85604001516040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1580156115ac57600080fd5b505af11580156115c0573d6000803e3d6000fd5b50505050607060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561168957600080fd5b505af115801561169d573d6000803e3d6000fd5b505050506040513d60208110156116b357600080fd5b810190808051906020019092919050505015156116cf57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff167f854445a9a1b2b97212d606c21f3640b8b15b514332fc52b957f9c93125a274a4878660200151604051808381526020018281526020019250505060405180910390a2505050505050565b607260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000611761612bea565b73ffffffffffffffffffffffffffffffffffffffff1663734c1168836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050602060405180830381600087803b1580156117d757600080fd5b505af11580156117eb573d6000803e3d6000fd5b505050506040513d602081101561180157600080fd5b81019080805190602001909291905050509050919050565b607060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000611849612e0c565b73ffffffffffffffffffffffffffffffffffffffff16638bc865fd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156118ac57600080fd5b505af11580156118c0573d6000803e3d6000fd5b505050506040513d60208110156118d657600080fd5b810190808051906020019092919050505015905090565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61191b614358565b611923612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663f01a13e1336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156119bd57600080fd5b505af11580156119d1573d6000803e3d6000fd5b505050506040513d60208110156119e757600080fd5b8101908080519060200190929190505050151515611a0457600080fd5b6001611a0e61096c565b03611a17612de8565b73ffffffffffffffffffffffffffffffffffffffff1663bd695d21336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611ab157600080fd5b505af1158015611ac5573d6000803e3d6000fd5b505050506040513d6020811015611adb57600080fd5b8101908080519060200190929190505050141515611af857600080fd5b611b00612dfa565b73ffffffffffffffffffffffffffffffffffffffff166303cc89b4336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b158015611b9a57600080fd5b505af1158015611bae573d6000803e3d6000fd5b50505050611bba613be1565b73ffffffffffffffffffffffffffffffffffffffff1663ded86d6833611be1606854611757565b6040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040805180830381600087803b158015611c6557600080fd5b505af1158015611c79573d6000803e3d6000fd5b505050506040513d6040811015611c8f57600080fd5b8101908080519060200190929190805190602001909291905050505050611cb533612e1e565b9050611cc2338283613209565b607160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd333060016040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b158015611dbc57600080fd5b505af1158015611dd0573d6000803e3d6000fd5b505050506040513d6020811015611de657600080fd5b81019080805190602001909291905050501515611e0257600080fd5b3373ffffffffffffffffffffffffffffffffffffffff167f212ab1ff1ffcea0692d08ce958ff341c42bca858661e7811a8bd71e5d7fcba4260405160405180910390a250565b6000611e5261096c565b611e5a612de8565b73ffffffffffffffffffffffffffffffffffffffff1663cefc2bff846040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611ef457600080fd5b505af1158015611f08573d6000803e3d6000fd5b505050506040513d6020811015611f1e57600080fd5b81019080805190602001909291905050501480156120225750611f42603654611757565b611f4a612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663cd094a27846040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611fe457600080fd5b505af1158015611ff8573d6000803e3d6000fd5b505050506040513d602081101561200e57600080fd5b810190808051906020019092919050505010155b80156121145750612034603754611757565b61203c613be1565b73ffffffffffffffffffffffffffffffffffffffff16639c89a0e2846040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156120d657600080fd5b505af11580156120ea573d6000803e3d6000fd5b505050506040513d602081101561210057600080fd5b810190808051906020019092919050505010155b9050919050565b607360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b612149614358565b612151614358565b600080600061215e61096c565b6001811115612227576000612171612de8565b73ffffffffffffffffffffffffffffffffffffffff1663a78e00d6836040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b1580156121df57600080fd5b505af11580156121f3573d6000803e3d6000fd5b505050506040513d602081101561220957600080fd5b810190808051906020019092919050505011151561222657600080fd5b5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561226157600080fd5b61226a33612e1e565b95506122763387612fd2565b94506000935060008711156123395761228d613bf3565b73ffffffffffffffffffffffffffffffffffffffff16630b3b1595886040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b1580156122fb57600080fd5b505af115801561230f573d6000803e3d6000fd5b505050506040513d602081101561232557600080fd5b810190808051906020019092919050505093505b612350878660000151613c0590919063ffffffff16565b856000018181525050612370848660200151613c0590919063ffffffff16565b856020018181525050612390848660400151613c0590919063ffffffff16565b8560400181815250506123a16131f7565b73ffffffffffffffffffffffffffffffffffffffff166349da49bc336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b15801561243b57600080fd5b505af115801561244f573d6000803e3d6000fd5b5050505061245b612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663ad5c464733876000015188602001516040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018381526020018281526020019350505050600060405180830381600087803b15801561250d57600080fd5b505af1158015612521573d6000803e3d6000fd5b50505050612530338787613209565b612538612de8565b73ffffffffffffffffffffffffffffffffffffffff1663cefc2bff336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156125d257600080fd5b505af11580156125e6573d6000803e3d6000fd5b505050506040513d60208110156125fc57600080fd5b8101908080519060200190929190505050925061261761096c565b9150612624603554611757565b85602001511015156128b357612638612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663e41b4c5c336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156126d257600080fd5b505af11580156126e6573d6000803e3d6000fd5b505050506040513d60208110156126fc57600080fd5b8101908080519060200190929190505050508183101561289b5761271e612de8565b73ffffffffffffffffffffffffffffffffffffffff1663863eb74a33856040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b1580156127c057600080fd5b505af11580156127d4573d6000803e3d6000fd5b505050506127e0612de8565b73ffffffffffffffffffffffffffffffffffffffff1663927bb66833846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561288257600080fd5b505af1158015612896573d6000803e3d6000fd5b505050505b60008314156128ae576128ad33613c21565b5b6129b6565b6128ce856020015186604001516131de90919063ffffffff16565b8560400181815250506128df612dfa565b73ffffffffffffffffffffffffffffffffffffffff166344d9bfe6336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561297957600080fd5b505af115801561298d573d6000803e3d6000fd5b505050506040513d60208110156129a357600080fd5b8101908080519060200190929190505050505b6129be612dfa565b73ffffffffffffffffffffffffffffffffffffffff16631538e68c86604001516040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b158015612a3057600080fd5b505af1158015612a44573d6000803e3d6000fd5b50505050607060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd33308a6040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b158015612b4157600080fd5b505af1158015612b55573d6000803e3d6000fd5b505050506040513d6020811015612b6b57600080fd5b81019080805190602001909291905050501515612b8757600080fd5b3373ffffffffffffffffffffffffffffffffffffffff167f31234eaf60e5e9eb15f098a26504dfe889551da611f4f904c9031e8b52382050888760200151604051808381526020018281526020019250505060405180910390a250505050505050565b6000612bf7602b5461082d565b905090565b6000612c06614292565b1515612c1157600080fd5b612c1c603954611757565b612cd4612c27612e0c565b73ffffffffffffffffffffffffffffffffffffffff1663d9c6bb206040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015612c8a57600080fd5b505af1158015612c9e573d6000803e3d6000fd5b505050506040513d6020811015612cb457600080fd5b8101908080519060200190929190505050846131de90919063ffffffff16565b811515612cdd57fe5b069050919050565b6000612cef614292565b1515612cfa57600080fd5b612de16001612dd3612d0d603954611757565b612dc5612d18612e0c565b73ffffffffffffffffffffffffffffffffffffffff1663d9c6bb206040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015612d7b57600080fd5b505af1158015612d8f573d6000803e3d6000fd5b505050506040513d6020811015612da557600080fd5b8101908080519060200190929190505050876131de90919063ffffffff16565b61434290919063ffffffff16565b613c0590919063ffffffff16565b9050919050565b6000612df5602d5461082d565b905090565b6000612e07602c5461082d565b905090565b6000612e1960275461082d565b905090565b612e26614358565b612e2e612dfa565b73ffffffffffffffffffffffffffffffffffffffff16635bdd2743836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019150506040805180830381600087803b158015612ec757600080fd5b505af1158015612edb573d6000803e3d6000fd5b505050506040513d6040811015612ef157600080fd5b810190808051906020019092919080519060200190929190505050826000018360200182815250828152505050612f26612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663abed029a6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015612f8957600080fd5b505af1158015612f9d573d6000803e3d6000fd5b505050506040513d6020811015612fb357600080fd5b8101908080519060200190929190505050816040018181525050919050565b612fda614358565b600082602001518260200181815250508260000151826000018181525050826040015182604001818152505061300e61096c565b905080613019612de8565b73ffffffffffffffffffffffffffffffffffffffff1663cefc2bff866040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156130b357600080fd5b505af11580156130c7573d6000803e3d6000fd5b505050506040513d60208110156130dd57600080fd5b810190808051906020019092919050505010156131d7576130fc613bf3565b73ffffffffffffffffffffffffffffffffffffffff16630b3b159584600001516040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b15801561316e57600080fd5b505af1158015613182573d6000803e3d6000fd5b505050506040513d602081101561319857600080fd5b81019080805190602001909291905050508260200181815250506131cd82602001518360400151613c0590919063ffffffff16565b8260400181815250505b5092915050565b60008282111515156131ec57fe5b818303905092915050565b6000613204601b5461082d565b905090565b60008061321461096c565b61321c612de8565b73ffffffffffffffffffffffffffffffffffffffff1663cefc2bff876040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156132b657600080fd5b505af11580156132ca573d6000803e3d6000fd5b505050506040513d60208110156132e057600080fd5b81019080805190602001909291905050501491506132fc612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663bf448a876040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561335f57600080fd5b505af1158015613373573d6000803e3d6000fd5b505050506040513d602081101561338957600080fd5b81019080805190602001909291905050509050600115156133a8612dfa565b73ffffffffffffffffffffffffffffffffffffffff166388954a6c876040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561344257600080fd5b505af1158015613456573d6000803e3d6000fd5b505050506040513d602081101561346c57600080fd5b81019080805190602001909291905050501515141561394d57613490603654611757565b8360200151108061358657506134a7603754611757565b6134af613be1565b73ffffffffffffffffffffffffffffffffffffffff16639c89a0e2876040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561354957600080fd5b505af115801561355d573d6000803e3d6000fd5b505050506040513d602081101561357357600080fd5b8101908080519060200190929190505050105b156137dd576001613595612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663e3bc96ba6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156135f857600080fd5b505af115801561360c573d6000803e3d6000fd5b505050506040513d602081101561362257600080fd5b81019080805190602001909291905050501180613644575061364261183f565b155b151561364f57600080fd5b613657612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663f2388b42866040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156136f157600080fd5b505af1158015613705573d6000803e3d6000fd5b505050506040513d602081101561371b57600080fd5b81019080805190602001909291905050505081156137d85761373b612dfa565b73ffffffffffffffffffffffffffffffffffffffff166391baa14461376d8660200151846131de90919063ffffffff16565b6040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1580156137bf57600080fd5b505af11580156137d3573d6000803e3d6000fd5b505050505b613948565b81156138a2576137eb612dfa565b73ffffffffffffffffffffffffffffffffffffffff166391baa14461383385602001516138258860200151866131de90919063ffffffff16565b613c0590919063ffffffff16565b6040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561388557600080fd5b505af1158015613899573d6000803e3d6000fd5b50505050613947565b6138aa612dfa565b73ffffffffffffffffffffffffffffffffffffffff166391baa1446138dc856020015184613c0590919063ffffffff16565b6040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561392e57600080fd5b505af1158015613942573d6000803e3d6000fd5b505050505b5b613bda565b613958603654611757565b836020015110158015613a515750613971603754611757565b613979613be1565b73ffffffffffffffffffffffffffffffffffffffff16639c89a0e2876040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015613a1357600080fd5b505af1158015613a27573d6000803e3d6000fd5b505050506040513d6020811015613a3d57600080fd5b810190808051906020019092919050505010155b15613bd957613a5e612dfa565b73ffffffffffffffffffffffffffffffffffffffff166303a996a1866040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015613af857600080fd5b505af1158015613b0c573d6000803e3d6000fd5b505050506040513d6020811015613b2257600080fd5b810190808051906020019092919050505050613b3c612dfa565b73ffffffffffffffffffffffffffffffffffffffff166391baa144613b6e856020015184613c0590919063ffffffff16565b6040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b158015613bc057600080fd5b505af1158015613bd4573d6000803e3d6000fd5b505050505b5b5050505050565b6000613bee60295461082d565b905090565b6000613c0060245461082d565b905090565b60008183019050828110151515613c1857fe5b80905092915050565b613c29612dfa565b73ffffffffffffffffffffffffffffffffffffffff16636d080338826040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015613cc357600080fd5b505af1158015613cd7573d6000803e3d6000fd5b505050506040513d6020811015613ced57600080fd5b810190808051906020019092919050505015613d085761428f565b607260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663aec2ccae826040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015613dc557600080fd5b505af1158015613dd9573d6000803e3d6000fd5b505050506040513d6020811015613def57600080fd5b810190808051906020019092919050505015613f0057613e0d613be1565b73ffffffffffffffffffffffffffffffffffffffff1663ded86d6882613e34606f54611757565b6040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040805180830381600087803b158015613eb857600080fd5b505af1158015613ecc573d6000803e3d6000fd5b505050506040513d6040811015613ee257600080fd5b81019080805190602001909291908051906020019092919050505050505b607360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663aec2ccae826040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015613fbd57600080fd5b505af1158015613fd1573d6000803e3d6000fd5b505050506040513d6020811015613fe757600080fd5b8101908080519060200190929190505050156140f857614005613be1565b73ffffffffffffffffffffffffffffffffffffffff1663ded86d688261402c606f54611757565b6040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040805180830381600087803b1580156140b057600080fd5b505af11580156140c4573d6000803e3d6000fd5b505050506040513d60408110156140da57600080fd5b81019080805190602001909291908051906020019092919050505050505b614100612de8565b73ffffffffffffffffffffffffffffffffffffffff166312d9b93933614137600161412961096c565b6131de90919063ffffffff16565b6040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b1580156141bc57600080fd5b505af11580156141d0573d6000803e3d6000fd5b505050506141dc612dfa565b73ffffffffffffffffffffffffffffffffffffffff16635515eb2c826040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b15801561427657600080fd5b505af115801561428a573d6000803e3d6000fd5b505050505b50565b60008061429d612e0c565b73ffffffffffffffffffffffffffffffffffffffff1663d9c6bb206040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561430057600080fd5b505af1158015614314573d6000803e3d6000fd5b505050506040513d602081101561432a57600080fd5b81019080805190602001909291905050501415905090565b6000818381151561434f57fe5b04905092915050565b60606040519081016040528060008152602001600081526020016000815250905600a165627a7a723058206176b0418a919026e5b54966c25f1b60b0a32151009fea4534e69ea8e16af3bc0029000000000000000000000000005f60ef7e1443f82ca7de947711f0966ca6e3b5000000000000000000000000e0b7927c4af23765cb51314a0e0521a9645f0e2a00000000000000000000000054bda709fed875224eae569bb6817d96ef7ed9ad0000000000000000000000009f56f330bceb9d4e756be94581298673e94ed592000000000000000000000000dec6c0dc7004ba23940c9ee7cb4a0528ec4c0580
Deployed Bytecode
0x608060405260043610610128576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806304f3bcec1461012d57806314efcd3c146101845780631b1e53ef146101b15780631d8ccd04146102085780633943380c146102795780633f83acff146102ac578063560a25ea1461031d578063685330601461034857806374cd7f6d146103775780637d6fed801461038e5780637f6a26b6146103bd578063929066f5146103e857806393ddad0814610443578063963cdbfd146104905780639bd71354146104bd578063b1e2b9dd14610514578063be6999c414610559578063d70d9358146105b0578063db4ecbc1146105df578063dda249f514610636578063fa6f39361461064d578063fbc28462146106a8575b600080fd5b34801561013957600080fd5b506101426106ff565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561019057600080fd5b506101af60048036038101908080359060200190929190505050610724565b005b3480156101bd57600080fd5b506101c661073f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561021457600080fd5b506102376004803603810190808035600019169060200190929190505050610765565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561028557600080fd5b5061028e610827565b60405180826000191660001916815260200191505060405180910390f35b3480156102b857600080fd5b506102db600480360381019080803560001916906020019092919050505061082d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561032957600080fd5b50610332610909565b6040518082815260200191505060405180910390f35b34801561035457600080fd5b5061035d610919565b604051808215151515815260200191505060405180910390f35b34801561038357600080fd5b5061038c610945565b005b34801561039a57600080fd5b506103a3610951565b604051808215151515815260200191505060405180910390f35b3480156103c957600080fd5b506103d261096c565b6040518082815260200191505060405180910390f35b3480156103f457600080fd5b50610429600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061097c565b604051808215151515815260200191505060405180910390f35b34801561044f57600080fd5b506104726004803603810190808035600019169060200190929190505050610b5d565b60405180826000191660001916815260200191505060405180910390f35b34801561049c57600080fd5b506104bb60048036038101908080359060200190929190505050610c1f565b005b3480156104c957600080fd5b506104d2611731565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561052057600080fd5b506105436004803603810190808035600019169060200190929190505050611757565b6040518082815260200191505060405180910390f35b34801561056557600080fd5b5061056e611819565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156105bc57600080fd5b506105c561183f565b604051808215151515815260200191505060405180910390f35b3480156105eb57600080fd5b506105f46118ed565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561064257600080fd5b5061064b611913565b005b34801561065957600080fd5b5061068e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611e48565b604051808215151515815260200191505060405180910390f35b3480156106b457600080fd5b506106bd61211b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008111151561073357600080fd5b61073c81612141565b50565b607160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600061076f612bea565b73ffffffffffffffffffffffffffffffffffffffff1663e6b39eab836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050602060405180830381600087803b1580156107e557600080fd5b505af11580156107f9573d6000803e3d6000fd5b505050506040513d602081101561080f57600080fd5b81019080805190602001909291905050509050919050565b60015481565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633f83acff836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050602060405180830381600087803b1580156108c757600080fd5b505af11580156108db573d6000803e3d6000fd5b505050506040513d60208110156108f157600080fd5b81019080805190602001909291905050509050919050565b600061091442612bfc565b905090565b600061092361183f565b80156109405750610935603854611757565b61093d610909565b10155b905090565b61094f6000612141565b565b600061095e603854611757565b610966610909565b10905090565b600061097742612ce5565b905090565b600061098661096c565b61098e612de8565b73ffffffffffffffffffffffffffffffffffffffff1663cefc2bff846040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015610a2857600080fd5b505af1158015610a3c573d6000803e3d6000fd5b505050506040513d6020811015610a5257600080fd5b8101908080519060200190929190505050148015610b565750610a76603554611757565b610a7e612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663cd094a27846040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015610b1857600080fd5b505af1158015610b2c573d6000803e3d6000fd5b505050506040513d6020811015610b4257600080fd5b810190808051906020019092919050505010155b9050919050565b6000610b67612bea565b73ffffffffffffffffffffffffffffffffffffffff1663c0a8405d836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050602060405180830381600087803b158015610bdd57600080fd5b505af1158015610bf1573d6000803e3d6000fd5b505050506040513d6020811015610c0757600080fd5b81019080805190602001909291905050509050919050565b610c27614358565b610c2f614358565b600080610c3a61096c565b6001811115610d03576000610c4d612de8565b73ffffffffffffffffffffffffffffffffffffffff1663a78e00d6836040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b158015610cbb57600080fd5b505af1158015610ccf573d6000803e3d6000fd5b505050506040513d6020811015610ce557600080fd5b8101908080519060200190929190505050111515610d0257600080fd5b5b610d0b610951565b80610db85750610d19612e0c565b73ffffffffffffffffffffffffffffffffffffffff16638bc865fd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015610d7c57600080fd5b505af1158015610d90573d6000803e3d6000fd5b505050506040513d6020811015610da657600080fd5b81019080805190602001909291905050505b1515610dc357600080fd5b610dcc33612e1e565b9450610dd83386612fd2565b935060008560000151111515610ded57600080fd5b85856000015110151515610e0057600080fd5b610e178685600001516131de90919063ffffffff16565b846000018181525050610e378685602001516131de90919063ffffffff16565b846020018181525050610e578685604001516131de90919063ffffffff16565b846040018181525050610e686131f7565b73ffffffffffffffffffffffffffffffffffffffff166349da49bc336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b158015610f0257600080fd5b505af1158015610f16573d6000803e3d6000fd5b50505050610f25338686613209565b610f2d612de8565b73ffffffffffffffffffffffffffffffffffffffff1663cefc2bff336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015610fc757600080fd5b505af1158015610fdb573d6000803e3d6000fd5b505050506040513d6020811015610ff157600080fd5b8101908080519060200190929190505050925061100c61096c565b9150611019603554611757565b846020015110156112d257818314156111cb57611034612de8565b73ffffffffffffffffffffffffffffffffffffffff1663927bb66833611058612de8565b73ffffffffffffffffffffffffffffffffffffffff1663bcda6424336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156110f257600080fd5b505af1158015611106573d6000803e3d6000fd5b505050506040513d602081101561111c57600080fd5b81019080805190602001909291905050506040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b1580156111b257600080fd5b505af11580156111c6573d6000803e3d6000fd5b505050505b6111e6846020015185604001516131de90919063ffffffff16565b8460400181815250506111f7612dfa565b73ffffffffffffffffffffffffffffffffffffffff166344d9bfe6336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561129157600080fd5b505af11580156112a5573d6000803e3d6000fd5b505050506040513d60208110156112bb57600080fd5b810190808051906020019092919050505050611460565b8183101561145f576112e2612de8565b73ffffffffffffffffffffffffffffffffffffffff1663863eb74a33856040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561138457600080fd5b505af1158015611398573d6000803e3d6000fd5b505050506113a4612de8565b73ffffffffffffffffffffffffffffffffffffffff1663927bb66833846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561144657600080fd5b505af115801561145a573d6000803e3d6000fd5b505050505b5b611468612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663ad5c464733866000015187602001516040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018381526020018281526020019350505050600060405180830381600087803b15801561151a57600080fd5b505af115801561152e573d6000803e3d6000fd5b5050505061153a612dfa565b73ffffffffffffffffffffffffffffffffffffffff16631538e68c85604001516040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1580156115ac57600080fd5b505af11580156115c0573d6000803e3d6000fd5b50505050607060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561168957600080fd5b505af115801561169d573d6000803e3d6000fd5b505050506040513d60208110156116b357600080fd5b810190808051906020019092919050505015156116cf57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff167f854445a9a1b2b97212d606c21f3640b8b15b514332fc52b957f9c93125a274a4878660200151604051808381526020018281526020019250505060405180910390a2505050505050565b607260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000611761612bea565b73ffffffffffffffffffffffffffffffffffffffff1663734c1168836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050602060405180830381600087803b1580156117d757600080fd5b505af11580156117eb573d6000803e3d6000fd5b505050506040513d602081101561180157600080fd5b81019080805190602001909291905050509050919050565b607060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000611849612e0c565b73ffffffffffffffffffffffffffffffffffffffff16638bc865fd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156118ac57600080fd5b505af11580156118c0573d6000803e3d6000fd5b505050506040513d60208110156118d657600080fd5b810190808051906020019092919050505015905090565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61191b614358565b611923612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663f01a13e1336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156119bd57600080fd5b505af11580156119d1573d6000803e3d6000fd5b505050506040513d60208110156119e757600080fd5b8101908080519060200190929190505050151515611a0457600080fd5b6001611a0e61096c565b03611a17612de8565b73ffffffffffffffffffffffffffffffffffffffff1663bd695d21336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611ab157600080fd5b505af1158015611ac5573d6000803e3d6000fd5b505050506040513d6020811015611adb57600080fd5b8101908080519060200190929190505050141515611af857600080fd5b611b00612dfa565b73ffffffffffffffffffffffffffffffffffffffff166303cc89b4336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b158015611b9a57600080fd5b505af1158015611bae573d6000803e3d6000fd5b50505050611bba613be1565b73ffffffffffffffffffffffffffffffffffffffff1663ded86d6833611be1606854611757565b6040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040805180830381600087803b158015611c6557600080fd5b505af1158015611c79573d6000803e3d6000fd5b505050506040513d6040811015611c8f57600080fd5b8101908080519060200190929190805190602001909291905050505050611cb533612e1e565b9050611cc2338283613209565b607160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd333060016040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b158015611dbc57600080fd5b505af1158015611dd0573d6000803e3d6000fd5b505050506040513d6020811015611de657600080fd5b81019080805190602001909291905050501515611e0257600080fd5b3373ffffffffffffffffffffffffffffffffffffffff167f212ab1ff1ffcea0692d08ce958ff341c42bca858661e7811a8bd71e5d7fcba4260405160405180910390a250565b6000611e5261096c565b611e5a612de8565b73ffffffffffffffffffffffffffffffffffffffff1663cefc2bff846040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611ef457600080fd5b505af1158015611f08573d6000803e3d6000fd5b505050506040513d6020811015611f1e57600080fd5b81019080805190602001909291905050501480156120225750611f42603654611757565b611f4a612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663cd094a27846040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015611fe457600080fd5b505af1158015611ff8573d6000803e3d6000fd5b505050506040513d602081101561200e57600080fd5b810190808051906020019092919050505010155b80156121145750612034603754611757565b61203c613be1565b73ffffffffffffffffffffffffffffffffffffffff16639c89a0e2846040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156120d657600080fd5b505af11580156120ea573d6000803e3d6000fd5b505050506040513d602081101561210057600080fd5b810190808051906020019092919050505010155b9050919050565b607360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b612149614358565b612151614358565b600080600061215e61096c565b6001811115612227576000612171612de8565b73ffffffffffffffffffffffffffffffffffffffff1663a78e00d6836040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b1580156121df57600080fd5b505af11580156121f3573d6000803e3d6000fd5b505050506040513d602081101561220957600080fd5b810190808051906020019092919050505011151561222657600080fd5b5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561226157600080fd5b61226a33612e1e565b95506122763387612fd2565b94506000935060008711156123395761228d613bf3565b73ffffffffffffffffffffffffffffffffffffffff16630b3b1595886040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b1580156122fb57600080fd5b505af115801561230f573d6000803e3d6000fd5b505050506040513d602081101561232557600080fd5b810190808051906020019092919050505093505b612350878660000151613c0590919063ffffffff16565b856000018181525050612370848660200151613c0590919063ffffffff16565b856020018181525050612390848660400151613c0590919063ffffffff16565b8560400181815250506123a16131f7565b73ffffffffffffffffffffffffffffffffffffffff166349da49bc336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b15801561243b57600080fd5b505af115801561244f573d6000803e3d6000fd5b5050505061245b612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663ad5c464733876000015188602001516040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018381526020018281526020019350505050600060405180830381600087803b15801561250d57600080fd5b505af1158015612521573d6000803e3d6000fd5b50505050612530338787613209565b612538612de8565b73ffffffffffffffffffffffffffffffffffffffff1663cefc2bff336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156125d257600080fd5b505af11580156125e6573d6000803e3d6000fd5b505050506040513d60208110156125fc57600080fd5b8101908080519060200190929190505050925061261761096c565b9150612624603554611757565b85602001511015156128b357612638612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663e41b4c5c336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156126d257600080fd5b505af11580156126e6573d6000803e3d6000fd5b505050506040513d60208110156126fc57600080fd5b8101908080519060200190929190505050508183101561289b5761271e612de8565b73ffffffffffffffffffffffffffffffffffffffff1663863eb74a33856040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b1580156127c057600080fd5b505af11580156127d4573d6000803e3d6000fd5b505050506127e0612de8565b73ffffffffffffffffffffffffffffffffffffffff1663927bb66833846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b15801561288257600080fd5b505af1158015612896573d6000803e3d6000fd5b505050505b60008314156128ae576128ad33613c21565b5b6129b6565b6128ce856020015186604001516131de90919063ffffffff16565b8560400181815250506128df612dfa565b73ffffffffffffffffffffffffffffffffffffffff166344d9bfe6336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561297957600080fd5b505af115801561298d573d6000803e3d6000fd5b505050506040513d60208110156129a357600080fd5b8101908080519060200190929190505050505b6129be612dfa565b73ffffffffffffffffffffffffffffffffffffffff16631538e68c86604001516040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b158015612a3057600080fd5b505af1158015612a44573d6000803e3d6000fd5b50505050607060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd33308a6040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b158015612b4157600080fd5b505af1158015612b55573d6000803e3d6000fd5b505050506040513d6020811015612b6b57600080fd5b81019080805190602001909291905050501515612b8757600080fd5b3373ffffffffffffffffffffffffffffffffffffffff167f31234eaf60e5e9eb15f098a26504dfe889551da611f4f904c9031e8b52382050888760200151604051808381526020018281526020019250505060405180910390a250505050505050565b6000612bf7602b5461082d565b905090565b6000612c06614292565b1515612c1157600080fd5b612c1c603954611757565b612cd4612c27612e0c565b73ffffffffffffffffffffffffffffffffffffffff1663d9c6bb206040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015612c8a57600080fd5b505af1158015612c9e573d6000803e3d6000fd5b505050506040513d6020811015612cb457600080fd5b8101908080519060200190929190505050846131de90919063ffffffff16565b811515612cdd57fe5b069050919050565b6000612cef614292565b1515612cfa57600080fd5b612de16001612dd3612d0d603954611757565b612dc5612d18612e0c565b73ffffffffffffffffffffffffffffffffffffffff1663d9c6bb206040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015612d7b57600080fd5b505af1158015612d8f573d6000803e3d6000fd5b505050506040513d6020811015612da557600080fd5b8101908080519060200190929190505050876131de90919063ffffffff16565b61434290919063ffffffff16565b613c0590919063ffffffff16565b9050919050565b6000612df5602d5461082d565b905090565b6000612e07602c5461082d565b905090565b6000612e1960275461082d565b905090565b612e26614358565b612e2e612dfa565b73ffffffffffffffffffffffffffffffffffffffff16635bdd2743836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019150506040805180830381600087803b158015612ec757600080fd5b505af1158015612edb573d6000803e3d6000fd5b505050506040513d6040811015612ef157600080fd5b810190808051906020019092919080519060200190929190505050826000018360200182815250828152505050612f26612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663abed029a6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015612f8957600080fd5b505af1158015612f9d573d6000803e3d6000fd5b505050506040513d6020811015612fb357600080fd5b8101908080519060200190929190505050816040018181525050919050565b612fda614358565b600082602001518260200181815250508260000151826000018181525050826040015182604001818152505061300e61096c565b905080613019612de8565b73ffffffffffffffffffffffffffffffffffffffff1663cefc2bff866040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156130b357600080fd5b505af11580156130c7573d6000803e3d6000fd5b505050506040513d60208110156130dd57600080fd5b810190808051906020019092919050505010156131d7576130fc613bf3565b73ffffffffffffffffffffffffffffffffffffffff16630b3b159584600001516040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b15801561316e57600080fd5b505af1158015613182573d6000803e3d6000fd5b505050506040513d602081101561319857600080fd5b81019080805190602001909291905050508260200181815250506131cd82602001518360400151613c0590919063ffffffff16565b8260400181815250505b5092915050565b60008282111515156131ec57fe5b818303905092915050565b6000613204601b5461082d565b905090565b60008061321461096c565b61321c612de8565b73ffffffffffffffffffffffffffffffffffffffff1663cefc2bff876040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156132b657600080fd5b505af11580156132ca573d6000803e3d6000fd5b505050506040513d60208110156132e057600080fd5b81019080805190602001909291905050501491506132fc612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663bf448a876040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561335f57600080fd5b505af1158015613373573d6000803e3d6000fd5b505050506040513d602081101561338957600080fd5b81019080805190602001909291905050509050600115156133a8612dfa565b73ffffffffffffffffffffffffffffffffffffffff166388954a6c876040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561344257600080fd5b505af1158015613456573d6000803e3d6000fd5b505050506040513d602081101561346c57600080fd5b81019080805190602001909291905050501515141561394d57613490603654611757565b8360200151108061358657506134a7603754611757565b6134af613be1565b73ffffffffffffffffffffffffffffffffffffffff16639c89a0e2876040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561354957600080fd5b505af115801561355d573d6000803e3d6000fd5b505050506040513d602081101561357357600080fd5b8101908080519060200190929190505050105b156137dd576001613595612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663e3bc96ba6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156135f857600080fd5b505af115801561360c573d6000803e3d6000fd5b505050506040513d602081101561362257600080fd5b81019080805190602001909291905050501180613644575061364261183f565b155b151561364f57600080fd5b613657612dfa565b73ffffffffffffffffffffffffffffffffffffffff1663f2388b42866040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156136f157600080fd5b505af1158015613705573d6000803e3d6000fd5b505050506040513d602081101561371b57600080fd5b81019080805190602001909291905050505081156137d85761373b612dfa565b73ffffffffffffffffffffffffffffffffffffffff166391baa14461376d8660200151846131de90919063ffffffff16565b6040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1580156137bf57600080fd5b505af11580156137d3573d6000803e3d6000fd5b505050505b613948565b81156138a2576137eb612dfa565b73ffffffffffffffffffffffffffffffffffffffff166391baa14461383385602001516138258860200151866131de90919063ffffffff16565b613c0590919063ffffffff16565b6040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561388557600080fd5b505af1158015613899573d6000803e3d6000fd5b50505050613947565b6138aa612dfa565b73ffffffffffffffffffffffffffffffffffffffff166391baa1446138dc856020015184613c0590919063ffffffff16565b6040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561392e57600080fd5b505af1158015613942573d6000803e3d6000fd5b505050505b5b613bda565b613958603654611757565b836020015110158015613a515750613971603754611757565b613979613be1565b73ffffffffffffffffffffffffffffffffffffffff16639c89a0e2876040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015613a1357600080fd5b505af1158015613a27573d6000803e3d6000fd5b505050506040513d6020811015613a3d57600080fd5b810190808051906020019092919050505010155b15613bd957613a5e612dfa565b73ffffffffffffffffffffffffffffffffffffffff166303a996a1866040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015613af857600080fd5b505af1158015613b0c573d6000803e3d6000fd5b505050506040513d6020811015613b2257600080fd5b810190808051906020019092919050505050613b3c612dfa565b73ffffffffffffffffffffffffffffffffffffffff166391baa144613b6e856020015184613c0590919063ffffffff16565b6040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b158015613bc057600080fd5b505af1158015613bd4573d6000803e3d6000fd5b505050505b5b5050505050565b6000613bee60295461082d565b905090565b6000613c0060245461082d565b905090565b60008183019050828110151515613c1857fe5b80905092915050565b613c29612dfa565b73ffffffffffffffffffffffffffffffffffffffff16636d080338826040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015613cc357600080fd5b505af1158015613cd7573d6000803e3d6000fd5b505050506040513d6020811015613ced57600080fd5b810190808051906020019092919050505015613d085761428f565b607260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663aec2ccae826040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015613dc557600080fd5b505af1158015613dd9573d6000803e3d6000fd5b505050506040513d6020811015613def57600080fd5b810190808051906020019092919050505015613f0057613e0d613be1565b73ffffffffffffffffffffffffffffffffffffffff1663ded86d6882613e34606f54611757565b6040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040805180830381600087803b158015613eb857600080fd5b505af1158015613ecc573d6000803e3d6000fd5b505050506040513d6040811015613ee257600080fd5b81019080805190602001909291908051906020019092919050505050505b607360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663aec2ccae826040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b158015613fbd57600080fd5b505af1158015613fd1573d6000803e3d6000fd5b505050506040513d6020811015613fe757600080fd5b8101908080519060200190929190505050156140f857614005613be1565b73ffffffffffffffffffffffffffffffffffffffff1663ded86d688261402c606f54611757565b6040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001925050506040805180830381600087803b1580156140b057600080fd5b505af11580156140c4573d6000803e3d6000fd5b505050506040513d60408110156140da57600080fd5b81019080805190602001909291908051906020019092919050505050505b614100612de8565b73ffffffffffffffffffffffffffffffffffffffff166312d9b93933614137600161412961096c565b6131de90919063ffffffff16565b6040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b1580156141bc57600080fd5b505af11580156141d0573d6000803e3d6000fd5b505050506141dc612dfa565b73ffffffffffffffffffffffffffffffffffffffff16635515eb2c826040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b15801561427657600080fd5b505af115801561428a573d6000803e3d6000fd5b505050505b50565b60008061429d612e0c565b73ffffffffffffffffffffffffffffffffffffffff1663d9c6bb206040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15801561430057600080fd5b505af1158015614314573d6000803e3d6000fd5b505050506040513d602081101561432a57600080fd5b81019080805190602001909291905050501415905090565b6000818381151561434f57fe5b04905092915050565b60606040519081016040528060008152602001600081526020016000815250905600a165627a7a723058206176b0418a919026e5b54966c25f1b60b0a32151009fea4534e69ea8e16af3bc0029
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000005f60ef7e1443f82ca7de947711f0966ca6e3b5000000000000000000000000E0B7927c4aF23765Cb51314A0E0521A9645F0E2A00000000000000000000000054BDa709FED875224EAe569bb6817d96ef7Ed9ad0000000000000000000000009f56f330bcEB9d4e756BE94581298673e94ED592000000000000000000000000DEC6c0Dc7004BA23940C9eE7cB4a0528Ec4C0580
-----Decoded View---------------
Arg [0] : _resolver (address): 0x005F60EF7E1443f82CA7de947711f0966ca6e3b5
Arg [1] : _dgdToken (address): 0xE0B7927c4aF23765Cb51314A0E0521A9645F0E2A
Arg [2] : _dgdBadgeToken (address): 0x54BDa709FED875224EAe569bb6817d96ef7Ed9ad
Arg [3] : _carbonVoting1 (address): 0x9f56f330bcEB9d4e756BE94581298673e94ED592
Arg [4] : _carbonVoting2 (address): 0xDEC6c0Dc7004BA23940C9eE7cB4a0528Ec4C0580
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000005f60ef7e1443f82ca7de947711f0966ca6e3b5
Arg [1] : 000000000000000000000000E0B7927c4aF23765Cb51314A0E0521A9645F0E2A
Arg [2] : 00000000000000000000000054BDa709FED875224EAe569bb6817d96ef7Ed9ad
Arg [3] : 0000000000000000000000009f56f330bcEB9d4e756BE94581298673e94ED592
Arg [4] : 000000000000000000000000DEC6c0Dc7004BA23940C9eE7cB4a0528Ec4C0580
Swarm Source
bzzr://6176b0418a919026e5b54966c25f1b60b0a32151009fea4534e69ea8e16af3bc
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.