Skip to content

Commit

Permalink
Add the actual v0101_1 file >.<
Browse files Browse the repository at this point in the history
  • Loading branch information
XertroV committed May 20, 2018
1 parent 540d686 commit bab88de
Showing 1 changed file with 370 additions and 0 deletions.
370 changes: 370 additions & 0 deletions contracts/SVDelegationV0101_1.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,370 @@
pragma solidity ^0.4.24;

// DELEGATION SC v1.1
// (c) SecureVote 2018
// Author: Max Kaye <max@secure.vote>
// Released under MIT licence

// the most up-to-date version of the contract lives at delegate.secvote.eth


import "./SVCommon.sol"; // particularly for ERC20Interface


// Main delegation contract v1.1
contract SVDelegationV0101_1 {

address public owner;

// in the last version we didn't include enough data - this makes it trivial to traverse off-chain
struct Delegation {
uint64 thisDelegationId;
uint64 prevDelegationId;
uint64 setAtBlock;
address delegatee;
address delegator;
address tokenContract;
}

// easy lookups
mapping (address => mapping (address => Delegation)) tokenDlgts;
mapping (address => Delegation) globalDlgts;

// track which token contracts we know about for easy traversal + backwards compatibility
mapping (address => bool) knownTokenContracts;
address[] logTokenContracts;

// track all delegations via an indexed map
mapping (uint64 => Delegation) historicalDelegations;
uint64 public totalDelegations = 0;

// reference to v1.0 of contract
SVDelegation prevSVDelegation;

// pretty straight forward - events
event SetGlobalDelegation(address voter, address delegate);
event SetTokenDelegation(address voter, address tokenContract, address delegate);

// main constructor - requires the prevDelegationSC address
function SVDelegationV0101_1(address prevDelegationSC) public {
owner = msg.sender;

prevSVDelegation = SVDelegation(prevDelegationSC);

// commit the genesis historical delegation to history (like genesis block) - somewhere to point back to
createDelegation(address(0), 0, address(0));
}

// internal function to handle inserting delegates into state
function createDelegation(address dlgtAddress, uint64 prevDelegationId, address tokenContract) internal returns(Delegation) {
// use this to log known tokenContracts
if (!knownTokenContracts[tokenContract]) {
logTokenContracts.push(tokenContract);
knownTokenContracts[tokenContract] = true;
}

uint64 myDelegationId = totalDelegations;
historicalDelegations[myDelegationId] = Delegation(myDelegationId, prevDelegationId, uint64(block.number), dlgtAddress, msg.sender, tokenContract);
totalDelegations += 1;

return historicalDelegations[myDelegationId];
}

// get previous delegation, create new delegation via function and then commit to globalDlgts
function setGlobalDelegation(address dlgtAddress) public {
uint64 prevDelegationId = globalDlgts[msg.sender].thisDelegationId;
globalDlgts[msg.sender] = createDelegation(dlgtAddress, prevDelegationId, address(0));
emit SetGlobalDelegation(msg.sender, dlgtAddress);
}

// get previous delegation, create new delegation via function and then commit to tokenDlgts
function setTokenDelegation(address tokenContract, address dlgtAddress) public {
uint64 prevDelegationId = tokenDlgts[tokenContract][msg.sender].thisDelegationId;
tokenDlgts[tokenContract][msg.sender] = createDelegation(dlgtAddress, prevDelegationId, tokenContract);
emit SetTokenDelegation(msg.sender, tokenContract, dlgtAddress);
}

// given some voter and token address, get the delegation id - failover to global on 0 address
function getDelegationID(address voter, address tokenContract) public constant returns(uint64) {
// default to token resolution but use global if no delegation
Delegation memory _tokenDlgt = tokenDlgts[tokenContract][voter];
if (tokenContract == address(0)) {
_tokenDlgt = globalDlgts[voter];
}

// default to 0 if we don't have a valid delegation
if (_validDelegation(_tokenDlgt)) {
return _tokenDlgt.thisDelegationId;
}
return 0;
}

function resolveDelegation(address voter, address tokenContract) public constant returns(uint64, uint64, uint64, address, address, address) {
Delegation memory _tokenDlgt = tokenDlgts[tokenContract][voter];

// if we have a delegation in this contract return it
if (_validDelegation(_tokenDlgt)) {
return _dlgtRet(_tokenDlgt);
}

// otherwise try the global delegation
Delegation memory _globalDlgt = globalDlgts[voter];
if (_validDelegation(_globalDlgt)) {
return _dlgtRet(_globalDlgt);
}

// CHANGE: Potential bug here: if (v1, t1) -> d1 on the old contract, and
// there's a global v1 -> d2 on this smartcontract, then this function
// resovleDelegation(v1, t1) -> d2 instead of d1. Oops. As it happens this
// doesn't affect any delegations AFAIK, but is something to be aware of.
// ------
// but if we don't have a delegation in this contract then resolve according the prev contract
address _dlgt;
uint256 meh;
(meh, _dlgt, meh, meh) = prevSVDelegation.resolveDelegation(voter, tokenContract);
return (0, 0, 0, _dlgt, voter, tokenContract);
}

// returns 2 lists: first of voter addresses, second of token contracts
function findPossibleDelegatorsOf(address delegate) public view returns(address[] memory, address[] memory) {
// not meant to be run on-chain, but off-chain via API, mostly convenience
address[] memory voters;
address[] memory tokenContracts;
Delegation memory _delegation;


// first loop through delegations in this contract
uint64 i;
// start at 1 because the first delegation is a "genesis" delegation in constructor
for (i = 1; i < totalDelegations; i++) {
_delegation = historicalDelegations[i];
if (_delegation.delegatee == delegate) {
// since `.push` isn't available on memory arrays, use their length as the next index location
voters = _appendMemArray(voters, _delegation.delegator);
tokenContracts = _appendMemArray(tokenContracts, _delegation.tokenContract);
}
}

return resolveOlderDelegations(delegate, voters, tokenContracts);
}

// CHANGE: BROKE THIS OUT INTO IT'S OWN FUNCTION
// this allows it to scan all known voters and tokens in the
// past contract
// ---
// just get older delegations
function resolveOlderDelegations(address delegate, address[] memory _voters, address[] memory _tcs) internal view returns (address[] memory voters, address[] memory tokenContracts) {
// all the senders who participated in v1.0 of the contract prior to block 5203500
address[43] memory oldSenders =
[ 0xE8193Bc3D5F3F482406706F843A5f161563F37Bf
, 0x7A933c8a0Eb99e8Bdb07E1b42Aa10872845394B7
, 0x88341191EfA40Cd031F46138817830A5D3545Ba9
, 0xB6dc48E8583C8C6e320DaF918CAdef65f2d85B46
, 0xF02d417c8c6736Dbc7Eb089DC6738b950c2F444e
, 0xF66fE29Ad1E87104A8816AD1A8427976d83CB033
, 0xfd5955bf412B7537873CBB77eB1E39871e20e142
, 0xe83Efc57d9C487ACc55a7B62896dA43928E64C3E
, 0xd0c41588b27E64576ddA4e6a08452c59F5A2B2dD
, 0x640370126072f6B890d4Ca2E893103e9363DbE8B
, 0x887dbaCD9a0e58B46065F93cc1f82a52DEfDb979
, 0xe223771699665bCB0AAf7930277C35d3deC573aF
, 0x364B503B0e86b20B7aC1484c247DE50f10DfD8cf
, 0x4512F5867d91D6B0131427b89Bdb7b460fF30397
, 0xF5fBff477F5Bf5a950F661B70F6b5364875A1bD7
, 0x9EbB758483Da174DC3d411386B75afd093CEfCf1
, 0x499B36A6B92F91524A6B5b8Ff321740e84a2B57e
, 0x05D6e87fd6326F977a2d8c67b9F3EcC030527261
, 0x7f679053a1679dE7913885F0Db1278e91e8927Ca
, 0xF9CD08d36e972Bb070bBD2C1598D21045259AB0D
, 0xa5617800B8FD754fB81F47A65dc49A60acCc3432
, 0xa9F6238B83fcb65EcA3c3189a0dce8689e275D57
, 0xa30F92F9cc478562e0dde73665f1B7ADddDC2dCd
, 0x70278C15A29f0Ef62A845e1ac31AE41988F24C10
, 0xd42622471946CCFf9F7b9246e8D786c74410bFcC
, 0xd65955EF0f8890D7996f5a7b7b5b05B80605C06a
, 0xB46F4eBDD6404686D785EDACE37D66f815ED7cF8
, 0xf4d3aa8091D23f97706177CDD94b8dF4c7e4C2FB
, 0x4Fe584FFc9C755BF6Aa9354323e97166958475c9
, 0xB4802f497Bf6238A29e043103EE6eeae1331BFde
, 0x3EeE0f8Fadc1C29bFB782E70067a8D91B4ddeD56
, 0x46381F606014C5D68B38aD5C7e8f9401149FAa75
, 0xC81Be3496d053364255f9cb052F81Ca9e84A9cF3
, 0xa632837B095d8fa2ef46a22099F91Fe10B3F0538
, 0x19FA94aEbD4bC694802B566Ae65aEd8F07B992f7
, 0xE9Ef7664d36191Ad7aB001b9BB0aAfAcD260277F
, 0x17DAB6BB606f32447aff568c1D0eEDC3649C101C
, 0xaBA96c77E3dd7EEa16cc5EbdAAA05483CDD0FF89
, 0x57d36B0B5f5E333818b1ce072A6D84218E734deC
, 0x59E7612706DFB1105220CcB97aaF3cBF304cD608
, 0xCf7EC4dcA84b5c8Dc7896c38b4834DC6379BB73D
, 0x5Ed1Da246EA52F302FFf9391e56ec64b9c14cce1
, 0x4CabFD1796Ec9EAd77457768e5cA782a1A9e576F
];

uint i = 0;

// there were no global delegations in v1.0 of contract
address oldToken = 0x9e88613418cF03dCa54D6a2cf6Ad934A78C7A17A;

address[] memory allPossibleSenders = new address[](43 + _voters.length);
for (i = 0; i < allPossibleSenders.length; i++) {
if (i < 43) {
allPossibleSenders[i] = oldSenders[i];
} else {
allPossibleSenders[i] = _voters[i - 43];
}
}

// loop through delegations in the previous contract
for (i = 0; i < (allPossibleSenders.length); i++) {
for (uint j = 0; j < logTokenContracts.length + 1; j++) {
uint256 _oldId;
address _oldDlgt;
uint256 _oldSetAtBlock;
uint256 _oldPrevId;
address tc = j == 0 ? oldToken : logTokenContracts[j-1];
if (tc == address(0)) {
(_oldId, _oldDlgt, _oldSetAtBlock, _oldPrevId) = prevSVDelegation._rawGetGlobalDelegation(allPossibleSenders[i]);
} else {
(_oldId, _oldDlgt, _oldSetAtBlock, _oldPrevId) = prevSVDelegation._rawGetTokenDelegation(allPossibleSenders[i], tc);
}

if (_oldDlgt == delegate) {
voters = _appendMemArray(voters, allPossibleSenders[i]);
tokenContracts = _appendMemArray(tokenContracts, tc);
}
}
}

return (_concatMemArray(voters, _voters), _concatMemArray(tokenContracts, _tcs));
}

// give access to historicalDelegations
function getHistoricalDelegation(uint64 delegationId) public constant returns(uint64, uint64, uint64, address, address, address) {
return _dlgtRet(historicalDelegations[delegationId]);
}

// access the globalDelegation map
function _rawGetGlobalDelegation(address _voter) public constant returns(uint64, uint64, uint64, address, address, address) {
return _dlgtRet(globalDlgts[_voter]);
}

// access the tokenDelegation map
function _rawGetTokenDelegation(address _voter, address _tokenContract) public constant returns(uint64, uint64, uint64, address, address, address) {
return _dlgtRet(tokenDlgts[_tokenContract][_voter]);
}

// access our log list of token contracts
function _getLogTokenContract(uint256 i) public constant returns(address) {
return logTokenContracts[i];
}

// convenience function to turn Delegations into a returnable structure
function _dlgtRet(Delegation d) internal pure returns(uint64, uint64, uint64, address, address, address) {
return (d.thisDelegationId, d.prevDelegationId, d.setAtBlock, d.delegatee, d.delegator, d.tokenContract);
}

// internal function to test if a delegation is valid or revoked / nonexistent
function _validDelegation(Delegation d) internal pure returns(bool) {
// probs simplest test to check if we have a valid delegation - important to check if delegation is set to 0x00
// to avoid counting a revocation (which is done by delegating to 0x00)
return d.setAtBlock > 0 && d.delegatee != address(0);
}

function _appendMemArray(address[] memory arr, address toAppend) internal pure returns(address[] memory arr2) {
arr2 = new address[](arr.length + 1);

for (uint k = 0; k < arr.length; k++) {
arr2[k] = arr[k];
}

arr2[arr.length] = toAppend;
}

function _concatMemArray(address[] memory a1, address[] memory a2) internal pure returns (address[] memory a3) {
a3 = new address[](a1.length + a2.length);
for (uint i = 0; i < a3.length; i++) {
if (i < a1.length) {
a3[i] = a1[i];
} else {
a3[i] = a2[i - a1.length];
}
}
}
}


