Merged 172 changes, and set contracts.json to deploy required contracts
This commit is contained in:
commit
3476f96171
|
@ -14,4 +14,6 @@ Usage:
|
|||
| Contract | Deploy | Test | UI |
|
||||
| -------------------------------------- | ------ | ---- | --- |
|
||||
| token/TestToken | Yes | Yes | Yes |
|
||||
| token/ERC20Token | No | Yes | Yes |
|
||||
| token/ERC20Token | No | Yes | Yes |
|
||||
| deploy/Instance | No | No | No |
|
||||
| deploy/Factory | No | No | No |
|
|
@ -1,7 +1,7 @@
|
|||
import web3 from "Embark/web3"
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import React from 'react';
|
||||
import SNT from 'Embark/contracts/TestToken'; // TODO change this to SNT
|
||||
import SNT from 'Embark/contracts/SNT'; // TODO change this to SNT
|
||||
|
||||
class StatusBar extends React.Component {
|
||||
|
||||
|
|
|
@ -6,10 +6,12 @@ import EmbarkJS from 'Embark/EmbarkJS';
|
|||
import TopNavbar from './components/topnavbar';
|
||||
import TestTokenUI from './components/testtoken';
|
||||
import ERC20TokenUI from './components/erc20token';
|
||||
import ProposalManager from './components/proposalManager'
|
||||
|
||||
import ProposalManager from './components/proposal-manager/proposal-manager'
|
||||
import VotingDapp from './components/voting-dapp/voting-dapp';
|
||||
|
||||
import SNT from 'Embark/contracts/SNT';
|
||||
window['SNT'] = SNT;
|
||||
|
||||
import './dapp.css';
|
||||
|
||||
class App extends React.Component {
|
||||
|
|
|
@ -24,26 +24,18 @@
|
|||
"MiniMeTokenFactory": {
|
||||
"deploy": true
|
||||
},
|
||||
"FeeRecycler": {
|
||||
"deploy": false
|
||||
},
|
||||
"DelegationProxy": {
|
||||
"deploy": false
|
||||
},
|
||||
"DelegationProxyFactory": {
|
||||
"deploy": false
|
||||
},
|
||||
"Democracy": {
|
||||
"deploy": false
|
||||
},
|
||||
"DemocracyStorage": {
|
||||
"deploy": false
|
||||
"deploy": true
|
||||
},
|
||||
"ProposalManager": {
|
||||
"deploy": false
|
||||
},
|
||||
"TrustNetwork": {
|
||||
"deploy": false
|
||||
"deploy": true,
|
||||
"args": ["$DelegationProxyFactory"]
|
||||
},
|
||||
"Factory": {
|
||||
"deploy": false
|
||||
|
@ -72,6 +64,24 @@
|
|||
"TST",
|
||||
true
|
||||
]
|
||||
},
|
||||
"DelegationProxyView": {
|
||||
"deploy": false
|
||||
},
|
||||
"DelegationProxyKernel": {
|
||||
"deploy": false
|
||||
},
|
||||
"ProposalCuration": {
|
||||
"deploy": true,
|
||||
"args": ["$SNT", "$TrustNetwork"]
|
||||
},
|
||||
"Democracy": {
|
||||
"deploy": true,
|
||||
"args": [
|
||||
"$SNT",
|
||||
"$DelegationProxyFactory"
|
||||
],
|
||||
"gasLimit": 5000000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,14 +10,26 @@ import "./DelegationProxyInterface.sol";
|
|||
* @dev Creates a delegation proxy layer for MiniMeTokenInterface.
|
||||
*/
|
||||
contract DelegationProxy is DelegationProxyInterface {
|
||||
|
||||
//default delegation proxy, being used when user didn't set any delegation at this level.
|
||||
address public parentProxy;
|
||||
|
||||
//snapshots of changes, allow delegation changes be done at any time without compromising vote results.
|
||||
mapping (address => Delegation[]) public delegations;
|
||||
|
||||
//storage of indexes of the addresses to `delegations[to].from`
|
||||
mapping (address => uint256) toIndexes;
|
||||
|
||||
struct Delegation {
|
||||
uint128 fromBlock; //when this was updated
|
||||
address to; //who recieved this delegaton
|
||||
address[] from; //list of addresses that delegated to this address
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Calls Constructor
|
||||
*/
|
||||
function DelegationProxy(address _parentProxy) public {
|
||||
constructor(address _parentProxy) public {
|
||||
parentProxy = _parentProxy;
|
||||
}
|
||||
|
||||
|
@ -258,7 +270,7 @@ contract DelegationProxy is DelegationProxyInterface {
|
|||
*/
|
||||
function _updateDelegate(address _from, address _to) internal {
|
||||
require(delegationOfAt(_to, block.number) != msg.sender); //block impossible circular delegation
|
||||
Delegate(_from, _to);
|
||||
emit Delegate(_from, _to);
|
||||
Delegation memory _newFrom; //allocate memory
|
||||
Delegation[] storage fromHistory = delegations[_from];
|
||||
if (fromHistory.length > 0) { //have old config?
|
||||
|
|
|
@ -12,7 +12,7 @@ import "../deploy/Instance.sol";
|
|||
*/
|
||||
contract DelegationProxyFactory is Factory {
|
||||
|
||||
function DelegationProxyFactory()
|
||||
constructor()
|
||||
Factory(new DelegationProxyKernel())
|
||||
public
|
||||
{ }
|
||||
|
|
|
@ -5,17 +5,6 @@ import "../token/MiniMeTokenInterface.sol";
|
|||
|
||||
contract DelegationProxyInterface {
|
||||
|
||||
struct Delegation {
|
||||
uint128 fromBlock; //when this was updated
|
||||
address to; //who recieved this delegaton
|
||||
address[] from; //list of addresses that delegated to this address
|
||||
}
|
||||
|
||||
//default delegation proxy, being used when user didn't set any delegation at this level.
|
||||
address public parentProxy;
|
||||
//snapshots of changes, allow delegation changes be done at any time without compromising vote results.
|
||||
mapping (address => Delegation[]) public delegations;
|
||||
|
||||
event Delegate(address who, address to);
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,7 +14,7 @@ contract DelegationProxyKernel is InstanceStorage, DelegationProxyView {
|
|||
/**
|
||||
* @notice Constructor of the model - only knows about watchdog that can trigger upgrade
|
||||
*/
|
||||
function DelegationProxyKernel() DelegationProxy(0x0) public {
|
||||
constructor() DelegationProxyView(0x0) public {
|
||||
ready = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,12 +12,16 @@ contract DelegationProxyView is DelegationProxy {
|
|||
|
||||
//storage of preprocessed view of FinalDelegate
|
||||
mapping(bytes32 => FinalDelegate) public delegationView;
|
||||
|
||||
|
||||
struct FinalDelegate {
|
||||
address delegate;
|
||||
bool found;
|
||||
}
|
||||
|
||||
constructor(address _parentTopic) DelegationProxy(0x0) public {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Reads the final delegate of `_who` at block number `_block`.
|
||||
* @param _who Address to lookup.
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./DemocracyInterface.sol";
|
||||
import "../token/MiniMeTokenInterface.sol";
|
||||
import "./DelegationProxyFactory.sol";
|
||||
import "./TrustNetwork.sol";
|
||||
import "./ProposalCuration.sol";
|
||||
import "./ProposalManager.sol";
|
||||
import "./FeeRecycler.sol";
|
||||
|
||||
|
||||
contract Democracy is DemocracyInterface {
|
||||
contract Democracy {
|
||||
|
||||
MiniMeTokenInterface public token;
|
||||
TrustNetwork public trustNet;
|
||||
ProposalManager public proposalManager;
|
||||
|
||||
mapping (bytes32 => Allowance) topicAllowance;
|
||||
mapping (uint256 => bool) executedProposals;
|
||||
|
||||
|
@ -15,11 +21,10 @@ contract Democracy is DemocracyInterface {
|
|||
mapping(bytes32 => bool) calls;
|
||||
}
|
||||
|
||||
function Democracy(MiniMeTokenInterface _token, TrustNetworkInterface _trustNetwork) public {
|
||||
constructor(MiniMeTokenInterface _token, DelegationProxyFactory _delegationProxyFactory) public {
|
||||
token = _token;
|
||||
trustNet = _trustNetwork;
|
||||
feeCollector = new FeeRecycler(_token);
|
||||
proposalManager = new ProposalManager(_token, _trustNetwork, feeCollector);
|
||||
trustNet = new TrustNetwork(_delegationProxyFactory);
|
||||
proposalManager = new ProposalCuration(_token, trustNet).proposalManager();
|
||||
}
|
||||
|
||||
function allowTopicSpecific(bytes32 _topic, address _destination, bytes4 _allowedCall, bool allowance)
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./DemocracyStorage.sol";
|
||||
|
||||
/**
|
||||
* @title DemocracyInterface
|
||||
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
|
||||
*/
|
||||
contract DemocracyInterface is DemocracyStorage {
|
||||
|
||||
function executeProposal(
|
||||
uint256 _proposalId,
|
||||
address _destination,
|
||||
uint _value,
|
||||
bytes _data
|
||||
)
|
||||
external
|
||||
returns(bool success);
|
||||
|
||||
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../deploy/InstanceStorage.sol";
|
||||
import "../token/MiniMeTokenInterface.sol";
|
||||
import "./TrustNetworkInterface.sol";
|
||||
import "./ProposalManagerInterface.sol";
|
||||
import "./FeeCollector.sol";
|
||||
|
||||
/**
|
||||
* @title DemocracyStorage
|
||||
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
|
||||
* @dev Defines kernel vars that Kernel contract share with Instance.
|
||||
* Important to avoid overwriting wrong storage pointers is that
|
||||
* InstanceStorage should be always the first contract at heritance.
|
||||
*/
|
||||
contract DemocracyStorage is InstanceStorage {
|
||||
// protected zone start (InstanceStorage vars)
|
||||
MiniMeTokenInterface public token;
|
||||
TrustNetworkInterface public trustNet;
|
||||
ProposalManagerInterface public proposalManager;
|
||||
FeeCollector public feeCollector;
|
||||
// protected zone end
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
pragma solidity ^0.4.21;
|
||||
|
||||
/** @notice Interface for fee collector */
|
||||
contract FeeCollector {
|
||||
|
||||
/**
|
||||
* @notice Collect a fee from yourself in your address
|
||||
* @param _amount to be collected
|
||||
*/
|
||||
function collect(uint256 _amount) external;
|
||||
|
||||
/**
|
||||
* @notice Collect a fee from your address in name of someone
|
||||
* @param _from to which address fee will be registered to
|
||||
* @param _amount to be collected
|
||||
*/
|
||||
function collectFor(address _from, uint256 _amount) external;
|
||||
|
||||
/**
|
||||
* @notice Collect a fee from someone
|
||||
* @param _from who allowed collection
|
||||
* @param _amount to be collected
|
||||
*/
|
||||
function collectFrom(address _from, uint256 _amount) external;
|
||||
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../common/Controlled.sol";
|
||||
import "../token/ERC20Token.sol";
|
||||
import "../token/MiniMeTokenInterface.sol";
|
||||
import "./FeeCollector.sol";
|
||||
/**
|
||||
* @title FeeRecycler
|
||||
* @author Ricardo Guilherme Schmidt (Status Research & Development GmBH)
|
||||
* @dev Allow user selecting predefined destinations to where this fees will be invested
|
||||
*/
|
||||
contract FeeRecycler is Controlled, FeeCollector {
|
||||
|
||||
//allowed democratically choosen destinations
|
||||
mapping (address => bool) public destinations;
|
||||
//balances of users
|
||||
mapping (address => uint256) public balances;
|
||||
//used for withdrawing lost tokens
|
||||
uint256 public totalLocked;
|
||||
//base token
|
||||
MiniMeTokenInterface public token;
|
||||
|
||||
/**
|
||||
* @notice Constructor defines the unchangable (?) baseToken
|
||||
* @param _token base token
|
||||
*/
|
||||
function FeeRecycler(MiniMeTokenInterface _token) public {
|
||||
token = _token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Collect a fee from yourself in your address
|
||||
* @param _amount to be collected
|
||||
*/
|
||||
function collect(uint256 _amount) external {
|
||||
require(token.transferFrom(msg.sender, address(this), _amount));
|
||||
balances[msg.sender] += _amount;
|
||||
totalLocked += _amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Collect a fee from someone
|
||||
* @param _from who allowed collection
|
||||
* @param _amount to be collected
|
||||
*/
|
||||
function collectFrom(address _from, uint256 _amount) external {
|
||||
require(token.transferFrom(_from, address(this), _amount));
|
||||
balances[_from] += _amount;
|
||||
totalLocked += _amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Lock a fee in name of someone
|
||||
* @param _from who would be able to recycle this funds
|
||||
* @param _amount to be locked
|
||||
*/
|
||||
function collectFor(address _from, uint256 _amount) external {
|
||||
require(token.transferFrom(msg.sender, address(this), _amount));
|
||||
balances[_from] += _amount;
|
||||
totalLocked += _amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Unlock and approveAndCall
|
||||
* @param _to Allowed destination to get tokens
|
||||
* @param _amount that will be transfered
|
||||
*/
|
||||
function recycle(address _to, uint256 _amount) external {
|
||||
require(destinations[_to]);
|
||||
require(balances[msg.sender] >= _amount);
|
||||
balances[msg.sender] -= _amount;
|
||||
totalLocked -= _amount;
|
||||
token.approveAndCall(_to, _amount, new bytes(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Controller should enable destinations to recycle
|
||||
* @param _destination that would be available to recycle
|
||||
* @param _allowed users can recycle to this address?
|
||||
*/
|
||||
function setDestination(address _destination, bool _allowed)
|
||||
external
|
||||
onlyController
|
||||
{
|
||||
destinations[_destination] = _allowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Withdraw lost tokens in the contract
|
||||
* @param _token if is base token than can only transfer unlocked amount
|
||||
* @param _destination address receiving this tokens
|
||||
* @param _amount the amount to be transfered
|
||||
*/
|
||||
function withdraw(ERC20Token _token, address _destination, uint256 _amount)
|
||||
external
|
||||
onlyController
|
||||
{
|
||||
if (address(_token) == address(token)) {
|
||||
require(_amount <= _token.balanceOf(address(this)) - totalLocked);
|
||||
} else if (address(_token) == address(0)) {
|
||||
require(address(this).balance <= _amount);
|
||||
}
|
||||
if (address(_token) != address(0)) {
|
||||
_token.transfer(_destination, _amount);
|
||||
} else {
|
||||
_destination.transfer(_amount);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../common/Controlled.sol";
|
||||
import "../token/MiniMeTokenInterface.sol";
|
||||
import "./ProposalManager.sol";
|
||||
|
||||
contract ProposalCuration is Controlled {
|
||||
|
||||
uint256 public constant RESULT_NULL = 0;
|
||||
uint256 public constant RESULT_REJECT = 1;
|
||||
uint256 public constant RESULT_APPROVE = 2;
|
||||
uint256 public constant RESULT_VETO = 3;
|
||||
|
||||
mapping (uint256 => ProposalData) public proposals;
|
||||
ProposalManager public proposalManager;
|
||||
|
||||
uint256 public approvalTimeLimit;
|
||||
MiniMeTokenInterface token;
|
||||
|
||||
mapping (address => SubmitPrice) submitAllowances;
|
||||
|
||||
struct SubmitPrice {
|
||||
bool allowedSubmitter;
|
||||
uint256 stakePrice;
|
||||
}
|
||||
|
||||
struct ProposalData {
|
||||
address proposer;
|
||||
address to;
|
||||
uint256 value;
|
||||
bytes data;
|
||||
bytes description;
|
||||
uint256 stakedAmount;
|
||||
}
|
||||
|
||||
constructor(
|
||||
MiniMeTokenInterface _token,
|
||||
TrustNetworkInterface _trustNet
|
||||
)
|
||||
public
|
||||
{
|
||||
token = _token;
|
||||
proposalManager = new ProposalManager(_token, _trustNet);
|
||||
}
|
||||
|
||||
function submitProposal(
|
||||
bytes32 _topic,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes _data,
|
||||
bytes _description
|
||||
)
|
||||
external
|
||||
returns (uint256 proposalId)
|
||||
{
|
||||
uint256 submitPrice = getSubmitPrice(msg.sender);
|
||||
require(token.allowance(msg.sender, address(this)) >= submitPrice);
|
||||
require(token.transferFrom(msg.sender, address(this), submitPrice));
|
||||
proposalId = proposalManager.addProposal(_topic,keccak256(_to,_value,_data));
|
||||
proposals[proposalId] = ProposalData(
|
||||
msg.sender,
|
||||
_to,
|
||||
_value,
|
||||
_data,
|
||||
_description,
|
||||
submitPrice
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function withdrawStake(
|
||||
uint256 _proposalId
|
||||
)
|
||||
external
|
||||
{
|
||||
require(proposalManager.getProposalFinalResult(_proposalId) == RESULT_APPROVE);
|
||||
uint256 refundValue = proposals[_proposalId].stakedAmount;
|
||||
address refundAddress = proposals[_proposalId].proposer;
|
||||
delete proposals[_proposalId];
|
||||
if (refundValue > 0) {
|
||||
require(token.transfer(refundAddress, refundValue));
|
||||
}
|
||||
}
|
||||
|
||||
function slashStake(
|
||||
uint256 _proposalId
|
||||
)
|
||||
external
|
||||
{
|
||||
uint8 result = proposalManager.getProposalFinalResult(_proposalId);
|
||||
require(result == RESULT_REJECT || result == RESULT_VETO);
|
||||
uint256 refundValue = proposals[_proposalId].stakedAmount;
|
||||
delete proposals[_proposalId];
|
||||
if (refundValue > 0) {
|
||||
require(token.transfer(controller, refundValue));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function setSubmitPrice(address _who, bool _allowedSubmitter, uint256 _stakeValue)
|
||||
external
|
||||
onlyController
|
||||
{
|
||||
if (_allowedSubmitter) {
|
||||
submitAllowances[_who] = SubmitPrice(_allowedSubmitter, _stakeValue);
|
||||
} else {
|
||||
delete submitAllowances[_who];
|
||||
}
|
||||
}
|
||||
|
||||
function getSubmitPrice(address _who)
|
||||
public
|
||||
view
|
||||
returns (uint256 price)
|
||||
{
|
||||
SubmitPrice memory allowance = submitAllowances[_who];
|
||||
if(allowance.allowedSubmitter){
|
||||
return allowance.stakePrice;
|
||||
} else {
|
||||
allowance = submitAllowances[_who];
|
||||
require(allowance.allowedSubmitter);
|
||||
return allowance.stakePrice;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,83 +2,136 @@ pragma solidity ^0.4.21;
|
|||
|
||||
import "../common/Controlled.sol";
|
||||
import "../token/MiniMeTokenInterface.sol";
|
||||
import "./ProposalManagerInterface.sol";
|
||||
import "./TrustNetworkInterface.sol";
|
||||
import "./DelegationProxyInterface.sol";
|
||||
import "./TrustNetworkInterface.sol";
|
||||
|
||||
/**
|
||||
* @title ProposalManager
|
||||
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
|
||||
* Store the proposals, votes and tabulate results for Democracy
|
||||
*/
|
||||
contract ProposalManager is ProposalManagerInterface, Controlled {
|
||||
contract ProposalManager is Controlled {
|
||||
event ProposalSet(bytes32 indexed topic, uint256 proposalId, bytes32 txHash);
|
||||
event ProposalResult(uint256 proposalId, uint8 finalResult);
|
||||
|
||||
function ProposalManager(
|
||||
MiniMeTokenInterface _SNT,
|
||||
TrustNetworkInterface _trustNet,
|
||||
FeeCollector _feeCollector
|
||||
MiniMeTokenInterface public token;
|
||||
TrustNetworkInterface public trustNet;
|
||||
uint256 public tabulationBlockDelay;
|
||||
Proposal[] public proposals;
|
||||
|
||||
struct Proposal {
|
||||
bytes32 topic;
|
||||
bytes32 txHash;
|
||||
|
||||
uint blockStart;
|
||||
uint voteBlockEnd;
|
||||
|
||||
address[] voters;
|
||||
mapping(address => Vote) voteMap;
|
||||
|
||||
mapping(address => bool) tabulated;
|
||||
mapping(uint8 => uint256) results;
|
||||
Vote result;
|
||||
uint256 lastTabulationTimestamp;
|
||||
}
|
||||
|
||||
enum Vote {
|
||||
Null,
|
||||
Reject,
|
||||
Approve
|
||||
}
|
||||
|
||||
constructor(
|
||||
MiniMeTokenInterface _token,
|
||||
TrustNetworkInterface _trustNet
|
||||
)
|
||||
public
|
||||
{
|
||||
trustNet = _trustNet;
|
||||
token = _SNT;
|
||||
feeCollector = _feeCollector;
|
||||
token = _token;
|
||||
|
||||
}
|
||||
|
||||
function addProposal(
|
||||
bytes32 _topic,
|
||||
bytes32 _txHash,
|
||||
uint _visibilityFee
|
||||
bytes32 _txHash
|
||||
)
|
||||
public
|
||||
returns (uint proposalId)
|
||||
{
|
||||
require(_visibilityFee > minVisibilityFee);
|
||||
require(
|
||||
token.transferFrom(
|
||||
msg.sender,
|
||||
address(this),
|
||||
_visibilityFee
|
||||
)
|
||||
);
|
||||
token.approve(feeCollector, _visibilityFee);
|
||||
feeCollector.collectFor(msg.sender, _visibilityFee);
|
||||
proposalId = proposals.length++;
|
||||
Proposal storage p = proposals[proposalId];
|
||||
|
||||
p.topic = _topic;
|
||||
p.txHash = _txHash;
|
||||
p.visibilityFee = _visibilityFee;
|
||||
|
||||
p.blockStart = block.number + 1000; //will be replaced by configurations
|
||||
p.voteBlockEnd = p.blockStart + 10000; //dummy value
|
||||
p.vetoBlockEnd = p.voteBlockEnd + 5000; //dummy value
|
||||
emit ProposalSet(_topic, proposalId, _txHash, _visibilityFee);
|
||||
emit ProposalSet(_topic, proposalId, _txHash);
|
||||
}
|
||||
|
||||
function increaseProposalVisibility(
|
||||
uint _proposalId,
|
||||
uint256 _visibilityFee
|
||||
)
|
||||
external
|
||||
function voteProposal(uint _proposalId, Vote _vote)
|
||||
public
|
||||
{
|
||||
require(_visibilityFee > minVisibilityFee);
|
||||
require(
|
||||
token.transferFrom(
|
||||
msg.sender,
|
||||
address(this),
|
||||
_visibilityFee
|
||||
)
|
||||
);
|
||||
token.approve(feeCollector, _visibilityFee);
|
||||
feeCollector.collectFor(msg.sender, _visibilityFee);
|
||||
proposals[_proposalId].visibilityFee += _visibilityFee;
|
||||
Proposal memory p = proposals[_proposalId];
|
||||
emit ProposalSet(p.topic, _proposalId, p.txHash, p.visibilityFee);
|
||||
Proposal storage proposal = proposals[_proposalId];
|
||||
require(block.number >= proposal.blockStart);
|
||||
require(block.number <= proposal.voteBlockEnd);
|
||||
proposal.voteMap[msg.sender] = _vote;
|
||||
|
||||
}
|
||||
|
||||
function tabulateVote(uint _proposalId, address _delegator)
|
||||
public
|
||||
{
|
||||
Proposal storage proposal = proposals[_proposalId];
|
||||
require(block.number > proposal.voteBlockEnd);
|
||||
require(!proposal.tabulated[_delegator]);
|
||||
proposal.tabulated[_delegator] = true;
|
||||
Vote _vote = proposal.voteMap[_delegator];
|
||||
if(_vote == Vote.Null) {
|
||||
address delegate = trustNet.getVoteDelegation(proposal.topic).delegationOfAt(_delegator, proposal.voteBlockEnd);
|
||||
_vote = proposal.voteMap[delegate];
|
||||
}
|
||||
|
||||
if (_vote == Vote.Reject || _vote == Vote.Approve) {
|
||||
proposal.results[uint8(_vote)] += token.balanceOfAt(_delegator, proposal.voteBlockEnd);
|
||||
}
|
||||
proposal.lastTabulationTimestamp = block.timestamp;
|
||||
}
|
||||
|
||||
function finalResult(uint _proposalId)
|
||||
public
|
||||
{
|
||||
Proposal storage proposal = proposals[_proposalId];
|
||||
require(proposal.lastTabulationTimestamp + tabulationBlockDelay > block.number);
|
||||
require(proposal.result == Vote.Null);
|
||||
uint256 totalTokens = token.totalSupplyAt(proposal.voteBlockEnd);
|
||||
uint256 approvals = proposal.results[uint8(Vote.Approve)];
|
||||
uint256 approvalQuorum = (totalTokens / 2);
|
||||
if(approvals >= approvalQuorum) {
|
||||
proposal.result = Vote.Approve;
|
||||
} else {
|
||||
proposal.result = Vote.Reject;
|
||||
}
|
||||
emit ProposalResult(_proposalId, uint8(proposal.result));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function getProposalFinalResult(
|
||||
uint256 _proposalId
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (uint8)
|
||||
{
|
||||
|
||||
return uint8(proposals[_proposalId].result);
|
||||
}
|
||||
|
||||
function getProposal(uint _proposalId)
|
||||
public
|
||||
external
|
||||
view
|
||||
returns (
|
||||
bytes32 topic,
|
||||
|
@ -89,86 +142,21 @@ contract ProposalManager is ProposalManagerInterface, Controlled {
|
|||
Proposal memory p = proposals[_proposalId];
|
||||
return (p.topic, p.txHash, p.result == Vote.Approve);
|
||||
}
|
||||
|
||||
function getProposalTxHash(uint _proposalId)
|
||||
public
|
||||
|
||||
function offchainTabulateVoteResult(uint256 _proposalId)
|
||||
external
|
||||
view
|
||||
returns(bytes32)
|
||||
returns (uint256[] votes)
|
||||
{
|
||||
return proposals[_proposalId].txHash;
|
||||
}
|
||||
|
||||
function voteProposal(uint _proposalId, Vote _vote)
|
||||
public
|
||||
{
|
||||
Proposal storage proposal = proposals[_proposalId];
|
||||
require(block.number >= proposal.blockStart);
|
||||
if (_vote == Vote.Veto) {
|
||||
require(block.number <= proposal.vetoBlockEnd);
|
||||
} else {
|
||||
require(block.number <= proposal.voteBlockEnd);
|
||||
}
|
||||
|
||||
proposal.voteMap[msg.sender] = _vote;
|
||||
|
||||
}
|
||||
|
||||
function tabulateVote(uint _proposalId, address _delegator)
|
||||
public
|
||||
{
|
||||
Proposal storage proposal = proposals[_proposalId];
|
||||
require(block.number > proposal.voteBlockEnd);
|
||||
require(!proposal.tabulated[_delegator].vote);
|
||||
proposal.tabulated[_delegator].vote = true;
|
||||
Vote _vote = proposal.voteMap[_delegator];
|
||||
if(_vote == Vote.Null) {
|
||||
address delegate = trustNet.getVoteDelegation(proposal.topic).delegationOfAt(_delegator, proposal.vetoBlockEnd);
|
||||
_vote = proposal.voteMap[delegate];
|
||||
}
|
||||
|
||||
if (_vote == Vote.Reject || _vote == Vote.Approve) {
|
||||
proposal.results[uint8(_vote)] += token.balanceOfAt(_delegator, proposal.voteBlockEnd);
|
||||
}
|
||||
}
|
||||
|
||||
function tabulateVeto(uint _proposalId, address _delegator)
|
||||
public
|
||||
{
|
||||
Proposal storage proposal = proposals[_proposalId];
|
||||
require(block.number > proposal.vetoBlockEnd);
|
||||
require(!proposal.tabulated[_delegator].veto);
|
||||
proposal.tabulated[_delegator].veto = true;
|
||||
Vote _vote = proposal.voteMap[_delegator];
|
||||
if (_vote == Vote.Null) {
|
||||
address delegate = trustNet.getVetoDelegation(proposal.topic).delegationOfAt(_delegator, proposal.vetoBlockEnd);
|
||||
_vote = proposal.voteMap[delegate];
|
||||
}
|
||||
|
||||
if (_vote == Vote.Veto) {
|
||||
proposal.results[uint8(Vote.Veto)] += token.balanceOfAt(_delegator, proposal.vetoBlockEnd);
|
||||
Proposal memory proposal = proposals[_proposalId];
|
||||
address[] memory voters = proposal.voters;
|
||||
uint256 len = proposal.voters.length;
|
||||
votes = new uint256[](4);
|
||||
for(uint256 i = 0; i < len; i++) {
|
||||
address voter = proposal.voters[i];
|
||||
uint8 voteIndex = uint8(proposals[_proposalId].voteMap[voter]);
|
||||
votes[voteIndex] += trustNet.getVoteDelegation(proposal.topic).influenceOfAt(proposal.voters[i], token, proposal.voteBlockEnd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function finalResult(uint _proposalId)
|
||||
public
|
||||
{
|
||||
Proposal storage proposal = proposals[_proposalId];
|
||||
require(proposal.vetoBlockEnd + tabulationBlockDelay > block.number);
|
||||
require(proposal.result == Vote.Null);
|
||||
uint256 totalTokens = token.totalSupplyAt(proposal.vetoBlockEnd);
|
||||
uint256 approvals = proposal.results[uint8(Vote.Approve)];
|
||||
uint256 vetos = proposal.results[uint8(Vote.Veto)];
|
||||
uint256 approvalQuorum = (totalTokens / 2);
|
||||
uint256 vetoQuorum = (totalTokens / 3);
|
||||
if (vetos >= vetoQuorum) {
|
||||
proposal.result = Vote.Veto;
|
||||
} else if(approvals >= approvalQuorum) {
|
||||
proposal.result = Vote.Approve;
|
||||
} else {
|
||||
proposal.result = Vote.Reject;
|
||||
}
|
||||
emit ProposalResult(_proposalId, proposal.result);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/MiniMeTokenInterface.sol";
|
||||
import "./TrustNetworkInterface.sol";
|
||||
import "./DelegationProxyInterface.sol";
|
||||
import "./FeeCollector.sol";
|
||||
/**
|
||||
* @title ProposalManagerInterface
|
||||
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
|
||||
*/
|
||||
contract ProposalManagerInterface {
|
||||
|
||||
struct Proposal {
|
||||
bytes32 topic;
|
||||
bytes32 txHash;
|
||||
|
||||
uint visibilityFee;
|
||||
|
||||
uint blockStart;
|
||||
uint voteBlockEnd;
|
||||
uint vetoBlockEnd;
|
||||
|
||||
mapping(address => Vote) voteMap;
|
||||
mapping(address => Tabulations) tabulated;
|
||||
mapping(uint8 => uint256) results;
|
||||
|
||||
Vote result;
|
||||
}
|
||||
|
||||
struct Tabulations {
|
||||
bool vote;
|
||||
bool veto;
|
||||
}
|
||||
|
||||
enum Vote {
|
||||
Null,
|
||||
Reject,
|
||||
Approve,
|
||||
Veto
|
||||
}
|
||||
|
||||
TrustNetworkInterface public trustNet;
|
||||
MiniMeTokenInterface public token;
|
||||
FeeCollector public feeCollector;
|
||||
uint256 public tabulationBlockDelay;
|
||||
uint256 public minVisibilityFee = 1000;
|
||||
Proposal[] public proposals;
|
||||
|
||||
event ProposalSet(bytes32 indexed topic, uint256 _proposalId, bytes32 _txHash, uint256 _visibility);
|
||||
event ProposalResult(uint256 _proposalId, Vote finalResult);
|
||||
|
||||
function addProposal(bytes32 _topic, bytes32 _txHash, uint _visibilityFee) public returns (uint);
|
||||
function getProposal(uint _id) public view returns (bytes32 topic, bytes32 txHash, bool approved);
|
||||
function voteProposal(uint _proposal, Vote _vote) public;
|
||||
function tabulateVote(uint _proposal, address _delegator) public;
|
||||
function tabulateVeto(uint _proposal, address _delegator) public;
|
||||
function finalResult(uint _proposalId) public;
|
||||
}
|
|
@ -21,7 +21,7 @@ contract TrustNetwork is TrustNetworkInterface, Controlled {
|
|||
DelegationProxyInterface vetoDelegation;
|
||||
}
|
||||
|
||||
function TrustNetwork(address _delegationFactory) public {
|
||||
constructor(address _delegationFactory) public {
|
||||
delegationFactory = DelegationProxyFactory(_delegationFactory);
|
||||
topics[0x0] = newTopic(0x0, 0x0);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pragma solidity ^0.4.21;
|
||||
pragma solidity ^0.4.23;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -8,6 +8,10 @@ pragma solidity ^0.4.21;
|
|||
* Important to avoid overwriting wrong storage pointers is that never define storage to this contract
|
||||
*/
|
||||
contract DelegatedCall {
|
||||
|
||||
constructor() internal {
|
||||
|
||||
}
|
||||
/**
|
||||
* @dev delegates the call of this function
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pragma solidity ^0.4.17;
|
||||
pragma solidity ^0.4.23;
|
||||
|
||||
import "../common/Controlled.sol";
|
||||
|
||||
|
@ -19,7 +19,7 @@ contract Factory is Controlled {
|
|||
uint256 latestUpdate;
|
||||
address latestKernel;
|
||||
|
||||
function Factory(address _kernel)
|
||||
constructor(address _kernel)
|
||||
public
|
||||
{
|
||||
_setKernel(_kernel);
|
||||
|
|
|
@ -10,7 +10,7 @@ import "./DelegatedCall.sol";
|
|||
*/
|
||||
contract Instance is InstanceStorage, DelegatedCall {
|
||||
|
||||
function Instance(address _kernel) public {
|
||||
constructor(address _kernel) public {
|
||||
kernel = _kernel;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pragma solidity ^0.4.17;
|
||||
pragma solidity ^0.4.23;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -12,4 +12,5 @@ contract InstanceStorage {
|
|||
// protected zone start (InstanceStorage vars)
|
||||
address public kernel;
|
||||
// protected zone end
|
||||
constructor() internal { }
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
pragma solidity ^0.4.17;
|
||||
pragma solidity ^0.4.23;
|
||||
|
||||
import "./Instance.sol";
|
||||
|
||||
|
@ -12,7 +12,7 @@ contract UpdatableInstance is Instance {
|
|||
|
||||
event InstanceUpdated(address oldKernel, address newKernel);
|
||||
|
||||
function UpdatableInstance(address _kernel)
|
||||
constructor(address _kernel)
|
||||
Instance(_kernel)
|
||||
public
|
||||
{
|
||||
|
@ -21,7 +21,7 @@ contract UpdatableInstance is Instance {
|
|||
|
||||
function updateUpdatableInstance(address _kernel) external {
|
||||
require(msg.sender == address(this));
|
||||
InstanceUpdated(kernel, _kernel);
|
||||
emit InstanceUpdated(kernel, _kernel);
|
||||
kernel = _kernel;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ contract MiniMeToken is MiniMeTokenInterface, Controlled {
|
|||
|
||||
// `balances` is the map that tracks the balance of each address, in this
|
||||
// contract when the balance changes the block number that the change
|
||||
// occurred is also included in the map
|
||||
// occurred is also included in the map
|
||||
mapping (address => Checkpoint[]) balances;
|
||||
|
||||
// `allowed` tracks any extra transfer rights as in all ERC20 tokens
|
||||
|
|
|
@ -1,312 +1,320 @@
|
|||
const DelegationProxy = artifacts.require("DelegationProxy.sol")
|
||||
const MiniMeTokenFactory = artifacts.require("MiniMeTokenFactory.sol")
|
||||
const MiniMeToken = artifacts.require("MiniMeToken.sol")
|
||||
const TestUtils = require("./TestUtils.js")
|
||||
const utils = require("../utils/testUtils.js")
|
||||
|
||||
// TODO: This a very minimal set of tests purely for understanding the contract. I think they can be used though.
|
||||
contract("DelegationProxy", accounts => {
|
||||
|
||||
describe("DelegationProxy", async function() {
|
||||
this.timeout(0);
|
||||
//Initialize global/common contracts for all tests
|
||||
let accounts = [];
|
||||
|
||||
let delegationProxy = []
|
||||
const delegateTo = [
|
||||
[
|
||||
accounts[1],
|
||||
accounts[2],
|
||||
0x0
|
||||
],
|
||||
[
|
||||
0x0,
|
||||
accounts[2],
|
||||
0x0
|
||||
]
|
||||
]
|
||||
const delegationOf = [
|
||||
[
|
||||
accounts[2],
|
||||
accounts[2],
|
||||
accounts[2]
|
||||
],
|
||||
[
|
||||
accounts[0],
|
||||
accounts[2],
|
||||
accounts[2]
|
||||
]
|
||||
]
|
||||
let delegateTo = [[],[]]
|
||||
let delegationOf = [[],[]]
|
||||
let delegatedInfluence = [[],[]]
|
||||
let influence = [[],[]]
|
||||
|
||||
const delegatedInfluence = [
|
||||
[0, 1, 2],
|
||||
[0, 0, 1]
|
||||
]
|
||||
|
||||
const influence = [
|
||||
[0, 0, 3],
|
||||
[1, 0, 2]
|
||||
]
|
||||
let tokensBalance;
|
||||
|
||||
beforeEach(async () => {
|
||||
delegationProxy[0] = await DelegationProxy.new(0)
|
||||
delegationProxy[1] = await DelegationProxy.new(delegationProxy[0].address)
|
||||
before(function(done) {
|
||||
var contractsConfig = {
|
||||
"MiniMeTokenFactory": {
|
||||
},
|
||||
"MiniMeToken": {
|
||||
"args": [
|
||||
"$MiniMeTokenFactory",
|
||||
utils.zeroAddress,
|
||||
0,
|
||||
"TestMiniMeToken",
|
||||
18,
|
||||
"TST",
|
||||
true
|
||||
]
|
||||
},
|
||||
"DelegationProxy": {
|
||||
"args": [ 0 ]
|
||||
},
|
||||
"ChildDelegationProxy": {
|
||||
"instanceOf": "DelegationProxy",
|
||||
"args": [
|
||||
"$DelegationProxy"
|
||||
]
|
||||
}
|
||||
|
||||
};
|
||||
EmbarkSpec.deployAll(contractsConfig, async function(accountsArr) {
|
||||
accounts = accountsArr
|
||||
delegationProxy[0] = DelegationProxy
|
||||
delegationProxy[1] = ChildDelegationProxy
|
||||
delegateTo = [
|
||||
[
|
||||
accounts[1],
|
||||
accounts[2],
|
||||
0x0
|
||||
],
|
||||
[
|
||||
0x0,
|
||||
accounts[2],
|
||||
0x0
|
||||
]
|
||||
]
|
||||
delegationOf = [
|
||||
[
|
||||
accounts[2],
|
||||
accounts[2],
|
||||
accounts[2]
|
||||
],
|
||||
[
|
||||
accounts[0],
|
||||
accounts[2],
|
||||
accounts[2]
|
||||
]
|
||||
]
|
||||
|
||||
delegatedInfluence = [
|
||||
[0, 1, 2],
|
||||
[0, 0, 1]
|
||||
]
|
||||
|
||||
influence = [
|
||||
[0, 0, 3],
|
||||
[1, 0, 2]
|
||||
]
|
||||
|
||||
tokensBalance = 1000
|
||||
|
||||
for(i=0;i<accounts.length;i++){
|
||||
await MiniMeToken.methods.generateTokens(accounts[i], tokensBalance).send({from: accounts[0]})
|
||||
}
|
||||
done()
|
||||
});
|
||||
})
|
||||
|
||||
describe("delegate(address _to)", () => {
|
||||
|
||||
it("creates Delegate Log event", async () => {
|
||||
const i = 0
|
||||
const j = 0
|
||||
delegationProxy[i].delegate(delegateTo[i][j], {from: accounts[j]})
|
||||
const delegateArgs = await TestUtils.listenForEvent(delegationProxy[i].Delegate())
|
||||
assert.equal(delegateArgs.who, accounts[j], "["+i+","+j+"] Delegate Log shows delegating from isn't sender")
|
||||
assert.equal(delegateArgs.to, delegateTo[i][j], "["+i+","+j+"]Delegate Log shows delegating to isn't passed address")
|
||||
|
||||
})
|
||||
|
||||
it("updates delegations mapping with new delegate", async () => {
|
||||
const i = 0
|
||||
const j = 0
|
||||
await delegationProxy[i].delegate(delegateTo[i][j], {from: accounts[j]})
|
||||
const delegations = await delegationProxy[i].delegations.call(accounts[j], 0)
|
||||
assert.equal(delegations[0].c, web3.eth.blockNumber, "["+i+","+j+"] Delegations block number is incorrect")
|
||||
assert.equal(delegations[1], delegateTo[i][j], "["+i+","+j+"] Delegations to account is incorrect")
|
||||
})
|
||||
|
||||
it("stores delegation checkpoints correctly", async () => {
|
||||
const delegateTo2 = [
|
||||
[
|
||||
0x0,
|
||||
accounts[0],
|
||||
accounts[0]
|
||||
],
|
||||
[
|
||||
accounts[2],
|
||||
0x0,
|
||||
accounts[1]
|
||||
]
|
||||
]
|
||||
|
||||
const delegationOf2 = [
|
||||
[
|
||||
accounts[0],
|
||||
accounts[0],
|
||||
accounts[0]
|
||||
],
|
||||
[
|
||||
accounts[1],
|
||||
accounts[1],
|
||||
accounts[1]
|
||||
]
|
||||
]
|
||||
|
||||
const delegateTo3 = [
|
||||
[
|
||||
0x0,
|
||||
0x0,
|
||||
0x0
|
||||
],
|
||||
[
|
||||
0x0,
|
||||
0x0,
|
||||
0x0
|
||||
]
|
||||
]
|
||||
|
||||
const delegationOf3 = [
|
||||
[
|
||||
accounts[0],
|
||||
accounts[1],
|
||||
accounts[2]
|
||||
],
|
||||
[
|
||||
accounts[0],
|
||||
accounts[1],
|
||||
accounts[2]
|
||||
]
|
||||
]
|
||||
|
||||
for (var i = 0; i < delegateTo.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
await delegationProxy[i].delegate(delegateTo[i][j], {from: accounts[j]});
|
||||
}
|
||||
}
|
||||
const blockn1 = web3.eth.blockNumber
|
||||
|
||||
for (var i = 0; i < delegateTo2.length; i++) {
|
||||
for (var j = 0; j < delegateTo2[i].length; j++) {
|
||||
await delegationProxy[i].delegate(delegateTo2[i][j], {from: accounts[j]});
|
||||
}
|
||||
}
|
||||
const blockn2 = web3.eth.blockNumber
|
||||
|
||||
for (var i = 0; i < delegateTo3.length; i++) {
|
||||
for (var j = 0; j < delegateTo3[i].length; j++) {
|
||||
await delegationProxy[i].delegate(delegateTo3[i][j], {from: accounts[j]});
|
||||
}
|
||||
}
|
||||
const blockn3 = web3.eth.blockNumber
|
||||
|
||||
for (var i = 0; i < delegateTo.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
assert.equal(
|
||||
await delegationProxy[i].delegatedToAt(accounts[j], blockn1),
|
||||
delegateTo[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegatedToAt("+accounts[j]+", +"+blockn1+") is incorrect")
|
||||
assert.equal(
|
||||
await delegationProxy[i].delegatedToAt(accounts[j], blockn2),
|
||||
delegateTo2[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegatedToAt("+accounts[j]+", +"+blockn2+") is incorrect")
|
||||
assert.equal(
|
||||
await delegationProxy[i].delegatedToAt(accounts[j], blockn3),
|
||||
delegateTo3[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegatedToAt("+accounts[j]+", +"+blockn3+") is incorrect")
|
||||
|
||||
assert.equal(
|
||||
await delegationProxy[i].delegationOfAt(accounts[j], blockn1),
|
||||
delegationOf[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegationOfAt("+accounts[j]+", +"+blockn1+") is incorrect")
|
||||
assert.equal(
|
||||
await delegationProxy[i].delegationOfAt(accounts[j], blockn2),
|
||||
delegationOf2[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegationOfAt("+accounts[j]+", +"+blockn2+") is incorrect")
|
||||
assert.equal(
|
||||
await delegationProxy[i].delegationOfAt(accounts[j], blockn3),
|
||||
delegationOf3[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegationOfAt("+accounts[j]+", +"+blockn3+") is incorrect")
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
it("delegates back to parentProxy", async () => {
|
||||
for (var i = 0; i < delegateTo.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
await delegationProxy[i].delegate(delegateTo[i][j], {from: accounts[j]});
|
||||
}
|
||||
}
|
||||
const blockn1 = web3.eth.blockNumber
|
||||
|
||||
for (var j = 0; j < delegateTo[1].length; j++) {
|
||||
await delegationProxy[1].delegate(delegationProxy[0].address, {from: accounts[j]});
|
||||
}
|
||||
|
||||
const blockn2 = web3.eth.blockNumber
|
||||
|
||||
for (var j = 0; j < delegateTo[1].length; j++) {
|
||||
assert.equal(
|
||||
await delegationProxy[1].delegatedToAt(accounts[j], blockn1),
|
||||
delegateTo[1][j],
|
||||
"["+j+"] +"+delegationProxy[1].address+".delegatedToAt("+accounts[j]+", +"+blockn1+") is incorrect")
|
||||
assert.equal(
|
||||
await delegationProxy[1].delegatedToAt(accounts[j], blockn2),
|
||||
delegateTo[0][j],
|
||||
"["+j+"] +"+delegationProxy[1].address+".delegatedToAt("+accounts[j]+", +"+blockn2+") is incorrect")
|
||||
it("creates Delegate Log event", async function () {
|
||||
const i = 0
|
||||
const j = 0
|
||||
let result = await delegationProxy[i].methods.delegate(delegateTo[i][j]).send({from: accounts[j]})
|
||||
const delegateArgs = result.events.Delegate.returnValues;
|
||||
assert.equal(delegateArgs.who, accounts[j], "["+i+","+j+"] Delegate Log shows delegating from isn't sender. " + delegateArgs.who + " != " + accounts[j])
|
||||
assert.equal(delegateArgs.to, delegateTo[i][j], "["+i+","+j+"]Delegate Log shows delegating to isn't passed address")
|
||||
|
||||
})
|
||||
|
||||
it("updates delegations mapping with new delegate", async function () {
|
||||
const i = 0
|
||||
const j = 0
|
||||
let result = await delegationProxy[i].methods.delegate(delegateTo[i][j]).send({from: accounts[j]})
|
||||
let delegations = await delegationProxy[i].methods.delegations(accounts[j], 1).call()
|
||||
assert.equal(delegations[0], result.blockNumber, "["+i+","+j+"] Delegations block number is incorrect. " + delegations[0] + ' != ' + result.blockNumber)
|
||||
assert.equal(delegations[1], delegateTo[i][j], "["+i+","+j+"] Delegations to account is incorrect")
|
||||
})
|
||||
|
||||
it("stores delegation checkpoints correctly", async function () {
|
||||
const delegateTo2 = [
|
||||
[
|
||||
0x0,
|
||||
accounts[0],
|
||||
accounts[0]
|
||||
],
|
||||
[
|
||||
accounts[2],
|
||||
0x0,
|
||||
accounts[1]
|
||||
]
|
||||
]
|
||||
|
||||
const delegationOf2 = [
|
||||
[
|
||||
accounts[0],
|
||||
accounts[0],
|
||||
accounts[0]
|
||||
],
|
||||
[
|
||||
accounts[1],
|
||||
accounts[1],
|
||||
accounts[1]
|
||||
]
|
||||
]
|
||||
|
||||
const delegateTo3 = [
|
||||
[
|
||||
0x0,
|
||||
0x0,
|
||||
0x0
|
||||
],
|
||||
[
|
||||
0x0,
|
||||
0x0,
|
||||
0x0
|
||||
]
|
||||
]
|
||||
|
||||
const delegationOf3 = [
|
||||
[
|
||||
accounts[0],
|
||||
accounts[1],
|
||||
accounts[2]
|
||||
],
|
||||
[
|
||||
accounts[0],
|
||||
accounts[1],
|
||||
accounts[2]
|
||||
]
|
||||
]
|
||||
|
||||
for (var i = 0; i < delegateTo.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
await delegationProxy[i].methods.delegate(delegateTo[i][j]).send({from: accounts[j]});
|
||||
}
|
||||
}
|
||||
const blockn1 = await web3.eth.getBlockNumber()
|
||||
|
||||
for (var i = 0; i < delegateTo2.length; i++) {
|
||||
for (var j = 0; j < delegateTo2[i].length; j++) {
|
||||
await delegationProxy[i].methods.delegate(delegateTo2[i][j]).send({from: accounts[j]});
|
||||
}
|
||||
}
|
||||
const blockn2 = await web3.eth.getBlockNumber()
|
||||
|
||||
for (var i = 0; i < delegateTo3.length; i++) {
|
||||
for (var j = 0; j < delegateTo3[i].length; j++) {
|
||||
await delegationProxy[i].methods.delegate(delegateTo3[i][j]).send({from: accounts[j]});
|
||||
}
|
||||
}
|
||||
const blockn3 = await web3.eth.getBlockNumber()
|
||||
|
||||
for (var i = 0; i < delegateTo.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
assert.equal(
|
||||
await delegationProxy[1].delegationOfAt(accounts[j], blockn1),
|
||||
delegationOf[1][j],
|
||||
"["+j+"] +"+delegationProxy[1].address+".delegationOfAt("+accounts[j]+", +"+blockn1+") is incorrect")
|
||||
await delegationProxy[i].methods.delegatedToAt(accounts[j], blockn1).call(),
|
||||
delegateTo[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegatedToAt("+accounts[j]+", +"+blockn1+") is incorrect")
|
||||
assert.equal(
|
||||
await delegationProxy[1].delegationOfAt(accounts[j], blockn2),
|
||||
delegationOf[0][j],
|
||||
"["+j+"] +"+delegationProxy[1].address+".delegationOfAt("+accounts[j]+", +"+blockn2+") is incorrect")
|
||||
await delegationProxy[i].methods.delegatedToAt(accounts[j], blockn2).call(),
|
||||
delegateTo2[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegatedToAt("+accounts[j]+", +"+blockn2+") is incorrect")
|
||||
assert.equal(
|
||||
await delegationProxy[i].methods.delegatedToAt(accounts[j], blockn3).call(),
|
||||
delegateTo3[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegatedToAt("+accounts[j]+", +"+blockn3+") is incorrect")
|
||||
|
||||
assert.equal(
|
||||
await delegationProxy[i].methods.delegationOfAt(accounts[j], blockn1).call(),
|
||||
delegationOf[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegationOfAt("+accounts[j]+", +"+blockn1+") is incorrect")
|
||||
assert.equal(
|
||||
await delegationProxy[i].methods.delegationOfAt(accounts[j], blockn2).call(),
|
||||
delegationOf2[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegationOfAt("+accounts[j]+", +"+blockn2+") is incorrect")
|
||||
assert.equal(
|
||||
await delegationProxy[i].methods.delegationOfAt(accounts[j], blockn3).call(),
|
||||
delegationOf3[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegationOfAt("+accounts[j]+", +"+blockn3+") is incorrect")
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
it("delegates back to parentProxy", async function () {
|
||||
for (var i = 0; i < delegateTo.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
await delegationProxy[i].methods.delegate(delegateTo[i][j]).send({from: accounts[j]});
|
||||
}
|
||||
}
|
||||
const blockn1 = await web3.eth.getBlockNumber()
|
||||
|
||||
for (var j = 0; j < delegateTo[1].length; j++) {
|
||||
await delegationProxy[1].delegate(delegationProxy[0].address).send({from: accounts[j]});
|
||||
}
|
||||
|
||||
const blockn2 = await web3.eth.getBlockNumber()
|
||||
|
||||
for (var j = 0; j < delegateTo[1].length; j++) {
|
||||
assert.equal(
|
||||
await delegationProxy[1].delegatedToAt(accounts[j], blockn1).call(),
|
||||
delegateTo[1][j],
|
||||
"["+j+"] +"+delegationProxy[1].address+".delegatedToAt("+accounts[j]+", +"+blockn1+") is incorrect")
|
||||
assert.equal(
|
||||
await delegationProxy[1].delegatedToAt(accounts[j], blockn2).call(),
|
||||
delegateTo[0][j],
|
||||
"["+j+"] +"+delegationProxy[1].address+".delegatedToAt("+accounts[j]+", +"+blockn2+") is incorrect")
|
||||
|
||||
assert.equal(
|
||||
await delegationProxy[1].delegationOfAt(accounts[j], blockn1).call(),
|
||||
delegationOf[1][j],
|
||||
"["+j+"] +"+delegationProxy[1].address+".delegationOfAt("+accounts[j]+", +"+blockn1+") is incorrect")
|
||||
assert.equal(
|
||||
await delegationProxy[1].delegationOfAt(accounts[j], blockn2).call(),
|
||||
delegationOf[0][j],
|
||||
"["+j+"] +"+delegationProxy[1].address+".delegationOfAt("+accounts[j]+", +"+blockn2+") is incorrect")
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
it("returns correctly delegated to address", async function () {
|
||||
let delegatedTo
|
||||
for (var i = 0; i < delegateTo.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
await delegationProxy[i].methods.delegate(delegateTo[i][j]).send({from: accounts[j]});
|
||||
let bn = await web3.eth.getBlockNumber();
|
||||
delegatedTo = await delegationProxy[i].methods.delegatedToAt(accounts[j], bn)
|
||||
assert.equal(
|
||||
delegatedTo,
|
||||
delegateTo[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegatedToAt("+accounts[j]+", +"+bn+") is incorrect")
|
||||
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("delegatedToAt(address _who, uint _block)", () => {
|
||||
|
||||
it("returns correctly delegated to address", async () => {
|
||||
let delegatedTo
|
||||
for (var i = 0; i < delegateTo.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
await delegationProxy[i].delegate(delegateTo[i][j], {from: accounts[j]});
|
||||
delegatedTo = await delegationProxy[i].delegatedToAt(accounts[j], web3.eth.blockNumber)
|
||||
assert.equal(
|
||||
delegatedTo,
|
||||
delegateTo[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegatedToAt("+accounts[j]+", +"+web3.eth.blockNumber+") is incorrect")
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("delegationOfAt(address _who, uint _block)", () => {
|
||||
|
||||
it("returns correctly delegation endpoints of address", async () => {
|
||||
let result = [[],[]]
|
||||
for (var i = 0; i < delegateTo.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
await delegationProxy[i].delegate(delegateTo[i][j], {from: accounts[j]});
|
||||
}
|
||||
for (j = 0; j < delegateTo[i].length; j++) {
|
||||
assert.equal(
|
||||
await delegationProxy[i].delegationOfAt(accounts[j], web3.eth.blockNumber),
|
||||
delegationOf[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegationOfAt("+accounts[j]+", +"+web3.eth.blockNumber+") is incorrect"
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("delegatedInfluenceFromAt(address _who, address _token, uint _block)", () => {
|
||||
|
||||
let miniMeTokenFactory
|
||||
let miniMeToken
|
||||
const tokensBalance = 1000
|
||||
|
||||
beforeEach(async () => {
|
||||
miniMeTokenFactory = await MiniMeTokenFactory.new();
|
||||
miniMeToken = await MiniMeToken.new(miniMeTokenFactory.address, 0, 0, "TestToken", 18, "TTN", true)
|
||||
for (var i = 0; i < 6; i++) {
|
||||
miniMeToken.generateTokens(accounts[i], tokensBalance)
|
||||
}
|
||||
})
|
||||
|
||||
it("returns expected amount of influence delegated from", async () => {
|
||||
|
||||
for (var i = 0; i < delegationProxy.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
await delegationProxy[i].delegate(delegateTo[i][j], {from: accounts[j]});
|
||||
}
|
||||
for (var j = 0; j < delegatedInfluence[i].length; j++) {
|
||||
assert.equal(
|
||||
delegatedInfluence[i][j] * tokensBalance,
|
||||
(await delegationProxy[i].delegatedInfluenceFromAt(accounts[j], miniMeToken.address, web3.eth.blockNumber)).toNumber(),
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegatedInfluenceFrom("+accounts[j]+", +"+web3.eth.blockNumber+") is not as expected"
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
describe("influenceOfAt(address _who, address _token, uint _block)", () => {
|
||||
let miniMeTokenFactory
|
||||
let miniMeToken
|
||||
const tokensBalance = 1000
|
||||
|
||||
beforeEach(async () => {
|
||||
miniMeTokenFactory = await MiniMeTokenFactory.new();
|
||||
miniMeToken = await MiniMeToken.new(miniMeTokenFactory.address, 0, 0, "TestToken", 18, "TTN", true)
|
||||
for (var i = 0; i < 6; i++) {
|
||||
miniMeToken.generateTokens(accounts[i], tokensBalance)
|
||||
it("returns correctly delegation endpoints of address", async function () {
|
||||
let result = [[],[]]
|
||||
for (var i = 0; i < delegateTo.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
await delegationProxy[i].methods.delegate(delegateTo[i][j]).send({from: accounts[j]});
|
||||
}
|
||||
})
|
||||
|
||||
it("returns expected influence", async () => {
|
||||
|
||||
for (var i = 0; i < influence.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
delegationProxy[i].delegate(delegateTo[i][j], {from: accounts[j]});
|
||||
}
|
||||
for (var j = 0; j < influence[i].length; j++) {
|
||||
assert.equal(
|
||||
influence[i][j] * tokensBalance,
|
||||
(await delegationProxy[i].influenceOfAt(accounts[j], miniMeToken.address, web3.eth.blockNumber)).toNumber(),
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".influenceOfAt("+accounts[j]+", +"+web3.eth.blockNumber+") is not as expected")
|
||||
}
|
||||
}
|
||||
})
|
||||
let bn = await web3.eth.getBlockNumber();
|
||||
for (j = 0; j < delegateTo[i].length; j++) {
|
||||
assert.equal(
|
||||
await delegationProxy[i].methods.delegationOfAt(accounts[j], bn).call(),
|
||||
delegationOf[i][j],
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegationOfAt("+accounts[j]+", +"+bn+") is incorrect"
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it("returns expected amount of influence delegated from", async function () {
|
||||
|
||||
for (var i = 0; i < delegationProxy.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
await delegationProxy[i].methods.delegate(delegateTo[i][j]).send({from: accounts[j]});
|
||||
}
|
||||
let bn = await web3.eth.getBlockNumber();
|
||||
for (var j = 0; j < delegatedInfluence[i].length; j++) {
|
||||
assert.equal(
|
||||
delegatedInfluence[i][j] * tokensBalance,
|
||||
await delegationProxy[i].methods.delegatedInfluenceFromAt(accounts[j], MiniMeToken.address, bn).call(),
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".delegatedInfluenceFrom("+accounts[j]+", +"+bn+") is not as expected"
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it("returns expected influence", async function () {
|
||||
|
||||
for (var i = 0; i < influence.length; i++) {
|
||||
for (var j = 0; j < delegateTo[i].length; j++) {
|
||||
await delegationProxy[i].methods.delegate(delegateTo[i][j]).send({from: accounts[j]});
|
||||
}
|
||||
let bn = await web3.eth.getBlockNumber();
|
||||
for (var j = 0; j < influence[i].length; j++) {
|
||||
let result = await delegationProxy[i].methods.influenceOfAt(accounts[j], MiniMeToken.address, bn).call();
|
||||
assert.equal(
|
||||
influence[i][j] * tokensBalance,
|
||||
result,
|
||||
"["+i+","+j+"] +"+delegationProxy[i].address+".influenceOfAt("+accounts[j]+", +"+bn+") is not as expected. "+influence[i][j] * tokensBalance+" != "+ result)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
})
|
Loading…
Reference in New Issue