mirror of https://github.com/nucypher/nucypher.git
Events for worklock
parent
e6fff3973b
commit
75865a2388
|
@ -56,6 +56,7 @@ contract StakingEscrow is Issuer {
|
|||
event ReStakeSet(address indexed staker, bool reStake);
|
||||
event ReStakeLocked(address indexed staker, uint16 lockUntilPeriod);
|
||||
event WorkerSet(address indexed staker, address indexed worker, uint16 indexed startPeriod);
|
||||
event WorkMeasurementSet(address indexed miner, bool measureWork);
|
||||
|
||||
struct SubStakeInfo {
|
||||
uint16 firstPeriod;
|
||||
|
@ -388,10 +389,10 @@ contract StakingEscrow is Issuer {
|
|||
**/
|
||||
function setWorkMeasurement(address _staker, bool _measureWork) public returns (uint256) {
|
||||
require(msg.sender == address(workLock));
|
||||
MinerInfo storage info = stakerInfo[_staker];
|
||||
StakerInfo storage info = stakerInfo[_staker];
|
||||
info.measureWork = _measureWork;
|
||||
emit WorkMeasurementSet(_staker, _measureWork);
|
||||
return info.workDone;
|
||||
// TODO event
|
||||
}
|
||||
|
||||
/** @notice Set worker
|
||||
|
|
|
@ -12,7 +12,9 @@ import "contracts/MinersEscrow.sol";
|
|||
contract WorkLock {
|
||||
using SafeMath for uint256;
|
||||
|
||||
// TODO events
|
||||
event Bid(address indexed miner, uint256 depositedETH, uint256 claimedTokens);
|
||||
event Claimed(address indexed miner, uint256 claimedTokens);
|
||||
event Refund(address indexed miner, uint256 refundETH, uint256 workDone);
|
||||
|
||||
struct WorkInfo {
|
||||
uint256 depositedETH;
|
||||
|
@ -32,10 +34,17 @@ contract WorkLock {
|
|||
uint256 public maxAllowableLockedTokens;
|
||||
uint256 public allClaimedTokens;
|
||||
uint16 public lockedPeriods;
|
||||
// TODO add some getters
|
||||
mapping(address => WorkInfo) public workInfo;
|
||||
|
||||
// TODO docs
|
||||
/**
|
||||
* @param _token Token contract
|
||||
* @param _escrow Escrow contract
|
||||
* @param _startBidDate Timestamp when bidding starts
|
||||
* @param _endBidDate Timestamp when bidding will end
|
||||
* @param _depositRate ETH -> NU rate
|
||||
* @param _refundRate Work -> ETH rate
|
||||
* @param _lockedPeriods Number of periods during which claimed tokens will be locked
|
||||
**/
|
||||
constructor(
|
||||
NuCypherToken _token,
|
||||
MinersEscrow _escrow,
|
||||
|
@ -80,6 +89,7 @@ contract WorkLock {
|
|||
allClaimedTokens = allClaimedTokens.add(newClaimedTokens);
|
||||
require(allClaimedTokens <= token.balanceOf(address(this)),
|
||||
"Not enough tokens in the contract");
|
||||
emit Bid(msg.sender, msg.value, newClaimedTokens);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,6 +104,7 @@ contract WorkLock {
|
|||
info.workDone = escrow.setWorkMeasurement(msg.sender, true);
|
||||
token.approve(address(escrow), claimedTokens);
|
||||
escrow.deposit(msg.sender, claimedTokens, lockedPeriods);
|
||||
emit Claimed(msg.sender, claimedTokens);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,8 +125,18 @@ contract WorkLock {
|
|||
escrow.setWorkMeasurement(msg.sender, false);
|
||||
}
|
||||
info.depositedETH = info.depositedETH.sub(refundETH);
|
||||
info.workDone = info.workDone.add(refundETH.mul(refundRate));
|
||||
workDone = refundETH.mul(refundRate);
|
||||
info.workDone = info.workDone.add(workDone);
|
||||
emit Refund(msg.sender, refundETH, workDone);
|
||||
msg.sender.transfer(refundETH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get remaining work to full refund
|
||||
**/
|
||||
function getRemainingWork(address _miner) public view returns (uint256) {
|
||||
WorkInfo storage info = workInfo[_miner];
|
||||
return info.depositedETH.mul(refundRate);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -706,6 +706,7 @@ def test_worker(testerchain, token, escrow_contract):
|
|||
def test_measure_work(testerchain, token, escrow_contract):
|
||||
escrow = escrow_contract(10000)
|
||||
creator, ursula, *everyone_else = testerchain.interface.w3.eth.accounts
|
||||
work_measurement_log = escrow.events.WorkMeasurementSet.createFilter(fromBlock='latest')
|
||||
|
||||
# Initialize escrow contract
|
||||
tx = token.functions.transfer(escrow.address, int(NU(10 ** 9, 'NuNit'))).transact({'from': creator})
|
||||
|
@ -742,6 +743,13 @@ def test_measure_work(testerchain, token, escrow_contract):
|
|||
stake = escrow.functions.getAllTokens(ursula).call()
|
||||
tx = worklock.functions.setWorkMeasurement(ursula, True).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
events = work_measurement_log.get_all_entries()
|
||||
assert 1 == len(events)
|
||||
event_args = events[0]['args']
|
||||
assert ursula == event_args['miner']
|
||||
assert event_args['measureWork']
|
||||
|
||||
tx = escrow.functions.confirmActivity().transact({'from': ursula})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
testerchain.time_travel(hours=2)
|
||||
|
@ -768,6 +776,13 @@ def test_measure_work(testerchain, token, escrow_contract):
|
|||
work_done = escrow.functions.getWorkDone(ursula).call()
|
||||
tx = worklock.functions.setWorkMeasurement(ursula, False).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
events = work_measurement_log.get_all_entries()
|
||||
assert 2 == len(events)
|
||||
event_args = events[1]['args']
|
||||
assert ursula == event_args['miner']
|
||||
assert not event_args['measureWork']
|
||||
|
||||
tx = escrow.functions.confirmActivity().transact({'from': ursula})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
testerchain.time_travel(hours=2)
|
||||
|
|
|
@ -58,6 +58,10 @@ def test_worklock(testerchain, token_economics):
|
|||
assert worklock.functions.depositRate().call() == deposit_rate
|
||||
assert worklock.functions.refundRate().call() == refund_rate
|
||||
|
||||
bidding_log = worklock.events.Bid.createFilter(fromBlock='latest')
|
||||
claim_log = worklock.events.Claimed.createFilter(fromBlock='latest')
|
||||
refund_log = worklock.events.Refund.createFilter(fromBlock='latest')
|
||||
|
||||
# Transfer tokens to WorkLock
|
||||
worklock_supply = 2 * token_economics.maximum_allowed_locked - 1
|
||||
tx = token.functions.transfer(worklock.address, worklock_supply).transact({'from': creator})
|
||||
|
@ -107,6 +111,13 @@ def test_worklock(testerchain, token_economics):
|
|||
assert worklock.functions.workInfo(ursula1).call()[0] == minimum_deposit_eth
|
||||
assert testerchain.interface.w3.eth.getBalance(worklock.address) == minimum_deposit_eth
|
||||
|
||||
events = bidding_log.get_all_entries()
|
||||
assert 1 == len(events)
|
||||
event_args = events[0]['args']
|
||||
assert event_args['miner'] == ursula1
|
||||
assert event_args['depositedETH'] == minimum_deposit_eth
|
||||
assert event_args['claimedTokens'] == token_economics.minimum_allowed_locked
|
||||
|
||||
# Second Ursula does first bid
|
||||
assert worklock.functions.workInfo(ursula2).call()[0] == 0
|
||||
tx = worklock.functions.bid().transact({'from': ursula2, 'value': maximum_deposit_eth, 'gas_price': 0})
|
||||
|
@ -116,6 +127,13 @@ def test_worklock(testerchain, token_economics):
|
|||
assert worklock.functions.workInfo(ursula2).call()[0] == maximum_deposit_eth
|
||||
assert testerchain.interface.w3.eth.getBalance(worklock.address) == maximum_deposit_eth + minimum_deposit_eth
|
||||
|
||||
events = bidding_log.get_all_entries()
|
||||
assert 2 == len(events)
|
||||
event_args = events[1]['args']
|
||||
assert event_args['miner'] == ursula2
|
||||
assert event_args['depositedETH'] == maximum_deposit_eth
|
||||
assert event_args['claimedTokens'] == token_economics.maximum_allowed_locked
|
||||
|
||||
# Can't bid again with too high ETH
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.bid().transact(
|
||||
|
@ -133,6 +151,13 @@ def test_worklock(testerchain, token_economics):
|
|||
assert worklock.functions.workInfo(ursula1).call()[0] == 2 * minimum_deposit_eth
|
||||
assert testerchain.interface.w3.eth.getBalance(worklock.address) == maximum_deposit_eth + 2 * minimum_deposit_eth
|
||||
|
||||
events = bidding_log.get_all_entries()
|
||||
assert 3 == len(events)
|
||||
event_args = events[2]['args']
|
||||
assert event_args['miner'] == ursula1
|
||||
assert event_args['depositedETH'] == minimum_deposit_eth
|
||||
assert event_args['claimedTokens'] == token_economics.minimum_allowed_locked
|
||||
|
||||
# Can't bid again: not enough tokens in worklock
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.bid().transact(
|
||||
|
@ -167,6 +192,7 @@ def test_worklock(testerchain, token_economics):
|
|||
assert periods == 0
|
||||
tx = worklock.functions.claim().transact({'from': ursula1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.getRemainingWork(ursula1).call() == 2 * minimum_deposit_eth * refund_rate
|
||||
value, measure_work, work_done, periods = escrow.functions.minerInfo(ursula1).call()
|
||||
assert value == 2 * token_economics.minimum_allowed_locked
|
||||
assert measure_work
|
||||
|
@ -175,6 +201,12 @@ def test_worklock(testerchain, token_economics):
|
|||
worklock_supply - 2 * token_economics.minimum_allowed_locked
|
||||
assert token.functions.balanceOf(escrow.address).call() == 2 * token_economics.minimum_allowed_locked
|
||||
|
||||
events = claim_log.get_all_entries()
|
||||
assert 1 == len(events)
|
||||
event_args = events[0]['args']
|
||||
assert event_args['miner'] == ursula1
|
||||
assert event_args['claimedTokens'] == 2 * token_economics.minimum_allowed_locked
|
||||
|
||||
# Can't claim more than once
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.claim().transact({'from': ursula1, 'gas_price': 0})
|
||||
|
@ -185,6 +217,31 @@ def test_worklock(testerchain, token_economics):
|
|||
tx = worklock.functions.refund().transact({'from': ursula1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Second Ursula claims tokens
|
||||
value, measure_work, _work_done, periods = escrow.functions.minerInfo(ursula2).call()
|
||||
assert value == 0
|
||||
assert not measure_work
|
||||
assert periods == 0
|
||||
tx = escrow.functions.setWorkDone(ursula2, refund_rate * minimum_deposit_eth).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = worklock.functions.claim().transact({'from': ursula2, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.getRemainingWork(ursula2).call() == maximum_deposit_eth * refund_rate
|
||||
value, measure_work, work_done, periods = escrow.functions.minerInfo(ursula2).call()
|
||||
assert value == token_economics.maximum_allowed_locked
|
||||
assert measure_work
|
||||
assert periods == 2 * token_economics.minimum_locked_periods
|
||||
assert token.functions.balanceOf(worklock.address).call() == \
|
||||
worklock_supply - 2 * token_economics.minimum_allowed_locked - token_economics.maximum_allowed_locked
|
||||
assert token.functions.balanceOf(escrow.address).call() == \
|
||||
2 * token_economics.minimum_allowed_locked + token_economics.maximum_allowed_locked
|
||||
|
||||
events = claim_log.get_all_entries()
|
||||
assert 2 == len(events)
|
||||
event_args = events[1]['args']
|
||||
assert event_args['miner'] == ursula2
|
||||
assert event_args['claimedTokens'] == token_economics.maximum_allowed_locked
|
||||
|
||||
# "Do" some work and partial refund
|
||||
ursula1_balance = testerchain.interface.w3.eth.getBalance(ursula1)
|
||||
work_done = refund_rate * minimum_deposit_eth + refund_rate // 2
|
||||
|
@ -193,11 +250,19 @@ def test_worklock(testerchain, token_economics):
|
|||
tx = worklock.functions.refund().transact({'from': ursula1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.workInfo(ursula1).call()[0] == minimum_deposit_eth
|
||||
assert worklock.functions.getRemainingWork(ursula1).call() == minimum_deposit_eth * refund_rate
|
||||
assert testerchain.interface.w3.eth.getBalance(ursula1) == ursula1_balance + minimum_deposit_eth
|
||||
assert testerchain.interface.w3.eth.getBalance(worklock.address) == maximum_deposit_eth + minimum_deposit_eth
|
||||
_value, measure_work, _work_done, _periods = escrow.functions.minerInfo(ursula1).call()
|
||||
assert measure_work
|
||||
|
||||
events = refund_log.get_all_entries()
|
||||
assert 1 == len(events)
|
||||
event_args = events[0]['args']
|
||||
assert event_args['miner'] == ursula1
|
||||
assert event_args['refundETH'] == minimum_deposit_eth
|
||||
assert event_args['workDone'] == minimum_deposit_eth * refund_rate
|
||||
|
||||
# "Do" more work and full refund
|
||||
ursula1_balance = testerchain.interface.w3.eth.getBalance(ursula1)
|
||||
work_done = refund_rate * 2 * minimum_deposit_eth
|
||||
|
@ -206,12 +271,22 @@ def test_worklock(testerchain, token_economics):
|
|||
tx = worklock.functions.refund().transact({'from': ursula1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert worklock.functions.workInfo(ursula1).call()[0] == 0
|
||||
assert worklock.functions.getRemainingWork(ursula1).call() == 0
|
||||
assert testerchain.interface.w3.eth.getBalance(ursula1) == ursula1_balance + minimum_deposit_eth
|
||||
assert testerchain.interface.w3.eth.getBalance(worklock.address) == maximum_deposit_eth
|
||||
_value, measure_work, _work_done, _periods = escrow.functions.minerInfo(ursula1).call()
|
||||
assert not measure_work
|
||||
|
||||
events = refund_log.get_all_entries()
|
||||
assert 2 == len(events)
|
||||
event_args = events[1]['args']
|
||||
assert event_args['miner'] == ursula1
|
||||
assert event_args['refundETH'] == minimum_deposit_eth
|
||||
assert event_args['workDone'] == minimum_deposit_eth * refund_rate
|
||||
|
||||
# Can't refund more tokens
|
||||
tx = escrow.functions.setWorkDone(ursula1, 2 * work_done).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = worklock.functions.refund().transact({'from': ursula1, 'gas_price': 0})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
|
Loading…
Reference in New Issue