Skip to content

Sync: l2-testnet / scenario1 > dev #703

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Sep 6, 2022
Merged
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
3 changes: 2 additions & 1 deletion TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ The command will perform the following actions:
- Run `migrate` hardhat task to deploy the protocol
- Run `migrate:ownership` hardhat task to transfer ownership of governed contracts to the governor
- Run `migrate:unpause` to unpause the protocol
- Run `e2e` hardhat task to run all e2e tests, including scenarios
- Run `e2e` hardhat task to run all deployment tests (config and init)
- Run `e2e:scenario` hardhat task to run a scenario

### Other networks

Expand Down
8 changes: 6 additions & 2 deletions cli/commands/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ const allContracts = [
'AllocationExchange',
]

export const migrate = async (cli: CLIEnvironment, cliArgs: CLIArgs): Promise<void> => {
export const migrate = async (
cli: CLIEnvironment,
cliArgs: CLIArgs,
autoMine = false,
): Promise<void> => {
const graphConfigPath = cliArgs.graphConfig
const force = cliArgs.force
const contractName = cliArgs.contract
Expand Down Expand Up @@ -140,7 +144,7 @@ export const migrate = async (cli: CLIEnvironment, cliArgs: CLIArgs): Promise<vo
logger.info(`Sent ${nTx} transaction${nTx === 1 ? '' : 's'} & spent ${EtherSymbol} ${spent}`)

if (chainId == 1337) {
await (cli.wallet.provider as providers.JsonRpcProvider).send('evm_setAutomine', [false])
await (cli.wallet.provider as providers.JsonRpcProvider).send('evm_setAutomine', [autoMine])
}
}

Expand Down
17 changes: 16 additions & 1 deletion config/graph.mainnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ contracts:
- fn: "setContractProxy"
id: "0x45fc200c7e4544e457d3c5709bfe0d520442c30bbcbdaede89e8d4a4bbc19247" # keccak256('GraphToken')
contractAddress: "${{GraphToken.address}}"
- fn: "setPauseGuardian"
pauseGuardian: *pauseGuardian
- fn: "transferOwnership"
owner: *governor
GraphProxyAdmin:
calls:
- fn: "transferOwnership"
owner: *governor
ServiceRegistry:
proxy: true
init:
Expand All @@ -45,6 +53,9 @@ contracts:
calls:
- fn: "addMinter"
minter: "${{RewardsManager.address}}"
- fn: "renounceMinter"
- fn: "transferOwnership"
owner: *governor
Curation:
proxy: true
init:
Expand Down Expand Up @@ -79,6 +90,8 @@ contracts:
tokenDescriptor: "${{SubgraphNFTDescriptor.address}}"
- fn: "setMinter"
minter: "${{GNS.address}}"
- fn: "transferOwnership"
owner: *governor
Staking:
proxy: true
init:
Expand Down Expand Up @@ -109,11 +122,13 @@ contracts:
calls:
- fn: "setIssuanceRate"
issuanceRate: "1000000012184945188" # per block increase of total supply, blocks in a year = 365*60*60*24/13
- fn: "setSubgraphAvailabilityOracle"
subgraphAvailabilityOracle: *availabilityOracle
AllocationExchange:
init:
graphToken: "${{GraphToken.address}}"
staking: "${{Staking.address}}"
governor: *governor
governor: *allocationExchangeOwner
authority: *authority
calls:
- fn: "approveAll"
48 changes: 48 additions & 0 deletions e2e/scenarios/close-allocations.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { expect } from 'chai'
import hre from 'hardhat'
import { AllocationFixture, getIndexerFixtures, IndexerFixture } from './fixtures/indexers'

enum AllocationState {
Null,
Active,
Closed,
Finalized,
Claimed,
}

let indexerFixtures: IndexerFixture[]

describe('Close allocations', () => {
const { contracts, getTestAccounts } = hre.graph()
const { Staking } = contracts

before(async () => {
indexerFixtures = getIndexerFixtures(await getTestAccounts())
})

describe('Allocations', () => {
let allocations: AllocationFixture[] = []
let openAllocations: AllocationFixture[] = []
let closedAllocations: AllocationFixture[] = []

before(async () => {
allocations = indexerFixtures.map((i) => i.allocations).flat()
openAllocations = allocations.filter((a) => !a.close)
closedAllocations = allocations.filter((a) => a.close)
})

it(`some allocatons should be open`, async function () {
for (const allocation of openAllocations) {
const state = await Staking.getAllocationState(allocation.signer.address)
expect(state).eq(AllocationState.Active)
}
})

it(`some allocatons should be closed`, async function () {
for (const allocation of closedAllocations) {
const state = await Staking.getAllocationState(allocation.signer.address)
expect(state).eq(AllocationState.Closed)
}
})
})
})
52 changes: 52 additions & 0 deletions e2e/scenarios/close-allocations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// ### Scenario description ###
// Common protocol actions > Close some allocations
// This scenario will close several open allocations. See fixtures for details.
// Need to wait at least 1 epoch after the allocations have been created before running it.
// On localhost, the epoch is automatically advanced to guarantee this.
// Run with:
// npx hardhat e2e:scenario close-allocations --network <network> --graph-config config/graph.<network>.yml

import hre from 'hardhat'
import { closeAllocation } from './lib/staking'
import { advanceToNextEpoch } from '../../test/lib/testHelpers'
import { fundAccountsETH } from './lib/accounts'
import { getIndexerFixtures } from './fixtures/indexers'
import { getGraphOptsFromArgv } from './lib/helpers'

async function main() {
const graphOpts = getGraphOptsFromArgv()
const graph = hre.graph(graphOpts)
const indexerFixtures = getIndexerFixtures(await graph.getTestAccounts())

const deployer = await graph.getDeployer()
const indexers = indexerFixtures.map((i) => i.signer.address)
const indexerETHBalances = indexerFixtures.map((i) => i.ethBalance)

// == Fund participants
console.log('\n== Fund indexers')
await fundAccountsETH(deployer, indexers, indexerETHBalances)

// == Time travel on local networks, ensure allocations can be closed
if (['hardhat', 'localhost'].includes(hre.network.name)) {
console.log('\n== Advancing to next epoch')
await advanceToNextEpoch(graph.contracts.EpochManager)
}

// == Close allocations
console.log('\n== Close allocations')

for (const indexer of indexerFixtures) {
for (const allocation of indexer.allocations.filter((a) => a.close)) {
await closeAllocation(graph.contracts, indexer.signer, allocation.signer.address)
}
}
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exitCode = 1
})
72 changes: 72 additions & 0 deletions e2e/scenarios/create-subgraphs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { expect } from 'chai'
import hre from 'hardhat'
import { recreatePreviousSubgraphId } from './lib/subgraph'
import { BigNumber } from 'ethers'
import { CuratorFixture, getCuratorFixtures } from './fixtures/curators'
import { SubgraphFixture, getSubgraphFixtures, getSubgraphOwner } from './fixtures/subgraphs'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'

