Skip to content

Commit 480257f

Browse files
committed
chore: add to delegation pool integration tests
1 parent f56f5f4 commit 480257f

File tree

5 files changed

+348
-35
lines changed

5 files changed

+348
-35
lines changed
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
import hre from 'hardhat'
2+
import { ethers } from 'hardhat'
3+
import { expect } from 'chai'
4+
import { HorizonStaking, IGraphToken } from '../../../typechain-types'
5+
import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'
6+
7+
import {
8+
addToDelegationPool,
9+
createProvision,
10+
delegate,
11+
slash,
12+
stake,
13+
} from '../shared/staking'
14+
15+
describe('Add to delegation pool (after transition period)', () => {
16+
let horizonStaking: HorizonStaking
17+
let graphToken: IGraphToken
18+
let governor: SignerWithAddress
19+
let serviceProvider: SignerWithAddress
20+
let delegator: SignerWithAddress
21+
let signer: SignerWithAddress
22+
let verifier: string
23+
let slashingVerifier: SignerWithAddress
24+
25+
const maxVerifierCut = 1000000
26+
const thawingPeriod = 2419200 // 28 days
27+
const tokens = ethers.parseEther('100000')
28+
const delegationTokens = ethers.parseEther('1000')
29+
30+
before(async () => {
31+
const graph = hre.graph()
32+
33+
horizonStaking = graph.horizon!.contracts.HorizonStaking
34+
graphToken = graph.horizon!.contracts.L2GraphToken as unknown as IGraphToken
35+
36+
[serviceProvider, governor, delegator, signer, slashingVerifier] = await ethers.getSigners()
37+
verifier = await ethers.Wallet.createRandom().getAddress()
38+
39+
// Enable delegation slashing
40+
await horizonStaking.connect(governor).setDelegationSlashingEnabled()
41+
42+
// Service provider stake
43+
await stake({
44+
horizonStaking,
45+
graphToken,
46+
serviceProvider,
47+
tokens,
48+
})
49+
50+
// Create provision
51+
const provisionTokens = ethers.parseEther('1000')
52+
await createProvision({
53+
horizonStaking,
54+
serviceProvider,
55+
verifier,
56+
tokens: provisionTokens,
57+
maxVerifierCut,
58+
thawingPeriod,
59+
})
60+
61+
// Send funds to delegator and signer
62+
await graphToken.connect(serviceProvider).transfer(delegator.address, tokens)
63+
await graphToken.connect(serviceProvider).transfer(signer.address, tokens)
64+
65+
// Initialize delegation pool
66+
await delegate({
67+
horizonStaking,
68+
graphToken,
69+
delegator,
70+
serviceProvider,
71+
verifier,
72+
tokens: delegationTokens,
73+
minSharesOut: 0n,
74+
})
75+
})
76+
77+
it('should add tokens to an existing delegation pool', async () => {
78+
const poolBefore = await horizonStaking.getDelegationPool(serviceProvider.address, verifier)
79+
const addTokens = ethers.parseEther('500')
80+
81+
// Add tokens to the delegation pool
82+
await addToDelegationPool({
83+
horizonStaking,
84+
graphToken,
85+
signer,
86+
serviceProvider,
87+
verifier,
88+
tokens: addTokens,
89+
})
90+
91+
// Verify tokens were added to the pool
92+
const poolAfter = await horizonStaking.getDelegationPool(serviceProvider.address, verifier)
93+
expect(poolAfter.tokens).to.equal(poolBefore.tokens + addTokens, 'Pool tokens should increase')
94+
expect(poolAfter.shares).to.equal(poolBefore.shares, 'Pool shares should remain the same')
95+
})
96+
97+
it('should revert when adding tokens to a non-existent provision', async () => {
98+
const invalidVerifier = await ethers.Wallet.createRandom().getAddress()
99+
const addTokens = ethers.parseEther('500')
100+
101+
// Attempt to add tokens to a non-existent provision
102+
await expect(
103+
addToDelegationPool({
104+
horizonStaking,
105+
graphToken,
106+
signer,
107+
serviceProvider,
108+
verifier: invalidVerifier,
109+
tokens: addTokens,
110+
}),
111+
).to.be.revertedWithCustomError(horizonStaking, 'HorizonStakingInvalidProvision')
112+
})
113+
114+
it('should revert when adding tokens to a provision with zero shares in delegation pool', async () => {
115+
// Create new provision without any delegations
116+
const newVerifier = await ethers.Wallet.createRandom().getAddress()
117+
const newVerifierProvisionTokens = ethers.parseEther('1000')
118+
await createProvision({
119+
horizonStaking,
120+
serviceProvider,
121+
verifier: newVerifier,
122+
tokens: newVerifierProvisionTokens,
123+
maxVerifierCut,
124+
thawingPeriod,
125+
})
126+
127+
// Attempt to add tokens to the new provision
128+
const addTokens = ethers.parseEther('500')
129+
await expect(
130+
addToDelegationPool({
131+
horizonStaking,
132+
graphToken,
133+
signer,
134+
serviceProvider,
135+
verifier: newVerifier,
136+
tokens: addTokens,
137+
}),
138+
).to.be.revertedWithCustomError(horizonStaking, 'HorizonStakingInvalidDelegationPool')
139+
})
140+
141+
it('should recover delegation pool from invalid state by adding tokens', async () => {
142+
// Create a new provision for the slashing verifier
143+
const slashingVerifierProvisionTokens = ethers.parseEther('1000')
144+
await createProvision({
145+
horizonStaking,
146+
serviceProvider,
147+
verifier: slashingVerifier.address,
148+
tokens: slashingVerifierProvisionTokens,
149+
maxVerifierCut,
150+
thawingPeriod,
151+
})
152+
153+
// Initialize delegation pool
154+
const initialDelegation = ethers.parseEther('1000')
155+
await delegate({
156+
horizonStaking,
157+
graphToken,
158+
delegator,
159+
serviceProvider,
160+
verifier: slashingVerifier.address,
161+
tokens: initialDelegation,
162+
minSharesOut: 0n,
163+
})
164+
const poolBefore = await horizonStaking.getDelegationPool(serviceProvider.address, slashingVerifier.address)
165+
166+
// Slash entire provision (service provider tokens + delegation pool tokens)
167+
const slashTokens = slashingVerifierProvisionTokens + initialDelegation
168+
const tokensVerifier = slashingVerifierProvisionTokens / 2n
169+
await slash({
170+
horizonStaking,
171+
verifier: slashingVerifier,
172+
serviceProvider,
173+
tokens: slashTokens,
174+
tokensVerifier,
175+
verifierDestination: slashingVerifier.address,
176+
})
177+
178+
// Log pool tokens after slashing
179+
// const poolAfterSlashing = await horizonStaking.getDelegationPool(serviceProvider.address, slashingVerifier.address)
180+
// console.log('Pool tokens after slashing:', poolAfterSlashing.tokens.toString())
181+
182+
// Delegating should revert since pool.tokens == 0 and pool.shares != 0
183+
const delegateTokens = ethers.parseEther('500')
184+
await expect(
185+
delegate({
186+
horizonStaking,
187+
graphToken,
188+
delegator,
189+
serviceProvider,
190+
verifier: slashingVerifier.address,
191+
tokens: delegateTokens,
192+
minSharesOut: 0n,
193+
}),
194+
).to.be.revertedWithCustomError(horizonStaking, 'HorizonStakingInvalidDelegationPoolState')
195+
196+
// Add tokens to the delegation pool to recover the pool
197+
const recoverPoolTokens = ethers.parseEther('500')
198+
await addToDelegationPool({
199+
horizonStaking,
200+
graphToken,
201+
signer,
202+
serviceProvider,
203+
verifier: slashingVerifier.address,
204+
tokens: recoverPoolTokens,
205+
})
206+
207+
// Verify delegation pool is recovered
208+
const poolAfter = await horizonStaking.getDelegationPool(serviceProvider.address, slashingVerifier.address)
209+
expect(poolAfter.tokens).to.equal(recoverPoolTokens, 'Pool tokens should be recovered')
210+
expect(poolAfter.shares).to.equal(poolBefore.shares, 'Pool shares should remain the same')
211+
212+
// Delegation should now succeed
213+
await delegate({
214+
horizonStaking,
215+
graphToken,
216+
delegator,
217+
serviceProvider,
218+
verifier: slashingVerifier.address,
219+
tokens: delegateTokens,
220+
minSharesOut: 0n,
221+
})
222+
})
223+
})

