Skip to content

Commit 09f0545

Browse files
authored
delegation: v1 (#216)
* delegation: interface v1 * staking: restore commented out tests * refactor: use factory for deployment * delegation: add tests and shares calculation * delegation: add distribution of fees to delegators * delegation: support delegation capacity when allocating * delegation: move delegation fee to claim * delegation: add redelegate function
1 parent 2df01fa commit 09f0545

15 files changed

+1239
-490
lines changed

contracts/Staking.sol

Lines changed: 402 additions & 47 deletions
Large diffs are not rendered by default.

contracts/libs/Stakes.sol

Lines changed: 37 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ pragma experimental ABIEncoderV2;
33

44
import "@openzeppelin/contracts/math/SafeMath.sol";
55

6-
76
/**
87
* @title A collection of data structures and functions to manage the Stake state
98
* Used for low-level state changes, require() conditions should be evaluated
@@ -20,16 +19,16 @@ library Stakes {
2019
}
2120

2221
struct Indexer {
23-
uint256 tokensIndexer; // Tokens on the indexer stake (staked by the indexer)
24-
uint256 tokensAllocated; // Tokens used in SubgraphDeployment allocations
22+
uint256 tokensStaked; // Tokens on the indexer stake (staked by the indexer)
23+
uint256 tokensAllocated; // Tokens used in allocations
2524
uint256 tokensLocked; // Tokens locked for withdrawal subject to thawing period
2625
uint256 tokensLockedUntil; // Time when locked tokens can be withdrawn
2726
// SubgraphDeployment stake allocation tracking : subgraphDeploymentID => Allocation
2827
mapping(bytes32 => Allocation) allocations;
2928
}
3029

3130
/**
32-
* @dev Allocate tokens from the available stack to a SubgraphDeployment
31+
* @dev Allocate tokens from the main stack to a SubgraphDeployment.
3332
* @param stake Stake data
3433
* @param _subgraphDeploymentID SubgraphDeployment where to allocate tokens
3534
* @param _tokens Amount of tokens to allocate
@@ -46,7 +45,7 @@ library Stakes {
4645
}
4746

4847
/**
49-
* @dev Unallocate tokens from a SubgraphDeployment
48+
* @dev Unallocate tokens from a SubgraphDeployment.
5049
* @param stake Stake data
5150
* @param _subgraphDeploymentID SubgraphDeployment from where to unallocate tokens
5251
* @param _tokens Amount of tokens to unallocate
@@ -63,25 +62,25 @@ library Stakes {
6362
}
6463

6564
/**
66-
* @dev Deposit tokens to the indexer stake
65+
* @dev Deposit tokens to the indexer stake.
6766
* @param stake Stake data
6867
* @param _tokens Amount of tokens to deposit
6968
*/
7069
function deposit(Stakes.Indexer storage stake, uint256 _tokens) internal {
71-
stake.tokensIndexer = stake.tokensIndexer.add(_tokens);
70+
stake.tokensStaked = stake.tokensStaked.add(_tokens);
7271
}
7372

7473
/**
75-
* @dev Release tokens from the indexer stake
74+
* @dev Release tokens from the indexer stake.
7675
* @param stake Stake data
7776
* @param _tokens Amount of tokens to release
7877
*/
7978
function release(Stakes.Indexer storage stake, uint256 _tokens) internal {
80-
stake.tokensIndexer = stake.tokensIndexer.sub(_tokens);
79+
stake.tokensStaked = stake.tokensStaked.sub(_tokens);
8180
}
8281

8382
/**
84-
* @dev Lock tokens until a thawing period expires
83+
* @dev Lock tokens until a thawing period expires,
8584
* @param stake Stake data
8685
* @param _tokens Amount of tokens to unstake
8786
* @param _thawingPeriod Period in blocks that need to pass before withdrawal
@@ -103,7 +102,7 @@ library Stakes {
103102
}
104103

105104
/**
106-
* @dev Unlock tokens
105+
* @dev Unlock tokens.
107106
* @param stake Stake data
108107
* @param _tokens Amount of tokens to unkock
109108
*/
@@ -115,7 +114,7 @@ library Stakes {
115114
}
116115

117116
/**
118-
* @dev Take all tokens out from the locked stack for withdrawal
117+
* @dev Take all tokens out from the locked stack for withdrawal.
119118
* @param stake Stake data
120119
* @return Amount of tokens being withdrawn
121120
*/
@@ -135,14 +134,15 @@ library Stakes {
135134
}
136135

137136
/**
138-
* @dev Get the locking period of the tokens to unstake, if already unstaked before calculate the weighted average
137+
* @dev Get the locking period of the tokens to unstake.
138+
* If already unstaked before calculate the weighted average.
139139
* @param stake Stake data
140140
* @param _tokens Amount of tokens to unstake
141141
* @param _thawingPeriod Period in blocks that need to pass before withdrawal
142142
* @return True if staked
143143
*/
144144
function getLockingPeriod(
145-
Stakes.Indexer storage stake,
145+
Stakes.Indexer memory stake,
146146
uint256 _tokens,
147147
uint256 _thawingPeriod
148148
) internal view returns (uint256) {
@@ -157,16 +157,16 @@ library Stakes {
157157
}
158158

159159
/**
160-
* @dev Return true if there are tokens staked by the Indexer
160+
* @dev Return true if there are tokens staked by the Indexer.
161161
* @param stake Stake data
162162
* @return True if staked
163163
*/
164-
function hasTokens(Stakes.Indexer storage stake) internal view returns (bool) {
165-
return stake.tokensIndexer > 0;
164+
function hasTokens(Stakes.Indexer memory stake) internal view returns (bool) {
165+
return stake.tokensStaked > 0;
166166
}
167167

168168
/**
169-
* @dev Return true if the indexer has allocated stake on the SubgraphDeployment
169+
* @dev Return true if the indexer has allocated stake on the SubgraphDeployment.
170170
* @param stake Stake data
171171
* @param _subgraphDeploymentID SubgraphDeployment for the allocation
172172
* @return True if allocated
@@ -180,77 +180,67 @@ library Stakes {
180180
}
181181

182182
/**
183-
* @dev Total tokens staked from indexer
183+
* @dev Return the amount of tokens used in allocations and locked for withdrawal.
184184
* @param stake Stake data
185185
* @return Token amount
186186
*/
187-
function tokensStaked(Stakes.Indexer storage stake) internal view returns (uint256) {
188-
return stake.tokensIndexer;
187+
function tokensUsed(Stakes.Indexer memory stake) internal view returns (uint256) {
188+
return stake.tokensAllocated.add(stake.tokensLocked);
189189
}
190190

191191
/**
192-
* @dev Tokens available for use in allocations
193-
* @dev tokensIndexer - tokensAllocated - tokensLocked
192+
* @dev Tokens free balance on the indexer stake.
193+
* tokensStaked - tokensAllocated - tokensLocked
194194
* @param stake Stake data
195195
* @return Token amount
196196
*/
197-
function tokensAvailable(Stakes.Indexer storage stake) internal view returns (uint256) {
198-
uint256 _tokensStaked = stake.tokensStaked();
199-
uint256 tokensUsed = stake.tokensAllocated.add(stake.tokensLocked);
200-
// Stake is over allocated: return 0 to avoid stake to be used until the overallocation
201-
// is restored by staking more tokens or unallocating tokens
202-
if (tokensUsed > _tokensStaked) {
197+
function tokensAvailable(Stakes.Indexer memory stake) internal view returns (uint256) {
198+
uint256 tokensUsed = stake.tokensUsed();
199+
// Indexer stake is over allocated: return 0 to avoid stake to be used until
200+
// the overallocation is restored by staking more tokens or unallocating tokens
201+
if (tokensUsed > stake.tokensStaked) {
203202
return 0;
204203
}
205-
return _tokensStaked.sub(tokensUsed);
206-
}
207-
208-
/**
209-
* @dev Tokens used for slashing whenever necessary
210-
* @param stake Stake data
211-
* @return Token amount
212-
*/
213-
function tokensSlashable(Stakes.Indexer storage stake) internal view returns (uint256) {
214-
return stake.tokensIndexer;
204+
return stake.tokensStaked.sub(tokensUsed);
215205
}
216206

217207
/**
218-
* @dev Tokens available for withdrawal after thawing period
208+
* @dev Tokens available for withdrawal after thawing period.
219209
* @param stake Stake data
220210
* @return Token amount
221211
*/
222-
function tokensWithdrawable(Stakes.Indexer storage stake) internal view returns (uint256) {
212+
function tokensWithdrawable(Stakes.Indexer memory stake) internal view returns (uint256) {
223213
// No tokens to withdraw before locking period
224214
if (stake.tokensLockedUntil == 0 || block.number < stake.tokensLockedUntil) {
225215
return 0;
226216
}
227217
// Cannot withdraw more than currently staked
228218
// This condition can happen if while tokens are locked for withdrawal a slash condition happens
229219
// In that case the total staked tokens could be below the amount to be withdrawn
230-
if (stake.tokensLocked > stake.tokensIndexer) {
231-
return stake.tokensIndexer;
220+
if (stake.tokensLocked > stake.tokensStaked) {
221+
return stake.tokensStaked;
232222
}
233223
return stake.tokensLocked;
234224
}
235225

236226
/**
237-
* @dev Return if channel for an allocation is active
227+
* @dev Return if channel for an allocation is active.
238228
* @param alloc Allocation data
239229
* @return True if channel related to allocation is active
240230
*/
241-
function hasChannel(Stakes.Allocation storage alloc) internal view returns (bool) {
231+
function hasChannel(Stakes.Allocation memory alloc) internal view returns (bool) {
242232
return alloc.channelID != address(0);
243233
}
244234

245235
/**
246-
* @dev Get the effective stake allocation considering epochs from allocation to settlement
236+
* @dev Get the effective stake allocation considering epochs from allocation to settlement.
247237
* @param alloc Allocation data
248238
* @param _numEpochs Number of epochs that passed from allocation to settlement
249239
* @param _maxEpochs Number of epochs used as a maximum to cap effective allocation
250240
* @return Effective allocated tokens accross epochs
251241
*/
252242
function getTokensEffectiveAllocation(
253-
Stakes.Allocation storage alloc,
243+
Stakes.Allocation memory alloc,
254244
uint256 _numEpochs,
255245
uint256 _maxEpochs
256246
) internal view returns (uint256) {

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/connext/general.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { bigNumberify, parseEther, BigNumberish, BigNumber } from 'ethers/utils'
55
import { ChallengeStatus, MinimalTransaction } from '@connext/types'
66
import { ChannelSigner, toBN, stringify } from '@connext/utils'
77

8-
import { deployGRTWithFactory, deployMultisigWithProxy } from '../lib/deployment'
8+
import { deployGRT, deployMultisigWithProxy } from '../lib/deployment'
99
import {
1010
getRandomFundedChannelSigners,
1111
fundMultisig,
@@ -61,7 +61,7 @@ describe('Indexer Channel Operations', () => {
6161
governer = accounts[0]
6262

6363
// Deploy graph token
64-
token = await deployGRTWithFactory(await governer.getAddress())
64+
token = await deployGRT(await governer.getAddress())
6565

6666
// Get channel signers
6767
const [_node, _indexer, _thirdparty] = await getRandomFundedChannelSigners(3, governer, token)

test/connext/multisig.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Signer } from 'ethers'
55
import { parseEther } from 'ethers/utils'
66

77
import { GraphToken } from '../../build/typechain/contracts/GraphToken'
8-
import { deployMultisigWithProxy, deployGRTWithFactory } from '../lib/deployment'
8+
import { deployMultisigWithProxy, deployGRT } from '../lib/deployment'
99
import { getRandomFundedChannelSigners } from '../lib/channel'
1010
import { MinimumViableMultisig } from '../../build/typechain/contracts/MinimumViableMultisig'
1111
import { IndexerCtdt } from '../../build/typechain/contracts/IndexerCtdt'
@@ -32,7 +32,7 @@ describe('MinimumViableMultisig.sol', () => {
3232
governor = accounts[0]
3333

3434
// Deploy graph token
35-
token = await deployGRTWithFactory(await governor.getAddress())
35+
token = await deployGRT(await governor.getAddress())
3636

3737
// Get channel signers
3838
const [_node, _indexer] = await getRandomFundedChannelSigners(2, governor, token)

test/curation.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ describe('Curation', () => {
2020

2121
beforeEach(async function() {
2222
// Deploy graph token
23-
grt = await deployment.deployGRT(governor.address, me)
23+
grt = await deployment.deployGRT(governor.address)
2424

2525
// Deploy curation contract
26-
curation = await deployment.deployCuration(governor.address, grt.address, me)
26+
curation = await deployment.deployCuration(governor.address, grt.address)
2727
await curation.connect(governor).setStaking(staking.address)
2828
})
2929

test/disputes.test.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,18 +105,17 @@ describe('Disputes', async () => {
105105

106106
beforeEach(async function() {
107107
// Deploy epoch contract
108-
epochManager = await deployment.deployEpochManager(governor.address, me)
108+
epochManager = await deployment.deployEpochManager(governor.address)
109109

110110
// Deploy graph token
111-
grt = await deployment.deployGRT(governor.address, me)
111+
grt = await deployment.deployGRT(governor.address)
112112

113113
// Deploy staking contract
114114
staking = await deployment.deployStaking(
115115
governor,
116116
grt.address,
117117
epochManager.address,
118118
AddressZero,
119-
me,
120119
)
121120

122121
// Deploy dispute contract
@@ -125,7 +124,6 @@ describe('Disputes', async () => {
125124
grt.address,
126125
arbitrator.address,
127126
staking.address,
128-
me,
129127
)
130128

131129
// Create an attestation
@@ -146,7 +144,7 @@ describe('Disputes', async () => {
146144
}
147145
})
148146

149-
describe('state variables functions', () => {
147+
describe('configuration', () => {
150148
it('should set `governor`', async function() {
151149
// Set right in the constructor
152150
expect(await disputeManager.governor()).to.eq(governor.address)

test/epochs.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ describe('EpochManager', () => {
2222

2323
beforeEach(async function() {
2424
// Deploy epoch manager contract
25-
epochManager = await deployment.deployEpochManager(governor.address, me)
25+
epochManager = await deployment.deployEpochManager(governor.address)
2626
})
2727

28-
describe('state variables functions', () => {
28+
describe('configuration', () => {
2929
it('should set `governor`', async function() {
3030
// Set right in the constructor
3131
expect(await epochManager.governor()).to.eq(governor.address)

0 commit comments

Comments
 (0)