base structure of upgradable republic

This commit is contained in:
Ricardo Guilherme Schmidt 2017-11-28 01:33:25 -02:00
commit c07850d068
7 changed files with 914 additions and 0 deletions

View File

@ -0,0 +1,311 @@
pragma solidity ^0.4.11;
import "../token/MiniMeToken.sol";
/**
* @title DelegationProxy
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
* @dev Creates a delegation proxy layer for MiniMeToken.
*/
contract DelegationProxy {
event Delegate(address who, address to);
//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 {
parentProxy = _parentProxy;
}
/**
* @notice Changes the delegation of `msg.sender` to `_to`. if _to 0x00: delegate to self.
* In case of having a parent proxy, if never defined, fall back to parent proxy.
* If once defined and want to delegate to parent proxy, set `_to` as parent address.
* @param _to To what address the caller address will delegate to.
*/
function delegate(address _to) external {
_updateDelegate(msg.sender, _to);
}
/**
* @notice Reads `_who` configured delegation in this level,
* or from parent level if `_who` never defined/defined to parent address.
* @param _who What address to lookup.
* @return The address `_who` choosen delegate to.
*/
function delegatedTo(address _who) public constant returns (address) {
return delegatedToAt(_who, block.number);
}
/**
* @notice Reads the final delegate of `_who` at block number `_block`.
* @param _who Address to lookup.
* @return Final delegate address.
*/
function delegationOf(address _who) public constant returns(address) {
return delegationOfAt(_who, block.number);
}
/**
* @notice Reads the sum of votes a `_who' have at block number `_block`.
* @param _who From what address.
* @param _token Address of source MiniMeToken.
* @return Amount of influence of `who` have.
*/
function influenceOf(address _who, MiniMeToken _token) public constant returns(uint256 _total) {
return influenceOfAt(_who, _token, block.number);
}
/**
* @notice Reads amount delegated influence `_who` received from other addresses.
* @param _who What address to lookup.
* @param _token Source MiniMeToken.
* @return Sum of delegated influence received by `_who` in block `_block` from other addresses.
*/
function delegatedInfluenceFrom(address _who, address _token) public constant returns(uint256 _total) {
return delegatedInfluenceFromAt(_who, _token, block.number, address(this));
}
/**
* @notice Reads amount delegated influence `_who` received from other addresses at block number `_block`.
* @param _who What address to lookup.
* @param _token Source MiniMeToken.
* @param _block Position in history to lookup.
* @return Sum of delegated influence received by `_who` in block `_block` from other addresses
*/
function delegatedInfluenceFromAt(
address _who,
address _token,
uint _block
)
public
constant
returns(uint256 _total)
{
return delegatedInfluenceFromAt(_who, _token, _block, address(this));
}
/**
* @notice Reads `_who` configured delegation at block number `_block` in this level,
* or from parent level if `_who` never defined/defined to parent address.
* @param _who What address to lookup.
* @param _block Block number of what height in history.
* @return The address `_who` choosen delegate to.
*/
function delegatedToAt(address _who, uint _block) public constant returns (address addr) {
Delegation[] storage checkpoints = delegations[_who];
//In case there is no registry
if (checkpoints.length == 0) {
if (parentProxy != 0x0) {
return DelegationProxy(parentProxy).delegatedToAt(_who, _block);
} else {
return 0x0;
}
}
Delegation memory d = _getMemoryAt(checkpoints, _block);
// Case user set delegate to parentProxy address
if (d.to == parentProxy && parentProxy != 0x0) {
return DelegationProxy(parentProxy).delegatedToAt(_who, _block);
}
return d.to;
}
/**
* @notice Reads the final delegate of `_who` at block number `_block`.
* @param _who Address to lookup.
* @param _block From what block.
* @return Final delegate address.
*/
function delegationOfAt(address _who, uint _block) public constant returns(address) {
address delegate = delegatedToAt(_who, _block);
if (delegate != 0x0) { //_who is delegating?
return delegationOfAt(delegate, _block); //load the delegation of _who delegation
} else {
return _who; //reached the endpoint of delegation
}
}
/**
* @dev Reads amount delegated influence received from other addresses.
* @param _who What address to lookup.
* @param _token Source MiniMeToken.
* @param _block Position in history to lookup.
* @param _childProxy The child DelegationProxy requesting the call to parent.
* @return Sum of delegated influence received by `_who` in block `_block` from other addresses.
*/
function delegatedInfluenceFromAt(
address _who,
address _token,
uint _block,
address _childProxy
)
public
constant
returns(uint256 _total)
{
Delegation[] storage checkpoints = delegations[_who];
//In case there is no registry
if (checkpoints.length == 0) {
if (parentProxy != 0x0) {
return DelegationProxy(parentProxy).delegatedInfluenceFromAt(
_from,
_token,
_block,
_childProxy
);
} else {
return 0;
}
}
Delegation memory d = _getMemoryAt(checkpoints, _block);
// Case user set delegate to parentProxy
if (d.to == parentProxy && parentProxy != 0x0) {
return DelegationProxy(parentProxy).delegatedInfluenceFromAt(
_from,
_token,
_block,
_childProxy
);
}
uint _len = d.from.length;
for (uint256 i = 0; _len > i; i++) {
address _from = d.from[i];
_total += MiniMeToken(_token).balanceOfAt(_from, _block); // source of _who votes
_total += DelegationProxy(_childProxy).delegatedInfluenceFromAt(
_from,
_token,
_block,
_childProxy
); //sum the from delegation votes
}
}
/**
* @notice Reads the sum of votes a `_who' have at block number `_block`.
* @param _who From what address.
* @param _token Address of source MiniMeToken.
* @param _block From what block
* @return Amount of influence of `who` have.
*/
function influenceOfAt(address _who, MiniMeToken _token, uint _block) public constant returns(uint256 _total) {
if (delegationOfAt(_who, _block) == _who) { //is endpoint of delegation?
_total = MiniMeToken(_token).balanceOfAt(_who, _block); // source of _who votes
_total += delegatedInfluenceFromAt(_who, _token, _block, address(this)); //votes delegated to `_who`
} else {
_total = 0; //no influence because were delegated
}
}
/**
* @dev Changes the delegation of `_from` to `_to`. if _to 0x00: delegate to self.
* In case of having a parent proxy, if never defined, fall back to parent proxy.
* If once defined and want to delegate to parent proxy, set `_to` as parent address.
* @param _from Address delegating.
* @param _to Address delegated.
*/
function _updateDelegate(address _from, address _to) internal {
require(delegationOfAt(_to, block.number) != msg.sender); //block impossible circular delegation
Delegate(_from, _to);
Delegation memory _newFrom; //allocate memory
Delegation[] storage fromHistory = delegations[_from];
if (fromHistory.length > 0) { //have old config?
_newFrom = fromHistory[fromHistory.length - 1]; //load to memory
_newFrom.from = fromHistory[fromHistory.length - 1].from;
if (toIndexes[_from] > 0) { //was delegating? remove old link
_removeDelegated(_newFrom.to, toIndexes[_from]);
}
}
//Add the new delegation
_newFrom.fromBlock = uint128(block.number);
_newFrom.to = _to; //delegate address
if (_to != 0x0 && _to != parentProxy) { //_to is an address?
_addDelegated(_from, _to);
} else {
toIndexes[_from] = 0; //zero index
}
fromHistory.push(_newFrom); //register `from` delegation update;
}
/**
* @dev `_getDelegationAt` retrieves the delegation at a given block number.
* @param checkpoints The memory being queried.
* @param _block The block number to retrieve the value at.
* @return The delegation being queried.
*/
function _getMemoryAt(Delegation[] storage checkpoints, uint _block) internal constant returns (Delegation d) {
// Case last checkpoint is the one;
if (_block >= checkpoints[checkpoints.length-1].fromBlock) {
d = checkpoints[checkpoints.length-1];
} else {
// Lookup in array;
uint min = 0;
uint max = checkpoints.length-1;
while (max > min) {
uint mid = (max + min + 1) / 2;
if (checkpoints[mid].fromBlock <= _block) {
min = mid;
} else {
max = mid-1;
}
}
d = checkpoints[min];
}
}
/**
* @dev Removes delegation at `_toIndex` from `_to` address.
* @param _to Delegate address to remove delegation.
* @param _toIndex Index of delegation being removed.
*/
function _removeDelegated(address _to, uint _toIndex) private {
Delegation[] storage oldTo = delegations[_to]; //load delegation storage
uint _oldToLen = oldTo.length;
assert(_oldToLen > 0); //if code tried to remove from nothing this is absolutely bad
Delegation memory _newOldTo = oldTo[_oldToLen - 1];//copy to memory last result
address replacer = _newOldTo.from[_newOldTo.from.length - 1];
_newOldTo.from[_toIndex - 1] = replacer; //replace delegated address at `_toIndex`
oldTo.push(_newOldTo); //save the value at memory
oldTo[_oldToLen].from.length--; //remove duplicated `to`
toIndexes[replacer] = _toIndex;
}
/**
* @dev Add delegation of `_from` in delegate `_to`.
* @param _from Delegator address delegating their influence.
* @param _to Delegate address receiving the influence;
* @return _toIndex The index of `_from` in `_to` delegate.
*/
function _addDelegated(address _from, address _to) private {
Delegation memory _newTo; // allocates space in memory
Delegation[] storage toHistory = delegations[_to]; //load delegation storage
uint toHistLen = toHistory.length;
if (toHistLen > 0) { //have data, should copy 'from' array.
_newTo = toHistory[toHistLen - 1]; //copy to memory last one
} else {
_newTo.to = parentProxy; // configure delegate of `_to` because it was never defined
}
_newTo.fromBlock = uint128(block.number); //define the new block number
toHistory.push(_newTo); //register `to` delegated from
toHistory[toHistLen].from.push(_from); //add the delegated from in to list
toIndexes[_from] = toHistory[toHistLen].from.length; //link to index
}
}

