Skip to content

Commit

Permalink
Merge pull request #96 from stakedotlink/ccip-stage-2
Browse files Browse the repository at this point in the history
CCIP stage 2 deployment scripts
  • Loading branch information
BkChoy authored Mar 4, 2024
2 parents bb51455 + 9e7cb18 commit 7c6d88b
Show file tree
Hide file tree
Showing 7 changed files with 311 additions and 7 deletions.
5 changes: 3 additions & 2 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ const config: HardhatUserConfig = {
url: 'http://127.0.0.1:8545',
accounts,
},
rinkeby: {
sepolia: {
url: '',
accounts,
},
ropsten: {
'arbitrum-sepolia': {
url: '',
chainId: 421614,
accounts,
},
mainnet: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { updateDeployments, deploy } from '../../utils/deployment'
import { updateDeployments, deploy } from '../../../utils/deployment'

// SDL
const sdl = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { WrappedTokenBridge } from '../../../typechain-types'
import { updateDeployments, deploy, getContract } from '../../utils/deployment'
import { WrappedTokenBridge } from '../../../../typechain-types'
import { updateDeployments, deploy, getContract } from '../../../utils/deployment'

// should be deployed on primary chain (Ethereum Mainnet)

Expand Down
103 changes: 103 additions & 0 deletions scripts/prod/ccip/stage-2/1-deploy-primary-chain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { toEther } from '../../../utils/helpers'
import { updateDeployments, deploy } from '../../../utils/deployment'
import { RewardsInitiator, SDLPoolCCIPControllerPrimary } from '../../../../typechain-types'
import { ethers, upgrades } from 'hardhat'
import { getContract } from '../../../utils/deployment'

// Execute on Ethereum Mainnet

const ccipRouter = '0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D'
const multisigAddress = '0xB351EC0FEaF4B99FdFD36b484d9EC90D0422493D'

// Linear Boost Controller
const LinearBoostControllerParams = {
minLockingDuration: 86400, // minimum locking duration in seconds
maxLockingDuration: 4 * 365 * 86400, // maximum locking duration in seconds
maxBoost: 8, // maximum boost amount
}
// SDL Pool CCIP Controller Primary
const SDLPoolCCIPControllerParams = {
maxLINKFee: toEther(10), // max LINK fee to paid on outgoing CCIP updates
updateInitiator: '', // address authorized to send CCIP updates
}
// Rewards Initiator
const RewardsInitiatorParams = {
whitelistedCaller: '', // address authorized to initiate rebase and rewards distribution
}

async function main() {
const sdlPool = await getContract('SDLPool')
const sdlToken = await getContract('SDLToken')
const linkToken = await getContract('LINKToken')
const wstLINKToken = await getContract('LINK_WrappedSDToken')
const stakingPool = await getContract('LINK_StakingPool')

const boostController = await deploy('LinearBoostController', [
LinearBoostControllerParams.minLockingDuration,
LinearBoostControllerParams.maxLockingDuration,
LinearBoostControllerParams.maxBoost,
])
console.log('LinearBoostController deployed: ', boostController.address)

const sdlPoolPrimaryImp = (await upgrades.prepareUpgrade(
sdlPool.address,
await ethers.getContractFactory('SDLPoolPrimary'),
{
kind: 'uups',
}
)) as string
console.log('SDLPoolPrimary implementation deployed at: ', sdlPoolPrimaryImp)

const ccipController = (await deploy('SDLPoolCCIPControllerPrimary', [
ccipRouter,
linkToken.address,
sdlToken.address,
sdlPool.address,
SDLPoolCCIPControllerParams.maxLINKFee,
SDLPoolCCIPControllerParams.updateInitiator,
])) as SDLPoolCCIPControllerPrimary
console.log('SDLPoolCCIPControllerPrimary deployed: ', ccipController.address)

const reSDLTokenBridge = await deploy('RESDLTokenBridge', [
linkToken.address,
sdlToken.address,
sdlPool.address,
ccipController.address,
])
console.log('RESDLTokenBridge deployed: ', reSDLTokenBridge.address)

const rewardsInitiator = (await deploy('RewardsInitiator', [
stakingPool.address,
ccipController.address,
])) as RewardsInitiator
console.log('RewardsInitiator deployed: ', rewardsInitiator.address)

updateDeployments({
LinearBoostController: boostController.address,
SDLPoolCCIPControllerPrimary: ccipController.address,
RESDLTokenBridge: reSDLTokenBridge.address,
RewardsInitiator: rewardsInitiator.address,
})

await (await boostController.transferOwnership(multisigAddress)).wait()

await (
await rewardsInitiator.whitelistCaller(RewardsInitiatorParams.whitelistedCaller, true)
).wait()
await (await rewardsInitiator.transferOwnership(multisigAddress)).wait()

await (
await ccipController.setWrappedRewardToken(stakingPool.address, wstLINKToken.address)
).wait()
await (await ccipController.approveRewardTokens([wstLINKToken.address])).wait()
await (await ccipController.setRESDLTokenBridge(reSDLTokenBridge.address)).wait()
await (await ccipController.setRewardsInitiator(rewardsInitiator.address)).wait()
await (await ccipController.transferOwnership(multisigAddress)).wait()
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
114 changes: 114 additions & 0 deletions scripts/prod/ccip/stage-2/2-deploy-secondary-chain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { toEther } from '../../../utils/helpers'
import {
updateDeployments,
deploy,
deployUpgradeable,
getContract,
} from '../../../utils/deployment'
import {
RESDLTokenBridge,
SDLPoolCCIPControllerSecondary,
SDLPoolSecondary,
} from '../../../../typechain-types'

// Execute on Arbitrum Mainnet

const ccipRouter = '0x141fa059441E0ca23ce184B6A78bafD2A517DdE8'
const multisigAddress = ''

const primaryChainSelector = '5009297550715157269' // ETH Mainnet
const primaryChainSDLPoolCCIPController = '' // ETH Mainnet

// Linear Boost Controller
const LinearBoostControllerParams = {
minLockingDuration: 86400, // minimum locking duration in seconds
maxLockingDuration: 4 * 365 * 86400, // maximum locking duration
maxBoost: 8, // maximum boost amount
}
// SDL Pool Secondary
const SDLPoolParams = {
derivativeTokenName: 'Reward Escrowed SDL', // SDL staking derivative token name
derivativeTokenSymbol: 'reSDL', // SDL staking derivative token symbol
queuedNewLockLimit: 50, // max number of queued new locks a user can have at once
baseURI: '', // base URI for reSDL NFTs
}
// SDL Pool CCIP Controller Secondary
const SDLPoolCCIPControllerParams = {
maxLINKFee: toEther(10), // max LINK fee to be paid on outgoing CCIP updates
updateInitiator: '', // address authorized to send CCIP updates
minTimeBetweenUpdates: '82800', // min time between updates in seconds
}

async function main() {
const sdlToken = await getContract('SDLToken')
const linkToken = await getContract('LINKToken')
const wstLINKToken = await getContract('LINK_WrappedSDToken')

const boostController = await deploy('LinearBoostController', [
LinearBoostControllerParams.minLockingDuration,
LinearBoostControllerParams.maxLockingDuration,
LinearBoostControllerParams.maxBoost,
])
console.log('LinearBoostController deployed: ', boostController.address)

const sdlPool = (await deployUpgradeable('SDLPoolSecondary', [
SDLPoolParams.derivativeTokenName,
SDLPoolParams.derivativeTokenSymbol,
sdlToken.address,
boostController.address,
SDLPoolParams.queuedNewLockLimit,
])) as SDLPoolSecondary
console.log('SDLPoolSecondary deployed: ', sdlPool.address)

const rewardsPool = await deploy('RewardsPool', [sdlPool.address, wstLINKToken.address])
console.log('wstLINK_SDLRewardsPool deployed: ', rewardsPool.address)

const ccipController = (await deploy('SDLPoolCCIPControllerSecondary', [
ccipRouter,
linkToken.address,
sdlToken.address,
sdlPool.address,
primaryChainSelector,
primaryChainSDLPoolCCIPController,
SDLPoolCCIPControllerParams.maxLINKFee,
SDLPoolCCIPControllerParams.updateInitiator,
SDLPoolCCIPControllerParams.minTimeBetweenUpdates,
])) as SDLPoolCCIPControllerSecondary
console.log('SDLPoolCCIPControllerSecondary deployed: ', ccipController.address)

const reSDLTokenBridge = (await deploy('RESDLTokenBridge', [
linkToken.address,
sdlToken.address,
sdlPool.address,
ccipController.address,
])) as RESDLTokenBridge
console.log('RESDLTokenBridge deployed: ', reSDLTokenBridge.address)

await (await boostController.transferOwnership(multisigAddress)).wait()

await (await sdlPool.setCCIPController(ccipController.address)).wait()
await (await sdlPool.addToken(wstLINKToken.address, rewardsPool.address)).wait()
await (await sdlPool.setBaseURI(SDLPoolParams.baseURI)).wait()
await (await sdlPool.transferOwnership(multisigAddress)).wait()

await (await ccipController.setRESDLTokenBridge(reSDLTokenBridge.address)).wait()
await (await ccipController.transferOwnership(multisigAddress)).wait()

updateDeployments(
{
SDLPoolSecondary: sdlPool.address,
LinearBoostController: boostController.address,
wstLINK_SDLRewardsPool: rewardsPool.address,
SDLPoolCCIPControllerSecondary: ccipController.address,
RESDLTokenBridge: reSDLTokenBridge.address,
},
{ wstLINK_SDLRewardsPool: 'RewardsPool' }
)
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
86 changes: 86 additions & 0 deletions scripts/prod/ccip/stage-2/3-upgrade-primary-chain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { getContract } from '../../../utils/deployment'
import { SDLPoolCCIPControllerPrimary, SDLPoolPrimary } from '../../../../typechain-types'
import { getAccounts } from '../../../utils/helpers'
import Safe, { EthersAdapter } from '@safe-global/protocol-kit'
import SafeApiKit from '@safe-global/api-kit'
import { ethers } from 'hardhat'
import { MetaTransactionData } from '@safe-global/safe-core-sdk-types'

// Execute on Ethereum Mainnet

const multisigAddress = '0xB351EC0FEaF4B99FdFD36b484d9EC90D0422493D'
const secondaryChainSelector = '4949039107694359620' // Arbitrum Mainnet
const secondaryChainSDLPoolCCIPController = '' // Arbitrum Mainnet
const sdlPoolPrimaryImplementation = ''

async function main() {
const { signers, accounts } = await getAccounts()
const ethAdapter = new EthersAdapter({
ethers,
signerOrProvider: signers[0],
})
const safeSdk = await Safe.create({ ethAdapter, safeAddress: multisigAddress })
const safeService = new SafeApiKit({
txServiceUrl: 'https://safe-transaction-mainnet.safe.global',
ethAdapter,
})

const sdlPool = (await getContract('SDLPool')) as SDLPoolPrimary
const ccipController = (await getContract(
'SDLPoolCCIPControllerPrimary'
)) as SDLPoolCCIPControllerPrimary

const safeTransactionData: MetaTransactionData[] = [
{
to: sdlPool.address,
data:
(
await sdlPool.populateTransaction.upgradeToAndCall(
sdlPoolPrimaryImplementation,
sdlPool.interface.encodeFunctionData('initialize', [
'',
'',
ethers.constants.AddressZero,
ethers.constants.AddressZero,
])
)
).data || '',
value: '0',
},
{
to: sdlPool.address,
data:
(await sdlPool.populateTransaction.setCCIPController(ccipController.address)).data || '',
value: '0',
},
{
to: ccipController.address,
data:
(
await ccipController.populateTransaction.addWhitelistedChain(
secondaryChainSelector,
secondaryChainSDLPoolCCIPController
)
).data || '',
value: '0',
},
]
const safeTransaction = await safeSdk.createTransaction({ safeTransactionData })
const safeTxHash = await safeSdk.getTransactionHash(safeTransaction)
const senderSignature = await safeSdk.signTransactionHash(safeTxHash)

await safeService.proposeTransaction({
safeAddress: multisigAddress,
safeTransactionData: safeTransaction.data,
safeTxHash,
senderAddress: accounts[0],
senderSignature: senderSignature.data,
})
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
4 changes: 2 additions & 2 deletions scripts/utils/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ethers } from 'hardhat'
import { BigNumber } from 'ethers'
import { BigNumber, Signer } from 'ethers'
import { ERC677 } from '../../typechain-types'

export const toEther = (amount: string | number) => {
Expand All @@ -10,7 +10,7 @@ export const fromEther = (amount: BigNumber) => {
return Number(ethers.utils.formatEther(amount))
}

export const getAccounts = async () => {
export const getAccounts = async (): Promise<any> => {
const signers = await ethers.getSigners()
const accounts = await Promise.all(signers.map(async (signer) => signer.getAddress()))
return { signers, accounts }
Expand Down

0 comments on commit 7c6d88b

Please sign in to comment.