Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(Horizon): reprovision only tokens thawed #1046

Merged
merged 2 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -614,13 +614,12 @@ interface IHorizonStakingMain {
* @param serviceProvider The service provider address
* @param oldVerifier The verifier address for which the tokens are currently provisioned
* @param newVerifier The verifier address for which the tokens will be provisioned
* @param tokens The amount of tokens to move
* @param nThawRequests The number of thaw requests to fulfill. Set to 0 to fulfill all thaw requests.
*/
function reprovision(
address serviceProvider,
address oldVerifier,
address newVerifier,
uint256 tokens,
uint256 nThawRequests
) external;

Expand Down
22 changes: 13 additions & 9 deletions packages/horizon/contracts/staking/HorizonStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,6 @@ contract HorizonStaking is HorizonStakingBase, IHorizonStakingMain {
address serviceProvider,
address oldVerifier,
address newVerifier,
uint256 tokens,
uint256 nThawRequests
)
external
Expand All @@ -216,8 +215,8 @@ contract HorizonStaking is HorizonStakingBase, IHorizonStakingMain {
onlyAuthorized(serviceProvider, oldVerifier)
onlyAuthorized(serviceProvider, newVerifier)
{
_deprovision(serviceProvider, oldVerifier, nThawRequests);
_addToProvision(serviceProvider, newVerifier, tokens);
uint256 tokensThawed = _deprovision(serviceProvider, oldVerifier, nThawRequests);
_addToProvision(serviceProvider, newVerifier, tokensThawed);
}

/**
Expand Down Expand Up @@ -693,13 +692,17 @@ contract HorizonStaking is HorizonStakingBase, IHorizonStakingMain {
/**
* @notice See {IHorizonStakingMain-deprovision}.
*/
function _deprovision(address _serviceProvider, address _verifier, uint256 _nThawRequests) private {
function _deprovision(
address _serviceProvider,
address _verifier,
uint256 _nThawRequests
) private returns (uint256 tokensThawed) {
Maikol marked this conversation as resolved.
Show resolved Hide resolved
Provision storage prov = _provisions[_serviceProvider][_verifier];

uint256 tokensThawed = 0;
uint256 tokensThawed_ = 0;
uint256 sharesThawing = prov.sharesThawing;
uint256 tokensThawing = prov.tokensThawing;
(tokensThawed, tokensThawing, sharesThawing) = _fulfillThawRequests(
(tokensThawed_, tokensThawing, sharesThawing) = _fulfillThawRequests(
_serviceProvider,
_verifier,
_serviceProvider,
Expand All @@ -708,12 +711,13 @@ contract HorizonStaking is HorizonStakingBase, IHorizonStakingMain {
_nThawRequests
);

prov.tokens = prov.tokens - tokensThawed;
prov.tokens = prov.tokens - tokensThawed_;
prov.sharesThawing = sharesThawing;
prov.tokensThawing = tokensThawing;
_serviceProviders[_serviceProvider].tokensProvisioned -= tokensThawed;
_serviceProviders[_serviceProvider].tokensProvisioned -= tokensThawed_;

emit TokensDeprovisioned(_serviceProvider, _verifier, tokensThawed);
emit TokensDeprovisioned(_serviceProvider, _verifier, tokensThawed_);
return tokensThawed_;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,6 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest {
address serviceProvider,
address verifier,
address newVerifier,
uint256 tokens,
uint256 nThawRequests
) internal {
// before
Expand Down Expand Up @@ -595,8 +594,8 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest {
vm.expectEmit(address(staking));
emit IHorizonStakingMain.TokensDeprovisioned(serviceProvider, verifier, calcValues.tokensThawed);
vm.expectEmit();
emit IHorizonStakingMain.ProvisionIncreased(serviceProvider, newVerifier, tokens);
staking.reprovision(serviceProvider, verifier, newVerifier, tokens, nThawRequests);
emit IHorizonStakingMain.ProvisionIncreased(serviceProvider, newVerifier, calcValues.tokensThawed);
staking.reprovision(serviceProvider, verifier, newVerifier, nThawRequests);

// after
Provision memory afterProvision = staking.getProvision(serviceProvider, verifier);
Expand All @@ -619,7 +618,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest {
assertEq(afterProvision.thawingPeriodPending, beforeValues.provision.thawingPeriodPending);

// assert: provision new verifier
assertEq(afterProvisionNewVerifier.tokens, beforeValues.provisionNewVerifier.tokens + tokens);
assertEq(afterProvisionNewVerifier.tokens, beforeValues.provisionNewVerifier.tokens + calcValues.tokensThawed);
assertEq(afterProvisionNewVerifier.tokensThawing, beforeValues.provisionNewVerifier.tokensThawing);
assertEq(afterProvisionNewVerifier.sharesThawing, beforeValues.provisionNewVerifier.sharesThawing);
assertEq(afterProvisionNewVerifier.maxVerifierCut, beforeValues.provisionNewVerifier.maxVerifierCut);
Expand All @@ -632,7 +631,7 @@ abstract contract HorizonStakingSharedTest is GraphBaseTest {
assertEq(afterServiceProvider.tokensStaked, beforeValues.serviceProvider.tokensStaked);
assertEq(
afterServiceProvider.tokensProvisioned,
beforeValues.serviceProvider.tokensProvisioned + tokens - calcValues.tokensThawed
beforeValues.serviceProvider.tokensProvisioned + calcValues.tokensThawed - calcValues.tokensThawed
);
assertEq(afterServiceProvider.__DEPRECATED_tokensAllocated, beforeValues.serviceProvider.__DEPRECATED_tokensAllocated);
assertEq(afterServiceProvider.__DEPRECATED_tokensLocked, beforeValues.serviceProvider.__DEPRECATED_tokensLocked);
Expand Down
48 changes: 4 additions & 44 deletions packages/horizon/test/staking/provision/reprovision.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,7 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest {

_createProvision(users.indexer, newDataService, 1 ether, 0, thawingPeriod);

_reprovision(users.indexer, subgraphDataServiceAddress, newDataService, provisionAmount, 0);
}

function testReprovision_TokensOverThawingTokens() public useIndexer {
uint64 thawingPeriod = 1 days;

// create provision A, thaw 10 ether, skip time so they are fully thawed
_createProvision(users.indexer, subgraphDataServiceAddress, 100 ether, 0, thawingPeriod);
_thaw(users.indexer, subgraphDataServiceAddress, 10 ether);
skip(thawingPeriod + 1);

// create provision B
_createProvision(users.indexer, newDataService, 1 ether, 0, thawingPeriod);

// reprovision 100 ether from A to B
// this should revert because there are only 10 ether that thawed and the service provider
// doesn't have additional idle stake to cover the difference
vm.expectRevert();
staking.reprovision(users.indexer, subgraphDataServiceAddress, newDataService, 100 ether, 0);

// now add some idle stake and try again, it should not revert
_stake(100 ether);
_reprovision(users.indexer, subgraphDataServiceAddress, newDataService, 100 ether, 0);
_reprovision(users.indexer, subgraphDataServiceAddress, newDataService, 0);
}

function testReprovision_OperatorMovingTokens(
Expand All @@ -64,7 +42,7 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest {
// Switch back to operator
vm.startPrank(users.operator);
_createProvision(users.indexer, newDataService, 1 ether, 0, thawingPeriod);
_reprovision(users.indexer, subgraphDataServiceAddress, newDataService, provisionAmount, 0);
_reprovision(users.indexer, subgraphDataServiceAddress, newDataService, 0);
}

function testReprovision_RevertWhen_OperatorNotAuthorizedForNewDataService(
Expand All @@ -85,30 +63,12 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest {
newDataService
);
vm.expectRevert(expectedError);
staking.reprovision(users.indexer, subgraphDataServiceAddress, newDataService, provisionAmount, 0);
staking.reprovision(users.indexer, subgraphDataServiceAddress, newDataService, 0);
}

function testReprovision_RevertWhen_NoThawingTokens(uint256 amount) public useIndexer useProvision(amount, 0, 0) {
bytes memory expectedError = abi.encodeWithSignature("HorizonStakingNothingThawing()");
vm.expectRevert(expectedError);
staking.reprovision(users.indexer, subgraphDataServiceAddress, newDataService, amount, 0);
}

function testReprovision_RevertWhen_StillThawing(
uint64 thawingPeriod,
uint256 provisionAmount
) public useIndexer useProvision(provisionAmount, 0, thawingPeriod) {
vm.assume(thawingPeriod > 0);
_thaw(users.indexer, subgraphDataServiceAddress, provisionAmount);

_createProvision(users.indexer, newDataService, 1 ether, 0, thawingPeriod);

bytes memory expectedError = abi.encodeWithSignature(
"HorizonStakingInsufficientIdleStake(uint256,uint256)",
provisionAmount,
0
);
vm.expectRevert(expectedError);
staking.reprovision(users.indexer, subgraphDataServiceAddress, newDataService, provisionAmount, 0);
staking.reprovision(users.indexer, subgraphDataServiceAddress, newDataService, 0);
}
}
Loading