Skip to content

Commit

Permalink
PRECBDApplication: syncing amount with StakeInfo, tests for syncing o…
Browse files Browse the repository at this point in the history
…perator with StakeInfo
  • Loading branch information
vzotova committed Jul 14, 2023
1 parent c076d41 commit 8eafef3
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 8 deletions.
35 changes: 30 additions & 5 deletions contracts/contracts/PRECBDApplication.sol
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ contract PRECBDApplication is IApplication, OwnableUpgradeable {

info.authorized = _toAmount;
emit AuthorizationIncreased(_stakingProvider, _fromAmount, _toAmount);
_updateAuthorization(_stakingProvider, info);
}

/**
Expand Down Expand Up @@ -406,9 +407,9 @@ contract PRECBDApplication is IApplication, OwnableUpgradeable {
if (info.authorized == 0) {
_stakingProviderFromOperator[info.operator] = address(0);
info.operator = address(0);
info.operatorConfirmed = false;
_releaseOperator(_stakingProvider);
}
_updateAuthorization(_stakingProvider, info);
}

/**
Expand Down Expand Up @@ -438,6 +439,7 @@ contract PRECBDApplication is IApplication, OwnableUpgradeable {
info.deauthorizing = _fromAmount - _toAmount;
info.endDeauthorization = uint64(block.timestamp + deauthorizationDuration);
emit AuthorizationDecreaseRequested(_stakingProvider, _fromAmount, _toAmount);
_updateAuthorization(_stakingProvider, info);
}

/**
Expand All @@ -463,9 +465,9 @@ contract PRECBDApplication is IApplication, OwnableUpgradeable {
if (info.authorized == 0) {
_stakingProviderFromOperator[info.operator] = address(0);
info.operator = address(0);
info.operatorConfirmed = false;
_releaseOperator(_stakingProvider);
}
_updateAuthorization(_stakingProvider, info);
}

/**
Expand All @@ -490,9 +492,9 @@ contract PRECBDApplication is IApplication, OwnableUpgradeable {
if (info.authorized == 0) {
_stakingProviderFromOperator[info.operator] = address(0);
info.operator = address(0);
info.operatorConfirmed = false;
_releaseOperator(_stakingProvider);
}
_updateAuthorization(_stakingProvider, info);
}

//-------------------------Main-------------------------
Expand All @@ -517,6 +519,13 @@ contract PRECBDApplication is IApplication, OwnableUpgradeable {
return stakingProviderInfo[_stakingProvider].authorized;
}

/**
* @notice Get all tokens delegated to the staking provider
*/
function getEligibleAmount(StakingProviderInfo storage _info) internal view returns (uint96) {
return _info.authorized - _info.deauthorizing;
}

/**
* @notice Get the value of authorized tokens for active providers as well as providers and their authorized tokens
* @param _startIndex Start index for looking in providers array
Expand All @@ -542,7 +551,7 @@ contract PRECBDApplication is IApplication, OwnableUpgradeable {
for (uint256 i = _startIndex; i < endIndex; i++) {
address stakingProvider = stakingProviders[i];
StakingProviderInfo storage info = stakingProviderInfo[stakingProvider];
uint256 eligibleAmount = info.authorized - info.deauthorizing;
uint256 eligibleAmount = getEligibleAmount(info);
if (eligibleAmount < minAuthorization || !info.operatorConfirmed) {
continue;
}
Expand Down Expand Up @@ -629,7 +638,6 @@ contract PRECBDApplication is IApplication, OwnableUpgradeable {
// Bond new operator (or unbond if _operator == address(0))
info.operator = _operator;
info.operatorStartTimestamp = uint64(block.timestamp);
info.operatorConfirmed = false;
emit OperatorBonded(_stakingProvider, _operator, previousOperator, block.timestamp);
_releaseOperator(_stakingProvider);
}
Expand All @@ -653,13 +661,30 @@ contract PRECBDApplication is IApplication, OwnableUpgradeable {
updatableStakeInfo.updateOperator(stakingProvider, msg.sender);
}
}

//-------------------------XChain-------------------------

/**
* @notice Resets operator confirmation
*/
function _releaseOperator(address _stakingProvider) internal {
stakingProviderInfo[_stakingProvider].operatorConfirmed = false;
if (address(updatableStakeInfo) != address(0)) {
updatableStakeInfo.updateOperator(_stakingProvider, address(0));
}
}

