Skip to content

Commit

Permalink
Merge pull request #1087 from graphprotocol/tmigone/ignition-v0.15.9
Browse files Browse the repository at this point in the history
  • Loading branch information
tmigone authored Jan 27, 2025
2 parents 17692b7 + 353902e commit 519c5d8
Show file tree
Hide file tree
Showing 22 changed files with 1,496 additions and 313 deletions.
12 changes: 12 additions & 0 deletions packages/horizon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

Graph Horizon is the next evolution of the Graph Protocol.

## Configuration

The following environment variables might be required:

- `ETHERSCAN_API_KEY`: Etherscan API key

You can set them using Hardhat:

```bash
npx hardhat vars set ETHERSCAN_API_KEY
```

## Deployment

We use Hardhat Ignition to deploy the contracts. To build and deploy Graph Horizon run the following commands:
Expand Down
7 changes: 7 additions & 0 deletions packages/horizon/contracts/mocks/imports.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later

// We import these here to force Hardhat to compile them.
// This ensures that their artifacts are available for Hardhat Ignition to use.
pragma solidity 0.8.27;

import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
15 changes: 9 additions & 6 deletions packages/horizon/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { vars } from 'hardhat/config'
import type { HardhatUserConfig } from 'hardhat/config'

// Hardhat plugins
import '@nomicfoundation/hardhat-foundry'
import '@nomicfoundation/hardhat-toolbox'
import '@nomicfoundation/hardhat-ignition-ethers'
import '@tenderly/hardhat-tenderly'
import 'hardhat-storage-layout'
import 'hardhat-contract-sizer'
import 'hardhat-secure-accounts'
import * as dotenv from 'dotenv'

import type { HardhatUserConfig } from 'hardhat/config'

dotenv.config()
// Environment variables
const ETHERSCAN_API_KEY = vars.get('ETHERSCAN_API_KEY', '')
const ARBITRUM_VIRTUAL_TESTNET_URL = vars.get('ARBITRUM_VIRTUAL_TESTNET_URL', '')

