Skip to content

Commit 9ef1c13

Browse files
abarmatdavekay100
andauthored
curation: refactor of signalToTokens to return withdrawal fee (#254)
* curation: update signalToToken to return withdrawal fee * Fix tests failing from not considering fees * Fix failing tests on node 10 Co-authored-by: David Kajpust <[email protected]>
1 parent 446f151 commit 9ef1c13

File tree

6 files changed

+179
-119
lines changed

6 files changed

+179
-119
lines changed

contracts/GNS.sol

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ contract GNS is Governed, BancorFormula {
555555
}
556556

557557
/**
558-
* @dev Calculations for buying name signal
558+
* @dev Calculations for burning name signal
559559
* @param _graphAccount Subgraph owner
560560
* @param _subgraphNumber Subgraph owners subgraph number which was curated on by nameCurators
561561
* @param _nSignal nSignal being burnt to receive vSignal to be burnt into GRT
@@ -576,8 +576,8 @@ contract GNS is Governed, BancorFormula {
576576
}
577577

578578
/**
579-
* @dev Calculations burning vSignal from disabled or upgrade, and takes the withdrawal fee
580-
* from the name curator owner so they cannot grief all the name curators stake
579+
* @dev Calculations burning vSignal from disabled or upgrade, while keeping n signal constant.
580+
* Takes the withdrawal fee from the name owner so they cannot grief all the name curators
581581
* @param _graphAccount Subgraph owner
582582
* @param _subgraphDeploymentID Subgraph deployment to burn all vSignal from
583583
* @param _vSignal vSignal being burnt
@@ -625,11 +625,22 @@ contract GNS is Governed, BancorFormula {
625625
address _graphAccount,
626626
uint256 _subgraphNumber,
627627
uint256 _nSignal
628-
) public view returns (uint256, uint256) {
628+
)
629+
public
630+
view
631+
returns (
632+
uint256,
633+
uint256,
634+
uint256
635+
)
636+
{
629637
NameCurationPool memory namePool = nameSignals[_graphAccount][_subgraphNumber];
630638
uint256 vSignal = nSignalToVSignal(_graphAccount, _subgraphNumber, _nSignal);
631-
uint256 tokens = curation.signalToTokens(namePool.subgraphDeploymentID, vSignal);
632-
return (vSignal, tokens);
639+
(uint256 tokens, uint256 withdrawalFees) = curation.signalToTokens(
640+
namePool.subgraphDeploymentID,
641+
vSignal
642+
);
643+
return (vSignal, tokens, withdrawalFees);
633644
}
634645

635646
/**

contracts/curation/Curation.sol

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,7 @@ contract Curation is CurationV1Storage, ICuration, Governed {
206206
);
207207

208208
// Stake tokens to a curation pool reserve
209-
uint256 signal = _mint(curator, _subgraphDeploymentID, _tokens);
210-
return signal;
209+
return _mint(curator, _subgraphDeploymentID, _tokens);
211210
}
212211

213212
/**
@@ -231,17 +230,19 @@ contract Curation is CurationV1Storage, ICuration, Governed {
231230
);
232231

233232
// Update balance and get the amount of tokens to refund based on returned signal
234-
uint256 tokens = _burnSignal(curator, _subgraphDeploymentID, _signal);
233+
(uint256 tokens, uint256 withdrawalFees) = _burnSignal(
234+
curator,
235+
_subgraphDeploymentID,
236+
_signal
237+
);
235238

236239
// If all signal burnt delete the curation pool
237240
if (getCurationPoolSignal(_subgraphDeploymentID) == 0) {
238241
delete pools[_subgraphDeploymentID];
239242
}
240243

241-
// Calculate withdrawal fees and burn the tokens
242-
uint256 withdrawalFees = uint256(withdrawalFeePercentage).mul(tokens).div(MAX_PPM);
244+
// Burn withdrawal fees
243245
if (withdrawalFees > 0) {
244-
tokens = tokens.sub(withdrawalFees);
245246
token.burn(withdrawalFees);
246247
}
247248

@@ -332,13 +333,13 @@ contract Curation is CurationV1Storage, ICuration, Governed {
332333
* @dev Calculate number of tokens to get when burning signal from a curation pool.
333334
* @param _subgraphDeploymentID Subgraph deployment to burn signal
334335
* @param _signal Amount of signal to burn
335-
* @return Amount of tokens to get after burning signal
336+
* @return Amount of tokens to get after burning signal and withdrawal fees
336337
*/
337338
function signalToTokens(bytes32 _subgraphDeploymentID, uint256 _signal)
338339
public
339340
override
340341
view
341-
returns (uint256)
342+
returns (uint256, uint256)
342343
{
343344
CurationPool memory curationPool = pools[_subgraphDeploymentID];
344345
uint256 curationPoolSignal = getCurationPoolSignal(_subgraphDeploymentID);
@@ -350,13 +351,16 @@ contract Curation is CurationV1Storage, ICuration, Governed {
350351
curationPoolSignal >= _signal,
351352
"Signal must be above or equal to signal issued in the curation pool"
352353
);
353-
return
354-
calculateSaleReturn(
355-
curationPoolSignal,
356-
curationPool.tokens,
357-
uint32(curationPool.reserveRatio),
358-
_signal
359-
);
354+
355+
uint256 tokens = calculateSaleReturn(
356+
curationPoolSignal,
357+
curationPool.tokens,
358+
curationPool.reserveRatio,
359+
_signal
360+
);
361+
uint256 withdrawalFees = tokens.mul(uint256(withdrawalFeePercentage)).div(MAX_PPM);
362+
363+
return (tokens.sub(withdrawalFees), withdrawalFees);
360364
}
361365

362366
/**
@@ -388,23 +392,23 @@ contract Curation is CurationV1Storage, ICuration, Governed {
388392
* @param _curator Curator address
389393
* @param _subgraphDeploymentID Subgraph deployment pool to burn signal
390394
* @param _signal Amount of signal to burn
391-
* @return Number of tokens received
395+
* @return Number of tokens received and withdrawal fees
392396
*/
393397
function _burnSignal(
394398
address _curator,
395399
bytes32 _subgraphDeploymentID,
396400
uint256 _signal
397-
) private returns (uint256) {
401+
) private returns (uint256, uint256) {
398402
CurationPool storage curationPool = pools[_subgraphDeploymentID];
399-
uint256 tokens = signalToTokens(_subgraphDeploymentID, _signal);
403+
(uint256 tokens, uint256 withdrawalFees) = signalToTokens(_subgraphDeploymentID, _signal);
400404

401405
// Update GRT tokens held as reserves
402-
curationPool.tokens = curationPool.tokens.sub(tokens);
406+
curationPool.tokens = curationPool.tokens.sub(tokens.add(withdrawalFees));
403407

404408
// Burn signal from curator
405409
curationPool.gst.burnFrom(_curator, _signal);
406410

407-
return tokens;
411+
return (tokens, withdrawalFees);
408412
}
409413

410414
/**

contracts/curation/ICuration.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,5 @@ interface ICuration {
4040
function signalToTokens(bytes32 _subgraphDeploymentID, uint256 _signal)
4141
external
4242
view
43-
returns (uint256);
43+
returns (uint256, uint256);
4444
}

scripts/flatten

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#!/bin/bash
22

33
OUT_DIR="build/full"
4-
IFS='/'
54

5+
echo ${OUT_DIR}/contracts
66
mkdir -p ${OUT_DIR}/contracts
77

88
echo "Flattening contracts..."
99

10+
IFS='/'
11+
1012
for path in contracts/**/*.sol; do
1113
parts=( $path )
1214
name=${parts[${#parts[@]}-1]}

test/curation/curation.test.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ describe('Curation', () => {
9999

100100
// Calculations
101101
const withdrawalFeePercentage = await curation.withdrawalFeePercentage()
102-
const withdrawalFees = toBN(withdrawalFeePercentage).mul(expectedTokens).div(toBN(MAX_PPM))
102+
const withdrawalFees = expectedTokens.mul(toBN(withdrawalFeePercentage)).div(toBN(MAX_PPM))
103103

104104
// Redeem
105105
const tx = curation.connect(curator.signer).burn(subgraphDeploymentID, signalToRedeem)
@@ -194,8 +194,29 @@ describe('Curation', () => {
194194

195195
// Conversion
196196
const signal = await curation.getCurationPoolSignal(subgraphDeploymentID)
197-
const tokens = await curation.signalToTokens(subgraphDeploymentID, signal)
198-
expect(tokens).eq(tokensToStake)
197+
const { 0: expectedTokens } = await curation.signalToTokens(subgraphDeploymentID, signal)
198+
expect(expectedTokens).eq(tokensToStake)
199+
})
200+
201+
it('convert signal to tokens (with withdrawal fees)', async function () {
202+
// Set fees for withdrawal
203+
const withdrawalFeePercentage = 50000 // 5%
204+
await curation.connect(governor.signer).setWithdrawalFeePercentage(withdrawalFeePercentage)
205+
206+
// Curate
207+
await curation.connect(curator.signer).mint(subgraphDeploymentID, tokensToStake)
208+
209+
// Expected
210+
const expectedWithdrawalFees = tokensToStake.mul(withdrawalFeePercentage).div(MAX_PPM)
211+
212+
// Conversion
213+
const signal = await curation.getCurationPoolSignal(subgraphDeploymentID)
214+
const { 0: tokens, 1: withdrawalFees } = await curation.signalToTokens(
215+
subgraphDeploymentID,
216+
signal,
217+
)
218+
expect(tokens).eq(tokensToStake.sub(expectedWithdrawalFees))
219+
expect(withdrawalFees).eq(expectedWithdrawalFees)
199220
})
200221

201222
it('convert tokens to signal', async function () {
@@ -290,7 +311,10 @@ describe('Curation', () => {
290311
// Redeem "almost" all signal
291312
const signal = await curation.getCuratorSignal(curator.address, subgraphDeploymentID)
292313
const signalToRedeem = signal.sub(toGRT('0.000001'))
293-
const expectedTokens = await curation.signalToTokens(subgraphDeploymentID, signalToRedeem)
314+
const { 0: expectedTokens } = await curation.signalToTokens(
315+
subgraphDeploymentID,
316+
signalToRedeem,
317+
)
294318
await shouldRedeem(signalToRedeem, expectedTokens)
295319

296320
// The pool should have less tokens that required by minimumCurationStake
@@ -304,7 +328,8 @@ describe('Curation', () => {
304328
})
305329

306330
it('should allow to redeem and account for withdrawal fees', async function () {
307-
await curation.connect(governor.signer).setWithdrawalFeePercentage(50000)
331+
// Set fees for withdrawal
332+
await curation.connect(governor.signer).setWithdrawalFeePercentage(50000) // 5%
308333

309334
// Get all signal of the curator
310335
const signalToRedeem = await curation.getCuratorSignal(curator.address, subgraphDeploymentID)

0 commit comments

Comments
 (0)