mirror of https://github.com/nucypher/nucypher.git
Draft of the WorkLock implementation
parent
8cf2fa7b44
commit
9b4aa51a89
|
@ -23,6 +23,14 @@ contract AdjudicatorInterface {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @notice WorkLock interface
|
||||
**/
|
||||
contract WorkLockInterface {
|
||||
function escrow() public view returns (address);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @notice Contract holds and locks stakers tokens.
|
||||
* Each staker that locks their tokens will receive some compensation
|
||||
|
@ -79,8 +87,10 @@ contract StakingEscrow is Issuer {
|
|||
address worker;
|
||||
// period when worker was set
|
||||
uint16 workerStartPeriod;
|
||||
// downtime
|
||||
// last confirmed active period
|
||||
uint16 lastActivePeriod;
|
||||
bool measureWork;
|
||||
uint256 workDone;
|
||||
Downtime[] pastDowntime;
|
||||
SubStakeInfo[] subStakes;
|
||||
}
|
||||
|
@ -110,6 +120,7 @@ contract StakingEscrow is Issuer {
|
|||
uint256 public maxAllowableLockedTokens;
|
||||
PolicyManagerInterface public policyManager;
|
||||
AdjudicatorInterface public adjudicator;
|
||||
WorkLockInterface public workLock;
|
||||
|
||||
/**
|
||||
* @notice Constructor sets address of token contract and coefficients for mining
|
||||
|
@ -181,6 +192,16 @@ contract StakingEscrow is Issuer {
|
|||
adjudicator = _adjudicator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Set worklock address
|
||||
**/
|
||||
function setWorkLock(WorkLockInterface _workLock) external onlyOwner {
|
||||
// Two-part require...
|
||||
require(address(workLock) == address(0) && // Can't workLock once it is set.
|
||||
_workLock.escrow() == address(this)); // This is the escrow for the new workLock.
|
||||
workLock = _workLock;
|
||||
}
|
||||
|
||||
//------------------------Main getters------------------------
|
||||
/**
|
||||
* @notice Get all tokens belonging to the staker
|
||||
|
@ -351,9 +372,29 @@ contract StakingEscrow is Issuer {
|
|||
return workerToStaker[_worker];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get work that done by the staker
|
||||
**/
|
||||
function getWorkDone(address _staker) public view returns (uint256) {
|
||||
return stakerInfo[_staker].workDone;
|
||||
}
|
||||
|
||||
//------------------------Main methods------------------------
|
||||
/**
|
||||
* @notice Set worker
|
||||
* @notice Start or stop measuring the work of a staker
|
||||
* @param _staker Staker
|
||||
* @param _measureWork Value for `measureWork` parameter
|
||||
* @return Work that was previously done
|
||||
**/
|
||||
function setWorkMeasurement(address _staker, bool _measureWork) public returns (uint256) {
|
||||
require(msg.sender == address(workLock));
|
||||
MinerInfo storage info = stakerInfo[_staker];
|
||||
info.measureWork = _measureWork;
|
||||
return info.workDone;
|
||||
// TODO event
|
||||
}
|
||||
|
||||
/** @notice Set worker
|
||||
* @param _worker Worker address. Must be a real address, not a contract
|
||||
**/
|
||||
function setWorker(address _worker) public onlyStaker {
|
||||
|
@ -414,6 +455,7 @@ contract StakingEscrow is Issuer {
|
|||
* @param _values Amount of tokens to deposit for each staker
|
||||
* @param _periods Amount of periods during which tokens will be locked for each staker
|
||||
**/
|
||||
// TODO remove?
|
||||
function preDeposit(address[] memory _stakers, uint256[] memory _values, uint16[] memory _periods)
|
||||
public isInitialized
|
||||
{
|
||||
|
@ -472,7 +514,7 @@ contract StakingEscrow is Issuer {
|
|||
payload := calldataload(0xA4)
|
||||
}
|
||||
payload = payload >> 8*(32 - payloadSize);
|
||||
deposit(_from, _value, uint16(payload));
|
||||
deposit(_from, _from, _value, uint16(payload));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -481,7 +523,7 @@ contract StakingEscrow is Issuer {
|
|||
* @param _periods Amount of periods during which tokens will be locked
|
||||
**/
|
||||
function deposit(uint256 _value, uint16 _periods) public {
|
||||
deposit(msg.sender, _value, _periods);
|
||||
deposit(msg.sender, msg.sender, _value, _periods);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -490,7 +532,18 @@ contract StakingEscrow is Issuer {
|
|||
* @param _value Amount of tokens to deposit
|
||||
* @param _periods Amount of periods during which tokens will be locked
|
||||
**/
|
||||
function deposit(address _staker, uint256 _value, uint16 _periods) internal isInitialized {
|
||||
function deposit(address _staker, uint256 _value, uint16 _periods) public {
|
||||
deposit(_miner, msg.sender, _value, _periods);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deposit tokens
|
||||
* @param _staker Staker
|
||||
* @param _payor Owner of tokens
|
||||
* @param _value Amount of tokens to deposit
|
||||
* @param _periods Amount of periods during which tokens will be locked
|
||||
**/
|
||||
function deposit(address _staker, address _payor, uint256 _value, uint16 _periods) internal isInitialized {
|
||||
require(_value != 0);
|
||||
StakerInfo storage info = stakerInfo[_staker];
|
||||
require(workerToStaker[_staker] == address(0) || workerToStaker[_staker] == info.worker,
|
||||
|
@ -501,7 +554,7 @@ contract StakingEscrow is Issuer {
|
|||
policyManager.register(_staker, getCurrentPeriod());
|
||||
}
|
||||
info.value = info.value.add(_value);
|
||||
token.safeTransferFrom(_staker, address(this), _value);
|
||||
token.safeTransferFrom(_payor, address(this), _value);
|
||||
lock(_staker, _value, _periods);
|
||||
emit Deposited(_staker, _value, _periods);
|
||||
}
|
||||
|
@ -752,6 +805,9 @@ contract StakingEscrow is Issuer {
|
|||
}
|
||||
|
||||
info.value = info.value.add(reward);
|
||||
if (info.measureWork) {
|
||||
info.workDone = info.workDone.add(reward);
|
||||
}
|
||||
emit Mined(_staker, previousPeriod, reward);
|
||||
}
|
||||
|
||||
|
@ -1219,6 +1275,7 @@ contract StakingEscrow is Issuer {
|
|||
require(delegateGet(_testTarget, "maxAllowableLockedTokens()") == maxAllowableLockedTokens);
|
||||
require(address(delegateGet(_testTarget, "policyManager()")) == address(policyManager));
|
||||
require(address(delegateGet(_testTarget, "adjudicator()")) == address(adjudicator));
|
||||
require(address(delegateGet(_testTarget, "workLock()")) == address(workLock));
|
||||
require(delegateGet(_testTarget, "lockedPerPeriod(uint16)",
|
||||
bytes32(bytes2(RESERVED_PERIOD))) == lockedPerPeriod[RESERVED_PERIOD]);
|
||||
require(address(delegateGet(_testTarget, "workerToStaker(address)", bytes32(0))) ==
|
||||
|
@ -1241,6 +1298,7 @@ contract StakingEscrow is Issuer {
|
|||
infoToCheck.lastActivePeriod == info.lastActivePeriod &&
|
||||
infoToCheck.worker == info.worker &&
|
||||
infoToCheck.workerStartPeriod == info.workerStartPeriod);
|
||||
// TODO check work
|
||||
|
||||
require(delegateGet(_testTarget, "getPastDowntimeLength(address)", staker) ==
|
||||
info.pastDowntime.length);
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
pragma solidity ^0.5.3;
|
||||
|
||||
|
||||
import "zeppelin/math/SafeMath.sol";
|
||||
import "contracts/NuCypherToken.sol";
|
||||
import "contracts/MinersEscrow.sol";
|
||||
|
||||
|
||||
/**
|
||||
* @notice The WorkLock distribution contract
|
||||
**/
|
||||
contract WorkLock {
|
||||
using SafeMath for uint256;
|
||||
|
||||
// TODO events
|
||||
|
||||
struct WorkInfo {
|
||||
uint256 depositedETH;
|
||||
uint256 workDone;
|
||||
}
|
||||
|
||||
NuCypherToken public token;
|
||||
MinersEscrow public escrow;
|
||||
// ETH -> NU
|
||||
uint256 public depositRate;
|
||||
// Work (reward in NU) -> ETH
|
||||
uint256 public refundRate;
|
||||
uint16 public lockedPeriods;
|
||||
mapping(address => WorkInfo) workInfo;
|
||||
|
||||
/**
|
||||
* @notice Claim tokens by transferring ETH. Claimed tokens will be deposited and locked as stake
|
||||
* in the MinersEscrow contract.
|
||||
**/
|
||||
function claim() public payable returns (uint256 claimedTokens) {
|
||||
claimedTokens = msg.value.mul(depositRate);
|
||||
require(token.balanceOf(address(this)) >= claimedTokens, "Not enough tokens in the contract");
|
||||
WorkInfo storage info = workInfo[msg.sender];
|
||||
if (info.depositedETH == 0) {
|
||||
info.workDone = escrow.setWorkMeasurement(msg.sender, true);
|
||||
}
|
||||
info.depositedETH = info.depositedETH.add(msg.value);
|
||||
token.approve(address(escrow), claimedTokens);
|
||||
escrow.deposit(msg.sender, claimedTokens, lockedPeriods);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Refund ETH for the work done
|
||||
**/
|
||||
function refund() public {
|
||||
WorkInfo storage info = workInfo[msg.sender];
|
||||
require(info.depositedETH > 0, "Nothing deposited");
|
||||
uint256 currentWork = escrow.getWorkDone(msg.sender);
|
||||
uint256 workDone = currentWork.sub(info.workDone);
|
||||
require(workDone > 0, "No work has been done.");
|
||||
uint256 refundETH = workDone.div(refundRate);
|
||||
if (refundETH > info.depositedETH) {
|
||||
refundETH = info.depositedETH;
|
||||
escrow.setWorkMeasurement(msg.sender, false);
|
||||
}
|
||||
info.depositedETH = info.depositedETH.sub(refundETH);
|
||||
info.workDone = currentWork;
|
||||
msg.sender.transfer(refundETH);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue