delegation proxy refactor
This commit is contained in:
parent
3c40812a52
commit
1544368968
|
@ -1,4 +1,4 @@
|
|||
pragma solidity ^0.4.17;
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../token/MiniMeTokenInterface.sol";
|
||||
import "./DelegationProxyInterface.sol";
|
||||
|
@ -11,26 +11,9 @@ import "./DelegationProxyInterface.sol";
|
|||
*/
|
||||
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;
|
||||
//storage of preprocessed view of FinalDelegate
|
||||
mapping(bytes32 => FinalDelegate) delegationView;
|
||||
|
||||
struct FinalDelegate {
|
||||
address delegate;
|
||||
bool found;
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
|
@ -48,82 +31,6 @@ contract DelegationProxy is DelegationProxyInterface {
|
|||
_updateDelegate(msg.sender, _to);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Dig into delegate chain to find final delegate, makes delegationOfAt cheaper to call;
|
||||
* Should be used when you want to track an isolated long delegation chain FinalDelegate
|
||||
* @param _delegator Address to lookup final delegate.
|
||||
* @param _block From what block.
|
||||
* @return True when found final delegate.
|
||||
*/
|
||||
function findFinalDelegate(
|
||||
address _delegator,
|
||||
uint256 _block,
|
||||
uint256 loopLimit
|
||||
)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
bytes32 searchIndex = keccak256(_delegator,_block);
|
||||
FinalDelegate memory search = delegationView[searchIndex];
|
||||
require(!search.found);
|
||||
for (uint i = 0; i < loopLimit; i++) {
|
||||
if (search.delegate == address(0)) {
|
||||
search.delegate = _delegator;
|
||||
}
|
||||
address delegateFrom = delegatedToAt(search.delegate, _block);
|
||||
if (delegateFrom == address(0)) {
|
||||
search.found = true;
|
||||
} else {
|
||||
search.delegate = delegateFrom;
|
||||
}
|
||||
if (search.found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
delegationView[searchIndex] = search;
|
||||
return search.found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Explore the chain from `_delegator`, saving FinalDelegate indexes for all delegates, makes delegationOfAt cheaper to call.
|
||||
* Should be used to track a common FinalDelegates in a small delegation chain, saving gas on repetitive lookups;
|
||||
* @param _delegator Address to lookup final delegate.
|
||||
* @param _block From what block.
|
||||
* @param _stackLimit how much deep explore to build the indexes
|
||||
* @return address of delegate when found, or the last top delegate found if stacklimit reached without getting into FinalDelegate.
|
||||
*/
|
||||
function buildFinalDelegateChain(
|
||||
address _delegator,
|
||||
uint256 _block,
|
||||
uint256 _stackLimit
|
||||
)
|
||||
public
|
||||
returns (address delegate, bool found)
|
||||
{
|
||||
require(_block > block.number); //cannot renderize current state view ?
|
||||
bytes32 searchIndex = keccak256(_delegator, _block);
|
||||
FinalDelegate memory search = delegationView[searchIndex];
|
||||
if (!search.found) {
|
||||
if (search.delegate == address(0)) {
|
||||
delegate = delegatedToAt(_delegator, _block);
|
||||
if (delegate == address(0)) {
|
||||
//`_delegator` FinalDelegate is itself
|
||||
delegate = _delegator;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && _stackLimit > 0) {
|
||||
//`_delegator` FinalDelegate is the same FinalDelegate of it's `delegate`
|
||||
(delegate, found) = buildFinalDelegateChain(delegate, _block, _stackLimit - 1);
|
||||
}
|
||||
delegationView[searchIndex] = FinalDelegate(delegate, found);
|
||||
}
|
||||
return (delegate, found);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @notice Reads `_who` configured delegation in this level,
|
||||
* or from parent level if `_who` never defined/defined to parent address.
|
||||
|
@ -217,7 +124,7 @@ contract DelegationProxy is DelegationProxyInterface {
|
|||
)
|
||||
public
|
||||
constant
|
||||
returns (address addr)
|
||||
returns (address directDelegate)
|
||||
{
|
||||
Delegation[] storage checkpoints = delegations[_who];
|
||||
|
||||
|
@ -231,7 +138,7 @@ contract DelegationProxy is DelegationProxyInterface {
|
|||
}
|
||||
Delegation memory d = _getMemoryAt(checkpoints, _block);
|
||||
// Case user set delegate to parentProxy address
|
||||
if (d.to == parentProxy && parentProxy != 0x0) {
|
||||
if (d.to == parentProxy && d.to != 0x0) {
|
||||
return DelegationProxy(parentProxy).delegatedToAt(_who, _block);
|
||||
}
|
||||
return d.to;
|
||||
|
@ -249,22 +156,15 @@ contract DelegationProxy is DelegationProxyInterface {
|
|||
)
|
||||
public
|
||||
constant
|
||||
returns(address delegate)
|
||||
returns(address finalDelegate)
|
||||
{
|
||||
bytes32 searchIndex = keccak256(_who, _block);
|
||||
FinalDelegate memory search = delegationView[searchIndex];
|
||||
if (search.found) {
|
||||
delegate = search.delegate;
|
||||
} else if (search.delegate != address(0)) {
|
||||
_who = search.delegate;
|
||||
delegate = delegatedToAt(_who, _block);
|
||||
delegate = delegate == 0x0 ? _who : delegate;
|
||||
}
|
||||
if (delegate != _who) { //_who is delegating?
|
||||
return delegationOfAt(delegate, _block); //load the delegation of _who delegation
|
||||
finalDelegate = delegatedToAt(_who, _block);
|
||||
if (finalDelegate != _who) { //_who is delegating?
|
||||
return delegationOfAt(finalDelegate, _block); //load the delegation of _who delegation
|
||||
} else {
|
||||
return _who; //reached the endpoint of delegation
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,30 +1,29 @@
|
|||
pragma solidity ^0.4.11;
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./DelegationProxyModel.sol";
|
||||
import "../deploy/RecoverableSystem.sol";
|
||||
import "../deploy/KillableModel.sol";
|
||||
import "./DelegationProxyInterface.sol";
|
||||
import "./DelegationProxyKernel.sol";
|
||||
import "../deploy/Factory.sol";
|
||||
import "../deploy/Instance.sol";
|
||||
|
||||
/**
|
||||
* @title DelegationProxyFactory
|
||||
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
|
||||
* @dev Upgradable delegation proxy factory
|
||||
*/
|
||||
contract DelegationProxyFactory {
|
||||
contract DelegationProxyFactory is Factory {
|
||||
|
||||
address public systemModel;
|
||||
address public recover;
|
||||
address public watchdog;
|
||||
function DelegationProxyFactory()
|
||||
Factory(new DelegationProxyKernel())
|
||||
public
|
||||
{ }
|
||||
|
||||
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));
|
||||
function createDelegationProxy(address _parent)
|
||||
external
|
||||
returns (DelegationProxyInterface)
|
||||
{
|
||||
DelegationProxyKernel instance = DelegationProxyKernel(address(new Instance(latestKernel)));
|
||||
instance.initializeDelegationProxy(_parent);
|
||||
return DelegationProxyInterface(address(instance));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,21 @@
|
|||
pragma solidity ^0.4.17;
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
|
@ -15,38 +26,6 @@ contract DelegationProxyInterface {
|
|||
*/
|
||||
function delegate(address _to) external;
|
||||
|
||||
/**
|
||||
* @notice Dig into delegate chain to find final delegate, makes delegationOfAt cheaper to call;
|
||||
* Should be used when you want to track an isolated long delegation chain FinalDelegate
|
||||
* @param _delegator Address to lookup final delegate.
|
||||
* @param _block From what block.
|
||||
* @return True when found final delegate.
|
||||
*/
|
||||
function findFinalDelegate(
|
||||
address _delegator,
|
||||
uint256 _block,
|
||||
uint256 loopLimit
|
||||
)
|
||||
external
|
||||
returns (bool);
|
||||
|
||||
/**
|
||||
* @notice Explore the chain from `_delegator`, saving FinalDelegate indexes for all delegates, makes delegationOfAt cheaper to call.
|
||||
* Should be used to track a common FinalDelegates in a small delegation chain, saving gas on repetitive lookups;
|
||||
* @param _delegator Address to lookup final delegate.
|
||||
* @param _block From what block.
|
||||
* @param _stackLimit how much deep explore to build the indexes
|
||||
* @return address of delegate when found, or the last top delegate found if stacklimit reached without getting into FinalDelegate.
|
||||
*/
|
||||
function buildFinalDelegateChain(
|
||||
address _delegator,
|
||||
uint256 _block,
|
||||
uint256 _stackLimit
|
||||
)
|
||||
public
|
||||
returns (address delegate, bool found);
|
||||
|
||||
|
||||
/**
|
||||
* @notice Reads `_who` configured delegation in this level,
|
||||
* or from parent level if `_who` never defined/defined to parent address.
|
||||
|
@ -56,7 +35,7 @@ contract DelegationProxyInterface {
|
|||
function delegatedTo(address _who)
|
||||
public
|
||||
constant
|
||||
returns (address);
|
||||
returns (address directDelegate);
|
||||
|
||||
/**
|
||||
* @notice Reads the final delegate of `_who` at block number `_block`.
|
||||
|
@ -66,7 +45,7 @@ contract DelegationProxyInterface {
|
|||
function delegationOf(address _who)
|
||||
public
|
||||
constant
|
||||
returns(address);
|
||||
returns(address finalDelegate);
|
||||
|
||||
/**
|
||||
* @notice Reads the sum of votes a `_who' have at block number `_block`.
|
||||
|
@ -125,7 +104,7 @@ contract DelegationProxyInterface {
|
|||
)
|
||||
public
|
||||
constant
|
||||
returns (address addr);
|
||||
returns (address directDelegate);
|
||||
|
||||
/**
|
||||
* @notice Reads the final delegate of `_who` at block number `_block`.
|
||||
|
@ -139,7 +118,7 @@ contract DelegationProxyInterface {
|
|||
)
|
||||
public
|
||||
constant
|
||||
returns(address delegate);
|
||||
returns(address finalDelegate);
|
||||
|
||||
/**
|
||||
* @dev Reads amount delegated influence received from other addresses.
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
pragma solidity ^0.4.11;
|
||||
pragma solidity ^0.4.21;
|
||||
|
||||
import "../deploy/KillableModel.sol";
|
||||
import "./DelegationProxy.sol";
|
||||
import "../deploy/InstanceStorage.sol";
|
||||
import "./DelegationProxyView.sol";
|
||||
|
||||
/**
|
||||
* @title DelegationProxyModel
|
||||
* @title DelegationProxyKernel
|
||||
* @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;
|
||||
contract DelegationProxyKernel is InstanceStorage, DelegationProxyView {
|
||||
bool private ready = false; //TODO: abstract initialized flag
|
||||
|
||||
/**
|
||||
* @notice Constructor of the model - only knows about watchdog that can trigger upgrade
|
||||
*/
|
||||
function DelegationProxyModel(address _watchdog) KillableModel(_watchdog) DelegationProxy(0x0) public {
|
||||
ready = true;
|
||||
function DelegationProxyKernel() DelegationProxy(0x0) public {
|
||||
ready = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Creates a new DelegationProxy with `_parentProxy` as default delegation.
|
||||
*/
|
||||
function initialize(address _parentProxy) public {
|
||||
function initializeDelegationProxy(address _parentProxy) public {
|
||||
require(!ready);
|
||||
ready = true;
|
||||
parentProxy = _parentProxy;
|
|
@ -0,0 +1,120 @@
|
|||
pragma solidity ^0.4.21;
|
||||
|
||||
import "./DelegationProxy.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @title DelegationProxy
|
||||
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
|
||||
* @dev Creates a delegation proxy layer for MiniMeTokenInterface.
|
||||
*/
|
||||
contract DelegationProxyView is DelegationProxy {
|
||||
|
||||
//storage of preprocessed view of FinalDelegate
|
||||
mapping(bytes32 => FinalDelegate) public delegationView;
|
||||
|
||||
struct FinalDelegate {
|
||||
address delegate;
|
||||
bool found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 finalDelegate)
|
||||
{
|
||||
bytes32 searchIndex = keccak256(_who, _block);
|
||||
FinalDelegate memory search = delegationView[searchIndex];
|
||||
if (search.found) {
|
||||
return search.delegate;
|
||||
} else {
|
||||
return super.delegationOfAt(_who, _block);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Dig into delegate chain to find final delegate, makes delegationOfAt cheaper to call;
|
||||
* Should be used when you want to track an isolated long delegation chain FinalDelegate
|
||||
* @param _delegator Address to lookup final delegate.
|
||||
* @param _block From what block.
|
||||
* @return True when found final delegate.
|
||||
*/
|
||||
function findFinalDelegate(
|
||||
address _delegator,
|
||||
uint256 _block,
|
||||
uint256 loopLimit
|
||||
)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
bytes32 searchIndex = keccak256(_delegator,_block);
|
||||
FinalDelegate memory search = delegationView[searchIndex];
|
||||
require(!search.found);
|
||||
for (uint i = 0; i < loopLimit; i++) {
|
||||
if (search.delegate == address(0)) {
|
||||
search.delegate = _delegator;
|
||||
}
|
||||
address delegateFrom = delegatedToAt(search.delegate, _block);
|
||||
if (delegateFrom == address(0)) {
|
||||
// search.delegate demonsted this address didnt delegated,
|
||||
search.found = true; // so its the final delegate
|
||||
} else {
|
||||
search.delegate = delegateFrom;
|
||||
}
|
||||
if (search.found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
delegationView[searchIndex] = search; //save search
|
||||
return search.found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Explore the chain from `_delegator`, saving FinalDelegate indexes for all delegates, makes delegationOfAt cheaper to call.
|
||||
* Should be used to track a common FinalDelegates in a small delegation chain, saving gas on repetitive lookups;
|
||||
* @param _delegator Address to lookup final delegate.
|
||||
* @param _block From what block.
|
||||
* @param _stackLimit how much deep explore to build the indexes
|
||||
* @return address of delegate when found, or the last top delegate found if stacklimit reached without getting into FinalDelegate.
|
||||
*/
|
||||
function buildFinalDelegateChain(
|
||||
address _delegator,
|
||||
uint256 _block,
|
||||
uint256 _stackLimit
|
||||
)
|
||||
public
|
||||
returns (address lastDelegate, bool found)
|
||||
{
|
||||
require(_block > block.number); //cannot renderize current state view ?
|
||||
bytes32 searchIndex = keccak256(_delegator, _block);
|
||||
FinalDelegate memory search = delegationView[searchIndex];
|
||||
if (!search.found) {
|
||||
if (search.delegate == address(0)) {
|
||||
lastDelegate = delegatedToAt(_delegator, _block);
|
||||
if (lastDelegate == address(0)) {
|
||||
//`_delegator` FinalDelegate is itself
|
||||
lastDelegate = _delegator;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && _stackLimit > 0) {
|
||||
//`_delegator` FinalDelegate is the same FinalDelegate of it's `delegate`
|
||||
(lastDelegate, found) = buildFinalDelegateChain(lastDelegate, _block, _stackLimit - 1);
|
||||
}
|
||||
delegationView[searchIndex] = FinalDelegate(lastDelegate, found);
|
||||
}
|
||||
return (lastDelegate, found);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue