mirror of https://github.com/nucypher/nucypher.git
SimplePREApplication: worker -> operator
parent
e461f2ff52
commit
33df782883
|
@ -13,46 +13,46 @@ import "threshold/IStaking.sol";
|
|||
contract SimplePREApplication {
|
||||
|
||||
/**
|
||||
* @notice Signals that a worker was bonded to the staking provider
|
||||
* @notice Signals that an operator was bonded to the staking provider
|
||||
* @param stakingProvider Staking provider address
|
||||
* @param worker Worker address
|
||||
* @param operator Operator address
|
||||
* @param startTimestamp Timestamp bonding occurred
|
||||
*/
|
||||
event WorkerBonded(address indexed stakingProvider, address indexed worker, uint256 startTimestamp);
|
||||
event OperatorBonded(address indexed stakingProvider, address indexed operator, uint256 startTimestamp);
|
||||
|
||||
/**
|
||||
* @notice Signals that a worker address is confirmed
|
||||
* @notice Signals that an operator address is confirmed
|
||||
* @param stakingProvider Staking provider address
|
||||
* @param worker Worker address
|
||||
* @param operator Operator address
|
||||
*/
|
||||
event WorkerConfirmed(address indexed stakingProvider, address indexed worker);
|
||||
event OperatorConfirmed(address indexed stakingProvider, address indexed operator);
|
||||
|
||||
struct StakingProviderInfo {
|
||||
address worker;
|
||||
bool workerConfirmed;
|
||||
uint256 workerStartTimestamp;
|
||||
address operator;
|
||||
bool operatorConfirmed;
|
||||
uint256 operatorStartTimestamp;
|
||||
}
|
||||
|
||||
uint256 public immutable minAuthorization;
|
||||
uint256 public immutable minWorkerSeconds;
|
||||
uint256 public immutable minOperatorSeconds;
|
||||
|
||||
IStaking public immutable tStaking;
|
||||
|
||||
mapping (address => StakingProviderInfo) public stakingProviderInfo;
|
||||
address[] public stakingProviders;
|
||||
mapping(address => address) internal _stakingProviderFromWorker;
|
||||
mapping(address => address) internal _stakingProviderFromOperator;
|
||||
|
||||
|
||||
/**
|
||||
* @notice Constructor sets address of token contract and parameters for staking
|
||||
* @param _tStaking T token staking contract
|
||||
* @param _minAuthorization Amount of minimum allowable authorization
|
||||
* @param _minWorkerSeconds Min amount of seconds while a worker can't be changed
|
||||
* @param _minOperatorSeconds Min amount of seconds while an operator can't be changed
|
||||
*/
|
||||
constructor(
|
||||
IStaking _tStaking,
|
||||
uint256 _minAuthorization,
|
||||
uint256 _minWorkerSeconds
|
||||
uint256 _minOperatorSeconds
|
||||
) {
|
||||
require(
|
||||
_tStaking.authorizedStake(address(this), address(this)) == 0,
|
||||
|
@ -60,7 +60,7 @@ contract SimplePREApplication {
|
|||
);
|
||||
minAuthorization = _minAuthorization;
|
||||
tStaking = _tStaking;
|
||||
minWorkerSeconds = _minWorkerSeconds;
|
||||
minOperatorSeconds = _minOperatorSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,17 +79,17 @@ contract SimplePREApplication {
|
|||
|
||||
//-------------------------Main-------------------------
|
||||
/**
|
||||
* @notice Returns staking provider for specified worker
|
||||
* @notice Returns staking provider for specified operator
|
||||
*/
|
||||
function stakingProviderFromWorker(address _worker) public view returns (address) {
|
||||
return _stakingProviderFromWorker[_worker];
|
||||
function stakingProviderFromOperator(address _operator) public view returns (address) {
|
||||
return _stakingProviderFromOperator[_operator];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Returns worker for specified staking provider
|
||||
* @notice Returns operator for specified staking provider
|
||||
*/
|
||||
function getWorkerFromStakingProvider(address _stakingProvider) public view returns (address) {
|
||||
return stakingProviderInfo[_stakingProvider].worker;
|
||||
function getOperatorFromStakingProvider(address _stakingProvider) public view returns (address) {
|
||||
return stakingProviderInfo[_stakingProvider].operator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,7 +126,7 @@ contract SimplePREApplication {
|
|||
address stakingProvider = stakingProviders[i];
|
||||
StakingProviderInfo storage info = stakingProviderInfo[stakingProvider];
|
||||
uint256 eligibleAmount = authorizedStake(stakingProvider);
|
||||
if (eligibleAmount < minAuthorization || !info.workerConfirmed) {
|
||||
if (eligibleAmount < minAuthorization || !info.operatorConfirmed) {
|
||||
continue;
|
||||
}
|
||||
activeStakingProviders[resultIndex][0] = uint256(uint160(stakingProvider));
|
||||
|
@ -153,13 +153,13 @@ contract SimplePREApplication {
|
|||
}
|
||||
|
||||
/**
|
||||
* @notice Returns true if worker has confirmed address
|
||||
* @notice Returns true if operator has confirmed address
|
||||
*/
|
||||
// TODO maybe _stakingProvider instead of _worker?
|
||||
function isWorkerConfirmed(address _worker) public view returns (bool) {
|
||||
address stakingProvider = _stakingProviderFromWorker[_worker];
|
||||
// TODO maybe _stakingProvider instead of _operator as input?
|
||||
function isOperatorConfirmed(address _operator) public view returns (bool) {
|
||||
address stakingProvider = _stakingProviderFromOperator[_operator];
|
||||
StakingProviderInfo storage info = stakingProviderInfo[stakingProvider];
|
||||
return info.workerConfirmed;
|
||||
return info.operatorConfirmed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,57 +170,57 @@ contract SimplePREApplication {
|
|||
}
|
||||
|
||||
/**
|
||||
* @notice Bond worker
|
||||
* @notice Bond operator
|
||||
* @param _stakingProvider Staking provider address
|
||||
* @param _worker Worker address. Must be a real address, not a contract
|
||||
* @param _operator Operator address. Must be a real address, not a contract
|
||||
*/
|
||||
function bondWorker(address _stakingProvider, address _worker)
|
||||
function bondOperator(address _stakingProvider, address _operator)
|
||||
external onlyOwnerOrStakingProvider(_stakingProvider)
|
||||
{
|
||||
StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider];
|
||||
require(_worker != info.worker, "Specified worker is already bonded with this provider");
|
||||
// If this staker had a worker ...
|
||||
if (info.worker != address(0)) {
|
||||
require(_operator != info.operator, "Specified operator is already bonded with this provider");
|
||||
// If this staker had a operator ...
|
||||
if (info.operator != address(0)) {
|
||||
require(
|
||||
block.timestamp >= info.workerStartTimestamp + minWorkerSeconds,
|
||||
"Not enough time passed to change worker"
|
||||
block.timestamp >= info.operatorStartTimestamp + minOperatorSeconds,
|
||||
"Not enough time passed to change operator"
|
||||
);
|
||||
// Remove the old relation "worker->stakingProvider"
|
||||
_stakingProviderFromWorker[info.worker] = address(0);
|
||||
// Remove the old relation "operator->stakingProvider"
|
||||
_stakingProviderFromOperator[info.operator] = address(0);
|
||||
}
|
||||
|
||||
if (_worker != address(0)) {
|
||||
require(_stakingProviderFromWorker[_worker] == address(0), "Specified worker is already in use");
|
||||
if (_operator != address(0)) {
|
||||
require(_stakingProviderFromOperator[_operator] == address(0), "Specified operator is already in use");
|
||||
require(
|
||||
_worker == _stakingProvider || getBeneficiary(_worker) == address(0),
|
||||
"Specified worker is a provider"
|
||||
_operator == _stakingProvider || getBeneficiary(_operator) == address(0),
|
||||
"Specified operator is a provider"
|
||||
);
|
||||
// Set new worker->stakingProvider relation
|
||||
_stakingProviderFromWorker[_worker] = _stakingProvider;
|
||||
// Set new operator->stakingProvider relation
|
||||
_stakingProviderFromOperator[_operator] = _stakingProvider;
|
||||
}
|
||||
|
||||
if (info.workerStartTimestamp == 0) {
|
||||
if (info.operatorStartTimestamp == 0) {
|
||||
stakingProviders.push(_stakingProvider);
|
||||
}
|
||||
|
||||
// Bond new worker (or unbond if _worker == address(0))
|
||||
info.worker = _worker;
|
||||
info.workerStartTimestamp = block.timestamp;
|
||||
info.workerConfirmed = false;
|
||||
emit WorkerBonded(_stakingProvider, _worker, block.timestamp);
|
||||
// Bond new operator (or unbond if _operator == address(0))
|
||||
info.operator = _operator;
|
||||
info.operatorStartTimestamp = block.timestamp;
|
||||
info.operatorConfirmed = false;
|
||||
emit OperatorBonded(_stakingProvider, _operator, block.timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Make a confirmation by worker
|
||||
* @notice Make a confirmation by operator
|
||||
*/
|
||||
function confirmWorkerAddress() external {
|
||||
address stakingProvider = _stakingProviderFromWorker[msg.sender];
|
||||
require(isAuthorized(stakingProvider), "No stake associated with the worker");
|
||||
function confirmOperatorAddress() external {
|
||||
address stakingProvider = _stakingProviderFromOperator[msg.sender];
|
||||
require(isAuthorized(stakingProvider), "No stake associated with the operator");
|
||||
StakingProviderInfo storage info = stakingProviderInfo[stakingProvider];
|
||||
require(!info.workerConfirmed, "Worker address is already confirmed");
|
||||
require(msg.sender == tx.origin, "Only worker with real address can make a confirmation");
|
||||
info.workerConfirmed = true;
|
||||
emit WorkerConfirmed(stakingProvider, msg.sender);
|
||||
require(!info.operatorConfirmed, "Operator address is already confirmed");
|
||||
require(msg.sender == tx.origin, "Only operator with real address can make a confirmation");
|
||||
info.operatorConfirmed = true;
|
||||
emit OperatorConfirmed(stakingProvider, msg.sender);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ contract ThresholdStakingForPREApplicationMock {
|
|||
|
||||
|
||||
/**
|
||||
* @notice Intermediary contract for testing worker
|
||||
* @notice Intermediary contract for testing operator
|
||||
*/
|
||||
contract Intermediary {
|
||||
|
||||
|
@ -138,12 +138,12 @@ contract Intermediary {
|
|||
preApplication = _preApplication;
|
||||
}
|
||||
|
||||
function bondWorker(address _worker) external {
|
||||
preApplication.bondWorker(address(this), _worker);
|
||||
function bondOperator(address _operator) external {
|
||||
preApplication.bondOperator(address(this), _operator);
|
||||
}
|
||||
|
||||
function confirmWorkerAddress() external {
|
||||
preApplication.confirmWorkerAddress();
|
||||
function confirmOperatorAddress() external {
|
||||
preApplication.confirmOperatorAddress();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,14 +24,14 @@ from eth_utils import to_checksum_address
|
|||
CONFIRMATION_SLOT = 1
|
||||
|
||||
|
||||
def test_bond_worker(testerchain, threshold_staking, pre_application, token_economics):
|
||||
def test_bond_operator(testerchain, threshold_staking, pre_application, token_economics):
|
||||
creator, staking_provider_1, staking_provider_2, staking_provider_3, staking_provider_4, \
|
||||
worker1, worker2, worker3, owner3, beneficiary, authorizer, *everyone_else = \
|
||||
operator1, operator2, operator3, owner3, beneficiary, authorizer, *everyone_else = \
|
||||
testerchain.client.accounts
|
||||
min_authorization = token_economics.minimum_allowed_locked
|
||||
min_worker_seconds = 24 * 60 * 60
|
||||
min_operator_seconds = 24 * 60 * 60
|
||||
|
||||
worker_log = pre_application.events.WorkerBonded.createFilter(fromBlock='latest')
|
||||
operator_log = pre_application.events.OperatorBonded.createFilter(fromBlock='latest')
|
||||
|
||||
# Prepare staking providers: two with intermediary contract and two just a staking provider
|
||||
tx = threshold_staking.functions.setRoles(staking_provider_1).transact()
|
||||
|
@ -52,46 +52,48 @@ def test_bond_worker(testerchain, threshold_staking, pre_application, token_econ
|
|||
tx = threshold_staking.functions.setStakes(staking_provider_4, 0, 0, min_authorization).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
assert pre_application.functions.getWorkerFromStakingProvider(staking_provider_1).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromWorker(staking_provider_1).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.getWorkerFromStakingProvider(staking_provider_2).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromWorker(staking_provider_2).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.getWorkerFromStakingProvider(staking_provider_3).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromWorker(staking_provider_3).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.getWorkerFromStakingProvider(staking_provider_4).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromWorker(staking_provider_4).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.getOperatorFromStakingProvider(staking_provider_1).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromOperator(staking_provider_1).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.getOperatorFromStakingProvider(staking_provider_2).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromOperator(staking_provider_2).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.getOperatorFromStakingProvider(staking_provider_3).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromOperator(staking_provider_3).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.getOperatorFromStakingProvider(staking_provider_4).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromOperator(staking_provider_4).call() == NULL_ADDRESS
|
||||
|
||||
# Staking provider can't confirm worker address because there is no worker by default
|
||||
# Staking provider can't confirm operator address because there is no operator by default
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.confirmWorkerAddress().transact({'from': staking_provider_1})
|
||||
tx = pre_application.functions.confirmOperatorAddress().transact({'from': staking_provider_1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Staking provider can't bond another staking provider as worker
|
||||
# Staking provider can't bond another staking provider as operator
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(staking_provider_1, staking_provider_2).transact({'from': staking_provider_1})
|
||||
tx = pre_application.functions.bondOperator(staking_provider_1, staking_provider_2)\
|
||||
.transact({'from': staking_provider_1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Staking provider can't bond worker if stake is less than minimum
|
||||
# Staking provider can't bond operator if stake is less than minimum
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(staking_provider_2, worker1).transact({'from': staking_provider_2})
|
||||
tx = pre_application.functions.bondOperator(staking_provider_2, operator1)\
|
||||
.transact({'from': staking_provider_2})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Only staking provider or stake owner can bond worker
|
||||
# Only staking provider or stake owner can bond operator
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(staking_provider_3, worker1).transact({'from': beneficiary})
|
||||
tx = pre_application.functions.bondOperator(staking_provider_3, operator1).transact({'from': beneficiary})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(staking_provider_3, worker1).transact({'from': authorizer})
|
||||
tx = pre_application.functions.bondOperator(staking_provider_3, operator1).transact({'from': authorizer})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Staking provider bonds worker and now worker can make a confirmation
|
||||
tx = pre_application.functions.bondWorker(staking_provider_3, worker1).transact({'from': owner3})
|
||||
# Staking provider bonds operator and now operator can make a confirmation
|
||||
tx = pre_application.functions.bondOperator(staking_provider_3, operator1).transact({'from': owner3})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert pre_application.functions.getWorkerFromStakingProvider(staking_provider_3).call() == worker1
|
||||
assert pre_application.functions.stakingProviderFromWorker(worker1).call() == staking_provider_3
|
||||
assert pre_application.functions.getOperatorFromStakingProvider(staking_provider_3).call() == operator1
|
||||
assert pre_application.functions.stakingProviderFromOperator(operator1).call() == staking_provider_3
|
||||
assert not pre_application.functions.stakingProviderInfo(staking_provider_3).call()[CONFIRMATION_SLOT]
|
||||
assert not pre_application.functions.isWorkerConfirmed(worker1).call()
|
||||
assert not pre_application.functions.isOperatorConfirmed(operator1).call()
|
||||
assert pre_application.functions.getStakingProvidersLength().call() == 1
|
||||
assert pre_application.functions.stakingProviders(0).call() == staking_provider_3
|
||||
|
||||
|
@ -100,205 +102,205 @@ def test_bond_worker(testerchain, threshold_staking, pre_application, token_econ
|
|||
assert all_locked == 0
|
||||
assert len(staking_providers) == 0
|
||||
|
||||
tx = pre_application.functions.confirmWorkerAddress().transact({'from': worker1})
|
||||
tx = pre_application.functions.confirmOperatorAddress().transact({'from': operator1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert pre_application.functions.stakingProviderInfo(staking_provider_3).call()[CONFIRMATION_SLOT]
|
||||
assert pre_application.functions.isWorkerConfirmed(worker1).call()
|
||||
assert pre_application.functions.isOperatorConfirmed(operator1).call()
|
||||
|
||||
number_of_events = 1
|
||||
events = worker_log.get_all_entries()
|
||||
events = operator_log.get_all_entries()
|
||||
assert len(events) == number_of_events
|
||||
event_args = events[-1]['args']
|
||||
assert event_args['stakingProvider'] == staking_provider_3
|
||||
assert event_args['worker'] == worker1
|
||||
assert event_args['operator'] == operator1
|
||||
assert event_args['startTimestamp'] == timestamp
|
||||
|
||||
# After confirmation worker is becoming active
|
||||
# After confirmation operator is becoming active
|
||||
all_locked, staking_providers = pre_application.functions.getActiveStakingProviders(0, 0).call()
|
||||
assert all_locked == min_authorization
|
||||
assert len(staking_providers) == 1
|
||||
assert to_checksum_address(staking_providers[0][0]) == staking_provider_3
|
||||
assert staking_providers[0][1] == min_authorization
|
||||
|
||||
# Worker is in use so other stakingProviders can't bond him
|
||||
# Operator is in use so other stakingProviders can't bond him
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(staking_provider_4, worker1).transact({'from': staking_provider_4})
|
||||
tx = pre_application.functions.bondOperator(staking_provider_4, operator1).transact({'from': staking_provider_4})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# # Worker can't be a staking provider
|
||||
# tx = threshold_staking.functions.setRoles(worker1).transact()
|
||||
# # Operator can't be a staking provider
|
||||
# tx = threshold_staking.functions.setRoles(operator1).transact()
|
||||
# testerchain.wait_for_receipt(tx)
|
||||
# tx = threshold_staking.functions.setStakes(worker1, min_authorization, 0, 0).transact()
|
||||
# tx = threshold_staking.functions.setStakes(operator1, min_authorization, 0, 0).transact()
|
||||
# testerchain.wait_for_receipt(tx)
|
||||
# with pytest.raises((TransactionFailed, ValueError)):
|
||||
# tx = threshold_staking.functions.increaseAuthorization(
|
||||
# worker1, min_authorization, pre_application.address).transact({'from': worker1})
|
||||
# operator1, min_authorization, pre_application.address).transact({'from': operator1})
|
||||
# testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Can't bond worker twice too soon
|
||||
# Can't bond operator twice too soon
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(staking_provider_3, worker2).transact({'from': staking_provider_3})
|
||||
tx = pre_application.functions.bondOperator(staking_provider_3, operator2).transact({'from': staking_provider_3})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# She can't unbond her worker too, until enough time has passed
|
||||
# She can't unbond her operator too, until enough time has passed
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(staking_provider_3, NULL_ADDRESS).transact({'from': staking_provider_3})
|
||||
tx = pre_application.functions.bondOperator(staking_provider_3, NULL_ADDRESS).transact({'from': staking_provider_3})
|
||||
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(staking_provider_3, NULL_ADDRESS).transact({'from': staking_provider_3})
|
||||
# Let's advance some time and unbond the operator
|
||||
testerchain.time_travel(seconds=min_operator_seconds)
|
||||
tx = pre_application.functions.bondOperator(staking_provider_3, NULL_ADDRESS).transact({'from': staking_provider_3})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert pre_application.functions.getWorkerFromStakingProvider(staking_provider_3).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromWorker(staking_provider_3).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromWorker(worker1).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.getOperatorFromStakingProvider(staking_provider_3).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromOperator(staking_provider_3).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromOperator(operator1).call() == NULL_ADDRESS
|
||||
assert not pre_application.functions.stakingProviderInfo(staking_provider_3).call()[CONFIRMATION_SLOT]
|
||||
assert not pre_application.functions.isWorkerConfirmed(worker1).call()
|
||||
assert not pre_application.functions.isOperatorConfirmed(operator1).call()
|
||||
assert pre_application.functions.getStakingProvidersLength().call() == 1
|
||||
assert pre_application.functions.stakingProviders(0).call() == staking_provider_3
|
||||
|
||||
# Resetting worker removes from active list before next confirmation
|
||||
# Resetting operator removes from active list before next confirmation
|
||||
all_locked, staking_providers = pre_application.functions.getActiveStakingProviders(0, 0).call()
|
||||
assert all_locked == 0
|
||||
assert len(staking_providers) == 0
|
||||
|
||||
number_of_events += 1
|
||||
events = worker_log.get_all_entries()
|
||||
events = operator_log.get_all_entries()
|
||||
assert len(events) == number_of_events
|
||||
event_args = events[-1]['args']
|
||||
assert event_args['stakingProvider'] == staking_provider_3
|
||||
# Now the worker has been unbonded ...
|
||||
assert event_args['worker'] == NULL_ADDRESS
|
||||
# Now the operator has been unbonded ...
|
||||
assert event_args['operator'] == NULL_ADDRESS
|
||||
# ... with a new starting period.
|
||||
assert event_args['startTimestamp'] == timestamp
|
||||
|
||||
# The staking provider can bond now a new worker, without waiting additional time.
|
||||
tx = pre_application.functions.bondWorker(staking_provider_3, worker2).transact({'from': staking_provider_3})
|
||||
# The staking provider can bond now a new operator, without waiting additional time.
|
||||
tx = pre_application.functions.bondOperator(staking_provider_3, operator2).transact({'from': staking_provider_3})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert pre_application.functions.getWorkerFromStakingProvider(staking_provider_3).call() == worker2
|
||||
assert pre_application.functions.stakingProviderFromWorker(worker2).call() == staking_provider_3
|
||||
assert pre_application.functions.getOperatorFromStakingProvider(staking_provider_3).call() == operator2
|
||||
assert pre_application.functions.stakingProviderFromOperator(operator2).call() == staking_provider_3
|
||||
assert not pre_application.functions.stakingProviderInfo(staking_provider_3).call()[CONFIRMATION_SLOT]
|
||||
assert not pre_application.functions.isWorkerConfirmed(worker2).call()
|
||||
assert not pre_application.functions.isOperatorConfirmed(operator2).call()
|
||||
assert pre_application.functions.getStakingProvidersLength().call() == 1
|
||||
assert pre_application.functions.stakingProviders(0).call() == staking_provider_3
|
||||
|
||||
number_of_events += 1
|
||||
events = worker_log.get_all_entries()
|
||||
events = operator_log.get_all_entries()
|
||||
assert len(events) == number_of_events
|
||||
event_args = events[-1]['args']
|
||||
assert event_args['stakingProvider'] == staking_provider_3
|
||||
assert event_args['worker'] == worker2
|
||||
assert event_args['operator'] == operator2
|
||||
assert event_args['startTimestamp'] == timestamp
|
||||
|
||||
# Now the previous worker can no longer make a confirmation
|
||||
# Now the previous operator can no longer make a confirmation
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.confirmWorkerAddress().transact({'from': worker1})
|
||||
tx = pre_application.functions.confirmOperatorAddress().transact({'from': operator1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
# Only new worker can
|
||||
tx = pre_application.functions.confirmWorkerAddress().transact({'from': worker2})
|
||||
# Only new operator can
|
||||
tx = pre_application.functions.confirmOperatorAddress().transact({'from': operator2})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert not pre_application.functions.isWorkerConfirmed(worker1).call()
|
||||
assert pre_application.functions.isWorkerConfirmed(worker2).call()
|
||||
assert not pre_application.functions.isOperatorConfirmed(operator1).call()
|
||||
assert pre_application.functions.isOperatorConfirmed(operator2).call()
|
||||
assert pre_application.functions.stakingProviderInfo(staking_provider_3).call()[CONFIRMATION_SLOT]
|
||||
|
||||
# Another staker can bond a free worker
|
||||
tx = pre_application.functions.bondWorker(staking_provider_4, worker1).transact({'from': staking_provider_4})
|
||||
# Another staker can bond a free operator
|
||||
tx = pre_application.functions.bondOperator(staking_provider_4, operator1).transact({'from': staking_provider_4})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert pre_application.functions.getWorkerFromStakingProvider(staking_provider_4).call() == worker1
|
||||
assert pre_application.functions.stakingProviderFromWorker(worker1).call() == staking_provider_4
|
||||
assert not pre_application.functions.isWorkerConfirmed(worker1).call()
|
||||
assert pre_application.functions.getOperatorFromStakingProvider(staking_provider_4).call() == operator1
|
||||
assert pre_application.functions.stakingProviderFromOperator(operator1).call() == staking_provider_4
|
||||
assert not pre_application.functions.isOperatorConfirmed(operator1).call()
|
||||
assert not pre_application.functions.stakingProviderInfo(staking_provider_4).call()[CONFIRMATION_SLOT]
|
||||
assert pre_application.functions.getStakingProvidersLength().call() == 2
|
||||
assert pre_application.functions.stakingProviders(1).call() == staking_provider_4
|
||||
|
||||
number_of_events += 1
|
||||
events = worker_log.get_all_entries()
|
||||
events = operator_log.get_all_entries()
|
||||
assert len(events) == number_of_events
|
||||
event_args = events[-1]['args']
|
||||
assert event_args['stakingProvider'] == staking_provider_4
|
||||
assert event_args['worker'] == worker1
|
||||
assert event_args['operator'] == operator1
|
||||
assert event_args['startTimestamp'] == timestamp
|
||||
|
||||
# # The first worker still can't be a staking provider
|
||||
# tx = threshold_staking.functions.setRoles(worker1).transact()
|
||||
# # The first operator still can't be a staking provider
|
||||
# tx = threshold_staking.functions.setRoles(operator1).transact()
|
||||
# testerchain.wait_for_receipt(tx)
|
||||
# tx = threshold_staking.functions.setStakes(worker1, min_authorization, 0, 0).transact()
|
||||
# tx = threshold_staking.functions.setStakes(operator1, min_authorization, 0, 0).transact()
|
||||
# testerchain.wait_for_receipt(tx)
|
||||
# with pytest.raises((TransactionFailed, ValueError)):
|
||||
# tx = threshold_staking.functions.increaseAuthorization(
|
||||
# worker1, min_authorization, pre_application.address).transact({'from': worker1})
|
||||
# operator1, min_authorization, pre_application.address).transact({'from': operator1})
|
||||
# testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Bond worker again
|
||||
tx = pre_application.functions.confirmWorkerAddress().transact({'from': worker1})
|
||||
# Bond operator again
|
||||
tx = pre_application.functions.confirmOperatorAddress().transact({'from': operator1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert pre_application.functions.isWorkerConfirmed(worker1).call()
|
||||
assert pre_application.functions.isOperatorConfirmed(operator1).call()
|
||||
assert pre_application.functions.stakingProviderInfo(staking_provider_4).call()[CONFIRMATION_SLOT]
|
||||
testerchain.time_travel(seconds=min_worker_seconds)
|
||||
tx = pre_application.functions.bondWorker(staking_provider_4, worker3).transact({'from': staking_provider_4})
|
||||
testerchain.time_travel(seconds=min_operator_seconds)
|
||||
tx = pre_application.functions.bondOperator(staking_provider_4, operator3).transact({'from': staking_provider_4})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert pre_application.functions.getWorkerFromStakingProvider(staking_provider_4).call() == worker3
|
||||
assert pre_application.functions.stakingProviderFromWorker(worker3).call() == staking_provider_4
|
||||
assert pre_application.functions.stakingProviderFromWorker(worker1).call() == NULL_ADDRESS
|
||||
assert not pre_application.functions.isWorkerConfirmed(worker3).call()
|
||||
assert not pre_application.functions.isWorkerConfirmed(worker1).call()
|
||||
assert pre_application.functions.getOperatorFromStakingProvider(staking_provider_4).call() == operator3
|
||||
assert pre_application.functions.stakingProviderFromOperator(operator3).call() == staking_provider_4
|
||||
assert pre_application.functions.stakingProviderFromOperator(operator1).call() == NULL_ADDRESS
|
||||
assert not pre_application.functions.isOperatorConfirmed(operator3).call()
|
||||
assert not pre_application.functions.isOperatorConfirmed(operator1).call()
|
||||
assert not pre_application.functions.stakingProviderInfo(staking_provider_4).call()[CONFIRMATION_SLOT]
|
||||
assert pre_application.functions.getStakingProvidersLength().call() == 2
|
||||
assert pre_application.functions.stakingProviders(1).call() == staking_provider_4
|
||||
|
||||
# Resetting worker removes from active list before next confirmation
|
||||
# Resetting operator removes from active list before next confirmation
|
||||
all_locked, staking_providers = pre_application.functions.getActiveStakingProviders(1, 0).call()
|
||||
assert all_locked == 0
|
||||
assert len(staking_providers) == 0
|
||||
|
||||
number_of_events += 1
|
||||
events = worker_log.get_all_entries()
|
||||
events = operator_log.get_all_entries()
|
||||
assert len(events) == number_of_events
|
||||
event_args = events[-1]['args']
|
||||
assert event_args['stakingProvider'] == staking_provider_4
|
||||
assert event_args['worker'] == worker3
|
||||
assert event_args['operator'] == operator3
|
||||
assert event_args['startTimestamp'] == timestamp
|
||||
|
||||
# The first worker is free and can deposit tokens and become a staker
|
||||
tx = threshold_staking.functions.setRoles(worker1).transact()
|
||||
# The first operator is free and can deposit tokens and become a staker
|
||||
tx = threshold_staking.functions.setRoles(operator1).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = threshold_staking.functions.setStakes(
|
||||
worker1, min_authorization // 3, min_authorization // 3, min_authorization // 3).transact()
|
||||
operator1, min_authorization // 3, min_authorization // 3, min_authorization // 3).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
# tx = threshold_staking.functions.increaseAuthorization(
|
||||
# worker1, min_authorization, pre_application.address).transact({'from': worker1})
|
||||
# operator1, min_authorization, pre_application.address).transact({'from': operator1})
|
||||
# testerchain.wait_for_receipt(tx)
|
||||
assert pre_application.functions.getWorkerFromStakingProvider(worker1).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromWorker(worker1).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.getOperatorFromStakingProvider(operator1).call() == NULL_ADDRESS
|
||||
assert pre_application.functions.stakingProviderFromOperator(operator1).call() == NULL_ADDRESS
|
||||
|
||||
testerchain.time_travel(seconds=min_worker_seconds)
|
||||
testerchain.time_travel(seconds=min_operator_seconds)
|
||||
|
||||
# Staking provider can't bond the first worker again because worker is a provider now
|
||||
# Staking provider can't bond the first operator again because operator is a provider now
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.bondWorker(staking_provider_4, worker1).transact({'from': staking_provider_4})
|
||||
tx = pre_application.functions.bondOperator(staking_provider_4, operator1).transact({'from': staking_provider_4})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Provider without intermediary contract can bond itself as worker
|
||||
# Provider without intermediary contract can bond itself as operator
|
||||
# (Probably not best idea, but whatever)
|
||||
tx = pre_application.functions.bondWorker(
|
||||
tx = pre_application.functions.bondOperator(
|
||||
staking_provider_1, staking_provider_1).transact({'from': staking_provider_1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
timestamp = testerchain.w3.eth.getBlock('latest').timestamp
|
||||
assert pre_application.functions.getWorkerFromStakingProvider(staking_provider_1).call() == staking_provider_1
|
||||
assert pre_application.functions.stakingProviderFromWorker(staking_provider_1).call() == staking_provider_1
|
||||
assert pre_application.functions.getOperatorFromStakingProvider(staking_provider_1).call() == staking_provider_1
|
||||
assert pre_application.functions.stakingProviderFromOperator(staking_provider_1).call() == staking_provider_1
|
||||
assert pre_application.functions.getStakingProvidersLength().call() == 3
|
||||
assert pre_application.functions.stakingProviders(2).call() == staking_provider_1
|
||||
|
||||
number_of_events += 1
|
||||
events = worker_log.get_all_entries()
|
||||
events = operator_log.get_all_entries()
|
||||
assert len(events) == number_of_events
|
||||
event_args = events[-1]['args']
|
||||
assert event_args['stakingProvider'] == staking_provider_1
|
||||
assert event_args['worker'] == staking_provider_1
|
||||
assert event_args['operator'] == staking_provider_1
|
||||
assert event_args['startTimestamp'] == timestamp
|
||||
|
||||
# If stake will be less than minimum then confirmation is not possible
|
||||
|
@ -306,13 +308,13 @@ def test_bond_worker(testerchain, threshold_staking, pre_application, token_econ
|
|||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.confirmWorkerAddress().transact({'from': staking_provider_1})
|
||||
tx = pre_application.functions.confirmOperatorAddress().transact({'from': staking_provider_1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Now provider can make a confirmation
|
||||
tx = threshold_staking.functions.setStakes(staking_provider_1, 0, 0, min_authorization).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = pre_application.functions.confirmWorkerAddress().transact({'from': staking_provider_1})
|
||||
tx = pre_application.functions.confirmOperatorAddress().transact({'from': staking_provider_1})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# If stake will be less than minimum then provider is not active
|
||||
|
@ -331,54 +333,54 @@ def test_bond_worker(testerchain, threshold_staking, pre_application, token_econ
|
|||
|
||||
|
||||
def test_confirm_address(testerchain, threshold_staking, pre_application, token_economics, deploy_contract):
|
||||
creator, staking_provider, worker, *everyone_else = testerchain.client.accounts
|
||||
creator, staking_provider, operator, *everyone_else = testerchain.client.accounts
|
||||
min_authorization = token_economics.minimum_allowed_locked
|
||||
min_worker_seconds = 24 * 60 * 60
|
||||
min_operator_seconds = 24 * 60 * 60
|
||||
|
||||
confirmations_log = pre_application.events.WorkerConfirmed.createFilter(fromBlock='latest')
|
||||
confirmations_log = pre_application.events.OperatorConfirmed.createFilter(fromBlock='latest')
|
||||
|
||||
# Worker must be associated with provider that has minimum amount of tokens
|
||||
# Operator must be associated with provider that has minimum amount of tokens
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.confirmWorkerAddress().transact({'from': staking_provider})
|
||||
tx = pre_application.functions.confirmOperatorAddress().transact({'from': staking_provider})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = threshold_staking.functions.setRoles(staking_provider).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = threshold_staking.functions.setStakes(staking_provider, min_authorization - 1, 0, 0).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.confirmWorkerAddress().transact({'from': staking_provider})
|
||||
tx = pre_application.functions.confirmOperatorAddress().transact({'from': staking_provider})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Deploy intermediary contract
|
||||
intermediary, _ = deploy_contract('Intermediary', pre_application.address)
|
||||
|
||||
# Bond contract as a worker
|
||||
# Bond contract as a operator
|
||||
tx = threshold_staking.functions.setStakes(staking_provider, min_authorization, 0, 0).transact()
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = pre_application.functions.bondWorker(staking_provider, intermediary.address).transact({'from': staking_provider})
|
||||
tx = pre_application.functions.bondOperator(staking_provider, intermediary.address).transact({'from': staking_provider})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# But can't make a confirmation using an intermediary contract
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = intermediary.functions.confirmWorkerAddress().transact({'from': staking_provider})
|
||||
tx = intermediary.functions.confirmOperatorAddress().transact({'from': staking_provider})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
|
||||
# Bond worker again and make confirmation
|
||||
testerchain.time_travel(seconds=min_worker_seconds)
|
||||
tx = pre_application.functions.bondWorker(staking_provider, worker).transact({'from': staking_provider})
|
||||
# Bond operator again and make confirmation
|
||||
testerchain.time_travel(seconds=min_operator_seconds)
|
||||
tx = pre_application.functions.bondOperator(staking_provider, operator).transact({'from': staking_provider})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
tx = pre_application.functions.confirmWorkerAddress().transact({'from': worker})
|
||||
tx = pre_application.functions.confirmOperatorAddress().transact({'from': operator})
|
||||
testerchain.wait_for_receipt(tx)
|
||||
assert pre_application.functions.isWorkerConfirmed(worker).call()
|
||||
assert pre_application.functions.isOperatorConfirmed(operator).call()
|
||||
assert pre_application.functions.stakingProviderInfo(staking_provider).call()[CONFIRMATION_SLOT]
|
||||
|
||||
events = confirmations_log.get_all_entries()
|
||||
assert len(events) == 1
|
||||
event_args = events[-1]['args']
|
||||
assert event_args['stakingProvider'] == staking_provider
|
||||
assert event_args['worker'] == worker
|
||||
assert event_args['operator'] == operator
|
||||
|
||||
# Can't confirm twice
|
||||
with pytest.raises((TransactionFailed, ValueError)):
|
||||
tx = pre_application.functions.confirmWorkerAddress().transact({'from': worker})
|
||||
tx = pre_application.functions.confirmOperatorAddress().transact({'from': operator})
|
||||
testerchain.wait_for_receipt(tx)
|
Loading…
Reference in New Issue