let curatorFixtures: CuratorFixture[]
let subgraphFixtures: SubgraphFixture[]
let subgraphOwnerFixture: SignerWithAddress

describe('Publish subgraphs', () => {
const { contracts, getTestAccounts } = hre.graph()
const { GNS, GraphToken, Curation } = contracts

before(async () => {
const testAccounts = await getTestAccounts()
curatorFixtures = getCuratorFixtures(testAccounts)
subgraphFixtures = getSubgraphFixtures()
subgraphOwnerFixture = getSubgraphOwner(testAccounts).signer
})

describe('GRT balances', () => {
it(`curator balances should match airdropped amount minus signalled`, async function () {
for (const curator of curatorFixtures) {
const address = curator.signer.address
const balance = await GraphToken.balanceOf(address)
expect(balance).eq(curator.grtBalance.sub(curator.signalled))
}
})
})

describe('Subgraphs', () => {
it(`should be published`, async function () {
for (let i = 0; i < subgraphFixtures.length; i++) {
const subgraphId = await recreatePreviousSubgraphId(
contracts,
subgraphOwnerFixture.address,
subgraphFixtures.length - i,
)
const isPublished = await GNS.isPublished(subgraphId)
expect(isPublished).eq(true)
}
})

it(`should have signal`, async function () {
for (let i = 0; i < subgraphFixtures.length; i++) {
const subgraph = subgraphFixtures[i]
const subgraphId = await recreatePreviousSubgraphId(
contracts,
subgraphOwnerFixture.address,
subgraphFixtures.length - i,
)

let totalSignal: BigNumber = BigNumber.from(0)
for (const curator of curatorFixtures) {
const _subgraph = curator.subgraphs.find((s) => s.deploymentId === subgraph.deploymentId)
if (_subgraph) {
totalSignal = totalSignal.add(_subgraph.signal)
}
}

const tokens = await GNS.subgraphTokens(subgraphId)
const MAX_PPM = 1000000
const curationTax = await Curation.curationTaxPercentage()
const tax = totalSignal.mul(curationTax).div(MAX_PPM)
expect(tokens).eq(totalSignal.sub(tax))
}
})
})
})
71 changes: 71 additions & 0 deletions e2e/scenarios/create-subgraphs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// ### Scenario description ###
// Common protocol actions > Set up subgraphs: publish and signal
// This scenario will create a set of subgraphs and add signal to them. See fixtures for details.
// Run with:
// npx hardhat e2e:scenario create-subgraphs --network <network> --graph-config config/graph.<network>.yml

