Skip to content

Commit

Permalink
Merge branch 'horizon' of github.com:graphprotocol/contracts into hor…
Browse files Browse the repository at this point in the history
…izon
  • Loading branch information
tmigone committed May 29, 2024
2 parents d7497d6 + e5f22e2 commit c3fe9d1
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 98 deletions.
5 changes: 3 additions & 2 deletions packages/horizon/contracts/staking/HorizonStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,9 @@ contract HorizonStaking is HorizonStakingBase, IHorizonStakingMain {
) external override notPaused {
address verifier = msg.sender;
Provision storage prov = _provisions[serviceProvider][verifier];
require(prov.tokens >= tokens, HorizonStakingInsufficientTokens(prov.tokens, tokens));
DelegationPoolInternal storage pool = _getDelegationPool(serviceProvider, verifier);
uint256 tokensProvisionTotal = prov.tokens + pool.tokens;
require(tokensProvisionTotal >= tokens, HorizonStakingInsufficientTokens(prov.tokens, tokens));

uint256 tokensToSlash = tokens;
uint256 providerTokensSlashed = MathUtils.min(prov.tokens, tokensToSlash);
Expand Down Expand Up @@ -386,7 +388,6 @@ contract HorizonStaking is HorizonStakingBase, IHorizonStakingMain {

tokensToSlash = tokensToSlash - providerTokensSlashed;
if (tokensToSlash > 0) {
DelegationPoolInternal storage pool = _getDelegationPool(serviceProvider, verifier);
if (_delegationSlashingEnabled) {
require(pool.tokens >= tokensToSlash, HorizonStakingNotEnoughDelegation(pool.tokens, tokensToSlash));
_graphToken().burnTokens(tokensToSlash);
Expand Down
4 changes: 2 additions & 2 deletions packages/horizon/test/staking/HorizonStaking.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ contract HorizonStakingTest is HorizonStakingSharedTest, IHorizonStakingTypes {
return staking.thaw(users.indexer, subgraphDataServiceAddress, thawAmount);
}

function _deprovision(uint256 amount) internal {
staking.deprovision(users.indexer, subgraphDataServiceAddress, amount);
function _deprovision(uint256 nThawRequests) internal {
staking.deprovision(users.indexer, subgraphDataServiceAddress, nThawRequests);
}

function _delegate(uint256 amount) internal {
Expand Down
74 changes: 37 additions & 37 deletions packages/horizon/test/staking/provision/deprovision.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,54 @@ import { HorizonStakingTest } from "../HorizonStaking.t.sol";

contract HorizonStakingDeprovisionTest is HorizonStakingTest {

function testDeprovision_Tokens(
function testDeprovision_AllRequests(
uint256 amount,
uint32 maxVerifierCut,
uint64 thawingPeriod
) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) useThawRequest(amount) {
skip(thawingPeriod + 1);

_deprovision(amount);
// nThawRequests == 0 removes all thaw requests
_deprovision(0);
uint256 idleStake = staking.getIdleStake(users.indexer);
assertEq(idleStake, amount);
}

function testDeprovision_FirstRequestOnly(
uint256 amount,
uint32 maxVerifierCut,
uint64 thawingPeriod,
uint256 thawAmount
) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) {
thawAmount = bound(thawAmount, MIN_DELEGATION, amount);
uint256 thawAmount1 = thawAmount / 2;
bytes32 thawRequestId = _createThawRequest(thawAmount1);
bytes32 thawRequestId2 = _createThawRequest(thawAmount - thawAmount1);
skip(thawingPeriod + 1);

console.log("thawAmount1: ", thawAmount1);
console.log("thawAmount2: ", thawAmount - thawAmount1);

ThawRequest memory thawRequest1 = staking.getThawRequest(thawRequestId);
ThawRequest memory thawRequest2 = staking.getThawRequest(thawRequestId2);
console.log("Thaw request 1 shares: ", thawRequest1.shares);
console.log("Thaw request 2 shares: ", thawRequest2.shares);

console.log("Idle stake before deprovision: ", staking.getIdleStake(users.indexer));
_deprovision(1);
uint256 idleStake = staking.getIdleStake(users.indexer);
console.log("Idle stake after deprovision: ", idleStake);
assertEq(idleStake, thawAmount1);
}

function testDeprovision_OperatorMovingTokens(
uint256 amount,
uint32 maxVerifierCut,
uint64 thawingPeriod
) public useOperator useProvision(amount, maxVerifierCut, thawingPeriod) useThawRequest(amount) {
skip(thawingPeriod + 1);

_deprovision(amount);
_deprovision(0);
uint256 idleStake = staking.getIdleStake(users.indexer);
assertEq(idleStake, amount);
}
Expand All @@ -44,54 +72,26 @@ contract HorizonStakingDeprovisionTest is HorizonStakingTest {
subgraphDataServiceAddress
);
vm.expectRevert(expectedError);
_deprovision(amount);
}

function testDeprovision_RevertWhen_ZeroTokens(
uint256 amount,
uint32 maxVerifierCut,
uint64 thawingPeriod
) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) useThawRequest(amount) {
bytes memory expectedError = abi.encodeWithSignature("HorizonStakingInvalidZeroTokens()");
vm.expectRevert(expectedError);
_deprovision(0);
}

function testDeprovision_RevertWhen_NoThawingTokens(
uint256 amount,
uint32 maxVerifierCut,
uint64 thawingPeriod
) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) {
bytes memory expectedError = abi.encodeWithSignature("HorizonStakingCannotFulfillThawRequest()");
bytes memory expectedError = abi.encodeWithSignature("HorizonStakingNothingThawing()");
vm.expectRevert(expectedError);
_deprovision(amount);
_deprovision(0);
}

function testDeprovision_RevertWhen_StillThawing(
function testDeprovision_StillThawing(
uint256 amount,
uint32 maxVerifierCut,
uint64 thawingPeriod
) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) useThawRequest(amount) {
vm.assume(thawingPeriod > 0);
bytes memory expectedError = abi.encodeWithSignature(
"HorizonStakingStillThawing(uint256)",
block.timestamp + thawingPeriod
);
vm.expectRevert(expectedError);
_deprovision(amount);
}

function testDeprovision_RevertWhen_NotEnoughThawedTokens(
uint256 amount,
uint32 maxVerifierCut,
uint64 thawingPeriod,
uint256 deprovisionAmount
) public useIndexer useProvision(amount, maxVerifierCut, thawingPeriod) {
vm.assume(deprovisionAmount > amount);
skip(thawingPeriod + 1);

bytes memory expectedError = abi.encodeWithSignature("HorizonStakingCannotFulfillThawRequest()");
vm.expectRevert(expectedError);
_deprovision(deprovisionAmount);
_deprovision(0);
uint256 idleStake = staking.getIdleStake(users.indexer);
assertEq(idleStake, 0);
}
}
41 changes: 12 additions & 29 deletions packages/horizon/test/staking/provision/reprovision.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest {

address private newDataService = makeAddr("newDataService");

function _reprovision(uint256 amount) private {
staking.reprovision(users.indexer, subgraphDataServiceAddress, newDataService, amount, 0);
function _reprovision(uint256 tokens, uint256 nThawRequests) private {
staking.reprovision(users.indexer, subgraphDataServiceAddress, newDataService, tokens, nThawRequests);
}

function testReprovision_MovingTokens(
Expand All @@ -25,7 +25,9 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest {
skip(thawingPeriod + 1);

_createProvision(newDataService, MIN_PROVISION_SIZE, 0, thawingPeriod);
_reprovision(provisionAmount);

// nThawRequests == 0 reprovisions all thaw requests
_reprovision(provisionAmount, 0);
uint256 idleStake = staking.getIdleStake(users.indexer);
assertEq(idleStake, 0 ether);

Expand All @@ -51,7 +53,7 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest {
// Switch back to operator
vm.startPrank(users.operator);
_createProvision(newDataService, MIN_PROVISION_SIZE, 0, thawingPeriod);
_reprovision(provisionAmount);
_reprovision(provisionAmount, 0);
uint256 idleStake = staking.getIdleStake(users.indexer);
assertEq(idleStake, 0 ether);

Expand Down Expand Up @@ -80,15 +82,15 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest {
newDataService
);
vm.expectRevert(expectedError);
_reprovision(provisionAmount);
_reprovision(provisionAmount, 0);
}

function testReprovision_RevertWhen_NoThawingTokens(
uint256 amount
) public useIndexer useProvision(amount, 0, 0) {
bytes memory expectedError = abi.encodeWithSignature("HorizonStakingCannotFulfillThawRequest()");
bytes memory expectedError = abi.encodeWithSignature("HorizonStakingNothingThawing()");
vm.expectRevert(expectedError);
_reprovision(amount);
_reprovision(amount, 0);
}

function testReprovision_RevertWhen_StillThawing(
Expand All @@ -101,30 +103,11 @@ contract HorizonStakingReprovisionTest is HorizonStakingTest {
useThawRequest(provisionAmount)
{
vm.assume(thawingPeriod > 0);
bytes memory expectedError = abi.encodeWithSignature(
"HorizonStakingStillThawing(uint256)",
block.timestamp + thawingPeriod
);
vm.expectRevert(expectedError);
_reprovision(provisionAmount);
}

function testReprovision_RevertWhen_NotEnoughThawedTokens(
uint64 thawingPeriod,
uint256 provisionAmount,
uint256 newProvisionAmount
)
public
useIndexer
useProvision(provisionAmount, 0, thawingPeriod)
useThawRequest(provisionAmount)
{
newProvisionAmount = bound(newProvisionAmount, provisionAmount + 1, type(uint256).max - provisionAmount);
skip(thawingPeriod + 1);
_createProvision(newDataService, MIN_PROVISION_SIZE, 0, thawingPeriod);

_createProvision(newDataService, newProvisionAmount, 0, thawingPeriod);
bytes memory expectedError = abi.encodeWithSignature("HorizonStakingCannotFulfillThawRequest()");
bytes memory expectedError = abi.encodeWithSignature("HorizonStakingInsufficientCapacity()");
vm.expectRevert(expectedError);
_reprovision(newProvisionAmount);
_reprovision(provisionAmount, 0);
}
}
82 changes: 56 additions & 26 deletions packages/horizon/test/staking/slash/slash.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import { HorizonStakingTest } from "../HorizonStaking.t.sol";

contract HorizonStakingSlashTest is HorizonStakingTest {

modifier useDelegationSlashingDisabled() {
modifier useDelegationSlashing(bool enabled) {
address msgSender;
(, msgSender,) = vm.readCallers();
vm.startPrank(users.governor);
staking.setDelegationSlashingEnabled(false);
staking.setDelegationSlashingEnabled(enabled);
vm.startPrank(msgSender);
_;
}
Expand Down Expand Up @@ -41,33 +41,63 @@ contract HorizonStakingSlashTest is HorizonStakingTest {
assertEq(verifierTokens, verifierCutAmount);
}

// TODO: Should be re-enabled when slashin is fixed to count for delegated tokens
// function testSlash_DelegationDisabled_SlashingOverProvisionTokens(
// uint256 amount,
// uint256 slashAmount,
// uint256 verifierCutAmount,
// uint256 delegationAmount
// ) public useIndexer useProvision(amount, 100000, 0) useDelegationSlashingDisabled {
// vm.assume(slashAmount > amount);
// vm.assume(delegationAmount > 0);
// uint32 delegationRatio = 5;

// vm.stopPrank();
// vm.startPrank(users.delegator);
// _delegate(delegationAmount);

// vm.startPrank(subgraphDataServiceAddress);
// _slash(slashAmount, verifierCutAmount);
function testSlash_DelegationDisabled_SlashingOverProvisionTokens(
uint256 amount,
uint256 slashAmount,
uint256 verifierCutAmount,
uint256 delegationAmount
) public useIndexer useProvision(amount, MAX_MAX_VERIFIER_CUT, 0) useDelegationSlashing(false) {
// TODO: changePrank?
vm.stopPrank();
delegationAmount = bound(delegationAmount, MIN_DELEGATION, 10_000_000_000 ether);
slashAmount = bound(slashAmount, amount + 1, amount + delegationAmount);
verifierCutAmount = bound(verifierCutAmount, 0, MAX_MAX_VERIFIER_CUT);

vm.startPrank(users.delegator);
_delegate(delegationAmount);

vm.startPrank(subgraphDataServiceAddress);
_slash(slashAmount, verifierCutAmount);

uint256 provisionProviderTokens = staking.getProviderTokensAvailable(users.indexer, subgraphDataServiceAddress);
assertEq(provisionProviderTokens, 0 ether);

uint256 verifierTokens = token.balanceOf(address(subgraphDataServiceAddress));
assertEq(verifierTokens, verifierCutAmount);

uint256 delegatedTokens = staking.getDelegatedTokensAvailable(users.indexer, subgraphDataServiceAddress);
// No slashing occurred for delegation
assertEq(delegatedTokens, delegationAmount);
}

function testSlash_DelegationEnabled_SlashingOverProvisionTokens(
uint256 amount,
uint256 slashAmount,
uint256 verifierCutAmount,
uint256 delegationAmount
) public useIndexer useProvision(amount, MAX_MAX_VERIFIER_CUT, 0) useDelegationSlashing(true) {
// TODO: changePrank?
vm.stopPrank();
delegationAmount = bound(delegationAmount, MIN_DELEGATION, 10_000_000_000 ether);
slashAmount = bound(slashAmount, amount + 1, amount + delegationAmount);
verifierCutAmount = bound(verifierCutAmount, 0, MAX_MAX_VERIFIER_CUT);

vm.startPrank(users.delegator);
_delegate(delegationAmount);

vm.startPrank(subgraphDataServiceAddress);
_slash(slashAmount, verifierCutAmount);

// uint256 provisionProviderTokens = staking.getProviderTokensAvailable(users.indexer, subgraphDataServiceAddress);
// assertEq(provisionProviderTokens, 0 ether);
uint256 provisionProviderTokens = staking.getProviderTokensAvailable(users.indexer, subgraphDataServiceAddress);
assertEq(provisionProviderTokens, 0 ether);

// uint256 verifierTokens = token.balanceOf(address(subgraphDataServiceAddress));
// assertEq(verifierTokens, verifierCutAmount);
uint256 verifierTokens = token.balanceOf(address(subgraphDataServiceAddress));
assertEq(verifierTokens, verifierCutAmount);

// uint256 delegatedTokens = staking.getTokensAvailable(users.indexer, subgraphDataServiceAddress, delegationRatio);
// assertEq(delegatedTokens, delegationAmount);
// }
uint256 delegatedTokens = staking.getDelegatedTokensAvailable(users.indexer, subgraphDataServiceAddress);
uint256 slashedDelegation = slashAmount - amount;
assertEq(delegatedTokens, delegationAmount - slashedDelegation);
}

function testSlash_RevertWhen_NoProvision(
uint256 amount,
Expand Down
3 changes: 1 addition & 2 deletions packages/horizon/test/staking/thaw/thaw.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ contract HorizonStakingThawTest is HorizonStakingTest {
assertEq(thawRequest.next, thawRequestId2);

ThawRequest memory thawRequest2 = staking.getThawRequest(thawRequestId2);
uint256 totalThawAmount = thawAmount + thawAmount2;
assertEq(thawRequest2.shares, (thawRequest.shares * thawAmount2) / totalThawAmount);
assertEq(thawRequest2.shares, thawAmount2);
assertEq(thawRequest2.thawingUntil, block.timestamp + thawingPeriod);
}

Expand Down

0 comments on commit c3fe9d1

Please sign in to comment.