// Include previous contract in this one so we can access the various components. Not all things needed are accessible
// through functions - e.g. `historicalDelegations` mapping.
contract SVDelegation {

address public owner;

struct Delegation {
uint256 thisDelegationId;
address dlgt;
uint256 setAtBlock;
uint256 prevDelegation;
}

mapping (address => mapping (address => Delegation)) tokenDlgts;
mapping (address => Delegation) globalDlgts;

mapping (uint256 => Delegation) public historicalDelegations;
uint256 public totalDelegations = 0;

event SetGlobalDelegation(address voter, address delegate);
event SetTokenDelegation(address voter, address tokenContract, address delegate);

function SVDelegation() public {
owner = msg.sender;

// commit the genesis historical delegation to history (like genesis block)
createDelegation(address(0), 0);
}

function createDelegation(address dlgtAddress, uint256 prevDelegationId) internal returns(Delegation) {
uint256 myDelegationId = totalDelegations;
historicalDelegations[myDelegationId] = Delegation(myDelegationId, dlgtAddress, block.number, prevDelegationId);
totalDelegations += 1;

return historicalDelegations[myDelegationId];
}

// get previous delegation, create new delegation via function and then commit to globalDlgts
function setGlobalDelegation(address dlgtAddress) public {
uint256 prevDelegationId = globalDlgts[msg.sender].thisDelegationId;
globalDlgts[msg.sender] = createDelegation(dlgtAddress, prevDelegationId);
emit SetGlobalDelegation(msg.sender, dlgtAddress);
}

// get previous delegation, create new delegation via function and then commit to tokenDlgts
function setTokenDelegation(address tokenContract, address dlgtAddress) public {
uint256 prevDelegationId = tokenDlgts[tokenContract][msg.sender].thisDelegationId;
tokenDlgts[tokenContract][msg.sender] = createDelegation(dlgtAddress, prevDelegationId);
emit SetTokenDelegation(msg.sender, tokenContract, dlgtAddress);
}

function resolveDelegation(address voter, address tokenContract) public constant returns(uint256, address, uint256, uint256) {
Delegation memory _tokenDlgt = tokenDlgts[tokenContract][voter];

// probs simplest test to check if we have a valid delegation
if (_tokenDlgt.setAtBlock > 0) {
return _dlgtRet(_tokenDlgt);
} else {
return _dlgtRet(globalDlgts[voter]);
}
}

function _rawGetGlobalDelegation(address _voter) public constant returns(uint256, address, uint256, uint256) {
return _dlgtRet(globalDlgts[_voter]);
}

function _rawGetTokenDelegation(address _voter, address _tokenContract) public constant returns(uint256, address, uint256, uint256) {
return _dlgtRet(tokenDlgts[_tokenContract][_voter]);
}

function _dlgtRet(Delegation d) internal pure returns(uint256, address, uint256, uint256) {
return (d.thisDelegationId, d.dlgt, d.setAtBlock, d.prevDelegation);
}
}

0 comments on commit bab88de

Please sign in to comment.