View File

@ -0,0 +1,30 @@
pragma solidity ^0.4.11;
import "./DelegationProxyModel.sol";
import "../deploy/RecoverableSystem.sol";
import "../deploy/KillableModel.sol";
/**
* @title DelegationProxyFactory
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
* @dev Upgradable delegation proxy factory
*/
contract DelegationProxyFactory {
address public systemModel;
address public recover;
address public watchdog;
function DelegationProxyFactory(address _recover, address _watchdog) public {
watchdog = _watchdog;
recover = _recover;
systemModel = new DelegationProxyModel(watchdog);
}
function create(address _parent) external returns (DelegationProxy) {
DelegationProxyModel instance = DelegationProxyModel(address(new RecoverableSystem(systemModel, recover)));
instance.initialize(_parent);
return DelegationProxy(address(instance));
}
}

View File

@ -0,0 +1,30 @@
pragma solidity ^0.4.11;
import "../deploy/KillableModel.sol";
import "./DelegationProxy.sol";
/**
* @title DelegationProxyModel
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
* @dev Creates a delegation proxy killable model for cheap redeploy and upgradability.
*/
contract DelegationProxyModel is KillableModel, DelegationProxy {
bool private ready = false;
/**
* @notice Constructor of the model - only knows about watchdog that can trigger upgrade
*/
function DelegationProxyModel(address _watchdog) KillableModel(_watchdog) DelegationProxy(0x0) public {
ready = true;
}
/**
* @notice Creates a new DelegationProxy with `_parentProxy` as default delegation.
*/
function initialize(address _parentProxy) public {
require(!ready);
ready = true;
parentProxy = _parentProxy;
}
}

