Skip to content

Commit d5aacb2

Browse files
authored
chore: create vesting contracts auth functions for horizon deployment (#1219)
1 parent ac4e1ea commit d5aacb2

File tree

2 files changed

+253
-0
lines changed

2 files changed

+253
-0
lines changed

packages/token-distribution/hardhat.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import './ops/delete'
2020
import './ops/info'
2121
import './ops/manager'
2222
import './ops/beneficiary'
23+
import './ops/update-auth-functions-horizon'
2324

2425
// Networks
2526

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
import consola from 'consola'
2+
import { task } from 'hardhat/config'
3+
import { HardhatRuntimeEnvironment } from 'hardhat/types'
4+
5+
import { askConfirm, getTokenLockManagerOrFail, prettyEnv, waitTransaction } from './create'
6+
import { TxBuilder } from './tx-builder'
7+
8+
const logger = consola.create({})
9+
10+
task('update-auth-functions-horizon', 'Update authorized functions for Horizon upgrade')
11+
.addParam('horizonStakingAddress', 'Address of the HorizonStaking contract')
12+
.addParam('subgraphServiceAddress', 'Address of the SubgraphService contract')
13+
.addParam('managerName', 'Name of the token lock manager deployment', 'GraphTokenLockManager')
14+
.addFlag('txBuilder', 'Output transaction batch in JSON format for Safe multisig')
15+
.addOptionalParam('txBuilderTemplate', 'File to use as a template for the transaction builder')
16+
.setAction(async (taskArgs, hre: HardhatRuntimeEnvironment) => {
17+
const manager = await getTokenLockManagerOrFail(hre, taskArgs.managerName)
18+
19+
logger.info('Updating authorized functions for Horizon upgrade...')
20+
logger.log(`> GraphTokenLockManager: ${manager.address}`)
21+
logger.log(`> HorizonStaking: ${taskArgs.horizonStakingAddress}`)
22+
logger.log(`> SubgraphService: ${taskArgs.subgraphServiceAddress}`)
23+
24+
logger.log(await prettyEnv(hre))
25+
26+
// Functions to ADD for HorizonStaking
27+
const horizonStakingFunctionsToAdd = [
28+
'provisionLocked(address,address,uint256,uint32,uint64)',
29+
'thaw(address,address,uint256)',
30+
'deprovision(address,address,uint256)',
31+
'setDelegationFeeCut(address,address,uint8,uint256)',
32+
'setOperatorLocked(address,address,bool)',
33+
'withdrawDelegated(address,address,uint256)',
34+
]
35+
36+
// Functions to ADD for SubgraphService
37+
const subgraphServiceFunctionsToAdd = ['setPaymentsDestination(address)']
38+
39+
// Functions to REMOVE for old Staking contract
40+
const functionsToRemove = [
41+
'setDelegationParameters(uint32,uint32,uint32)',
42+
'setOperator(address,bool)',
43+
'setRewardsDestination(address)',
44+
]
45+
46+
logger.info('\n=== Functions to be ADDED ===')
47+
logger.info('For HorizonStaking:')
48+
horizonStakingFunctionsToAdd.forEach((sig) => logger.log(` + ${sig}`))
49+
logger.info('\nFor SubgraphService:')
50+
subgraphServiceFunctionsToAdd.forEach((sig) => logger.log(` + ${sig}`))
51+
52+
logger.info('\n=== Functions to be REMOVED ===')
53+
functionsToRemove.forEach((sig) => logger.log(` - ${sig}`))
54+
55+
// Check if not using tx-builder that deployer is the manager owner
56+
if (!taskArgs.txBuilder) {
57+
const tokenLockManagerOwner = await manager.owner()
58+
const { deployer } = await hre.getNamedAccounts()
59+
if (tokenLockManagerOwner !== deployer) {
60+
logger.error('Only the owner can update authorized functions')
61+
process.exit(1)
62+
}
63+
logger.success(`\nDeployer is the manager owner: ${deployer}`)
64+
}
65+
66+
// Confirm before proceeding
67+
logger.info('\n=== Summary ===')
68+
logger.info(`Functions to remove: ${functionsToRemove.length}`)
69+
logger.info(`Functions to add for HorizonStaking: ${horizonStakingFunctionsToAdd.length}`)
70+
logger.info(`Functions to add for SubgraphService: ${subgraphServiceFunctionsToAdd.length}`)
71+
72+
if (!(await askConfirm())) {
73+
logger.log('Cancelled')
74+
process.exit(1)
75+
}
76+
77+
if (taskArgs.txBuilder) {
78+
// Generate tx-builder JSON for Safe multisig
79+
logger.info('\nCreating transaction builder JSON file for Safe multisig...')
80+
const chainId = (await hre.ethers.provider.getNetwork()).chainId.toString()
81+
const txBuilder = new TxBuilder(chainId, taskArgs.txBuilderTemplate)
82+
83+
// Add transactions to remove old functions
84+
logger.log('\nBuilding transactions to remove old functions...')
85+
for (const signature of functionsToRemove) {
86+
const tx = await manager.populateTransaction.unsetAuthFunctionCall(signature)
87+
txBuilder.addTx({
88+
to: manager.address,
89+
value: '0',
90+
data: tx.data,
91+
})
92+
logger.log(` - Remove: ${signature}`)
93+
}
94+
95+
// Add transactions to add HorizonStaking functions
96+
logger.log('\nBuilding transactions to add HorizonStaking functions...')
97+
const horizonTargets = Array(horizonStakingFunctionsToAdd.length).fill(taskArgs.horizonStakingAddress)
98+
const tx1 = await manager.populateTransaction.setAuthFunctionCallMany(
99+
horizonStakingFunctionsToAdd,
100+
horizonTargets,
101+
)
102+
txBuilder.addTx({
103+
to: manager.address,
104+
value: '0',
105+
data: tx1.data,
106+
})
107+
logger.log(` + Added ${horizonStakingFunctionsToAdd.length} functions for HorizonStaking`)
108+
109+
// Add transactions to add SubgraphService functions
110+
logger.log('\nBuilding transactions to add SubgraphService functions...')
111+
const subgraphTargets = Array(subgraphServiceFunctionsToAdd.length).fill(taskArgs.subgraphServiceAddress)
112+
const tx2 = await manager.populateTransaction.setAuthFunctionCallMany(
113+
subgraphServiceFunctionsToAdd,
114+
subgraphTargets,
115+
)
116+
txBuilder.addTx({
117+
to: manager.address,
118+
value: '0',
119+
data: tx2.data,
120+
})
121+
logger.log(` + Added ${subgraphServiceFunctionsToAdd.length} functions for SubgraphService`)
122+
123+
// Add token destinations if needed
124+
logger.log('\nChecking and adding token destinations if needed...')
125+
126+
// Check if HorizonStaking is already a token destination
127+
const isHorizonStakingDestination = await manager.isTokenDestination(taskArgs.horizonStakingAddress)
128+
if (!isHorizonStakingDestination) {
129+
const tx3 = await manager.populateTransaction.addTokenDestination(taskArgs.horizonStakingAddress)
130+
txBuilder.addTx({
131+
to: manager.address,
132+
value: '0',
133+
data: tx3.data,
134+
})
135+
logger.log(` + Add HorizonStaking as token destination`)
136+
} else {
137+
logger.log(` ✓ HorizonStaking already added as token destination`)
138+
}
139+
140+
// Check if SubgraphService is already a token destination
141+
const isSubgraphServiceDestination = await manager.isTokenDestination(taskArgs.subgraphServiceAddress)
142+
if (!isSubgraphServiceDestination) {
143+
const tx4 = await manager.populateTransaction.addTokenDestination(taskArgs.subgraphServiceAddress)
144+
txBuilder.addTx({
145+
to: manager.address,
146+
value: '0',
147+
data: tx4.data,
148+
})
149+
logger.log(` + Add SubgraphService as token destination`)
150+
} else {
151+
logger.log(` ✓ SubgraphService already added as token destination`)
152+
}
153+
154+
// Save result into json file
155+
const outputFile = txBuilder.saveToFile()
156+
logger.success(`\nTransaction batch saved to ${outputFile}`)
157+
logger.info('\nUpload this file to your Safe multisig to execute the transactions.')
158+
159+
// Summary
160+
logger.info('\n=== SUMMARY ===')
161+
logger.info(`Total transactions: ${txBuilder.contents.transactions.length}`)
162+
logger.info(` - Remove functions: ${functionsToRemove.length}`)
163+
logger.info(` - Add HorizonStaking functions: 1 batch (${horizonStakingFunctionsToAdd.length} functions)`)
164+
logger.info(` - Add SubgraphService functions: 1 batch (${subgraphServiceFunctionsToAdd.length} functions)`)
165+
const destinationsAdded = (!isHorizonStakingDestination ? 1 : 0) + (!isSubgraphServiceDestination ? 1 : 0)
166+
logger.info(` - Add token destinations: ${destinationsAdded}`)
167+
} else {
168+
// Execute transactions
169+
logger.info('\nExecuting transactions...')
170+
171+
// Remove old functions
172+
logger.info('\nRemoving old functions...')
173+
for (const signature of functionsToRemove) {
174+
try {
175+
logger.log(` Removing: ${signature}`)
176+
const tx = await manager.unsetAuthFunctionCall(signature)
177+
await waitTransaction(tx)
178+
logger.success(` ✓ Removed: ${signature}`)
179+
} catch (error) {
180+
logger.error(` ✗ Failed to remove ${signature}: ${error.message}`)
181+
process.exit(1)
182+
}
183+
}
184+
185+
// Add HorizonStaking functions
186+
logger.info('\nAdding HorizonStaking functions...')
187+
try {
188+
const horizonTargets = Array(horizonStakingFunctionsToAdd.length).fill(taskArgs.horizonStakingAddress)
189+
const tx = await manager.setAuthFunctionCallMany(horizonStakingFunctionsToAdd, horizonTargets)
190+
await waitTransaction(tx)
191+
logger.success(` ✓ Added ${horizonStakingFunctionsToAdd.length} functions for HorizonStaking`)
192+
} catch (error) {
193+
logger.error(` ✗ Failed to add HorizonStaking functions: ${error.message}`)
194+
process.exit(1)
195+
}
196+
197+
// Add SubgraphService functions
198+
logger.info('\nAdding SubgraphService functions...')
199+
try {
200+
const subgraphTargets = Array(subgraphServiceFunctionsToAdd.length).fill(taskArgs.subgraphServiceAddress)
201+
const tx = await manager.setAuthFunctionCallMany(subgraphServiceFunctionsToAdd, subgraphTargets)
202+
await waitTransaction(tx)
203+
logger.success(` ✓ Added ${subgraphServiceFunctionsToAdd.length} functions for SubgraphService`)
204+
} catch (error) {
205+
logger.error(` ✗ Failed to add SubgraphService functions: ${error.message}`)
206+
process.exit(1)
207+
}
208+
209+
// Add token destinations if needed
210+
logger.info('\nChecking and adding token destinations if needed...')
211+
212+
// Check if HorizonStaking is already a token destination
213+
const isHorizonStakingDestination = await manager.isTokenDestination(taskArgs.horizonStakingAddress)
214+
if (!isHorizonStakingDestination) {
215+
try {
216+
logger.log(` Adding HorizonStaking as token destination...`)
217+
const tx = await manager.addTokenDestination(taskArgs.horizonStakingAddress)
218+
await waitTransaction(tx)
219+
logger.success(` ✓ Added HorizonStaking as token destination`)
220+
} catch (error) {
221+
logger.error(` ✗ Failed to add HorizonStaking as token destination: ${error.message}`)
222+
process.exit(1)
223+
}
224+
} else {
225+
logger.success(` ✓ HorizonStaking already a token destination`)
226+
}
227+
228+
// Check if SubgraphService is already a token destination
229+
const isSubgraphServiceDestination = await manager.isTokenDestination(taskArgs.subgraphServiceAddress)
230+
if (!isSubgraphServiceDestination) {
231+
try {
232+
logger.log(` Adding SubgraphService as token destination...`)
233+
const tx = await manager.addTokenDestination(taskArgs.subgraphServiceAddress)
234+
await waitTransaction(tx)
235+
logger.success(` ✓ Added SubgraphService as token destination`)
236+
} catch (error) {
237+
logger.error(` ✗ Failed to add SubgraphService as token destination: ${error.message}`)
238+
process.exit(1)
239+
}
240+
} else {
241+
logger.success(` ✓ SubgraphService already a token destination`)
242+
}
243+
244+
// Summary
245+
logger.info('\n=== COMPLETED SUCCESSFULLY ===')
246+
logger.info(`Removed ${functionsToRemove.length} old functions`)
247+
logger.info(`Added ${horizonStakingFunctionsToAdd.length} functions for HorizonStaking`)
248+
logger.info(`Added ${subgraphServiceFunctionsToAdd.length} functions for SubgraphService`)
249+
const destinationsAdded = (!isHorizonStakingDestination ? 1 : 0) + (!isSubgraphServiceDestination ? 1 : 0)
250+
logger.info(`Added ${destinationsAdded} token destinations`)
251+
}
252+
})

0 commit comments

Comments
 (0)