Skip to content

Commit 9e7e3d2

Browse files
authored
Merge pull request #6 from gammaswap/feat/sonic-deployment
Feat: Deploy & Set up GS Token in Sonic & SonicTestnet
2 parents 3783110 + e335da4 commit 9e7e3d2

26 files changed

+12077
-77
lines changed

README.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,30 @@ GammaSwap token used to secure liquidation and rebalancing logic in exchange for
1414
# Deployment Steps
1515

1616
1. Run 01-deploy-gs-token.ts in every chain
17-
2. Set addresses of GS Token deployed in every chain in helper-hardhat-config.ts in erc20Tokens section in networkConfigInfo
18-
3. Run 02-deploy-set-lzpeers.ts to connect every token to every token in every chain where it is deployed
19-
4. Run 03-deploy-timelock-controller.ts to transfer ownership of the GS Token to the timelock controller
17+
(No need to set up mintGSTokenTo or initialGSTokenAmt in helper-hardhat-config.ts unless it's first deployment)
18+
2. Update helper-hardhat-config.ts
19+
Set lzEid and lzEndpoing for new chain from LayerZero's docs
20+
Set addresses of GS Token deployed in every chain in helper-hardhat-config.ts in erc20Tokens section in networkConfigInfo
21+
Add the chain name to developmentLzPeers and productionLzPeers in helper-hardhat-config.ts
22+
Add gnosis multisig address as timelock proposer and executor
23+
3. Run 02-deploy-set-lzpeers.ts to connect every token to every token in every chain where it is deployed.
24+
If it's the first deployment, it must be run for every chain.
25+
4. Run 03-deploy-timelock-controller.ts to deploy timelockController for new GS token chain (use a short minDelay)
26+
5. Run 05-transfer-gs-ownership.ts to transfer GS Token ownership to timelock-controller
27+
6. Run 07-update-enforced-options.ts on all non-new chains to set the enforced options from all peers to new peer.
28+
7. Run 08-deploy-timelock-set-lzpeers.ts to set LZ peers of non-new chains to new peer
29+
8. Check that network has correct configurations using task lz-config.ts. Make sure DVNs and Libs are not dead.
30+
If they're not set or are dead then set the DVNs, SendLib, ReceiveLib, and Executor following the steps from section below.
31+
8. Run 06-update-timelock-delay.ts, to set the timelock on the new chain to 1 day (set minDelay to 1 day in seconds)
32+
33+
# How to set DVNs, SendLib, ReceiveLib, and Executors
34+
35+
*The delegate of GS token has to also be the timelockController. Otherwise the timelockController
36+
won't be able to set the configurations. Set the delegate using task lz-set-delegate.ts.
37+
38+
1. Fill in LZ configurations in helper-hardhat-config.ts.
39+
Get DVNs from https://docs.layerzero.network/v2/deployments/dvn-addresses
40+
Get Send/Rec/Exec Libs from https://docs.layerzero.network/v2/deployments/deployed-contracts
41+
2. Make sure the DVN count, confirmations, and providers from send to receive chain match.
42+
3. Run task lz-set-config.ts
43+
4. Check configurations were set correctly (i.e. they match on both send and receive chain) using task lz-config.ts

deploy/02-deploy-set-lzpeers.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { DeployFunction } from "hardhat-deploy/types"
33
import { isMainnet } from "../helper-functions"
44
import { ethers } from "hardhat";
55
import { networkConfig, developmentLzPeers, productionLzPeers } from "../helper-hardhat-config";
6+
import { Options } from "@layerzerolabs/lz-v2-utilities";
67

78
const deploySetLZPeers: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
89
// @ts-ignore
@@ -37,6 +38,21 @@ const deploySetLZPeers: DeployFunction = async function (hre: HardhatRuntimeEnvi
3738
const tx = await (await gsContract.connect(_deployer).setPeer(lzEid, _gsAddr)).wait(confirmations);
3839
if(tx && tx.transactionHash) {
3940
log("GS in",network.name,"set peer for",peerNetwork,"in",tx.transactionHash)
41+
42+
const op = await gsContract.enforcedOptions(lzEid, 1)
43+
log("op[",lzEid,"] before >> ", op)
44+
45+
const options = Options.newOptions().addExecutorLzReceiveOption(200000, 0).toHex().toString()
46+
const enforcedOptionParams = [{
47+
eid: lzEid,
48+
msgType: 1, // 1: SEND, 2: SEND_AND_CALL
49+
options: options
50+
}];
51+
52+
const _tx = await (await gsContract.connect(_deployer).setEnforcedOptions(enforcedOptionParams)).wait(confirmations);
53+
if(_tx && _tx.transactionHash) {
54+
log("GS in",network.name,"set options",options,"for",peerNetwork,"in",_tx.transactionHash)
55+
}
4056
}
4157
} else {
4258
log("GS already has peer at",peerNetwork)

deploy/05-transfer-gs-ownership.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const deployTransferGSOwnership: DeployFunction = async function (hre: HardhatRu
4747
const iface = new hre.ethers.utils.Interface(abi);
4848

4949
const data = iface.encodeFunctionData("acceptOwnership", []);
50+
log("data:", data.toString())
5051

5152
const timelockControllerContract = await ethers.getContractAt("TimelockController", timelockController.address);
5253

deploy/06-update-timelock-delay.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const updateMinDelay: DeployFunction = async function (hre: HardhatRuntimeEnviro
1212
log(`deployer: ${deployer}`)
1313

1414
const confirmations = networkConfig[network.name].longBlockConfirmations;
15+
log(`confirmations: ${confirmations}`)
1516

1617
const _deployer = await hre.ethers.getSigner(deployer);
1718

deploy/07-update-enforced-options.ts

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,32 @@ const updateEnforcedOptions: DeployFunction = async function (hre: HardhatRuntim
3838
const lzEid = Number(cfg.lzEid || "0");
3939
const op = await gsContract.enforcedOptions(lzEid, 1)
4040
log("op[",lzEid,"] before >> ", op)
41-
42-
const enforcedOptionParams = [{
43-
eid: lzEid,
44-
msgType: 1, // 1: SEND, 2: SEND_AND_CALL
45-
options: options
46-
}];
47-
48-
const data = gsContract.interface.encodeFunctionData('setEnforcedOptions', [enforcedOptionParams]);
49-
log("data >>", data)
50-
payloads.push(data)
51-
targets.push(gs.address)
52-
values.push(0)
41+
if(op == "0x") {
42+
const enforcedOptionParams = [{
43+
eid: lzEid,
44+
msgType: 1, // 1: SEND, 2: SEND_AND_CALL
45+
options: options
46+
}];
47+
48+
const data = gsContract.interface.encodeFunctionData('setEnforcedOptions', [enforcedOptionParams]);
49+
log("data >>", data)
50+
payloads.push(data)
51+
targets.push(gs.address)
52+
values.push(0)
53+
} else {
54+
log("enforced options already set for",peerNetwork,"lzEid:",lzEid)
55+
}
5356
}
5457
}
5558
log("payloads >> ", payloads)
5659
log("targets >> ", targets)
5760
log("values >> ", values)
5861

62+
if(payloads.length == 0) {
63+
log("enforced options have already been set for all chains")
64+
return
65+
}
66+
5967
const timelockControllerContract = await ethers.getContractAt("TimelockController", timelockController.address);
6068

6169
const currMinDelay = await timelockControllerContract.getMinDelay();
@@ -71,6 +79,12 @@ const updateEnforcedOptions: DeployFunction = async function (hre: HardhatRuntim
7179
const lastId = events.length > 0 ? events[events.length - 1].args.id : hre.ethers.constants.HashZero;
7280
log("lastId:", lastId)
7381

82+
log("==================scheduleBatch parameters==================")
83+
log("payloads:", payloads)
84+
log("targets :", targets)
85+
log("values :", values)
86+
log("lastId :", lastId)
87+
log("============================================================")
7488
let tx = await (await timelockControllerContract.connect(_deployer).scheduleBatch(targets, values, payloads, lastId, hre.ethers.constants.HashZero, currMinDelay)).wait(confirmations);
7589
if(tx && tx.transactionHash) {
7690
log("scheduled setEnforcedOptions(struct) at", tx.transactionHash)
@@ -94,7 +108,7 @@ const updateEnforcedOptions: DeployFunction = async function (hre: HardhatRuntim
94108
const cfg = networkConfig[peerNetwork]
95109
const lzEid = Number(cfg.lzEid || "0");
96110
const op = await gsContract.enforcedOptions(lzEid, 1)
97-
log("op[", lzEid, " after >> ", op)
111+
log("op[", lzEid, "] after >> ", op)
98112
}
99113
}
100114
log("----------------------------------------------------")
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { HardhatRuntimeEnvironment } from "hardhat/types"
2+
import { DeployFunction } from "hardhat-deploy/types"
3+
import { isMainnet, sleep } from "../helper-functions";
4+
import { developmentLzPeers, networkConfig, productionLzPeers } from "../helper-hardhat-config";
5+
import { ethers } from "hardhat";
6+
import { TimelockController, GS } from "../typechain-types";
7+
8+
const updateEnforcedOptions: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
9+
const { getNamedAccounts, deployments, network } = hre
10+
const { log, get } = deployments
11+
const { deployer } = await getNamedAccounts()
12+
log(`deployer: ${deployer}`)
13+
14+
const confirmations = networkConfig[network.name].longBlockConfirmations;
15+
16+
const _deployer = await hre.ethers.getSigner(deployer);
17+
18+
const timelockController = await get("TimelockController");
19+
log(`timelockController: ${timelockController.address}`)
20+
21+
const gs = await get("GS");
22+
log(`gs: ${gs.address}`)
23+
24+
const gsContract = (await ethers.getContractAt('GS', gs.address)) as unknown as GS;
25+
26+
const lzPeers = isMainnet(hre) ? productionLzPeers : developmentLzPeers
27+
28+
const payloads = []
29+
const targets = []
30+
const values = []
31+
for(let i = 0; i < lzPeers.length; i++) {
32+
const peerNetwork = lzPeers[i]
33+
if (network.name != peerNetwork) {
34+
const cfg = networkConfig[peerNetwork]
35+
const lzEid = Number(cfg.lzEid || "0");
36+
const gsAddr = cfg.erc20Tokens?.gs || ""
37+
log("Setting Peer for network",peerNetwork," >> lzEid:", lzEid," gs:",gsAddr)
38+
if(lzEid > 0 && ethers.utils.isAddress(gsAddr)) {
39+
const _gsAddr = ethers.utils.zeroPad(gsAddr, 32)
40+
const hasPeer = await gsContract.isPeer(lzEid, _gsAddr);
41+
if(!hasPeer) {
42+
log("set peer")
43+
const _gsAddrStr = ethers.utils.hexlify(_gsAddr)
44+
log("_gsAddr:",_gsAddrStr);
45+
const data = gsContract.interface.encodeFunctionData('setPeer', [lzEid, _gsAddrStr]);
46+
payloads.push(data)
47+
targets.push(gs.address)
48+
values.push(0)
49+
} else {
50+
log("GS already has peer at", peerNetwork)
51+
}
52+
} else {
53+
log("Peer not set for", peerNetwork)
54+
}
55+
}
56+
}
57+
log("payloads >> ", payloads)
58+
log("targets >> ", targets)
59+
log("values >> ", values)
60+
61+
if(payloads.length == 0) {
62+
log("Peers have already been set for all chains")
63+
return
64+
}
65+
66+
const timelockControllerContract = await ethers.getContractAt("TimelockController", timelockController.address);
67+
68+
const currMinDelay = await timelockControllerContract.getMinDelay();
69+
log(`currMinDelay: ${currMinDelay}`)
70+
71+
const eventName = "CallScheduled";
72+
const latestBlock = await hre.ethers.provider.getBlockNumber();
73+
log("latestBlock:", latestBlock)
74+
75+
// Fetch events
76+
const events = await timelockControllerContract.queryFilter(timelockControllerContract.filters[eventName](), 0, latestBlock);
77+
78+
const lastId = events.length > 0 ? events[events.length - 1].args.id : hre.ethers.constants.HashZero;
79+
log("lastId:", lastId)
80+
81+
log("==================scheduleBatch parameters==================")
82+
log("payloads:", payloads)
83+
log("targets :", targets)
84+
log("values :", values)
85+
log("lastId :", lastId)
86+
log("============================================================")
87+
let tx = await (await timelockControllerContract.connect(_deployer).scheduleBatch(targets, values, payloads, lastId, hre.ethers.constants.HashZero, currMinDelay)).wait(confirmations);
88+
if(tx && tx.transactionHash) {
89+
log("scheduled setPeer(lzEid,peerAddr) at", tx.transactionHash)
90+
} else {
91+
log("ERROR scheduling setPeer(lzEid,peerAddr)")
92+
return
93+
}
94+
95+
const waitSeconds = Number(currMinDelay) + 20
96+
log("waitSeconds:",waitSeconds)
97+
await sleep(waitSeconds * 1000)
98+
99+
tx = await (await timelockControllerContract.connect(_deployer).executeBatch(targets, values, payloads, lastId, hre.ethers.constants.HashZero)).wait(confirmations);
100+
if(tx && tx.transactionHash) {
101+
log("execute setPeer(lzEid,peerAddr) at", tx.transactionHash)
102+
}
103+
104+
for(let i = 0; i < lzPeers.length; i++) {
105+
const peerNetwork = lzPeers[i]
106+
if (network.name != peerNetwork) {
107+
const cfg = networkConfig[peerNetwork]
108+
const lzEid = Number(cfg.lzEid || "0");
109+
const gsAddr = cfg.erc20Tokens?.gs || ""
110+
const _gsAddr = ethers.utils.zeroPad(gsAddr, 32)
111+
const hasPeer = await gsContract.isPeer(lzEid, _gsAddr);
112+
log("Checking if Peer for network",peerNetwork," lzEid:", lzEid," gs:",gsAddr," is set?",hasPeer)
113+
}
114+
}
115+
log("----------------------------------------------------")
116+
}
117+
118+
export default updateEnforcedOptions
119+
updateEnforcedOptions.tags = ["all-timelock", "timelock-lz-peers"]

deployments/sonic/.chainId

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
146

deployments/sonic/GS.json

Lines changed: 143 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)