View File

@ -0,0 +1,146 @@
pragma solidity ^0.4.10;
import "./TrustNetwork.sol";
import "./DelegationProxy.sol";
import "../token/MiniMeToken.sol";
import "../common/Controlled.sol";
/**
* @title ProposalManager
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
* Store the proposals, votes and results for other smartcontracts
*/
contract ProposalManager is Controlled {
TrustNetwork public trustNet;
MiniMeToken public SNT;
address public stakeBank;
Proposal[] proposals;
struct Proposal {
address topic;
address destination;
uint value;
bytes data;
uint stake;
uint blockStart;
uint voteBlockEnd;
uint vetoBlockEnd;
VoteTicket[] votes;
mapping(address => uint) voteIndex;
uint tabulationPosition;
bool tabulated;
mapping(uint8 => uint) results;
bool approved;
bool executed;
}
struct VoteTicket {
address voter;
Vote vote;
}
enum Vote {
Reject,
Approve,
Veto
}
function ProposalManager(MiniMeToken _SNT, TrustNetwork _trustNet, address _stakeBank) public {
trustNet = _trustNet;
SNT = _SNT;
stakeBank = _stakeBank;
}
function addProposal(address topic, address destination, uint value, bytes data, uint stake) returns (uint) {
require(stake > 1000);
require(SNT.transferFrom(msg.sender, stakeBank, stake));
uint pos = proposals.length++;
Proposal storage p = proposals[pos];
p.topic = topic;
p.destination = destination;
p.value = value;
p.data = data;
p.stake = stake;
p.blockStart = block.number + 1000; //will be replaced by configurations
p.voteBlockEnd = p.blockStart + 10000; //dummy value
p.vetoBlockEnd = p.voteBlockEnd + 5000; //dummy value
return pos;
}
function getProposal(uint id) public constant returns (address topic, address destination, uint value, uint stake, bool approved, bool executed) {
Proposal memory p = proposals[id];
return (p.topic, p.destination, p.value, p.stake, p.approved, p.executed);
}
function getProposalData(uint id) public constant returns(bytes){
return proposals[id].data;
}
function setExecuted(uint id) public onlyController {
proposals[id].executed = true;
}
function vote(uint _proposal, Vote _vote) {
Proposal storage proposal = proposals[_proposal];
require(block.number >= proposal.blockStart);
if (_vote == Vote.Veto) {
require(block.number <= proposal.vetoBlockEnd);
} else {
require(block.number <= proposal.voteBlockEnd);
}
uint votePos = proposal.voteIndex[msg.sender];
if (votePos == 0) {
votePos = proposal.votes.length;
} else {
votePos = votePos - 1;
}
VoteTicket storage ticket = proposal.votes[votePos];
assert (ticket.voter == 0x0 || ticket.voter == msg.sender);
ticket.voter = msg.sender;
ticket.vote = _vote;
proposal.voteIndex[msg.sender] = votePos + 1;
}
function tabulate(uint _proposal, uint loopLimit) {
Proposal storage proposal = proposals[_proposal];
require(block.number > proposal.vetoBlockEnd);
require(!proposal.tabulated);
uint totalVoted = proposal.votes.length;
if (loopLimit == 0) {
loopLimit = totalVoted;
}
require (loopLimit <= totalVoted);
require (loopLimit > proposal.tabulationPosition);
DelegationProxy voteDelegation;
DelegationProxy vetoDelegation;
(voteDelegation, vetoDelegation) = trustNet.getTopic(proposal.topic);
for (uint i = proposal.tabulationPosition; i < loopLimit; i++) {
VoteTicket memory _vote = proposal.votes[i];
if (_vote.vote == Vote.Reject || _vote.vote == Vote.Approve) {
proposal.results[uint8(_vote.vote)] += voteDelegation.influenceOfAt(_vote.voter, SNT, proposal.voteBlockEnd);
} else {
proposal.results[uint8(_vote.vote)] += vetoDelegation.influenceOfAt(_vote.voter, SNT, proposal.vetoBlockEnd);
}
}
proposal.tabulationPosition = i;
if (proposal.tabulationPosition == totalVoted) {
proposal.tabulated = true;
}
}
}