const getNetworkAccounts = () => {
const accounts: string[] = []
Expand Down Expand Up @@ -57,7 +60,7 @@ const config: HardhatUserConfig = {
enabled: false,
},
chainId: 421615,
url: process.env.ARBITRUM_VIRTUAL_TESTNET_URL || '',
url: ARBITRUM_VIRTUAL_TESTNET_URL,
accounts: getNetworkAccounts(),
},
},
Expand All @@ -74,7 +77,7 @@ const config: HardhatUserConfig = {
},
etherscan: {
apiKey: {
arbitrumSepolia: process.env.ETHERSCAN_API_KEY ?? '',
arbitrumSepolia: ETHERSCAN_API_KEY,
},
customChains: [
{
Expand Down
4 changes: 2 additions & 2 deletions packages/horizon/ignition/configs/horizon.hardhat.json5
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
"EpochManager": {
"epochLength": 60
},
"Curation": {
"L2Curation": {
"curationTaxPercentage": 10000,
"minimumCurationDeposit": 1
},
"GraphToken": {
"L2GraphToken": {
"initialSupply": "10000000000000000000000000000n"
},
"HorizonStaking": {
Expand Down
6 changes: 3 additions & 3 deletions packages/horizon/ignition/modules/core/GraphPayments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import GraphPaymentsArtifact from '../../../build/contracts/contracts/payments/G

// TODO: transfer ownership of ProxyAdmin???
export default buildModule('GraphPayments', (m) => {
const { Controller, PeripheryRegistered } = m.useModule(GraphPeripheryModule)
const { GraphPaymentsProxyAdmin, GraphPaymentsProxy, HorizonRegistered } = m.useModule(HorizonProxiesModule)
const { Controller } = m.useModule(GraphPeripheryModule)
const { GraphPaymentsProxyAdmin, GraphPaymentsProxy } = m.useModule(HorizonProxiesModule)

const protocolPaymentCut = m.getParameter('protocolPaymentCut')

Expand All @@ -17,7 +17,7 @@ export default buildModule('GraphPayments', (m) => {
GraphPaymentsArtifact,
[Controller, protocolPaymentCut],
{
after: [PeripheryRegistered, HorizonRegistered],
after: [GraphPeripheryModule, HorizonProxiesModule],
},
)

Expand Down
28 changes: 8 additions & 20 deletions packages/horizon/ignition/modules/core/HorizonProxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,26 @@ import { ethers } from 'ethers'
import GraphPeripheryModule from '../periphery'
import GraphProxyAdminModule from '../periphery/GraphProxyAdmin'

import DummyArtifact from '../../../build/contracts/contracts/mocks/Dummy.sol/Dummy.json'
import GraphProxyArtifact from '@graphprotocol/contracts/build/contracts/contracts/upgrades/GraphProxy.sol/GraphProxy.json'

const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'

// HorizonStaking, GraphPayments and PaymentsEscrow use GraphDirectory but they also in the directory.
// So we need to deploy their proxies, register them in the controller before being able to deploy the implementations
export default buildModule('HorizonProxies', (m) => {
const { Controller, PeripheryRegistered } = m.useModule(GraphPeripheryModule)
const { Controller } = m.useModule(GraphPeripheryModule)
const { GraphProxyAdmin } = m.useModule(GraphProxyAdminModule)

const isMigrate = m.getParameter('isMigrate', false)

// Deploy HorizonStaking proxy without an implementation
let HorizonStakingProxy, setProxyHorizonStaking
let HorizonStakingProxy
if (isMigrate) {
const horizonStakingProxyAddress = m.getParameter('horizonStakingProxyAddress')
HorizonStakingProxy = m.contractAt('GraphProxy', GraphProxyArtifact, horizonStakingProxyAddress, { id: 'GraphProxy_HorizonStaking' })
setProxyHorizonStaking = HorizonStakingProxy
} else {
HorizonStakingProxy = m.contract('GraphProxy', GraphProxyArtifact, [ZERO_ADDRESS, GraphProxyAdmin], { after: [PeripheryRegistered], id: 'GraphProxy_HorizonStaking' })
setProxyHorizonStaking = m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('Staking')), HorizonStakingProxy], { id: 'setContractProxy_HorizonStaking' })
HorizonStakingProxy = m.contract('GraphProxy', GraphProxyArtifact, [ZERO_ADDRESS, GraphProxyAdmin], { id: 'GraphProxy_HorizonStaking' })
m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('Staking')), HorizonStakingProxy], { id: 'setContractProxy_HorizonStaking' })
}

// Deploy proxies for payments contracts using OZ TransparentUpgradeableProxy
Expand All @@ -36,18 +34,8 @@ export default buildModule('HorizonProxies', (m) => {
// Register the proxies in the controller
// if isMigrate then use from: governor
const options = isMigrate ? { from: m.getAccount(1) } : {}
const setProxyGraphPayments = m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('GraphPayments')), GraphPaymentsProxy], { ...options, id: 'setContractProxy_GraphPayments' })
const setProxyPaymentsEscrow = m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('PaymentsEscrow')), PaymentsEscrowProxy], { ...options, id: 'setContractProxy_PaymentsEscrow' })

// Deploy dummy contract to signal that all periphery contracts are registered
const HorizonRegistered = m.contract('Dummy', DummyArtifact, [], {
id: 'RegisteredDummy',
after: [
setProxyHorizonStaking,
setProxyGraphPayments,
setProxyPaymentsEscrow,
],
})

return { HorizonStakingProxy, GraphPaymentsProxy, PaymentsEscrowProxy, HorizonRegistered, GraphPaymentsProxyAdmin, PaymentsEscrowProxyAdmin }
m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('GraphPayments')), GraphPaymentsProxy], { ...options, id: 'setContractProxy_GraphPayments' })
m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('PaymentsEscrow')), PaymentsEscrowProxy], { ...options, id: 'setContractProxy_PaymentsEscrow' })

return { HorizonStakingProxy, GraphPaymentsProxy, PaymentsEscrowProxy, GraphPaymentsProxyAdmin, PaymentsEscrowProxyAdmin }
})
6 changes: 3 additions & 3 deletions packages/horizon/ignition/modules/core/HorizonStaking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import HorizonStakingExtensionModule from './HorizonStakingExtension'
import HorizonStakingArtifact from '../../../build/contracts/contracts/staking/HorizonStaking.sol/HorizonStaking.json'