import hre from 'hardhat'
import { publishNewSubgraph } from './lib/subgraph'
import { fundAccountsETH, fundAccountsGRT } from './lib/accounts'
import { signal } from './lib/curation'
import { getSubgraphFixtures, getSubgraphOwner } from './fixtures/subgraphs'
import { getCuratorFixtures } from './fixtures/curators'
import { getGraphOptsFromArgv } from './lib/helpers'

async function main() {
const graphOpts = getGraphOptsFromArgv()
const graph = hre.graph(graphOpts)
const testAccounts = await graph.getTestAccounts()

const subgraphFixtures = getSubgraphFixtures()
const subgraphOwnerFixture = getSubgraphOwner(testAccounts)
const curatorFixtures = getCuratorFixtures(testAccounts)

const deployer = await graph.getDeployer()
const subgraphOwners = [subgraphOwnerFixture.signer.address]
const subgraphOwnerETHBalance = [subgraphOwnerFixture.ethBalance]
const curators = curatorFixtures.map((c) => c.signer.address)
const curatorETHBalances = curatorFixtures.map((i) => i.ethBalance)
const curatorGRTBalances = curatorFixtures.map((i) => i.grtBalance)

// == Fund participants
console.log('\n== Fund subgraph owners and curators')
await fundAccountsETH(
deployer,
[...subgraphOwners, ...curators],
[...subgraphOwnerETHBalance, ...curatorETHBalances],
)
await fundAccountsGRT(deployer, curators, curatorGRTBalances, graph.contracts.GraphToken)

// == Publish subgraphs
console.log('\n== Publishing subgraphs')

for (const subgraph of subgraphFixtures) {
const id = await publishNewSubgraph(
graph.contracts,
subgraphOwnerFixture.signer,
subgraph.deploymentId,
)
const subgraphData = subgraphFixtures.find((s) => s.deploymentId === subgraph.deploymentId)
if (subgraphData) subgraphData.subgraphId = id
}

// == Signal subgraphs
console.log('\n== Signaling subgraphs')
for (const curator of curatorFixtures) {
for (const subgraph of curator.subgraphs) {
const subgraphData = subgraphFixtures.find((s) => s.deploymentId === subgraph.deploymentId)
if (subgraphData)
await signal(graph.contracts, curator.signer, subgraphData.subgraphId, subgraph.signal)
}
}
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exitCode = 1
})
Loading