Skip to content

Commit 9385b40

Browse files
committed
chore: improve and complete rebate pool tests
1 parent 24fbdcd commit 9385b40

File tree

3 files changed

+202
-163
lines changed

3 files changed

+202
-163
lines changed

contracts/tests/RebatePoolMock.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ contract RebatePoolMock {
4848
uint32 _alphaNumerator,
4949
uint32 _alphaDenominator
5050
) external pure returns (uint256) {
51-
if (_totalFees == 0) {
51+
if (_totalFees == 0 || _totalStake == 0) {
5252
return 0;
5353
}
5454

test/staking/allocation.test.ts

Lines changed: 180 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -345,11 +345,15 @@ describe('Staking:Allocation', () => {
345345
})
346346

347347
it('reject allocate if no tokens staked', async function () {
348-
const tokensOverCapacity = tokensToStake.add(toBN('1'))
349-
const tx = allocate(tokensOverCapacity)
348+
const tx = allocate(toBN('1'))
350349
await expect(tx).revertedWith('!capacity')
351350
})
352351

352+
it('reject allocate zero tokens if no tokens staked', async function () {
353+
const tx = allocate(toBN('0'))
354+
await expect(tx).revertedWith('!stake')
355+
})
356+
353357
context('> when staked', function () {
354358
beforeEach(async function () {
355359
await staking.connect(indexer.signer).stake(tokensToStake)
@@ -563,185 +567,200 @@ describe('Staking:Allocation', () => {
563567
beforeEach(async function () {
564568
// Stake and allocate
565569
await staking.connect(indexer.signer).stake(tokensToStake)
566-
await allocate(tokensToAllocate)
567-
})
568-
569-
it('reject close a non-existing allocation', async function () {
570-
const invalidAllocationID = randomHexBytes(20)
571-
const tx = staking.connect(indexer.signer).closeAllocation(invalidAllocationID, poi)
572-
await expect(tx).revertedWith('!active')
573570
})
574571

575-
it('reject close before at least one epoch has passed', async function () {
576-
const tx = staking.connect(indexer.signer).closeAllocation(allocationID, poi)
577-
await expect(tx).revertedWith('<epochs')
578-
})
579-
580-
it('reject close if not the owner of allocation', async function () {
581-
// Move at least one epoch to be able to close
582-
await advanceToNextEpoch(epochManager)
572+
for (const tokensToAllocate of [toBN(100), toBN(0)]) {
573+
context(`> with ${tokensToAllocate} allocated tokens`, async function () {
574+
beforeEach(async function () {
575+
await allocate(tokensToAllocate)
576+
})
583577

584-
// Close allocation
585-
const tx = staking.connect(me.signer).closeAllocation(allocationID, poi)
586-
await expect(tx).revertedWith('!auth')
587-
})
578+
it('reject close a non-existing allocation', async function () {
579+
const invalidAllocationID = randomHexBytes(20)
580+
const tx = staking.connect(indexer.signer).closeAllocation(invalidAllocationID, poi)
581+
await expect(tx).revertedWith('!active')
582+
})
588583

589-
it('reject close if allocation is already closed', async function () {
590-
// Move at least one epoch to be able to close
591-
await advanceToNextEpoch(epochManager)
584+
it('reject close before at least one epoch has passed', async function () {
585+
const tx = staking.connect(indexer.signer).closeAllocation(allocationID, poi)
586+
await expect(tx).revertedWith('<epochs')
587+
})
592588

593-
// First closing
594-
await staking.connect(indexer.signer).closeAllocation(allocationID, poi)
589+
it('reject close if not the owner of allocation', async function () {
590+
// Move at least one epoch to be able to close
591+
await advanceToNextEpoch(epochManager)
595592

596-
// Second closing
597-
const tx = staking.connect(indexer.signer).closeAllocation(allocationID, poi)
598-
await expect(tx).revertedWith('!active')
599-
})
593+
// Close allocation
594+
const tx = staking.connect(me.signer).closeAllocation(allocationID, poi)
595+
await expect(tx).revertedWith('!auth')
596+
})
600597

601-
it('should close an allocation', async function () {
602-
// Before state
603-
const beforeStake = await staking.stakes(indexer.address)
604-
const beforeAlloc = await staking.getAllocation(allocationID)
605-
const beforeRebatePool = await staking.rebates(
606-
(await epochManager.currentEpoch()).add(toBN('2')),
607-
)
598+
it('reject close if allocation is already closed', async function () {
599+
// Move at least one epoch to be able to close
600+
await advanceToNextEpoch(epochManager)
608601

609-
// Move at least one epoch to be able to close
610-
await advanceToNextEpoch(epochManager)
611-
await advanceToNextEpoch(epochManager)
602+
// First closing
603+
await staking.connect(indexer.signer).closeAllocation(allocationID, poi)
612604

613-
// Calculations
614-
const currentEpoch = await epochManager.currentEpoch()
615-
const epochs = currentEpoch.sub(beforeAlloc.createdAtEpoch)
616-
const maxAllocationEpochs = toBN(await staking.maxAllocationEpochs())
617-
const effectiveAllocation = calculateEffectiveAllocation(
618-
beforeAlloc.tokens,
619-
epochs,
620-
maxAllocationEpochs,
621-
)
605+
// Second closing
606+
const tx = staking.connect(indexer.signer).closeAllocation(allocationID, poi)
607+
await expect(tx).revertedWith('!active')
608+
})
622609

623-
// Close allocation
624-
const tx = staking.connect(indexer.signer).closeAllocation(allocationID, poi)
625-
await expect(tx)
626-
.emit(staking, 'AllocationClosed')
627-
.withArgs(
628-
indexer.address,
629-
subgraphDeploymentID,
630-
currentEpoch,
631-
beforeAlloc.tokens,
632-
allocationID,
633-
effectiveAllocation,
634-
indexer.address,
635-
poi,
636-
false,
637-
)
610+
it('should close an allocation', async function () {
611+
// Before state
612+
const beforeStake = await staking.stakes(indexer.address)
613+
const beforeAlloc = await staking.getAllocation(allocationID)
614+
const beforeRebatePool = await staking.rebates(
615+
(await epochManager.currentEpoch()).add(toBN('2')),
616+
)
638617

639-
// After state
640-
const afterStake = await staking.stakes(indexer.address)
641-
const afterAlloc = await staking.getAllocation(allocationID)
642-
const afterRebatePool = await staking.rebates(currentEpoch)
643-
644-
// Stake updated
645-
expect(afterStake.tokensAllocated).eq(beforeStake.tokensAllocated.sub(beforeAlloc.tokens))
646-
// Allocation updated
647-
expect(afterAlloc.closedAtEpoch).eq(currentEpoch)
648-
expect(afterAlloc.effectiveAllocation).eq(effectiveAllocation)
649-
// Rebate updated
650-
expect(afterRebatePool.fees).eq(beforeRebatePool.fees.add(beforeAlloc.collectedFees))
651-
expect(afterRebatePool.effectiveAllocatedStake).eq(
652-
beforeRebatePool.effectiveAllocatedStake.add(effectiveAllocation),
653-
)
654-
expect(afterRebatePool.unclaimedAllocationsCount).eq(
655-
beforeRebatePool.unclaimedAllocationsCount + 1,
656-
)
657-
})
618+
// Move at least one epoch to be able to close
619+
await advanceToNextEpoch(epochManager)
620+
await advanceToNextEpoch(epochManager)
621+
622+
// Calculations
623+
const currentEpoch = await epochManager.currentEpoch()
624+
const epochs = currentEpoch.sub(beforeAlloc.createdAtEpoch)
625+
const maxAllocationEpochs = toBN(await staking.maxAllocationEpochs())
626+
const effectiveAllocation = calculateEffectiveAllocation(
627+
beforeAlloc.tokens,
628+
epochs,
629+
maxAllocationEpochs,
630+
)
658631

659-
it('should close an allocation (by operator)', async function () {
660-
// Move at least one epoch to be able to close
661-
await advanceToNextEpoch(epochManager)
662-
await advanceToNextEpoch(epochManager)
632+
// Close allocation
633+
const tx = staking.connect(indexer.signer).closeAllocation(allocationID, poi)
634+
await expect(tx)
635+
.emit(staking, 'AllocationClosed')
636+
.withArgs(
637+
indexer.address,
638+
subgraphDeploymentID,
639+
currentEpoch,
640+
beforeAlloc.tokens,
641+
allocationID,
642+
effectiveAllocation,
643+
indexer.address,
644+
poi,
645+
false,
646+
)
663647

664-
// Reject to close if the address is not operator
665-
const tx1 = staking.connect(me.signer).closeAllocation(allocationID, poi)
666-
await expect(tx1).revertedWith('!auth')
648+
// After state
649+
const afterStake = await staking.stakes(indexer.address)
650+
const afterAlloc = await staking.getAllocation(allocationID)
651+
const afterRebatePool = await staking.rebates(currentEpoch)
652+
653+
// Stake updated
654+
expect(afterStake.tokensAllocated).eq(beforeStake.tokensAllocated.sub(beforeAlloc.tokens))
655+
// Allocation updated
656+
expect(afterAlloc.closedAtEpoch).eq(currentEpoch)
657+
expect(afterAlloc.effectiveAllocation).eq(effectiveAllocation)
658+
// Rebate updated
659+
expect(afterRebatePool.fees).eq(beforeRebatePool.fees.add(beforeAlloc.collectedFees))
660+
expect(afterRebatePool.effectiveAllocatedStake).eq(
661+
beforeRebatePool.effectiveAllocatedStake.add(effectiveAllocation),
662+
)
663+
expect(afterRebatePool.unclaimedAllocationsCount).eq(
664+
beforeRebatePool.unclaimedAllocationsCount + 1,
665+
)
666+
})
667667

668-
// Should close if given operator auth
669-
await staking.connect(indexer.signer).setOperator(me.address, true)
670-
await staking.connect(me.signer).closeAllocation(allocationID, poi)
671-
})
668+
it('should close an allocation (by operator)', async function () {
669+
// Move at least one epoch to be able to close
670+
await advanceToNextEpoch(epochManager)
671+
await advanceToNextEpoch(epochManager)
672672

673-
it('should close an allocation (by public)', async function () {
674-
// Reject to close if public address and under max allocation epochs
675-
const tx1 = staking.connect(me.signer).closeAllocation(allocationID, poi)
676-
await expect(tx1).revertedWith('<epochs')
677-
678-
// Move max allocation epochs to close by delegator
679-
const maxAllocationEpochs = await staking.maxAllocationEpochs()
680-
await advanceEpochs(epochManager, maxAllocationEpochs)
681-
682-
// Calculations
683-
const beforeAlloc = await staking.getAllocation(allocationID)
684-
const currentEpoch = await epochManager.currentEpoch()
685-
const epochs = currentEpoch.sub(beforeAlloc.createdAtEpoch)
686-
const effectiveAllocation = calculateEffectiveAllocation(
687-
beforeAlloc.tokens,
688-
epochs,
689-
toBN(maxAllocationEpochs),
690-
)
673+
// Reject to close if the address is not operator
674+
const tx1 = staking.connect(me.signer).closeAllocation(allocationID, poi)
675+
await expect(tx1).revertedWith('!auth')
691676

692-
// Setup
693-
await grt.connect(governor.signer).mint(me.address, toGRT('1'))
694-
await grt.connect(me.signer).approve(staking.address, toGRT('1'))
677+
// Should close if given operator auth
678+
await staking.connect(indexer.signer).setOperator(me.address, true)
679+
await staking.connect(me.signer).closeAllocation(allocationID, poi)
680+
})
695681

696-
// Should close by public
697-
const tx = staking.connect(me.signer).closeAllocation(allocationID, poi)
698-
await expect(tx)
699-
.emit(staking, 'AllocationClosed')
700-
.withArgs(
701-
indexer.address,
702-
subgraphDeploymentID,
703-
currentEpoch,
704-
beforeAlloc.tokens,
705-
allocationID,
706-
effectiveAllocation,
707-
me.address,
708-
poi,
709-
true,
710-
)
711-
})
682+
it('should close an allocation (by public) only if allocation is non-zero', async function () {
683+
// Reject to close if public address and under max allocation epochs
684+
const tx1 = staking.connect(me.signer).closeAllocation(allocationID, poi)
685+
await expect(tx1).revertedWith('<epochs')
686+
687+
// Move max allocation epochs to close by delegator
688+
const maxAllocationEpochs = await staking.maxAllocationEpochs()
689+
await advanceEpochs(epochManager, maxAllocationEpochs)
690+
691+
// Closing should only be possible if allocated tokens > 0
692+
const alloc = await staking.getAllocation(allocationID)
693+
if (alloc.tokens.gt(0)) {
694+
// Calculations
695+
const beforeAlloc = await staking.getAllocation(allocationID)
696+
const currentEpoch = await epochManager.currentEpoch()
697+
const epochs = currentEpoch.sub(beforeAlloc.createdAtEpoch)
698+
const effectiveAllocation = calculateEffectiveAllocation(
699+
beforeAlloc.tokens,
700+
epochs,
701+
toBN(maxAllocationEpochs),
702+
)
712703

713-
it('should close many allocations in batch', async function () {
714-
// Setup a second allocation
715-
await staking.connect(indexer.signer).stake(tokensToAllocate)
716-
const channelKey2 = deriveChannelKey()
717-
const allocationID2 = channelKey2.address
718-
await staking
719-
.connect(indexer.signer)
720-
.allocate(
721-
subgraphDeploymentID,
722-
tokensToAllocate,
723-
allocationID2,
724-
metadata,
725-
await channelKey2.generateProof(indexer.address),
726-
)
704+
// Setup
705+
await grt.connect(governor.signer).mint(me.address, toGRT('1'))
706+
await grt.connect(me.signer).approve(staking.address, toGRT('1'))
707+
708+
// Should close by public
709+
const tx = staking.connect(me.signer).closeAllocation(allocationID, poi)
710+
await expect(tx)
711+
.emit(staking, 'AllocationClosed')
712+
.withArgs(
713+
indexer.address,
714+
subgraphDeploymentID,
715+
currentEpoch,
716+
beforeAlloc.tokens,
717+
allocationID,
718+
effectiveAllocation,
719+
me.address,
720+
poi,
721+
true,
722+
)
723+
} else {
724+
// closing by the public on a zero allocation is not authorized
725+
const tx = staking.connect(me.signer).closeAllocation(allocationID, poi)
726+
await expect(tx).revertedWith('!auth')
727+
}
728+
})
727729

728-
// Move at least one epoch to be able to close
729-
await advanceToNextEpoch(epochManager)
730-
await advanceToNextEpoch(epochManager)
730+
it('should close many allocations in batch', async function () {
731+
// Setup a second allocation
732+
await staking.connect(indexer.signer).stake(tokensToStake)
733+
const channelKey2 = deriveChannelKey()
734+
const allocationID2 = channelKey2.address
735+
await staking
736+
.connect(indexer.signer)
737+
.allocate(
738+
subgraphDeploymentID,
739+
tokensToAllocate,
740+
allocationID2,
741+
metadata,
742+
await channelKey2.generateProof(indexer.address),
743+
)
731744

732-
// Close multiple allocations in one tx
733-
const requests = [
734-
{
735-
allocationID: allocationID,
736-
poi: poi,
737-
},
738-
{
739-
allocationID: allocationID2,
740-
poi: poi,
741-
},
742-
]
743-
await staking.connect(indexer.signer).closeAllocationMany(requests)
744-
})
745+
// Move at least one epoch to be able to close
746+
await advanceToNextEpoch(epochManager)
747+
await advanceToNextEpoch(epochManager)
748+
749+
// Close multiple allocations in one tx
750+
const requests = [
751+
{
752+
allocationID: allocationID,
753+
poi: poi,
754+
},
755+
{
756+
allocationID: allocationID2,
757+
poi: poi,
758+
},
759+
]
760+
await staking.connect(indexer.signer).closeAllocationMany(requests)
761+
})
762+
})
763+
}
745764
})
746765

747766
describe('closeAndAllocate', function () {

0 commit comments

Comments
 (0)