export default buildModule('HorizonStaking', (m) => {
const { Controller, GraphProxyAdmin, PeripheryRegistered } = m.useModule(GraphPeripheryModule)
const { HorizonStakingProxy, HorizonRegistered } = m.useModule(HorizonProxiesModule)
const { Controller, GraphProxyAdmin } = m.useModule(GraphPeripheryModule)
const { HorizonStakingProxy } = m.useModule(HorizonProxiesModule)
const { HorizonStakingExtension } = m.useModule(HorizonStakingExtensionModule)

const subgraphServiceAddress = m.getParameter('subgraphServiceAddress')
Expand All @@ -22,7 +22,7 @@ export default buildModule('HorizonStaking', (m) => {
subgraphServiceAddress,
],
{
after: [PeripheryRegistered, HorizonRegistered],
after: [GraphPeripheryModule, HorizonProxiesModule],
},
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import ExponentialRebatesArtifact from '../../../build/contracts/contracts/staki
import HorizonStakingExtensionArtifact from '../../../build/contracts/contracts/staking/HorizonStakingExtension.sol/HorizonStakingExtension.json'

export default buildModule('HorizonStakingExtension', (m) => {
const { Controller, PeripheryRegistered } = m.useModule(GraphPeripheryModule)
const { HorizonRegistered } = m.useModule(HorizonProxiesModule)
const { Controller } = m.useModule(GraphPeripheryModule)

const subgraphServiceAddress = m.getParameter('subgraphServiceAddress')

Expand All @@ -19,7 +18,7 @@ export default buildModule('HorizonStakingExtension', (m) => {
libraries: {
ExponentialRebates: ExponentialRebates,
},
after: [PeripheryRegistered, HorizonRegistered],
after: [GraphPeripheryModule, HorizonProxiesModule],
})

return { HorizonStakingExtension }
Expand Down
6 changes: 3 additions & 3 deletions packages/horizon/ignition/modules/core/PaymentsEscrow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import PaymentsEscrowArtifact from '../../../build/contracts/contracts/payments/

// TODO: transfer ownership of ProxyAdmin???
export default buildModule('PaymentsEscrow', (m) => {
const { Controller, PeripheryRegistered } = m.useModule(GraphPeripheryModule)
const { PaymentsEscrowProxyAdmin, PaymentsEscrowProxy, HorizonRegistered } = m.useModule(HorizonProxiesModule)
const { Controller } = m.useModule(GraphPeripheryModule)
const { PaymentsEscrowProxyAdmin, PaymentsEscrowProxy } = m.useModule(HorizonProxiesModule)

const withdrawEscrowThawingPeriod = m.getParameter('withdrawEscrowThawingPeriod')

Expand All @@ -17,7 +17,7 @@ export default buildModule('PaymentsEscrow', (m) => {
PaymentsEscrowArtifact,
[Controller, withdrawEscrowThawingPeriod],
{
after: [PeripheryRegistered, HorizonRegistered],
after: [GraphPeripheryModule, HorizonProxiesModule],
},
)

Expand Down
10 changes: 7 additions & 3 deletions packages/horizon/ignition/modules/core/TAPCollector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@ import HorizonProxiesModule from './HorizonProxies'
import TAPCollectorArtifact from '../../../build/contracts/contracts/payments/collectors/TAPCollector.sol/TAPCollector.json'

export default buildModule('TAPCollector', (m) => {
const { Controller, PeripheryRegistered } = m.useModule(GraphPeripheryModule)
const { HorizonRegistered } = m.useModule(HorizonProxiesModule)
const { Controller } = m.useModule(GraphPeripheryModule)

const name = m.getParameter('eip712Name')
const version = m.getParameter('eip712Version')
const revokeSignerThawingPeriod = m.getParameter('revokeSignerThawingPeriod')

const TAPCollector = m.contract('TAPCollector', TAPCollectorArtifact, [name, version, Controller, revokeSignerThawingPeriod], { after: [PeripheryRegistered, HorizonRegistered] })
const TAPCollector = m.contract(
'TAPCollector',
TAPCollectorArtifact,
[name, version, Controller, revokeSignerThawingPeriod],
{ after: [GraphPeripheryModule, HorizonProxiesModule] },
)

return { TAPCollector }
})
31 changes: 7 additions & 24 deletions packages/horizon/ignition/modules/periphery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import GraphTokenGatewayModule from './periphery/GraphTokenGateway'
import GraphTokenModule from './periphery/GraphToken'
import RewardsManagerModule from './periphery/RewardsManager'

import DummyArtifact from '../../build/contracts/contracts/mocks/Dummy.sol/Dummy.json'

export default buildModule('GraphHorizon_Periphery', (m) => {
const { BridgeEscrow } = m.useModule(BridgeEscrowModule)
const { Controller } = m.useModule(ControllerModule)
Expand All @@ -25,34 +23,20 @@ export default buildModule('GraphHorizon_Periphery', (m) => {

const isMigrate = m.getParameter('isMigrate', false)

let PeripheryRegistered
if (!isMigrate) {
// Register contracts in the Controller
const setProxyEpochManager = m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('EpochManager')), EpochManager], { id: 'setContractProxy_EpochManager' })
const setProxyRewardsManager = m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('RewardsManager')), RewardsManager], { id: 'setContractProxy_RewardsManager' })
const setProxyGraphToken = m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('GraphToken')), GraphToken], { id: 'setContractProxy_GraphToken' })
const setProxyGraphTokenGateway = m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('GraphTokenGateway')), GraphTokenGateway], { id: 'setContractProxy_GraphTokenGateway' })
m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('EpochManager')), EpochManager], { id: 'setContractProxy_EpochManager' })
m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('RewardsManager')), RewardsManager], { id: 'setContractProxy_RewardsManager' })
m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('GraphToken')), GraphToken], { id: 'setContractProxy_GraphToken' })
m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('GraphTokenGateway')), GraphTokenGateway], { id: 'setContractProxy_GraphTokenGateway' })
// eslint-disable-next-line no-secrets/no-secrets
const setProxyGraphProxyAdmin = m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('GraphProxyAdmin')), GraphProxyAdmin], { id: 'setContractProxy_GraphProxyAdmin' })
const setProxyCuration = m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('Curation')), Curation], { id: 'setContractProxy_Curation' })

