Skip to content
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

horizon: create deployment scripts for production environment #1095

Open
wants to merge 4 commits into
base: horizon
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,8 @@ export const hardhatBaseConfig: HardhatUserConfig & { etherscan: Partial<Ethersc
networks: networksUserConfig,
graph: {
deployments: {
horizon: {
addressBook: 'addresses.json',
},
horizon: require.resolve('@graphprotocol/horizon/addresses.json'),
subgraphService: require.resolve('@graphprotocol/subgraph-service/addresses.json'),
},
},
etherscan: etherscanUserConfig,
Expand Down
35 changes: 35 additions & 0 deletions packages/hardhat-graph-protocol/src/sdk/ignition/ignition.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable no-prototype-builtins */
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-explicit-any */
require('json5/lib/register')

Expand All @@ -20,6 +22,39 @@ export function loadConfig(configPath: string, prefix: string, networkName: stri
return removeNFromBigInts(require(configFile))
}

export function patchConfig(jsonData: any, patches: Record<string, any>) {
function recursivePatch(obj: any) {
if (typeof obj === 'object' && obj !== null) {
for (const key in obj) {
if (key in patches) {
obj[key] = patches[key]
} else {
recursivePatch(obj[key])
}
}
}
}

recursivePatch(jsonData)
return jsonData
}

export function mergeConfigs(obj1: any, obj2: any) {
const merged = { ...obj1 }

for (const key in obj2) {
if (obj2.hasOwnProperty(key)) {
if (typeof obj2[key] === 'object' && obj2[key] !== null && obj1[key]) {
merged[key] = mergeConfigs(obj1[key], obj2[key])
} else {
merged[key] = obj2[key]
}
}
}

return merged
}

export function saveAddressBook(
contracts: any,
chainId: number | undefined,
Expand Down
4 changes: 2 additions & 2 deletions packages/hardhat-graph-protocol/src/sdk/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { loadConfig, saveAddressBook } from './ignition/ignition'
import { loadConfig, mergeConfigs, patchConfig, saveAddressBook } from './ignition/ignition'
import { hardhatBaseConfig } from './hardhat.base.config'

const IgnitionHelper = { saveAddressBook, loadConfig }
const IgnitionHelper = { saveAddressBook, loadConfig, patchConfig, mergeConfigs }
export { hardhatBaseConfig, IgnitionHelper }
1 change: 1 addition & 0 deletions packages/horizon/addresses.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
36 changes: 25 additions & 11 deletions packages/horizon/ignition/configs/horizon-migrate.default.json5
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
{
"$global": {
// Accounts
"governor": "0x72ee30d43Fb5A90B3FE983156C5d2fBE6F6d07B3",

// Addresses for contracts deployed in the original Graph Protocol
"graphProxyAdminAddress": "0x7474a6cc5fAeDEc620Db0fa8E4da6eD58477042C",
"controllerAddress": "0x9DB3ee191681f092607035d9BDA6e59FbEaCa695",
"horizonStakingAddress": "0x865365C425f3A593Ffe698D9c4E6707D14d51e08",
"epochManagerAddress": "0x88b3C7f37253bAA1A9b95feAd69bD5320585826D",
"graphTokenAddress": "0xf8c05dCF59E8B28BFD5eed176C562bEbcfc7Ac04",
"graphTokenGatewayAddress": "0xB24Ce0f8c18c4DdDa584A7EeC132F49C966813bb",
"rewardsManagerAddress": "0x1F49caE7669086c8ba53CC35d1E9f80176d67E79",
"curationAddress": "0xDe761f075200E75485F4358978FB4d1dC8644FD5",

// Placeholder address for a standalone Horizon deployment, see README.md for more details
// Must be set for step 4 of the migration
"subgraphServiceAddress": "0x0000000000000000000000000000000000000000"
},
"RewardsManager": {
"rewardsManagerAddress": "0x1F49caE7669086c8ba53CC35d1E9f80176d67E79"
},
"L2Curation": {
"curationAddress": "0xDe761f075200E75485F4358978FB4d1dC8644FD5"
},
"HorizonStaking": {
"maxThawingPeriod": 2419200
},
"GraphPayments": {
"GraphPayments": {
"protocolPaymentCut": 10000
},
"PaymentsEscrow": {
Expand All @@ -30,5 +26,23 @@
"eip712Name": "TAPCollector",
"eip712Version": "1",
"revokeSignerThawingPeriod": 10000
},
"HorizonProxiesGovernor": {
// These addresses must be set for step 2 of the migration
"graphPaymentsAddress": "0x0000000000000000000000000000000000000000",
"paymentsEscrowAddress": "0x0000000000000000000000000000000000000000"
},
"HorizonStakingGovernor": {
"maxThawingPeriod": 2419200,
// Must be set for step 4 of the migration
"horizonStakingImplementationAddress": "0x0000000000000000000000000000000000000000"
},
"L2CurationGovernor": {
// Must be set for step 4 of the migration
"curationImplementationAddress": "0x0000000000000000000000000000000000000000"
},
"RewardsManagerGovernor": {
// Must be set for step 4 of the migration
"rewardsManagerImplementationAddress": "0x0000000000000000000000000000000000000000"
}
}
1 change: 1 addition & 0 deletions packages/horizon/ignition/configs/horizon.default.json5
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"$global": {
"pauseGuardian": "0x95cED938F7991cd0dFcb48F0a06a40FA1aF46EBC",

// Placeholder address for a standalone Horizon deployment, see README.md for more details
"subgraphServiceAddress": "0x0000000000000000000000000000000000000000"
},
Expand Down
18 changes: 11 additions & 7 deletions packages/horizon/ignition/modules/core/GraphPayments.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { buildModule } from '@nomicfoundation/hardhat-ignition/modules'
import { deployImplementation } from '../proxy/implementation'
import { upgradeTransparentUpgradeableProxyNoLoad } from '../proxy/TransparentUpgradeableProxy'
import { upgradeTransparentUpgradeableProxy } from '../proxy/TransparentUpgradeableProxy'

import GraphPeripheryModule, { MigratePeripheryModule } from '../periphery/periphery'
import HorizonProxiesModule, { MigrateHorizonProxiesModule } from './HorizonProxies'
import HorizonProxiesModule, { MigrateHorizonProxiesDeployerModule } from './HorizonProxies'

import GraphPaymentsArtifact from '../../../build/contracts/contracts/payments/GraphPayments.sol/GraphPayments.json'

Expand All @@ -22,7 +22,7 @@ export default buildModule('GraphPayments', (m) => {
}, { after: [GraphPeripheryModule, HorizonProxiesModule] })

// Upgrade proxy to implementation contract
const GraphPayments = upgradeTransparentUpgradeableProxyNoLoad(m,
const GraphPayments = upgradeTransparentUpgradeableProxy(m,
GraphPaymentsProxyAdmin,
GraphPaymentsProxy,
GraphPaymentsImplementation, {
Expand All @@ -36,22 +36,26 @@ export default buildModule('GraphPayments', (m) => {
return { GraphPayments, GraphPaymentsProxyAdmin }
})

// Note that this module requires MigrateHorizonProxiesGovernorModule to be executed first
// The dependency is not made explicit to support the production workflow where the governor is a
// multisig owned by the Graph Council.
// For testnet, the dependency can be made explicit by having a parent module establish it.
export const MigrateGraphPaymentsModule = buildModule('GraphPayments', (m) => {
const { GraphPaymentsProxyAdmin, GraphPaymentsProxy } = m.useModule(MigrateHorizonProxiesModule)
const { GraphPaymentsProxyAdmin, GraphPaymentsProxy } = m.useModule(MigrateHorizonProxiesDeployerModule)
const { Controller } = m.useModule(MigratePeripheryModule)

const governor = m.getAccount(1)
const governor = m.getParameter('governor')
const protocolPaymentCut = m.getParameter('protocolPaymentCut')

// Deploy GraphPayments implementation
const GraphPaymentsImplementation = deployImplementation(m, {
name: 'GraphPayments',
artifact: GraphPaymentsArtifact,
constructorArgs: [Controller, protocolPaymentCut],
}, { after: [MigrateHorizonProxiesModule] })
})

// Upgrade proxy to implementation contract
const GraphPayments = upgradeTransparentUpgradeableProxyNoLoad(m,
const GraphPayments = upgradeTransparentUpgradeableProxy(m,
GraphPaymentsProxyAdmin,
GraphPaymentsProxy,
GraphPaymentsImplementation, {
Expand Down
39 changes: 24 additions & 15 deletions packages/horizon/ignition/modules/core/HorizonProxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { deployGraphProxy } from '../proxy/GraphProxy'
import { deployTransparentUpgradeableProxy } from '../proxy/TransparentUpgradeableProxy'
import { ethers } from 'ethers'

import GraphPeripheryModule, { MigratePeripheryModule } from '../periphery/periphery'
import GraphPeripheryModule from '../periphery/periphery'
import { MigrateControllerGovernorModule } from '../periphery/Controller'

import GraphPaymentsArtifact from '../../../build/contracts/contracts/payments/GraphPayments.sol/GraphPayments.json'
import PaymentsEscrowArtifact from '../../../build/contracts/contracts/payments/PaymentsEscrow.sol/PaymentsEscrow.json'
Expand Down Expand Up @@ -43,30 +44,38 @@ export default buildModule('HorizonProxies', (m) => {
return { HorizonStakingProxy, GraphPaymentsProxy, PaymentsEscrowProxy, GraphPaymentsProxyAdmin, PaymentsEscrowProxyAdmin }
})

export const MigrateHorizonProxiesModule = buildModule('HorizonProxies', (m) => {
const { Controller } = m.useModule(MigratePeripheryModule)

const governor = m.getAccount(1)

// Deploy and register GraphPayments proxy
export const MigrateHorizonProxiesDeployerModule = buildModule('HorizonProxiesDeployer', (m) => {
// Deploy GraphPayments proxy
const { Proxy: GraphPaymentsProxy, ProxyAdmin: GraphPaymentsProxyAdmin } = deployTransparentUpgradeableProxy(m, {
name: 'GraphPayments',
artifact: GraphPaymentsArtifact,
})
m.call(Controller, 'setContractProxy',
[ethers.keccak256(ethers.toUtf8Bytes('GraphPayments')), GraphPaymentsProxy],
{ id: 'setContractProxy_GraphPayments', from: governor },
)

// Deploy and registerPaymentsEscrow proxy
// Deploy PaymentsEscrow proxy
const { Proxy: PaymentsEscrowProxy, ProxyAdmin: PaymentsEscrowProxyAdmin } = deployTransparentUpgradeableProxy(m, {
name: 'PaymentsEscrow',
artifact: PaymentsEscrowArtifact,
})

return { GraphPaymentsProxy, PaymentsEscrowProxy, GraphPaymentsProxyAdmin, PaymentsEscrowProxyAdmin }
})

export const MigrateHorizonProxiesGovernorModule = buildModule('HorizonProxiesGovernor', (m) => {
const { Controller } = m.useModule(MigrateControllerGovernorModule)

const graphPaymentsAddress = m.getParameter('graphPaymentsAddress')
const paymentsEscrowAddress = m.getParameter('paymentsEscrowAddress')

// Register proxies in controller
m.call(Controller, 'setContractProxy',
[ethers.keccak256(ethers.toUtf8Bytes('PaymentsEscrow')), PaymentsEscrowProxy],
{ id: 'setContractProxy_PaymentsEscrow', from: governor },
[ethers.keccak256(ethers.toUtf8Bytes('GraphPayments')), graphPaymentsAddress],
{ id: 'setContractProxy_GraphPayments' },
)

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

return { }
})
38 changes: 26 additions & 12 deletions packages/horizon/ignition/modules/core/HorizonStaking.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { acceptUpgradeGraphProxy, upgradeGraphProxy } from '../proxy/GraphProxy'
import { buildModule } from '@nomicfoundation/hardhat-ignition/modules'
import { deployImplementation } from '../proxy/implementation'
import { upgradeGraphProxyNoLoad } from '../proxy/GraphProxy'

import GraphPeripheryModule, { MigratePeripheryModule } from '../periphery/periphery'
import HorizonProxiesModule, { MigrateHorizonProxiesModule } from './HorizonProxies'
import HorizonProxiesModule from './HorizonProxies'

import ExponentialRebatesArtifact from '../../../build/contracts/contracts/staking/libraries/ExponentialRebates.sol/ExponentialRebates.json'
import GraphProxyAdminArtifact from '@graphprotocol/contracts/build/contracts/contracts/upgrades/GraphProxyAdmin.sol/GraphProxyAdmin.json'
import GraphProxyArtifact from '@graphprotocol/contracts/build/contracts/contracts/upgrades/GraphProxy.sol/GraphProxy.json'
import HorizonStakingArtifact from '../../../build/contracts/contracts/staking/HorizonStaking.sol/HorizonStaking.json'
import HorizonStakingExtensionArtifact from '../../../build/contracts/contracts/staking/HorizonStakingExtension.sol/HorizonStakingExtension.json'
Expand Down Expand Up @@ -36,7 +37,7 @@ export default buildModule('HorizonStaking', (m) => {
})

// Upgrade proxy to implementation contract
const HorizonStaking = upgradeGraphProxyNoLoad(m, GraphProxyAdmin, HorizonStakingProxy, HorizonStakingImplementation, {
const HorizonStaking = upgradeGraphProxy(m, GraphProxyAdmin, HorizonStakingProxy, HorizonStakingImplementation, {
name: 'HorizonStaking',
artifact: HorizonStakingArtifact,
})
Expand All @@ -45,12 +46,13 @@ export default buildModule('HorizonStaking', (m) => {
return { HorizonStaking }
})

// HorizonStaking contract is owned by the governor
export const MigrateHorizonStakingModule = buildModule('HorizonStaking', (m) => {
const { Controller, GraphProxyAdmin } = m.useModule(MigratePeripheryModule)
// Note that this module requires MigrateHorizonProxiesGovernorModule to be executed first
// The dependency is not made explicit to support the production workflow where the governor is a
// multisig owned by the Graph Council.
// For testnet, the dependency can be made explicit by having a parent module establish it.
export const MigrateHorizonStakingDeployerModule = buildModule('HorizonStakingDeployer', (m) => {
const { Controller } = m.useModule(MigratePeripheryModule)

const governor = m.getAccount(1)
const maxThawingPeriod = m.getParameter('maxThawingPeriod')
const subgraphServiceAddress = m.getParameter('subgraphServiceAddress')
const horizonStakingAddress = m.getParameter('horizonStakingAddress')

Expand All @@ -64,7 +66,6 @@ export const MigrateHorizonStakingModule = buildModule('HorizonStaking', (m) =>
libraries: {
ExponentialRebates: ExponentialRebates,
},
after: [MigrateHorizonProxiesModule],
})

// Deploy HorizonStaking implementation
Expand All @@ -74,12 +75,25 @@ export const MigrateHorizonStakingModule = buildModule('HorizonStaking', (m) =>
constructorArgs: [Controller, HorizonStakingExtension, subgraphServiceAddress],
})

return { HorizonStakingProxy, HorizonStakingImplementation }
})

export const MigrateHorizonStakingGovernorModule = buildModule('HorizonStakingGovernor', (m) => {
const maxThawingPeriod = m.getParameter('maxThawingPeriod')
const graphProxyAdminAddress = m.getParameter('graphProxyAdminAddress')
const horizonStakingAddress = m.getParameter('horizonStakingAddress')
const horizonStakingImplementationAddress = m.getParameter('horizonStakingImplementationAddress')

const HorizonStakingImplementation = m.contractAt('HorizonStakingImplementation', HorizonStakingArtifact, horizonStakingImplementationAddress)
const HorizonStakingProxy = m.contractAt('HorizonStakingProxy', GraphProxyArtifact, horizonStakingAddress)
const GraphProxyAdmin = m.contractAt('GraphProxyAdmin', GraphProxyAdminArtifact, graphProxyAdminAddress)

// Upgrade proxy to implementation contract
const HorizonStaking = upgradeGraphProxyNoLoad(m, GraphProxyAdmin, HorizonStakingProxy, HorizonStakingImplementation, {
const HorizonStaking = acceptUpgradeGraphProxy(m, GraphProxyAdmin, HorizonStakingProxy, HorizonStakingImplementation, {
name: 'HorizonStaking',
artifact: HorizonStakingArtifact,
}, { from: governor })
m.call(HorizonStaking, 'setMaxThawingPeriod', [maxThawingPeriod], { from: governor })
})
m.call(HorizonStaking, 'setMaxThawingPeriod', [maxThawingPeriod])

return { HorizonStaking }
})
18 changes: 11 additions & 7 deletions packages/horizon/ignition/modules/core/PaymentsEscrow.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { buildModule } from '@nomicfoundation/hardhat-ignition/modules'
import { deployImplementation } from '../proxy/implementation'
import { upgradeTransparentUpgradeableProxyNoLoad } from '../proxy/TransparentUpgradeableProxy'
import { upgradeTransparentUpgradeableProxy } from '../proxy/TransparentUpgradeableProxy'

import GraphPeripheryModule, { MigratePeripheryModule } from '../periphery/periphery'
import HorizonProxiesModule, { MigrateHorizonProxiesModule } from './HorizonProxies'
import HorizonProxiesModule, { MigrateHorizonProxiesDeployerModule } from './HorizonProxies'

import PaymentsEscrowArtifact from '../../../build/contracts/contracts/payments/PaymentsEscrow.sol/PaymentsEscrow.json'

Expand All @@ -22,7 +22,7 @@ export default buildModule('PaymentsEscrow', (m) => {
}, { after: [GraphPeripheryModule, HorizonProxiesModule] })

// Upgrade proxy to implementation contract
const PaymentsEscrow = upgradeTransparentUpgradeableProxyNoLoad(m,
const PaymentsEscrow = upgradeTransparentUpgradeableProxy(m,
PaymentsEscrowProxyAdmin,
PaymentsEscrowProxy,
PaymentsEscrowImplementation, {
Expand All @@ -36,22 +36,26 @@ export default buildModule('PaymentsEscrow', (m) => {
return { PaymentsEscrow, PaymentsEscrowProxyAdmin }
})

// Note that this module requires MigrateHorizonProxiesGovernorModule to be executed first
// The dependency is not made explicit to support the production workflow where the governor is a
// multisig owned by the Graph Council.
// For testnet, the dependency can be made explicit by having a parent module establish it.
export const MigratePaymentsEscrowModule = buildModule('PaymentsEscrow', (m) => {
const { PaymentsEscrowProxyAdmin, PaymentsEscrowProxy } = m.useModule(MigrateHorizonProxiesModule)
const { PaymentsEscrowProxyAdmin, PaymentsEscrowProxy } = m.useModule(MigrateHorizonProxiesDeployerModule)
const { Controller } = m.useModule(MigratePeripheryModule)

const governor = m.getAccount(1)
const governor = m.getParameter('governor')
const withdrawEscrowThawingPeriod = m.getParameter('withdrawEscrowThawingPeriod')

// Deploy PaymentsEscrow implementation
const PaymentsEscrowImplementation = deployImplementation(m, {
name: 'PaymentsEscrow',
artifact: PaymentsEscrowArtifact,
constructorArgs: [Controller, withdrawEscrowThawingPeriod],
}, { after: [MigrateHorizonProxiesModule] })
})

// Upgrade proxy to implementation contract
const PaymentsEscrow = upgradeTransparentUpgradeableProxyNoLoad(m,
const PaymentsEscrow = upgradeTransparentUpgradeableProxy(m,
PaymentsEscrowProxyAdmin,
PaymentsEscrowProxy,
PaymentsEscrowImplementation, {
Expand Down
Loading
Loading