Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
8 changes: 7 additions & 1 deletion packages/contracts-test/tests/unit/disputes/poi.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DisputeManager } from '@graphprotocol/contracts'
import { DisputeManager, IRewardsManager } from '@graphprotocol/contracts'
import { EpochManager } from '@graphprotocol/contracts'
import { GraphToken } from '@graphprotocol/contracts'
import { IStaking } from '@graphprotocol/contracts'
Expand Down Expand Up @@ -30,6 +30,7 @@ describe('DisputeManager:POI', () => {
let epochManager: EpochManager
let grt: GraphToken
let staking: IStaking
let rewardsManager: IRewardsManager

// Derive some channel keys for each indexer used to sign attestations
const indexerChannelKey = deriveChannelKey()
Expand Down Expand Up @@ -92,10 +93,15 @@ describe('DisputeManager:POI', () => {
epochManager = contracts.EpochManager as EpochManager
grt = contracts.GraphToken as GraphToken
staking = contracts.Staking as IStaking
rewardsManager = contracts.RewardsManager as IRewardsManager

// Give some funds to the fisherman
await grt.connect(governor).mint(fisherman.address, fishermanTokens)
await grt.connect(fisherman).approve(disputeManager.address, fishermanTokens)

// HACK: we set the staking contract as the subgraph service to make tests pass.
// This is due to the test suite being outdated.
await rewardsManager.connect(governor).setSubgraphService(staking.address)
})

beforeEach(async function () {
Expand Down
8 changes: 7 additions & 1 deletion packages/contracts-test/tests/unit/disputes/query.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createAttestation, Receipt } from '@graphprotocol/common-ts'
import { DisputeManager } from '@graphprotocol/contracts'
import { DisputeManager, IRewardsManager } from '@graphprotocol/contracts'
import { EpochManager } from '@graphprotocol/contracts'
import { GraphToken } from '@graphprotocol/contracts'
import { IStaking } from '@graphprotocol/contracts'
Expand Down Expand Up @@ -35,6 +35,7 @@ describe('DisputeManager:Query', () => {
let epochManager: EpochManager
let grt: GraphToken
let staking: IStaking
let rewardsManager: IRewardsManager

// Derive some channel keys for each indexer used to sign attestations
const indexer1ChannelKey = deriveChannelKey()
Expand Down Expand Up @@ -121,6 +122,7 @@ describe('DisputeManager:Query', () => {
epochManager = contracts.EpochManager as EpochManager
grt = contracts.GraphToken as GraphToken
staking = contracts.Staking as IStaking
rewardsManager = contracts.RewardsManager as IRewardsManager

// Give some funds to the fisherman
for (const dst of [fisherman, fisherman2]) {
Expand All @@ -139,6 +141,10 @@ describe('DisputeManager:Query', () => {
indexerAddress: indexer.address,
receipt,
}

// HACK: we set the staking contract as the subgraph service to make tests pass.
// This is due to the test suite being outdated.
await rewardsManager.connect(governor).setSubgraphService(staking.address)
})

beforeEach(async function () {
Expand Down
27 changes: 15 additions & 12 deletions packages/contracts-test/tests/unit/l2/l2Curation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ describe('L2Curation', () => {
let me: SignerWithAddress
let governor: SignerWithAddress
let curator: SignerWithAddress
let stakingMock: SignerWithAddress
let subgraphServiceMock: SignerWithAddress
let gnsImpersonator: Signer

let fixture: NetworkFixture
Expand Down Expand Up @@ -310,8 +310,8 @@ describe('L2Curation', () => {
const beforeTotalBalance = await grt.balanceOf(curation.address)

// Source of tokens must be the staking for this to work
await grt.connect(stakingMock).transfer(curation.address, tokensToCollect)
const tx = curation.connect(stakingMock).collect(subgraphDeploymentID, tokensToCollect)
await grt.connect(subgraphServiceMock).transfer(curation.address, tokensToCollect)
const tx = curation.connect(subgraphServiceMock).collect(subgraphDeploymentID, tokensToCollect)
await expect(tx).emit(curation, 'Collected').withArgs(subgraphDeploymentID, tokensToCollect)

// After state
Expand All @@ -325,7 +325,7 @@ describe('L2Curation', () => {

before(async function () {
// Use stakingMock so we can call collect
;[me, curator, stakingMock] = await graph.getTestAccounts()
;[me, curator, subgraphServiceMock] = await graph.getTestAccounts()
;({ governor } = await graph.getNamedAccounts())
fixture = new NetworkFixture(graph.provider)
contracts = await fixture.load(governor, true)
Expand All @@ -343,8 +343,11 @@ describe('L2Curation', () => {
await grt.connect(gnsImpersonator).approve(curation.address, curatorTokens)

// Give some funds to the staking contract and approve the curation contract
await grt.connect(governor).mint(stakingMock.address, tokensToCollect)
await grt.connect(stakingMock).approve(curation.address, tokensToCollect)
await grt.connect(governor).mint(subgraphServiceMock.address, tokensToCollect)
await grt.connect(subgraphServiceMock).approve(curation.address, tokensToCollect)

// Set the subgraph service
await curation.connect(governor).setSubgraphService(subgraphServiceMock.address)
})

beforeEach(async function () {
Expand Down Expand Up @@ -514,10 +517,10 @@ describe('L2Curation', () => {
context('> not curated', function () {
it('reject collect tokens distributed to the curation pool', async function () {
// Source of tokens must be the staking for this to work
await controller.connect(governor).setContractProxy(utils.id('Staking'), stakingMock.address)
await controller.connect(governor).setContractProxy(utils.id('Staking'), subgraphServiceMock.address)
await curation.connect(governor).syncAllContracts() // call sync because we change the proxy for staking

const tx = curation.connect(stakingMock).collect(subgraphDeploymentID, tokensToCollect)
const tx = curation.connect(subgraphServiceMock).collect(subgraphDeploymentID, tokensToCollect)
await expect(tx).revertedWith('Subgraph deployment must be curated to collect fees')
})
})
Expand All @@ -529,11 +532,11 @@ describe('L2Curation', () => {

it('reject collect tokens distributed from invalid address', async function () {
const tx = curation.connect(me).collect(subgraphDeploymentID, tokensToCollect)
await expect(tx).revertedWith('Caller must be the subgraph service or staking contract')
await expect(tx).revertedWith('Caller must be the subgraph service')
})

it('should collect tokens distributed to the curation pool', async function () {
await controller.connect(governor).setContractProxy(utils.id('Staking'), stakingMock.address)
await controller.connect(governor).setContractProxy(utils.id('Staking'), subgraphServiceMock.address)
await curation.connect(governor).syncAllContracts() // call sync because we change the proxy for staking

await shouldCollect(toGRT('1'))
Expand All @@ -544,7 +547,7 @@ describe('L2Curation', () => {
})

it('should collect tokens and then unsignal all', async function () {
await controller.connect(governor).setContractProxy(utils.id('Staking'), stakingMock.address)
await controller.connect(governor).setContractProxy(utils.id('Staking'), subgraphServiceMock.address)
await curation.connect(governor).syncAllContracts() // call sync because we change the proxy for staking

// Collect increase the pool reserves
Expand All @@ -556,7 +559,7 @@ describe('L2Curation', () => {
})

it('should collect tokens and then unsignal multiple times', async function () {
await controller.connect(governor).setContractProxy(utils.id('Staking'), stakingMock.address)
await controller.connect(governor).setContractProxy(utils.id('Staking'), subgraphServiceMock.address)
await curation.connect(governor).syncAllContracts() // call sync because we change the proxy for staking

// Collect increase the pool reserves
Expand Down
106 changes: 1 addition & 105 deletions packages/contracts-test/tests/unit/l2/l2GNS.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ import { L2GNS } from '@graphprotocol/contracts'
import { L2GraphTokenGateway } from '@graphprotocol/contracts'
import { L2Curation } from '@graphprotocol/contracts'
import { GraphToken } from '@graphprotocol/contracts'
import { IL2Staking } from '@graphprotocol/contracts'
import { L1GNS, L1GraphTokenGateway } from '@graphprotocol/contracts'
import {
buildSubgraph,
buildSubgraphId,
deriveChannelKey,
GraphNetworkContracts,
helpers,
PublishSubgraph,
Expand Down Expand Up @@ -44,7 +42,6 @@ interface L1SubgraphParams {
describe('L2GNS', () => {
const graph = hre.graph()
let me: SignerWithAddress
let attacker: SignerWithAddress
let other: SignerWithAddress
let governor: SignerWithAddress
let fixture: NetworkFixture
Expand All @@ -58,7 +55,6 @@ describe('L2GNS', () => {
let gns: L2GNS
let curation: L2Curation
let grt: GraphToken
let staking: IL2Staking

let newSubgraph0: PublishSubgraph
let newSubgraph1: PublishSubgraph
Expand Down Expand Up @@ -109,7 +105,7 @@ describe('L2GNS', () => {

before(async function () {
newSubgraph0 = buildSubgraph()
;[me, attacker, other] = await graph.getTestAccounts()
;[me, other] = await graph.getTestAccounts()
;({ governor } = await graph.getNamedAccounts())

fixture = new NetworkFixture(graph.provider)
Expand All @@ -118,7 +114,6 @@ describe('L2GNS', () => {
fixtureContracts = await fixture.load(governor, true)
l2GraphTokenGateway = fixtureContracts.L2GraphTokenGateway as L2GraphTokenGateway
gns = fixtureContracts.L2GNS as L2GNS
staking = fixtureContracts.L2Staking as unknown as IL2Staking
curation = fixtureContracts.L2Curation as L2Curation
grt = fixtureContracts.GraphToken as GraphToken

Expand Down Expand Up @@ -354,61 +349,6 @@ describe('L2GNS', () => {
.emit(gns, 'SignalMinted')
.withArgs(l2SubgraphId, me.address, expectedNSignal, expectedSignal, curatedTokens)
})
it('protects the owner against a rounding attack', async function () {
const { l1SubgraphId, curatedTokens, subgraphMetadata, versionMetadata } = await defaultL1SubgraphParams()
const collectTokens = curatedTokens.mul(20)

await staking.connect(governor).setCurationPercentage(100000)

// Set up an indexer account with some stake
await grt.connect(governor).mint(attacker.address, toGRT('1000000'))
// Curate 1 wei GRT by minting 1 GRT and burning most of it
await grt.connect(attacker).approve(curation.address, toBN(1))
await curation.connect(attacker).mint(newSubgraph0.subgraphDeploymentID, toBN(1), 0)

// Check this actually gave us 1 wei signal
expect(await curation.getCurationPoolTokens(newSubgraph0.subgraphDeploymentID)).eq(1)
await grt.connect(attacker).approve(staking.address, toGRT('1000000'))
await staking.connect(attacker).stake(toGRT('100000'))
const channelKey = deriveChannelKey()
// Allocate to the same deployment ID
await staking
.connect(attacker)
.allocateFrom(
attacker.address,
newSubgraph0.subgraphDeploymentID,
toGRT('100000'),
channelKey.address,
randomHexBytes(32),
await channelKey.generateProof(attacker.address),
)
// Spoof some query fees, 10% of which will go to the Curation pool
await staking.connect(attacker).collect(collectTokens, channelKey.address)
// The curation pool now has 1 wei shares and a lot of tokens, so the rounding attack is prepared
// But L2GNS will protect the owner by sending the tokens
const callhookData = defaultAbiCoder.encode(['uint8', 'uint256', 'address'], [toBN(0), l1SubgraphId, me.address])
await gatewayFinalizeTransfer(l1GNSMock.address, gns.address, curatedTokens, callhookData)

const l2SubgraphId = await gns.getAliasedL2SubgraphID(l1SubgraphId)
const tx = gns
.connect(me)
.finishSubgraphTransferFromL1(
l2SubgraphId,
newSubgraph0.subgraphDeploymentID,
subgraphMetadata,
versionMetadata,
)
await expect(tx)
.emit(gns, 'SubgraphPublished')
.withArgs(l2SubgraphId, newSubgraph0.subgraphDeploymentID, DEFAULT_RESERVE_RATIO)
await expect(tx).emit(gns, 'SubgraphMetadataUpdated').withArgs(l2SubgraphId, subgraphMetadata)
await expect(tx).emit(gns, 'CuratorBalanceReturnedToBeneficiary')
await expect(tx).emit(gns, 'SubgraphUpgraded').withArgs(l2SubgraphId, 0, 0, newSubgraph0.subgraphDeploymentID)
await expect(tx)
.emit(gns, 'SubgraphVersionUpdated')
.withArgs(l2SubgraphId, newSubgraph0.subgraphDeploymentID, versionMetadata)
await expect(tx).emit(gns, 'SubgraphL2TransferFinalized').withArgs(l2SubgraphId)
})
it('cannot be called by someone other than the subgraph owner', async function () {
const { l1SubgraphId, curatedTokens, subgraphMetadata, versionMetadata } = await defaultL1SubgraphParams()
const callhookData = defaultAbiCoder.encode(['uint8', 'uint256', 'address'], [toBN(0), l1SubgraphId, me.address])
Expand Down Expand Up @@ -654,50 +594,6 @@ describe('L2GNS', () => {
expect(gnsBalanceAfter).eq(gnsBalanceBefore)
})

it('protects the curator against a rounding attack', async function () {
// Transfer a subgraph from L1 with only 1 wei GRT of curated signal
const { l1SubgraphId, subgraphMetadata, versionMetadata } = await defaultL1SubgraphParams()
const curatedTokens = toBN('1')
await transferMockSubgraphFromL1(l1SubgraphId, curatedTokens, subgraphMetadata, versionMetadata)
// Prepare the rounding attack by setting up an indexer and collecting a lot of query fees
const curatorTokens = toGRT('10000')
const collectTokens = curatorTokens.mul(20)
await staking.connect(governor).setCurationPercentage(100000)
// Set up an indexer account with some stake
await grt.connect(governor).mint(attacker.address, toGRT('1000000'))

await grt.connect(attacker).approve(staking.address, toGRT('1000000'))
await staking.connect(attacker).stake(toGRT('100000'))
const channelKey = deriveChannelKey()
// Allocate to the same deployment ID
await staking
.connect(attacker)
.allocateFrom(
attacker.address,
newSubgraph0.subgraphDeploymentID,
toGRT('100000'),
channelKey.address,
randomHexBytes(32),
await channelKey.generateProof(attacker.address),
)
// Spoof some query fees, 10% of which will go to the Curation pool
await staking.connect(attacker).collect(collectTokens, channelKey.address)

const callhookData = defaultAbiCoder.encode(['uint8', 'uint256', 'address'], [toBN(1), l1SubgraphId, me.address])
const curatorTokensBefore = await grt.balanceOf(me.address)
const gnsBalanceBefore = await grt.balanceOf(gns.address)
const tx = gatewayFinalizeTransfer(l1GNSMock.address, gns.address, curatorTokens, callhookData)
await expect(tx)
.emit(gns, 'CuratorBalanceReturnedToBeneficiary')
.withArgs(l1SubgraphId, me.address, curatorTokens)
const curatorTokensAfter = await grt.balanceOf(me.address)
expect(curatorTokensAfter).eq(curatorTokensBefore.add(curatorTokens))
const gnsBalanceAfter = await grt.balanceOf(gns.address)
// gatewayFinalizeTransfer will mint the tokens that are sent to the curator,
// so the GNS balance should be the same
expect(gnsBalanceAfter).eq(gnsBalanceBefore)
})

it('if a subgraph was deprecated after transfer, it returns the tokens to the beneficiary', async function () {
const l1GNSMockL2Alias = await helpers.getL2SignerFromL1(l1GNSMock.address)
// Eth for gas:
Expand Down
8 changes: 7 additions & 1 deletion packages/contracts-test/tests/unit/l2/l2Staking.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IL2Staking } from '@graphprotocol/contracts'
import { IL2Staking, IRewardsManager } from '@graphprotocol/contracts'
import { L2GraphTokenGateway } from '@graphprotocol/contracts'
import { GraphToken } from '@graphprotocol/contracts'
import { EpochManager, L1GNS, L1GraphTokenGateway, L1Staking } from '@graphprotocol/contracts'
Expand Down Expand Up @@ -35,6 +35,7 @@ describe('L2Staking', () => {
let l2GraphTokenGateway: L2GraphTokenGateway
let staking: IL2Staking
let grt: GraphToken
let rewardsManager: IRewardsManager

const tokens10k = toGRT('10000')
const tokens100k = toGRT('100000')
Expand Down Expand Up @@ -88,6 +89,7 @@ describe('L2Staking', () => {
l1StakingMock = l1MockContracts.L1Staking as L1Staking
l1GNSMock = l1MockContracts.L1GNS as L1GNS
l1GRTGatewayMock = l1MockContracts.L1GraphTokenGateway as L1GraphTokenGateway
rewardsManager = fixtureContracts.RewardsManager as IRewardsManager

// Deploy L2 arbitrum bridge
await fixture.loadL2ArbitrumBridge(governor)
Expand All @@ -99,6 +101,10 @@ describe('L2Staking', () => {
await grt.connect(me).approve(staking.address, tokens1m)
await grt.connect(governor).mint(other.address, tokens1m)
await grt.connect(other).approve(staking.address, tokens1m)

// HACK: we set the staking contract as the subgraph service to make tests pass.
// This is due to the test suite being outdated.
await rewardsManager.connect(governor).setSubgraphService(staking.address)
})

beforeEach(async function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ describe('Rewards - Calculations', () => {
await grt.connect(wallet).approve(staking.address, toGRT('1000000'))
await grt.connect(wallet).approve(curation.address, toGRT('1000000'))
}

// Set the staking contract as the subgraph service so it can call takeRewards
await rewardsManager.connect(governor).setSubgraphService(staking.address)
})

beforeEach(async function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ describe('Rewards - Distribution', () => {
await grt.connect(wallet).approve(staking.address, toGRT('1000000'))
await grt.connect(wallet).approve(curation.address, toGRT('1000000'))
}

// Set the staking contract as the subgraph service so it can call takeRewards
await rewardsManager.connect(governor).setSubgraphService(staking.address)
})

beforeEach(async function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ describe('Rewards - Eligibility Oracle', () => {
await grt.connect(wallet).approve(staking.address, toGRT('1000000'))
await grt.connect(wallet).approve(curation.address, toGRT('1000000'))
}

// Set the staking contract as the subgraph service so it can call takeRewards
await rewardsManager.connect(governor).setSubgraphService(staking.address)
})

beforeEach(async function () {
Expand Down
Loading
Loading