// Deploy dummy contract to signal that all periphery contracts are registered
PeripheryRegistered = m.contract('Dummy', DummyArtifact, [], {
after: [
setProxyEpochManager,
setProxyRewardsManager,
setProxyGraphToken,
setProxyGraphTokenGateway,
setProxyGraphProxyAdmin,
setProxyCuration,
],
})
m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('GraphProxyAdmin')), GraphProxyAdmin], { id: 'setContractProxy_GraphProxyAdmin' })
m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('Curation')), Curation], { id: 'setContractProxy_Curation' })
} else {
// TODO: Remove if not needed
const governor = m.getAccount(1)
// eslint-disable-next-line no-secrets/no-secrets
const setProxyGraphProxyAdmin = m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('GraphProxyAdmin')), GraphProxyAdmin], { id: 'setContractProxy_GraphProxyAdmin', from: governor })
PeripheryRegistered = m.contract('Dummy', DummyArtifact, [], { after: [setProxyGraphProxyAdmin] })
m.call(Controller, 'setContractProxy', [ethers.keccak256(ethers.toUtf8Bytes('GraphProxyAdmin')), GraphProxyAdmin], { id: 'setContractProxy_GraphProxyAdmin', from: governor })
}

return {
Expand All @@ -64,6 +48,5 @@ export default buildModule('GraphHorizon_Periphery', (m) => {
GraphToken,
GraphTokenGateway,
RewardsManager,
PeripheryRegistered,
}
})
6 changes: 3 additions & 3 deletions packages/horizon/ignition/modules/periphery/Curation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import CurationArtifact from '@graphprotocol/contracts/build/contracts/contracts
import GraphCurationTokenArtifact from '@graphprotocol/contracts/build/contracts/contracts/curation/GraphCurationToken.sol/GraphCurationToken.json'
import GraphProxyArtifact from '@graphprotocol/contracts/build/contracts/contracts/upgrades/GraphProxy.sol/GraphProxy.json'

