-
Notifications
You must be signed in to change notification settings - Fork 76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Modular contracts for easy upgrades #59
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
pragma solidity ^0.4.18; | ||
|
||
import "zeppelin-solidity/contracts/ownership/Ownable.sol"; | ||
|
||
interface authorizedStakingContract { | ||
function stakeBalanceOf(address addr) public returns (uint256); | ||
} | ||
|
||
|
||
/** | ||
* @title Staking Proxy Contract | ||
* @dev An ownable staking proxy contract to provide upgradable staking. | ||
* Upgraded contract can be authorized as an active contract by the owner. | ||
* The old contracts are put into legacyContracts array. | ||
* The staking contracts must call emit events on this contract. | ||
*/ | ||
contract StakingProxy is Ownable { | ||
/** | ||
* @dev Only authorized contracts can invoke functions with this modifier. | ||
*/ | ||
modifier onlyAuthorized { | ||
require(isAuthorized(msg.sender)); | ||
_; | ||
} | ||
|
||
address public activeContract; | ||
address[] public legacyContracts; | ||
|
||
event Staked(address indexed user, uint256 amount); | ||
event Unstaked(address indexed user, uint256 amount); | ||
|
||
/** | ||
* @dev Gets the sum of all staking balances of the specified staker address. | ||
* @param _staker The address to query the balance of. | ||
* @return An uint256 representing the amount staked by the passed address. | ||
*/ | ||
function balanceOf(address _staker) | ||
public | ||
constant | ||
returns (uint256 _balance) | ||
{ | ||
uint256 balance = authorizedStakingContract(activeContract).stakeBalanceOf(_staker); | ||
for (uint i = 0; i < legacyContracts.length; i++) { | ||
balance = balance + authorizedStakingContract(legacyContracts[i]).stakeBalanceOf(_staker); | ||
} | ||
return balance; | ||
} | ||
|
||
/** | ||
* @dev Update active contract. | ||
* @param _contract The address of a staking contract. | ||
*/ | ||
function updateActiveContract(address _contract) | ||
public | ||
onlyOwner | ||
{ | ||
require(_contract != address(0)); | ||
require(_contract != activeContract); | ||
legacyContracts.push(activeContract); | ||
activeContract = _contract; | ||
} | ||
|
||
/** | ||
* @dev Emit staked event. | ||
* @param _staker The address of the staker. | ||
* @param _amount The staked amount. | ||
*/ | ||
function emitStakedEvent(address _staker, uint256 _amount) | ||
public | ||
onlyAuthorized | ||
{ | ||
Staked(_staker, _amount); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The 2nd Event could just be added at this point. There are some tradeoffs. Is it better to have the proxy think and not do any work - or better to guarantee that both events always happen? |
||
} | ||
|
||
/** | ||
* @dev Emit unstaked event. | ||
* @param _staker The address of the staker. | ||
* @param _amount The unstaked amount. | ||
*/ | ||
function emitUnstakedEvent(address _staker, uint256 _amount) | ||
public | ||
onlyAuthorized | ||
{ | ||
Unstaked(_staker, _amount); | ||
} | ||
|
||
/** | ||
* @dev Check if a staking contract is authorized to work with this contract. | ||
* @param _address The address of a staking contract. | ||
* @return A bool wether it's authorized. | ||
*/ | ||
function isAuthorized(address _address) | ||
public | ||
returns (bool) | ||
{ | ||
if (_address == activeContract) { | ||
return true; | ||
} | ||
for (uint i = 0; i < legacyContracts.length; i++) { | ||
if (legacyContracts[i] == _address) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the Go interface I also need a 2nd Event StakedAny (or some more appropriate name) that leaves out the "indexed" on the "user"
The abigen Go code will not let me catch the Staked event (with
address indexed user
unless I know the address of the user. My understanding of the higher level code means that it will never know the address of the user until the event happens. This is a circular loop. (((If you find a way to get the Go code to listen for events like this w/o removing the "indexed" I am totally for just the one event)))There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The key problem here is the
indexed
, because it's used for filtering, right? My reading of theeth_newFilter
docs seems to indicate we should be able to ignore the indexed stuff (topics) with the right parameters, no? Or is it just that the generated Go code can't specify a null for the topic?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have tried using NULL for the filter and I never get back the event. Inside geth the bloom filter is different when I use NULL than if I setup the same test from node.js - This may indicate that I am not doing it right - or that there is a defect in Geth or Abigen.