/**
* @notice Send updated authorized amount to xchain contract
*/
function _updateAuthorization(address _stakingProvider, StakingProviderInfo storage _info) internal {
if (address(updatableStakeInfo) != address(0)) {
// TODO send both authorized and eligible amounts in case of slashing from StakeInfo
uint96 eligibleAmount = getEligibleAmount(_info);
updatableStakeInfo.updateAmount(_stakingProvider, eligibleAmount);
}
}

//-------------------------Slashing-------------------------
/**
* @notice Slash the provider's stake and reward the investigator
Expand Down
42 changes: 42 additions & 0 deletions tests/application/test_authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
MIN_AUTHORIZATION = Web3.to_wei(40_000, "ether")
DEAUTHORIZATION_DURATION = 60 * 60 * 24 * 60 # 60 days in seconds

STAKE_INFO_OPERATOR_SLOT = 0


def test_authorization_increase(accounts, threshold_staking, pre_cbd_application, stake_info):
"""
Expand Down Expand Up @@ -165,6 +167,7 @@ def test_involuntary_authorization_decrease(
assert pre_cbd_application.isAuthorized(staking_provider)
assert not pre_cbd_application.isOperatorConfirmed(staking_provider)
assert not pre_cbd_application.stakingProviderInfo(staking_provider)[OPERATOR_CONFIRMED_SLOT]
assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS

events = pre_cbd_application.AuthorizationInvoluntaryDecreased.from_receipt(tx)
assert len(events) == 1
Expand Down Expand Up @@ -194,6 +197,7 @@ def test_involuntary_authorization_decrease(
assert pre_cbd_application.isAuthorized(staking_provider)
assert not pre_cbd_application.isOperatorConfirmed(staking_provider)
assert not pre_cbd_application.stakingProviderInfo(staking_provider)[OPERATOR_CONFIRMED_SLOT]
assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS

events = pre_cbd_application.AuthorizationInvoluntaryDecreased.from_receipt(tx)
assert len(events) == 1
Expand Down Expand Up @@ -224,6 +228,7 @@ def test_involuntary_authorization_decrease(
assert pre_cbd_application.isOperatorConfirmed(staking_provider)
assert pre_cbd_application.getOperatorFromStakingProvider(staking_provider) == staking_provider
assert pre_cbd_application.stakingProviderFromOperator(staking_provider) == staking_provider
assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == staking_provider

events = pre_cbd_application.AuthorizationInvoluntaryDecreased.from_receipt(tx)
assert len(events) == 1
Expand All @@ -245,6 +250,7 @@ def test_involuntary_authorization_decrease(
assert not pre_cbd_application.stakingProviderInfo(staking_provider)[OPERATOR_CONFIRMED_SLOT]
assert pre_cbd_application.getOperatorFromStakingProvider(staking_provider) == ZERO_ADDRESS
assert pre_cbd_application.stakingProviderFromOperator(staking_provider) == ZERO_ADDRESS
assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS

events = pre_cbd_application.AuthorizationInvoluntaryDecreased.from_receipt(tx)
assert len(events) == 1
Expand Down Expand Up @@ -276,6 +282,14 @@ def test_involuntary_authorization_decrease(
assert event["fromAmount"] == value
assert event["toAmount"] == authorization

# Decrease everything again without syncing with StakeInfo
pre_cbd_application.setUpdatableStakeInfo(ZERO_ADDRESS, sender=creator)
threshold_staking.involuntaryAuthorizationDecrease(
staking_provider, authorization, 0, sender=creator
)
assert pre_cbd_application.getOperatorFromStakingProvider(staking_provider) == ZERO_ADDRESS
assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == staking_provider


def test_authorization_decrease_request(
accounts, threshold_staking, pre_cbd_application, stake_info, chain
Expand Down Expand Up @@ -460,6 +474,7 @@ def test_finish_authorization_decrease(
threshold_staking.authorizedStake(staking_provider, pre_cbd_application.address)
== new_value
)
assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == staking_provider

events = pre_cbd_application.AuthorizationDecreaseApproved.from_receipt(tx)
assert len(events) == 1
Expand All @@ -485,6 +500,7 @@ def test_finish_authorization_decrease(
assert not pre_cbd_application.isOperatorConfirmed(staking_provider)
assert not pre_cbd_application.stakingProviderInfo(staking_provider)[OPERATOR_CONFIRMED_SLOT]
assert threshold_staking.authorizedStake(staking_provider, pre_cbd_application.address) == 0
assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS

events = pre_cbd_application.AuthorizationDecreaseApproved.from_receipt(tx)
assert len(events) == 1
Expand All @@ -493,6 +509,18 @@ def test_finish_authorization_decrease(
assert event["fromAmount"] == value
assert event["toAmount"] == 0

# Decrease everything again without syncing with StakeInfo
value = minimum_authorization
threshold_staking.authorizationIncreased(staking_provider, 0, value, sender=creator)
pre_cbd_application.bondOperator(staking_provider, staking_provider, sender=staking_provider)
pre_cbd_application.confirmOperatorAddress(sender=staking_provider)
threshold_staking.authorizationDecreaseRequested(staking_provider, value, 0, sender=creator)
chain.pending_timestamp += deauthorization_duration
pre_cbd_application.setUpdatableStakeInfo(ZERO_ADDRESS, sender=creator)
pre_cbd_application.finishAuthorizationDecrease(staking_provider, sender=creator)
assert pre_cbd_application.getOperatorFromStakingProvider(staking_provider) == ZERO_ADDRESS
assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == staking_provider


def test_resync(accounts, threshold_staking, pre_cbd_application, stake_info):
"""
Expand Down Expand Up @@ -551,6 +579,7 @@ def test_resync(accounts, threshold_staking, pre_cbd_application, stake_info):
assert pre_cbd_application.authorizedStake(staking_provider) == new_value
assert pre_cbd_application.isAuthorized(staking_provider)
assert pre_cbd_application.isOperatorConfirmed(staking_provider)
assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == staking_provider

events = pre_cbd_application.AuthorizationReSynchronized.from_receipt(tx)
assert len(events) == 1
Expand Down Expand Up @@ -579,6 +608,7 @@ def test_resync(accounts, threshold_staking, pre_cbd_application, stake_info):
assert pre_cbd_application.authorizedStake(staking_provider) == new_value
assert pre_cbd_application.isAuthorized(staking_provider)
assert pre_cbd_application.isOperatorConfirmed(staking_provider)
assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == staking_provider

events = pre_cbd_application.AuthorizationReSynchronized.from_receipt(tx)
assert len(events) == 1
Expand All @@ -601,10 +631,22 @@ def test_resync(accounts, threshold_staking, pre_cbd_application, stake_info):
assert not pre_cbd_application.isAuthorized(staking_provider)
assert not pre_cbd_application.isOperatorConfirmed(staking_provider)
assert not pre_cbd_application.stakingProviderInfo(staking_provider)[OPERATOR_CONFIRMED_SLOT]
assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS

events = pre_cbd_application.AuthorizationReSynchronized.from_receipt(tx)
assert len(events) == 1
event = events[0]
assert event["stakingProvider"] == staking_provider
assert event["fromAmount"] == value
assert event["toAmount"] == 0

# Resync again without syncing with StakeInfo
value = minimum_authorization
threshold_staking.authorizationIncreased(staking_provider, 0, value, sender=creator)
pre_cbd_application.bondOperator(staking_provider, staking_provider, sender=staking_provider)
pre_cbd_application.confirmOperatorAddress(sender=staking_provider)
threshold_staking.setAuthorized(staking_provider, 0, sender=creator)
pre_cbd_application.setUpdatableStakeInfo(ZERO_ADDRESS, sender=creator)
pre_cbd_application.resynchronizeAuthorization(staking_provider, sender=creator)
assert pre_cbd_application.getOperatorFromStakingProvider(staking_provider) == ZERO_ADDRESS
assert stake_info.stakes(staking_provider)[STAKE_INFO_OPERATOR_SLOT] == staking_provider
28 changes: 25 additions & 3 deletions tests/application/test_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
MIN_AUTHORIZATION = Web3.to_wei(40_000, "ether")
MIN_OPERATOR_SECONDS = 24 * 60 * 60

STAKE_INFO_OPERATOR_SLOT = 0


def test_bond_operator(accounts, threshold_staking, pre_cbd_application, stake_info, chain):
(
Expand Down Expand Up @@ -94,6 +96,8 @@ def test_bond_operator(accounts, threshold_staking, pre_cbd_application, stake_i
assert not pre_cbd_application.isOperatorConfirmed(operator1)
assert pre_cbd_application.getStakingProvidersLength() == 1
assert pre_cbd_application.stakingProviders(0) == staking_provider_3
assert stake_info.stakes(staking_provider_3)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS
assert stake_info.operatorToProvider(operator1) == ZERO_ADDRESS

# No active stakingProviders before confirmation
all_locked, staking_providers = pre_cbd_application.getActiveStakingProviders(0, 0)
Expand All @@ -103,6 +107,8 @@ def test_bond_operator(accounts, threshold_staking, pre_cbd_application, stake_i
pre_cbd_application.confirmOperatorAddress(sender=operator1)
assert pre_cbd_application.stakingProviderInfo(staking_provider_3)[CONFIRMATION_SLOT]
assert pre_cbd_application.isOperatorConfirmed(operator1)
assert stake_info.stakes(staking_provider_3)[STAKE_INFO_OPERATOR_SLOT] == operator1
assert stake_info.operatorToProvider(operator1) == staking_provider_3

events = pre_cbd_application.OperatorBonded.from_receipt(tx)
assert len(events) == 1
Expand Down Expand Up @@ -152,6 +158,8 @@ def test_bond_operator(accounts, threshold_staking, pre_cbd_application, stake_i
assert not pre_cbd_application.isOperatorConfirmed(operator1)
assert pre_cbd_application.getStakingProvidersLength() == 1
assert pre_cbd_application.stakingProviders(0) == staking_provider_3
assert stake_info.stakes(staking_provider_3)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS
assert stake_info.operatorToProvider(operator1) == ZERO_ADDRESS

# Resetting operator removes from active list before next confirmation
all_locked, staking_providers = pre_cbd_application.getActiveStakingProviders(0, 0)
Expand All @@ -177,6 +185,8 @@ def test_bond_operator(accounts, threshold_staking, pre_cbd_application, stake_i
assert not pre_cbd_application.isOperatorConfirmed(operator2)
assert pre_cbd_application.getStakingProvidersLength() == 1
assert pre_cbd_application.stakingProviders(0) == staking_provider_3
assert stake_info.stakes(staking_provider_3)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS
assert stake_info.operatorToProvider(operator2) == ZERO_ADDRESS

events = pre_cbd_application.OperatorBonded.from_receipt(tx)
assert len(events) == 1
Expand All @@ -194,6 +204,8 @@ def test_bond_operator(accounts, threshold_staking, pre_cbd_application, stake_i
assert not pre_cbd_application.isOperatorConfirmed(operator1)
assert pre_cbd_application.isOperatorConfirmed(operator2)
assert pre_cbd_application.stakingProviderInfo(staking_provider_3)[CONFIRMATION_SLOT]
assert stake_info.stakes(staking_provider_3)[STAKE_INFO_OPERATOR_SLOT] == operator2
assert stake_info.operatorToProvider(operator2) == staking_provider_3

# Another staking provider can bond a free operator
assert pre_cbd_application.authorizedOverall() == min_authorization
Expand All @@ -206,6 +218,8 @@ def test_bond_operator(accounts, threshold_staking, pre_cbd_application, stake_i
assert pre_cbd_application.getStakingProvidersLength() == 2
assert pre_cbd_application.stakingProviders(1) == staking_provider_4
assert pre_cbd_application.authorizedOverall() == min_authorization
assert stake_info.stakes(staking_provider_4)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS
assert stake_info.operatorToProvider(operator1) == ZERO_ADDRESS

events = pre_cbd_application.OperatorBonded.from_receipt(tx)
assert len(events) == 1
Expand All @@ -226,6 +240,9 @@ def test_bond_operator(accounts, threshold_staking, pre_cbd_application, stake_i
assert pre_cbd_application.isOperatorConfirmed(operator1)
assert pre_cbd_application.stakingProviderInfo(staking_provider_4)[CONFIRMATION_SLOT]
assert pre_cbd_application.authorizedOverall() == 2 * min_authorization
assert stake_info.stakes(staking_provider_4)[STAKE_INFO_OPERATOR_SLOT] == operator1
assert stake_info.operatorToProvider(operator1) == staking_provider_4

chain.pending_timestamp += min_operator_seconds
tx = pre_cbd_application.bondOperator(staking_provider_4, operator3, sender=staking_provider_4)
timestamp = tx.timestamp
Expand All @@ -238,6 +255,8 @@ def test_bond_operator(accounts, threshold_staking, pre_cbd_application, stake_i
assert pre_cbd_application.getStakingProvidersLength() == 2
assert pre_cbd_application.stakingProviders(1) == staking_provider_4
assert pre_cbd_application.authorizedOverall() == min_authorization
assert stake_info.stakes(staking_provider_4)[STAKE_INFO_OPERATOR_SLOT] == ZERO_ADDRESS
assert stake_info.operatorToProvider(operator1) == ZERO_ADDRESS

# Resetting operator removes from active list before next confirmation
all_locked, staking_providers = pre_cbd_application.getActiveStakingProviders(1, 0)
Expand Down Expand Up @@ -290,6 +309,8 @@ def test_bond_operator(accounts, threshold_staking, pre_cbd_application, stake_i
staking_provider_1, min_authorization, min_authorization - 1, sender=creator
)
pre_cbd_application.confirmOperatorAddress(sender=staking_provider_1)
assert stake_info.stakes(staking_provider_1)[STAKE_INFO_OPERATOR_SLOT] == staking_provider_1
assert stake_info.operatorToProvider(staking_provider_1) == staking_provider_1

# If stake will be less than minimum then provider is not active
threshold_staking.authorizationIncreased(
Expand All @@ -309,6 +330,9 @@ def test_bond_operator(accounts, threshold_staking, pre_cbd_application, stake_i
assert all_locked == 0
assert len(staking_providers) == 0

# Reset xchain contract before next bonding
pre_cbd_application.setUpdatableStakeInfo(ZERO_ADDRESS, sender=creator)

# Unbond and rebond oeprator
pre_cbd_application.bondOperator(staking_provider_3, ZERO_ADDRESS, sender=staking_provider_3)
pre_cbd_application.bondOperator(staking_provider_3, operator2, sender=staking_provider_3)
Expand All @@ -321,9 +345,7 @@ def test_bond_operator(accounts, threshold_staking, pre_cbd_application, stake_i
assert pre_cbd_application.stakingProviderFromOperator(operator2) == ZERO_ADDRESS


def test_confirm_address(
accounts, threshold_staking, pre_cbd_application, stake_info, chain, project
):
def test_confirm_address(accounts, threshold_staking, pre_cbd_application, chain, project):
creator, staking_provider, operator, *everyone_else = accounts[0:]
min_authorization = MIN_AUTHORIZATION
min_operator_seconds = MIN_OPERATOR_SECONDS
Expand Down

0 comments on commit 8eafef3

Please sign in to comment.