View File

@ -0,0 +1,59 @@
pragma solidity ^0.4.10;
import "../common/Controlled.sol";
import "./DelegationProxyFactory.sol";
import "./DelegationProxy.sol";
/**
* @title TrustNetwork
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
* Defines two contolled DelegationProxy chains: vote and veto chains.
* New layers need to be defined under a unique topic address topic, and all fall back to root topic (topic 0x0)
*/
contract TrustNetwork is Controlled {
mapping (address => Topic) topics;
DelegationProxyFactory delegationFactory;
struct Topic {
DelegationProxy voteProxy;
DelegationProxy vetoProxy;
}
function TrustNetwork(address _delegationFactory) public {
delegationFactory = DelegationProxyFactory(_delegationFactory);
topics[0x0] = newTopic(0x0, 0x0);
}
function addTopic(address topicId, address parentTopic) onlyController {
Topic memory parent = topics[parentTopic];
address vote = address(parent.voteProxy);
address veto = address(parent.vetoProxy);
require(vote != 0x0);
require(veto != 0x0);
Topic storage topic = topics[topicId];
require(address(topic.voteProxy) == 0x0);
require(address(topic.vetoProxy) == 0x0);
topics[topicId] = newTopic(vote, veto);
}
function getTopic(address _topicId) public constant returns (DelegationProxy vote, DelegationProxy veto) {
Topic memory topic = topics[_topicId];
vote = topic.voteProxy;
veto = topic.vetoProxy;
}
function newTopic(address _vote, address _veto) internal returns (Topic topic) {
topic = Topic ({
voteProxy: delegationFactory.create(_vote),
vetoProxy: delegationFactory.create(_veto)
});
}
}

View File

@ -0,0 +1,26 @@
pragma solidity ^0.4.10;
import "./TrustNetwork.sol";
import "../deploy/KillableModel.sol";
/**
* @title TrustNetworkModel
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
* Model for TrustNetwork
*/
contract TrustNetworkModel is KillableModel, TrustNetwork {
function TrustNetworkModel(address _watchdog) KillableModel(_watchdog) TrustNetwork(0x0) public {
}
function create(address _delegationFactory) public {
require(topics[0x0].voteProxy == address(0x0));
delegationFactory = DelegationProxyFactory(_delegationFactory);
topics[0x0] = newTopic(0x0, 0x0);
}
}

312
test/DelegationProxyTest.js Normal file
View File

@ -0,0 +1,312 @@
const DelegationProxy = artifacts.require("DelegationProxy.sol")
const MiniMeTokenFactory = artifacts.require("MiniMeTokenFactory.sol")
const MiniMeToken = artifacts.require("MiniMeToken.sol")
const TestUtils = require("./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 => {
//Initialize global/common contracts for all tests
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]
]
]
const delegatedInfluence = [
[0, 1, 2],
[0, 0, 1]
]
const influence = [
[0, 0, 3],
[1, 0, 2]
]
beforeEach(async () => {
delegationProxy[0] = await DelegationProxy.new(0)
delegationProxy[1] = await DelegationProxy.new(delegationProxy[0].address)
})
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")
assert.equal(
await delegationProxy[1].delegationOfAt(accounts[j], blockn1),
delegationOf[1][j],
"["+j+"] +"+delegationProxy[1].address+".delegationOfAt("+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")
}
})
})
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 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")
}
}
})
})
})