diff --git a/hardhat.config.ts b/hardhat.config.ts index 302618d90..e545f203c 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -125,7 +125,7 @@ const config: HardhatUserConfig = { mnemonic: DEFAULT_TEST_MNEMONIC, }, mining: { - auto: true, + auto: false, interval: 30000, }, hardfork: 'london', diff --git a/scripts/test b/scripts/test index 782449c99..729b05ce6 100755 --- a/scripts/test +++ b/scripts/test @@ -41,7 +41,7 @@ fi mkdir -p reports # Run using the standalone evm instance -npx hardhat test --network hardhat +npx hardhat test --network hardhat $@ ### Cleanup diff --git a/test/lib/fixtures.ts b/test/lib/fixtures.ts index 00b151107..96fd68665 100644 --- a/test/lib/fixtures.ts +++ b/test/lib/fixtures.ts @@ -2,7 +2,7 @@ import { utils, Wallet, Signer } from 'ethers' import * as deployment from './deployment' -import { evmSnapshot, evmRevert } from './testHelpers' +import { evmSnapshot, evmRevert, provider } from './testHelpers' export class NetworkFixture { lastSnapshotId: number @@ -16,6 +16,12 @@ export class NetworkFixture { slasher: Signer = Wallet.createRandom() as Signer, arbitrator: Signer = Wallet.createRandom() as Signer, ): Promise { + // Enable automining with each transaction, and disable + // the mining interval. Individual tests may modify this + // behavior as needed. + provider().send('evm_setIntervalMining', [0]) + provider().send('evm_setAutomine', [true]) + // Roles const arbitratorAddress = await arbitrator.getAddress() const slasherAddress = await slasher.getAddress() diff --git a/test/lib/testHelpers.ts b/test/lib/testHelpers.ts index 7fd322719..ea07ba449 100644 --- a/test/lib/testHelpers.ts +++ b/test/lib/testHelpers.ts @@ -74,14 +74,13 @@ export const advanceBlocks = async (blocks: string | number | BigNumber): Promis const steps = typeof blocks === 'number' || typeof blocks === 'string' ? toBN(blocks) : blocks const currentBlock = await latestBlock() const toBlock = currentBlock.add(steps) - await advanceBlockTo(toBlock) + return advanceBlockTo(toBlock) } export const advanceToNextEpoch = async (epochManager: EpochManager): Promise => { - const currentBlock = await latestBlock() - const epochLength = await epochManager.epochLength() - const nextEpochBlock = currentBlock.add(epochLength) - await advanceBlockTo(nextEpochBlock) + const blocksSinceEpoch = await epochManager.currentEpochBlockSinceStart() + const epochLen = await epochManager.epochLength() + return advanceBlocks(epochLen.sub(blocksSinceEpoch)) } export const evmSnapshot = async (): Promise => provider().send('evm_snapshot', []) diff --git a/test/rewards/rewards.test.ts b/test/rewards/rewards.test.ts index e4e70a631..5bed9b83f 100644 --- a/test/rewards/rewards.test.ts +++ b/test/rewards/rewards.test.ts @@ -573,11 +573,14 @@ describe('Rewards', () => { } it('should distribute rewards on closed allocation and stake', async function () { + + // Align with the epoch boundary + await advanceToNextEpoch(epochManager) // Setup await setupIndexerAllocation() // Jump - await advanceBlocks(await epochManager.epochLength()) + await advanceToNextEpoch(epochManager) // Before state const beforeTokenSupply = await grt.totalSupply() @@ -585,7 +588,14 @@ describe('Rewards', () => { const beforeIndexer1Balance = await grt.balanceOf(indexer1.address) const beforeStakingBalance = await grt.balanceOf(staking.address) - const expectedIndexingRewards = toGRT('1471954234') + // All the rewards in this subgraph go to this allocation. + // Rewards per token will be (totalSupply * issuanceRate^nBlocks - totalSupply) / allocatedTokens + // The first snapshot is after allocating, that is 2 blocks after the signal is minted: + // startRewardsPerToken = (10004000000 * 1.01227 ^ 2 - 10004000000) / 12500 = 122945.16 + // The final snapshot is when we close the allocation, that happens 9 blocks later: + // endRewardsPerToken = (10004000000 * 1.01227 ^ 9 - 10004000000) / 12500 = 92861.24 + // Then our expected rewards are (endRewardsPerToken - startRewardsPerToken) * 12500. + const expectedIndexingRewards = toGRT('913715958') // Close allocation. At this point rewards should be collected for that indexer const tx = await staking @@ -623,11 +633,13 @@ describe('Rewards', () => { const destinationAddress = randomHexBytes(20) await staking.connect(indexer1.signer).setRewardsDestination(destinationAddress) + // Align with the epoch boundary + await advanceToNextEpoch(epochManager) // Setup await setupIndexerAllocation() // Jump - await advanceBlocks(await epochManager.epochLength()) + await advanceToNextEpoch(epochManager) // Before state const beforeTokenSupply = await grt.totalSupply() @@ -635,7 +647,14 @@ describe('Rewards', () => { const beforeDestinationBalance = await grt.balanceOf(destinationAddress) const beforeStakingBalance = await grt.balanceOf(staking.address) - const expectedIndexingRewards = toGRT('1471954234') + // All the rewards in this subgraph go to this allocation. + // Rewards per token will be (totalSupply * issuanceRate^nBlocks - totalSupply) / allocatedTokens + // The first snapshot is after allocating, that is 2 blocks after the signal is minted: + // startRewardsPerToken = (10004000000 * 1.01227 ^ 2 - 10004000000) / 12500 = 122945.16 + // The final snapshot is when we close the allocation, that happens 9 blocks later: + // endRewardsPerToken = (10004000000 * 1.01227 ^ 9 - 10004000000) / 12500 = 92861.24 + // Then our expected rewards are (endRewardsPerToken - startRewardsPerToken) * 12500. + const expectedIndexingRewards = toGRT('913715958') // Close allocation. At this point rewards should be collected for that indexer const tx = await staking @@ -678,10 +697,13 @@ describe('Rewards', () => { } const tokensToDelegate = toGRT('2000') + // Align with the epoch boundary + await advanceToNextEpoch(epochManager) + // Setup the allocation and delegators await setupIndexerAllocationWithDelegation(tokensToDelegate, delegationParams) // Jump - await advanceBlocks(await epochManager.epochLength()) + await advanceToNextEpoch(epochManager) // Before state const beforeTokenSupply = await grt.totalSupply() @@ -698,8 +720,15 @@ describe('Rewards', () => { // Check that rewards are put into indexer stake (only indexer cut) // Check that rewards are put into delegators pool accordingly - // NOTE: calculated manually on a spreadsheet - const expectedIndexingRewards = toGRT('1454109066') + + // All the rewards in this subgraph go to this allocation. + // Rewards per token will be (totalSupply * issuanceRate^nBlocks - totalSupply) / allocatedTokens + // The first snapshot is after allocating, that is 2 blocks after the signal is minted: + // startRewardsPerToken = (10004000000 * 1.01227 ^ 2 - 10004000000) / 14500 = 8466.995 + // The final snapshot is when we close the allocation, that happens 4 blocks later: + // endRewardsPerToken = (10004000000 * 1.01227 ^ 4 - 10004000000) / 14500 = 34496.55 + // Then our expected rewards are (endRewardsPerToken - startRewardsPerToken) * 14500. + const expectedIndexingRewards = toGRT('377428566.77') // Calculate delegators cut const indexerRewards = delegationParams.indexingRewardCut .mul(expectedIndexingRewards) @@ -725,7 +754,7 @@ describe('Rewards', () => { await setupIndexerAllocation() // Jump - await advanceBlocks(await epochManager.epochLength()) + await advanceToNextEpoch(epochManager) // Close allocation. At this point rewards should be collected for that indexer const tx = staking.connect(indexer1.signer).closeAllocation(allocationID, randomHexBytes()) @@ -769,7 +798,7 @@ describe('Rewards', () => { ) // Jump - await advanceBlocks(await epochManager.epochLength()) + await advanceToNextEpoch(epochManager) // Remove all signal from the subgraph const curatorShares = await curation.getCuratorSignal(curator1.address, subgraphDeploymentID1)