mirror of https://github.com/nucypher/nucypher.git
Allow stake owner to bond worker
parent
2855349a27
commit
7ce5844105
|
@ -64,11 +64,15 @@ contract SimplePREApplication {
|
|||
}
|
||||
|
||||
/**
|
||||
* @dev Checks the existence of an operator in the contract
|
||||
* @dev Checks caller is an operator or stake owner
|
||||
*/
|
||||
modifier onlyOperator()
|
||||
modifier onlyOwnerOrOperator(address _operator)
|
||||
{
|
||||
require(isAuthorized(msg.sender), "Caller is not the operator");
|
||||
require(isAuthorized(_operator), "Not owner or operator");
|
||||
if (_operator != msg.sender) {
|
||||
(address owner,,) = tStaking.rolesOf(_operator);
|
||||
require(owner == msg.sender, "Not owner or operator");
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
|
@ -165,10 +169,11 @@ contract SimplePREApplication {
|
|||
|
||||
/**
|
||||
* @notice Bond worker
|
||||
* @param _operator Operator address
|
||||
* @param _worker Worker address. Must be a real address, not a contract
|
||||
*/
|
||||
function bondWorker(address _worker) external onlyOperator {
|
||||
OperatorInfo storage info = operatorInfo[msg.sender];
|
||||
function bondWorker(address _operator, address _worker) external onlyOwnerOrOperator(_operator) {
|
||||
OperatorInfo storage info = operatorInfo[_operator];
|
||||
require(_worker != info.worker, "Specified worker is already bonded with this operator");
|
||||
// If this staker had a worker ...
|
||||
if (info.worker != address(0)) {
|
||||
|
@ -183,22 +188,22 @@ contract SimplePREApplication {
|
|||
if (_worker != address(0)) {
|
||||
require(_operatorFromWorker[_worker] == address(0), "Specified worker is already in use");
|
||||
require(
|
||||
_worker == msg.sender || getBeneficiary(_worker) == address(0),
|
||||
_worker == _operator || getBeneficiary(_worker) == address(0),
|
||||
"Specified worker is an operator"
|
||||
);
|
||||
// Set new worker->operator relation
|
||||
_operatorFromWorker[_worker] = msg.sender;
|
||||
_operatorFromWorker[_worker] = _operator;
|
||||
}
|
||||
|
||||
if (info.workerStartTimestamp == 0) {
|
||||
operators.push(msg.sender);
|
||||
operators.push(_operator);
|
||||
}
|
||||
|
||||
// Bond new worker (or unbond if _worker == address(0))
|
||||
info.worker = _worker;
|
||||
info.workerStartTimestamp = block.timestamp;
|
||||
info.workerConfirmed = false;
|
||||
emit WorkerBonded(msg.sender, _worker, block.timestamp);
|
||||
emit WorkerBonded(_operator, _worker, block.timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -135,7 +135,7 @@ contract Intermediary {
|
|||
}
|
||||
|
||||
function bondWorker(address _worker) external {
|
||||
preApplication.bondWorker(_worker);
|
||||
preApplication.bondWorker(address(this), _worker);
|
||||
}
|
||||
|
||||
function confirmWorkerAddress() external {
|
||||
|
|
|
@ -26,7 +26,7 @@ CONFIRMATION_SLOT = 1
|
|||
|
||||
|
||||
def test_bond_worker(testerchain, threshold_staking, pre_application, token_economics):
|
||||
creator, operator1, operator2, operator3, operator4, worker1, worker2, worker3, *everyone_else = \
|
||||
creator, operator1, operator2, operator3, operator4, worker1, worker2, worker3, owner3, *everyone_else = \
|
||||
testerchain.client.accounts
|
||||
min_authorization = token_economics.minimum_allowed_locked
|
||||
min_worker_seconds = 24 * 60 * 60
|
||||
|
@ -43,7 +43,7 @@ def test_bond_worker(testerchain, threshold_staking, pre_application, token_econ
|
|||
tx = threshold_staking.functions.setStakes(
|
||||
operator2, min_authorization // 3, min_authorization // 3, min_authorization // 3 - 1).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = threshold_staking.functions.setRoles(operator3).transact()
|
||||
tx = threshold_staking.functions.setRoles(operator3, owner3, everyone_else[0], everyone_else[1]).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = threshold_staking.functions.setStakes(operator3, 0, min_authorization, 0).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
@ -68,16 +68,24 @@ def test_bond_worker(testerchain, threshold_staking, pre_application, token_econ
|
|||
|
||||
# Operator can't bond another operator as worker
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(operator2).transact({'from': operator1})
|
||||
tx = pre_application.functions.bondWorker(operator1, operator2).transact({'from': operator1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Operator can't bond worker if stake is less than minimum
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(worker1).transact({'from': operator2})
|
||||
tx = pre_application.functions.bondWorker(operator2, worker1).transact({'from': operator2})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Only operator or stake owner can bond worker
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(operator3, worker1).transact({'from': everyone_else[0]})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(operator3, worker1).transact({'from': everyone_else[1]})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Operator bonds worker and now worker can make a confirmation
|
||||
tx = pre_application.functions.bondWorker(worker1).transact({'from': operator3})
|
||||
tx = pre_application.functions.bondWorker(operator3, worker1).transact({'from': owner3})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert pre_application.functions.getWorkerFromOperator(operator3).call() == worker1
|
||||
|
@ -114,7 +122,7 @@ def test_bond_worker(testerchain, threshold_staking, pre_application, token_econ
|
|||
|
||||
# Worker is in use so other operators can't bond him
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(worker1).transact({'from': operator4})
|
||||
tx = pre_application.functions.bondWorker(operator4, worker1).transact({'from': operator4})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# # Worker can't be an operator
|
||||
|
@ -129,17 +137,17 @@ def test_bond_worker(testerchain, threshold_staking, pre_application, token_econ
|
|||
|
||||
# Can't bond worker twice too soon
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(worker2).transact({'from': operator3})
|
||||
tx = pre_application.functions.bondWorker(operator3, worker2).transact({'from': operator3})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# She can't unbond her worker too, until enough time has passed
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(NULL_ADDRESS).transact({'from': operator3})
|
||||
tx = pre_application.functions.bondWorker(operator3, NULL_ADDRESS).transact({'from': operator3})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Let's advance some time and unbond the worker
|
||||
testerchain.time_travel(seconds=min_worker_seconds)
|
||||
tx = pre_application.functions.bondWorker(NULL_ADDRESS).transact({'from': operator3})
|
||||
tx = pre_application.functions.bondWorker(operator3, NULL_ADDRESS).transact({'from': operator3})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert pre_application.functions.getWorkerFromOperator(operator3).call() == NULL_ADDRESS
|
||||
|
@ -166,7 +174,7 @@ def test_bond_worker(testerchain, threshold_staking, pre_application, token_econ
|
|||
assert event_args['startTimestamp'] == timestamp
|
||||
|
||||
# The operator can bond now a new worker, without waiting additional time.
|
||||
tx = pre_application.functions.bondWorker(worker2).transact({'from': operator3})
|
||||
tx = pre_application.functions.bondWorker(operator3, worker2).transact({'from': operator3})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert pre_application.functions.getWorkerFromOperator(operator3).call() == worker2
|
||||
|
@ -196,7 +204,7 @@ def test_bond_worker(testerchain, threshold_staking, pre_application, token_econ
|
|||
assert pre_application.functions.operatorInfo(operator3).call()[CONFIRMATION_SLOT]
|
||||
|
||||
# Another staker can bond a free worker
|
||||
tx = pre_application.functions.bondWorker(worker1).transact({'from': operator4})
|
||||
tx = pre_application.functions.bondWorker(operator4, worker1).transact({'from': operator4})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert pre_application.functions.getWorkerFromOperator(operator4).call() == worker1
|
||||
|
@ -230,7 +238,7 @@ def test_bond_worker(testerchain, threshold_staking, pre_application, token_econ
|
|||
assert pre_application.functions.isWorkerConfirmed(worker1).call()
|
||||
assert pre_application.functions.operatorInfo(operator4).call()[CONFIRMATION_SLOT]
|
||||
testerchain.time_travel(seconds=min_worker_seconds)
|
||||
tx = pre_application.functions.bondWorker(worker3).transact({'from': operator4})
|
||||
tx = pre_application.functions.bondWorker(operator4, worker3).transact({'from': operator4})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert pre_application.functions.getWorkerFromOperator(operator4).call() == worker3
|
||||
|
@ -270,12 +278,12 @@ def test_bond_worker(testerchain, threshold_staking, pre_application, token_econ
|
|||
# Operator can't bond the first worker again because worker is an operator now
|
||||
testerchain.time_travel(seconds=min_worker_seconds)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(worker1).transact({'from': operator4})
|
||||
tx = pre_application.functions.bondWorker(operator4, worker1).transact({'from': operator4})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Operator without intermediary contract can bond itself as worker
|
||||
# (Probably not best idea, but whatever)
|
||||
tx = pre_application.functions.bondWorker(operator1).transact({'from': operator1})
|
||||
tx = pre_application.functions.bondWorker(operator1, operator1).transact({'from': operator1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert pre_application.functions.getWorkerFromOperator(operator1).call() == operator1
|
||||
|
@ -345,7 +353,7 @@ def test_confirm_address(testerchain, threshold_staking, pre_application, token_
|
|||
# Bond contract as a worker
|
||||
tx = threshold_staking.functions.setStakes(operator, min_authorization, 0, 0).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = pre_application.functions.bondWorker(intermediary.address).transact({'from': operator})
|
||||
tx = pre_application.functions.bondWorker(operator, intermediary.address).transact({'from': operator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# But can't make a confirmation using an intermediary contract
|
||||
|
@ -355,7 +363,7 @@ def test_confirm_address(testerchain, threshold_staking, pre_application, token_
|
|||
|
||||
# Bond worker again and make confirmation
|
||||
testerchain.time_travel(seconds=min_worker_seconds)
|
||||
tx = pre_application.functions.bondWorker(worker).transact({'from': operator})
|
||||
tx = pre_application.functions.bondWorker(operator, worker).transact({'from': operator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = pre_application.functions.confirmWorkerAddress().transact({'from': worker})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
|
Loading…
Reference in New Issue