export default buildModule('Curation', (m) => {
export default buildModule('L2Curation', (m) => {
const isMigrate = m.getParameter('isMigrate')

if (isMigrate) {
Expand All @@ -25,7 +25,7 @@ function upgradeCuration(m: IgnitionModuleBuilder) {

const GraphProxy = m.contractAt('GraphProxy', GraphProxyArtifact, graphCurationProxyAddress)
const { instance: Curation, implementation: CurationImplementation } = upgradeWithGraphProxy(m, {
name: 'Curation',
name: 'L2Curation',
artifact: CurationArtifact,
proxyContract: GraphProxy,
}, { from: governor })
Expand All @@ -43,7 +43,7 @@ function deployCuration(m: IgnitionModuleBuilder) {
const GraphCurationToken = m.contract('GraphCurationToken', GraphCurationTokenArtifact, [])

const { instance: Curation, implementation: CurationImplementation } = deployWithGraphProxy(m, {
name: 'Curation',
name: 'L2Curation',
artifact: CurationArtifact,
args: [Controller, GraphCurationToken, curationTaxPercentage, minimumCurationDeposit],
})
Expand Down
4 changes: 2 additions & 2 deletions packages/horizon/ignition/modules/periphery/GraphToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import RewardsManagerModule from '../periphery/RewardsManager'
import GraphTokenArtifact from '@graphprotocol/contracts/build/contracts/contracts/l2/token/L2GraphToken.sol/L2GraphToken.json'

// TODO: Ownership transfer is a two step process, the new owner needs to accept it by calling acceptOwnership
export default buildModule('GraphToken', (m) => {
export default buildModule('L2GraphToken', (m) => {
const isMigrate = m.getParameter('isMigrate', false)

let GraphToken
Expand All @@ -23,7 +23,7 @@ export default buildModule('GraphToken', (m) => {
const initialSupply = m.getParameter('initialSupply')

GraphToken = deployWithGraphProxy(m, {
name: 'GraphToken',
name: 'L2GraphToken',
artifact: GraphTokenArtifact,
args: [deployer],
}).instance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { deployWithGraphProxy } from '../proxy/GraphProxy'
import ControllerModule from '../periphery/Controller'
import GraphTokenGatewayArtifact from '@graphprotocol/contracts/build/contracts/contracts/l2/gateway/L2GraphTokenGateway.sol/L2GraphTokenGateway.json'

export default buildModule('GraphTokenGateway', (m) => {
export default buildModule('L2GraphTokenGateway', (m) => {
const isMigrate = m.getParameter('isMigrate', false)

let GraphTokenGateway
Expand All @@ -18,7 +18,7 @@ export default buildModule('GraphTokenGateway', (m) => {
const pauseGuardian = m.getParameter('pauseGuardian')

GraphTokenGateway = deployWithGraphProxy(m, {
name: 'GraphTokenGateway',
name: 'L2GraphTokenGateway',
artifact: GraphTokenGatewayArtifact,
args: [Controller],
}).instance
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { IgnitionModuleBuilder } from '@nomicfoundation/ignition-core'

import DummyArtifact from '../../../build/contracts/contracts/mocks/Dummy.sol/Dummy.json'
import ProxyAdminArtifact from '@openzeppelin/contracts/build/contracts/ProxyAdmin.json'
import TransparentUpgradeableProxyArtifact from '@openzeppelin/contracts/build/contracts/TransparentUpgradeableProxy.json'
import ProxyAdminArtifact from '../../../build/contracts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json'
import TransparentUpgradeableProxyArtifact from '../../../build/contracts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json'

// Deploy a TransparentUpgradeableProxy
// Note that this module uses a dummy contract as the implementation as the proxy requires a valid contract
Expand Down
Loading

0 comments on commit 519c5d8

Please sign in to comment.