-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from ExocoreNetwork/fix/v3-upgrade
fix: v3 testnet upgrade findings
- Loading branch information
Showing
11 changed files
with
440 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
pragma solidity ^0.8.19; | ||
|
||
import {ILayerZeroEndpointV2} from "@layerzero-v2/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol"; | ||
|
||
import {ProxyAdmin} from "@openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol"; | ||
import {TransparentUpgradeableProxy} from "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; | ||
|
||
import {ExocoreGateway} from "../src/core/ExocoreGateway.sol"; | ||
import "forge-std/Script.sol"; | ||
import {BaseScript} from "./BaseScript.sol"; | ||
|
||
contract DeployExocoreGatewayOnly is BaseScript { | ||
|
||
function setUp() public virtual override { | ||
// load keys | ||
super.setUp(); | ||
// load contracts | ||
string memory prerequisities = vm.readFile("script/prerequisiteContracts.json"); | ||
exocoreLzEndpoint = ILayerZeroEndpointV2(stdJson.readAddress(prerequisities, ".exocore.lzEndpoint")); | ||
require(address(exocoreLzEndpoint) != address(0), "exocore l0 endpoint should not be empty"); | ||
// fork | ||
exocore = vm.createSelectFork(exocoreRPCURL); | ||
} | ||
|
||
function run() public { | ||
vm.selectFork(exocore); | ||
vm.startBroadcast(deployer.privateKey); | ||
|
||
ProxyAdmin exocoreProxyAdmin = new ProxyAdmin(); | ||
ExocoreGateway exocoreGatewayLogic = new ExocoreGateway(address(exocoreLzEndpoint)); | ||
exocoreGateway = ExocoreGateway( | ||
payable( | ||
address( | ||
new TransparentUpgradeableProxy( | ||
address(exocoreGatewayLogic), | ||
address(exocoreProxyAdmin), | ||
abi.encodeWithSelector( | ||
exocoreGatewayLogic.initialize.selector, | ||
payable(exocoreValidatorSet.addr) | ||
) | ||
) | ||
) | ||
) | ||
); | ||
|
||
vm.stopBroadcast(); | ||
|
||
string memory exocoreContracts = "exocoreContracts"; | ||
vm.serializeAddress(exocoreContracts, "lzEndpoint", address(exocoreLzEndpoint)); | ||
vm.serializeAddress(exocoreContracts, "exocoreGatewayLogic", address(exocoreGatewayLogic)); | ||
string memory exocoreContractsOutput = | ||
vm.serializeAddress(exocoreContracts, "exocoreGateway", address(exocoreGateway)); | ||
|
||
string memory deployedContracts = "deployedContracts"; | ||
string memory finalJson = | ||
vm.serializeString(deployedContracts, "exocore", exocoreContractsOutput); | ||
|
||
vm.writeJson(finalJson, "script/deployedExocoreGatewayOnly.json"); | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
pragma solidity ^0.8.19; | ||
|
||
import {ExocoreGateway} from "../src/core/ExocoreGateway.sol"; | ||
import {Bootstrap} from "../src/core/Bootstrap.sol"; | ||
|
||
import {CLIENT_CHAINS_PRECOMPILE_ADDRESS} from "../src/interfaces/precompiles/IClientChains.sol"; | ||
|
||
import "forge-std/Script.sol"; | ||
import {BaseScript} from "./BaseScript.sol"; | ||
|
||
import "@layerzero-v2/protocol/contracts/libs/AddressCast.sol"; | ||
|
||
contract SetPeersAndUpgrade is BaseScript { | ||
using AddressCast for address; | ||
|
||
address bootstrapAddr; | ||
address exocoreGatewayAddr; | ||
|
||
function setUp() public virtual override { | ||
// load keys | ||
super.setUp(); | ||
// load contracts | ||
string memory deployed = vm.readFile("script/deployedBootstrapOnly.json"); | ||
bootstrapAddr = stdJson.readAddress(deployed, ".clientChain.bootstrap"); | ||
require(address(bootstrapAddr) != address(0), "bootstrap address should not be empty"); | ||
deployed = vm.readFile("script/deployedExocoreGatewayOnly.json"); | ||
exocoreGatewayAddr = stdJson.readAddress(deployed, ".exocore.exocoreGateway"); | ||
require(address(exocoreGatewayAddr) != address(0), "exocore gateway address should not be empty"); | ||
// forks | ||
exocore = vm.createSelectFork(exocoreRPCURL); | ||
clientChain = vm.createSelectFork(clientChainRPCURL); | ||
} | ||
|
||
function run() public { | ||
ExocoreGateway gateway = ExocoreGateway(payable(exocoreGatewayAddr)); | ||
|
||
vm.selectFork(exocore); | ||
vm.startBroadcast(exocoreValidatorSet.privateKey); | ||
gateway.setPeer(clientChainId, bootstrapAddr.toBytes32()); | ||
vm.stopBroadcast(); | ||
|
||
Bootstrap bootstrap = Bootstrap(payable(bootstrapAddr)); | ||
|
||
vm.selectFork(clientChain); | ||
vm.startBroadcast(exocoreValidatorSet.privateKey); | ||
bootstrap.setPeer(exocoreChainId, address(exocoreGatewayAddr).toBytes32()); | ||
vm.stopBroadcast(); | ||
|
||
// check that peer is set (we run with --slow but even then there's some risk) | ||
uint256 i = 0; | ||
uint256 tries = 5; | ||
bool success; | ||
while(i < tries) { | ||
|
||
vm.selectFork(exocore); | ||
success = gateway.peers(clientChainId) == bootstrapAddr.toBytes32(); | ||
|
||
vm.selectFork(clientChain); | ||
success = success && bootstrap.peers(exocoreChainId) == address(exocoreGatewayAddr).toBytes32(); | ||
|
||
if (success) { | ||
break; | ||
} | ||
|
||
i++; | ||
} | ||
require(i < tries, "peers not set"); | ||
|
||
// the upgrade does not work via script due to the precompile issue | ||
// https://github.com/ExocoreNetwork/exocore/issues/78 | ||
// // now that peers are set, we should upgrade the Bootstrap contract via gateway | ||
// // but first allow simulation to run | ||
// vm.selectFork(exocore); | ||
// bytes memory mockCode = vm.getDeployedCode("ClientChainsMock.sol"); | ||
// vm.etch(CLIENT_CHAINS_PRECOMPILE_ADDRESS, mockCode); | ||
|
||
// console.log("clientChainId", clientChainId); | ||
// vm.startBroadcast(exocoreValidatorSet.privateKey); | ||
// // fund the gateway | ||
// if (exocoreGatewayAddr.balance < 1 ether) { | ||
// (bool sent,) = exocoreGatewayAddr.call{value: 1 ether}(""); | ||
// require(sent, "Failed to send Ether"); | ||
// } | ||
// // gateway.markBootstrapOnAllChains(); | ||
|
||
// instruct the user to upgrade manually | ||
// this can be done even without calling x/assets UpdateParams | ||
// because that parameter is not involved in this process. | ||
console.log("Cross-chain upgrade command:"); | ||
console.log( | ||
"source .env && cast send --rpc-url $EXOCORE_TESETNET_RPC", | ||
exocoreGatewayAddr, | ||
"\"markBootstrapOnAllChains()\"", | ||
"--private-key $TEST_ACCOUNT_THREE_PRIVATE_KEY" | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
pragma solidity ^0.8.19; | ||
|
||
import {TransparentUpgradeableProxy} from "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; | ||
import {UpgradeableBeacon} from "@openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol"; | ||
|
||
import {Bootstrap} from "../src/core/Bootstrap.sol"; | ||
import {ClientChainGateway} from "../src/core/ClientChainGateway.sol"; | ||
import {CustomProxyAdmin} from "../src/core/CustomProxyAdmin.sol"; | ||
import {Vault} from "../src/core/Vault.sol"; | ||
import "../src/core/BeaconProxyBytecode.sol"; | ||
import "../src/core/ExoCapsule.sol"; | ||
|
||
import "forge-std/Script.sol"; | ||
import {BaseScript} from "./BaseScript.sol"; | ||
import {ILayerZeroEndpointV2} from "@layerzero-v2/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol"; | ||
import {ERC20PresetFixedSupply} from "@openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; | ||
import "@beacon-oracle/contracts/src/EigenLayerBeaconOracle.sol"; | ||
|
||
contract RedeployClientChainGateway is BaseScript { | ||
Bootstrap bootstrap; | ||
|
||
function setUp() public virtual override { | ||
// load keys | ||
super.setUp(); | ||
// load contracts | ||
string memory prerequisiteContracts = vm.readFile("script/deployedBootstrapOnly.json"); | ||
clientChainLzEndpoint = ILayerZeroEndpointV2( | ||
stdJson.readAddress(prerequisiteContracts, ".clientChain.lzEndpoint") | ||
); | ||
require(address(clientChainLzEndpoint) != address(0), "client chain l0 endpoint should not be empty"); | ||
beaconOracle = EigenLayerBeaconOracle( | ||
stdJson.readAddress(prerequisiteContracts, ".clientChain.beaconOracle") | ||
); | ||
require(address(beaconOracle) != address(0), "beacon oracle should not be empty"); | ||
vaultBeacon = UpgradeableBeacon( | ||
stdJson.readAddress(prerequisiteContracts, ".clientChain.vaultBeacon") | ||
); | ||
require(address(vaultBeacon) != address(0), "vault beacon should not be empty"); | ||
capsuleBeacon = UpgradeableBeacon( | ||
stdJson.readAddress(prerequisiteContracts, ".clientChain.capsuleBeacon") | ||
); | ||
require(address(capsuleBeacon) != address(0), "capsule beacon should not be empty"); | ||
beaconProxyBytecode = BeaconProxyBytecode( | ||
stdJson.readAddress(prerequisiteContracts, ".clientChain.beaconProxyBytecode") | ||
); | ||
require(address(beaconProxyBytecode) != address(0), "beacon proxy bytecode should not be empty"); | ||
bootstrap = Bootstrap( | ||
stdJson.readAddress(prerequisiteContracts, ".clientChain.bootstrap") | ||
); | ||
require(address(bootstrap) != address(0), "bootstrap should not be empty"); | ||
clientChain = vm.createSelectFork(clientChainRPCURL); | ||
} | ||
|
||
function run() public { | ||
vm.selectFork(clientChain); | ||
vm.startBroadcast(exocoreValidatorSet.privateKey); | ||
ClientChainGateway clientGatewayLogic = new ClientChainGateway( | ||
address(clientChainLzEndpoint), | ||
exocoreChainId, | ||
address(beaconOracle), | ||
address(vaultBeacon), | ||
address(capsuleBeacon), | ||
address(beaconProxyBytecode) | ||
); | ||
// then the client chain initialization | ||
address[] memory emptyList; | ||
bytes memory initialization = abi.encodeWithSelector( | ||
clientGatewayLogic.initialize.selector, | ||
exocoreValidatorSet.addr, | ||
emptyList | ||
); | ||
bootstrap.setClientChainGatewayLogic( | ||
address(clientGatewayLogic), | ||
initialization | ||
); | ||
vm.stopBroadcast(); | ||
|
||
string memory clientChainContracts = "clientChainContracts"; | ||
string memory clientChainContractsOutput = | ||
vm.serializeAddress(clientChainContracts, "clientGatewayLogic", address(clientGatewayLogic)); | ||
|
||
string memory deployedContracts = "deployedContracts"; | ||
string memory finalJson = | ||
vm.serializeString(deployedContracts, "clientChain", clientChainContractsOutput); | ||
|
||
vm.writeJson(finalJson, "script/redeployClientChainGateway.json"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
pragma solidity ^0.8.19; | ||
|
||
import {Bootstrap} from "../src/core/Bootstrap.sol"; | ||
import {Vault} from "../src/core/Vault.sol"; | ||
import {IOperatorRegistry} from "../src/interfaces/IOperatorRegistry.sol"; | ||
|
||
import {ERC20PresetFixedSupply} from "@openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; | ||
|
||
import "forge-std/Script.sol"; | ||
|
||
// This script does not intentionally inherit from BaseScript, since | ||
// that script has boilerplate that is not needed here. | ||
contract RegisterOperatorsAndDelegate is Script { | ||
// registration data for operators | ||
uint256[] operatorKeys; | ||
string[] exoAddresses; | ||
string[] names; | ||
bytes32[] consKeys; | ||
// rpc settings | ||
string clientChainRPCURL; | ||
uint256 clientChain; | ||
// addresses of contracts | ||
address bootstrapAddr; | ||
address tokenAddr; | ||
// each subarray sums to deposits, and each item is the delegation amount | ||
uint256[4][4] amounts = [ | ||
[ 1500 * 1e18, 250 * 1e18, 250 * 1e18, 0 * 1e18 ], | ||
[ 300 * 1e18, 1500 * 1e18, 0 * 1e18, 200 * 1e18 ], | ||
[ 0 * 1e18, 0 * 1e18, 2500 * 1e18, 500 * 1e18 ], | ||
[ 1000 * 1e18, 0 * 1e18, 0 * 1e18, 2000 * 1e18 ] | ||
]; | ||
|
||
function setUp() public { | ||
operatorKeys = vm.envUint("OPERATOR_KEYS", ","); | ||
exoAddresses = vm.envString("EXO_ADDRESSES", ","); | ||
names = vm.envString("NAMES", ","); | ||
consKeys = vm.envBytes32("CONS_KEYS", ","); | ||
|
||
clientChainRPCURL = vm.envString("SEPOLIA_RPC"); | ||
clientChain = vm.createSelectFork(clientChainRPCURL); | ||
|
||
require( | ||
operatorKeys.length == exoAddresses.length && | ||
operatorKeys.length == names.length && | ||
operatorKeys.length == consKeys.length, | ||
"Operator registration data length mismatch" | ||
); | ||
|
||
string memory deployedContracts = vm.readFile("script/deployedBootstrapOnly.json"); | ||
bootstrapAddr = stdJson.readAddress(deployedContracts, ".clientChain.bootstrap"); | ||
require(bootstrapAddr != address(0), "Bootstrap address should not be empty"); | ||
tokenAddr = stdJson.readAddress(deployedContracts, ".clientChain.erc20Token"); | ||
require(tokenAddr != address(0), "Token address should not be empty"); | ||
} | ||
|
||
function run() public { | ||
vm.selectFork(clientChain); | ||
IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( | ||
0, 1e18, 1e18 | ||
); | ||
Bootstrap bootstrap = Bootstrap(bootstrapAddr); | ||
ERC20PresetFixedSupply token = ERC20PresetFixedSupply(tokenAddr); | ||
address vaultAddr = address(bootstrap.tokenToVault(tokenAddr)); | ||
for(uint256 i = 0; i < operatorKeys.length; i++) { | ||
uint256 pk = operatorKeys[i]; | ||
// address addr = vm.addr(pk); | ||
string memory exoAddr = exoAddresses[i]; | ||
string memory name = names[i]; | ||
bytes32 consKey = consKeys[i]; | ||
vm.startBroadcast(pk); | ||
// register operator | ||
bootstrap.registerOperator( | ||
exoAddr, name, commission, consKey | ||
); | ||
uint256 depositAmount = 0; | ||
for(uint256 j = 0; j < amounts[i].length; j++) { | ||
depositAmount += amounts[i][j]; | ||
} | ||
// approve | ||
token.approve(vaultAddr, type(uint256).max); | ||
// transfer | ||
bootstrap.deposit(tokenAddr, depositAmount); | ||
vm.stopBroadcast(); | ||
} | ||
for(uint256 i = 0; i < operatorKeys.length; i++) { | ||
uint256 pk = operatorKeys[i]; | ||
vm.startBroadcast(pk); | ||
for(uint256 j = 0; j < operatorKeys.length; j++) { | ||
uint256 amount = amounts[i][j]; | ||
if (amount == 0) { | ||
continue; | ||
} | ||
// i is the transaction sender and j is the operator | ||
string memory exoAddr = exoAddresses[j]; | ||
bootstrap.delegateTo(exoAddr, tokenAddr, amount); | ||
} | ||
vm.stopBroadcast(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
pragma solidity ^0.8.19; | ||
|
||
import {Bootstrap} from "../src/core/Bootstrap.sol"; | ||
|
||
import "forge-std/Script.sol"; | ||
import {BaseScript} from "./BaseScript.sol"; | ||
|
||
contract SetBootstrapTime is BaseScript { | ||
address bootstrapAddr; | ||
|
||
function setUp() public virtual override { | ||
// load keys | ||
super.setUp(); | ||
// load contracts | ||
string memory deployedContracts = vm.readFile("script/deployedBootstrapOnly.json"); | ||
bootstrapAddr = stdJson.readAddress(deployedContracts, ".clientChain.bootstrap"); | ||
|
||
clientChain = vm.createSelectFork(clientChainRPCURL); | ||
} | ||
|
||
function run() public { | ||
vm.selectFork(clientChain); | ||
vm.startBroadcast(exocoreValidatorSet.privateKey); | ||
|
||
Bootstrap bootstrap = Bootstrap(bootstrapAddr); | ||
bootstrap.setSpawnTime(block.timestamp + 120 seconds); | ||
|
||
vm.stopBroadcast(); | ||
} | ||
} |
Oops, something went wrong.