packages/horizon/test/integration/after-transition-period/delegator.test.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ describe('Delegator (after transition period)', () => {
3838
newVerifier = await ethers.Wallet.createRandom().getAddress()
3939

4040
// Servide provider stake
41-
await stake(horizonStaking, graphToken, serviceProvider, tokens)
41+
await stake({ horizonStaking, graphToken, serviceProvider, tokens })
4242

4343
// Create provision
4444
await createProvision({
@@ -162,7 +162,12 @@ describe('Delegator (after transition period)', () => {
162162
})
163163

164164
// Create new provision for a new service provider and verifier combo
165-
await stake(horizonStaking, graphToken, newServiceProvider, newProvisionTokens)
165+
await stake({
166+
horizonStaking,
167+
graphToken,
168+
serviceProvider: newServiceProvider,
169+
tokens: newProvisionTokens,
170+
})
166171
await createProvision({
167172
horizonStaking,
168173
serviceProvider: newServiceProvider,

packages/horizon/test/integration/after-transition-period/operator.test.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,16 @@ describe('Operator', () => {
4141
const serviceProviderBalanceBefore = await graphToken.balanceOf(serviceProvider.address)
4242

4343
// Operator stakes on behalf of service provider
44-
await stakeTo(horizonStaking, graphToken, operator, serviceProvider, stakeTokens)
44+
await stakeTo({
45+
horizonStaking,
46+
graphToken,
47+
signer: operator,
48+
serviceProvider,
49+
tokens: stakeTokens,
50+
})
4551

4652
// Service provider unstakes
47-
await unstake(horizonStaking, serviceProvider, stakeTokens)
53+
await unstake({ horizonStaking, serviceProvider, tokens: stakeTokens })
4854

4955
// Verify tokens were removed from operator's address
5056
const operatorBalanceAfter = await graphToken.balanceOf(operator.address)
@@ -80,7 +86,13 @@ describe('Operator', () => {
8086
before(async () => {
8187
const provisionTokens = ethers.parseEther('10000')
8288
// Operator stakes tokens to service provider
83-
await stakeTo(horizonStaking, graphToken, operator, serviceProvider, provisionTokens)
89+
await stakeTo({
90+
horizonStaking,
91+
graphToken,
92+
signer: operator,
93+
serviceProvider,
94+
tokens: provisionTokens,
95+
})
8496

8597
// Operator creates provision
8698
await createProvision({

packages/horizon/test/integration/after-transition-period/service-provider.test.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ describe('HorizonStaking Integration Tests', () => {
3939

4040
it('should allow staking tokens and unstake right after', async () => {
4141
const serviceProviderBalanceBefore = await graphToken.balanceOf(serviceProvider.address)
42-
await stake(horizonStaking, graphToken, serviceProvider, stakeAmount)
43-
await unstake(horizonStaking, serviceProvider, stakeAmount)
42+
await stake({ horizonStaking, graphToken, serviceProvider, tokens: stakeAmount })
43+
await unstake({ horizonStaking, serviceProvider, tokens: stakeAmount })
4444
const serviceProviderBalanceAfter = await graphToken.balanceOf(serviceProvider.address)
4545
expect(serviceProviderBalanceAfter).to.equal(serviceProviderBalanceBefore, 'Service provider balance should not change')
4646
})
@@ -99,7 +99,7 @@ describe('HorizonStaking Integration Tests', () => {
9999
const createProvisionTokens = ethers.parseEther('10000')
100100

101101
// Add idle stake
102-
await stake(horizonStaking, graphToken, serviceProvider, tokensToStake)
102+
await stake({ horizonStaking, graphToken, serviceProvider, tokens: tokensToStake })
103103

104104
// Create provision
105105
await createProvision({
@@ -118,7 +118,13 @@ describe('HorizonStaking Integration Tests', () => {
118118

119119
// Add stake and provision on the same transaction
120120
const stakeToProvisionTokens = ethers.parseEther('100')
121-
await stakeToProvision(horizonStaking, graphToken, serviceProvider, verifier, stakeToProvisionTokens)
121+
await stakeToProvision({
122+
horizonStaking,
123+
graphToken,
124+
serviceProvider,
125+
verifier,
126+
tokens: stakeToProvisionTokens,
127+
})
122128

123129
// Verify provision tokens were updated
124130
provision = await horizonStaking.getProvision(serviceProvider.address, verifier)
@@ -170,7 +176,7 @@ describe('HorizonStaking Integration Tests', () => {
170176
await deprovision({ horizonStaking, serviceProvider, verifier, nThawRequests: 1n })
171177

172178
// Unstake
173-
await unstake(horizonStaking, serviceProvider, tokensToThaw)
179+
await unstake({ horizonStaking, serviceProvider, tokens: tokensToThaw })
174180

175181
// Verify service provider balance increased by the unstake tokens
176182
const serviceProviderBalanceAfter = await graphToken.balanceOf(serviceProvider.address)

0 commit comments

Comments
 (0)