120 lines
4.1 KiB
Solidity
120 lines
4.1 KiB
Solidity
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
|
|
view
|
|
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);
|
|
}
|
|
|
|
} |