diff --git a/packages/ua-utils/package.json b/packages/ua-utils/package.json index f22d077cc..9f0d5d584 100644 --- a/packages/ua-utils/package.json +++ b/packages/ua-utils/package.json @@ -37,7 +37,8 @@ "hardhat-deploy": "^0.11.22", "ts-node": "^10.9.1", "tsup": "^7.2.0", - "typescript": "^5.2.2" + "typescript": "^5.2.2", + "@layerzerolabs/hardhat-utils": "~0.0.1" }, "peerDependencies": { "@gnosis.pm/safe-core-sdk": "^2.0.0", diff --git a/packages/ua-utils/src/getConfig.ts b/packages/ua-utils/src/getConfig.ts index fb1768e93..bd5300766 100644 --- a/packages/ua-utils/src/getConfig.ts +++ b/packages/ua-utils/src/getConfig.ts @@ -1,49 +1,58 @@ -import { getDeploymentAddresses, getApplicationConfig, getEndpointAddress } from "./utils/crossChainHelper" -import { ENDPOINT_ABI, MESSAGING_LIBRARY_ABI } from "./constants/abi" -import { logError } from "./utils/helpers" +import { ActionType, HardhatRuntimeEnvironment } from "hardhat/types" +import { task, types } from "hardhat/config" +import { ethers } from "ethers" +import { createGetNetworkEnvironment } from "@layerzerolabs/hardhat-utils" -export default async (taskArgs: any, hre: any) => { - const network = hre.network.name - const remoteNetworks = taskArgs.remoteNetworks.split(",") - const contractName = taskArgs.name - let contractAddress = taskArgs.address +const action: ActionType = async (taskArgs, hre) => { + // TODO add logging + // const logger = createLogger() + + const localNetwork = hre.network.name + const getEnvironment = createGetNetworkEnvironment(hre) + const localEnvironment = await getEnvironment(localNetwork) + const localEndpointV2 = await localEnvironment.getContract("EndpointV2", localEnvironment.provider) + const localEid = await localEndpointV2.eid() - if (!contractName && !contractAddress) { - logError("Provide contract name or address") + let localContractAddress + if (taskArgs.name !== undefined) { + localContractAddress = (await localEnvironment.getContract(taskArgs.name, localEnvironment.provider)).address + } else if (taskArgs.address !== undefined) { + localContractAddress = taskArgs.address + } else { + // TODO log error return } - if (contractName && !contractAddress) { - contractAddress = getDeploymentAddresses(network, false)[contractName] - if (!contractAddress) { - logError(`Deployment information isn't found for ${contractName}`) - return - } - } + // TODO fix this: 'deployments' does not exist on type 'HardhatRuntimeEnvironment'. + const ulnConfigDeployment = await hre.deployments.get("UlnConfig") + const remoteNetworks = taskArgs.remoteNetworks.split(",") + const configByNetwork = await Promise.all( + remoteNetworks.map(async (remoteNetwork: string) => { + const remoteEnvironment = await getEnvironment(remoteNetwork) + const remoteEndpointV2 = await remoteEnvironment.getContract("EndpointV2", remoteEnvironment.provider) + const remoteEid = await remoteEndpointV2.eid() - const endpoint = await hre.ethers.getContractAt(ENDPOINT_ABI, getEndpointAddress(network)) - const appConfig = await endpoint.uaConfigLookup(contractAddress) - const sendVersion = appConfig.sendVersion - const receiveVersion = appConfig.receiveVersion - const sendLibraryAddress = sendVersion === 0 ? await endpoint.defaultSendLibrary() : appConfig.sendLibrary - const sendLibrary = await hre.ethers.getContractAt(MESSAGING_LIBRARY_ABI, sendLibraryAddress) - let receiveLibrary: any + const localSendLibrary = await localEndpointV2.getSendLibrary(localContractAddress, remoteEid) + // TODO fix this: 'getContractAt' does not exist on type 'typeof import("/Users/kz-layerzero/Documents/layerzero/git/lz-utils/node_modules/ethers/lib/ethers")'. + const localUlnConfig = await ethers.getContractAt(ulnConfigDeployment.abi, localSendLibrary) + const [ulnConfigStruct, outboundConfigStruct] = await localUlnConfig.getUlnAndOutboundConfig(localContractAddress, remoteEid) - if (sendVersion !== receiveVersion) { - const receiveLibraryAddress = receiveVersion === 0 ? await endpoint.defaultReceiveLibraryAddress() : appConfig.receiveLibraryAddress - receiveLibrary = await hre.ethers.getContractAt(MESSAGING_LIBRARY_ABI, receiveLibraryAddress) - } - - const remoteConfig: any[] = await Promise.all( - remoteNetworks.map(async (remoteNetwork: string) => { - if (network === remoteNetwork) return - return await getApplicationConfig(remoteNetwork, sendLibrary, receiveLibrary, contractAddress) + return { + Network: localNetwork, + OAppaddress: localContractAddress, + ...ulnConfigStruct, + ...outboundConfigStruct, + } }) ) - - console.log("Network ", network) - console.log("Application address", contractAddress) - console.log("Send version ", sendVersion) - console.log("Receive version ", receiveVersion) - console.table(remoteConfig) + console.table(configByNetwork) } + +task("getConfig", "outputs the application's Send and Receive Messaging Library versions and the config for remote networks") + .addParam("remoteNetworks", "comma separated list of remote networks") + .addOptionalParam( + "name", + "name of the deployed contract. Should be specified only if the deployment information is located in the deployments folder" + ) + .addOptionalParam("address", "the contract address") + .setAction(action) diff --git a/packages/ua-utils/src/getDefaultConfig.ts b/packages/ua-utils/src/getDefaultConfig.ts index f6cf2dee0..9dc6b1fa3 100644 --- a/packages/ua-utils/src/getDefaultConfig.ts +++ b/packages/ua-utils/src/getDefaultConfig.ts @@ -1,34 +1,72 @@ +import { ActionType } from "hardhat/types" +import { task, types } from "hardhat/config" import { ethers } from "ethers" -import { getProvider, getLayerZeroChainId, getEndpointAddress } from "./utils/crossChainHelper" -const { ENDPOINT_ABI, MESSAGING_LIBRARY_ABI } = require("./constants/abi") +import { createGetNetworkEnvironment } from "@layerzerolabs/hardhat-utils" -export default async (taskArgs: any, hre: any) => { - const networks = taskArgs.networks.split(",") +const CONFIG_TYPE_MAX_MESSAGE_SIZE = 1 +const CONFIG_TYPE_OUTBOUND_CONFIRMATIONS = 2 +const CONFIG_TYPE_EXECUTOR = 3 +const CONFIG_TYPE_INBOUND_CONFIRMATIONS = 4 +const CONFIG_TYPE_VERIFIERS = 5 +const CONFIG_TYPE_OPTIONAL_VERIFIERS = 6 + +const action: ActionType = async (taskArgs, hre) => { + // TODO add logging + // const logger = createLogger() + const networks = taskArgs.networks.split(",") + const getEnvironment = createGetNetworkEnvironment(hre) const configByNetwork = await Promise.all( networks.map(async (network: string) => { - const provider = getProvider(hre, network) - console.log() - const endpoint = new ethers.Contract(getEndpointAddress(network), ENDPOINT_ABI, provider) - const sendVersion = await endpoint.defaultSendVersion() - const receiveVersion = await endpoint.defaultReceiveVersion() - const sendLibraryAddress = await endpoint.defaultSendLibrary() - const messagingLibrary = new ethers.Contract(sendLibraryAddress, MESSAGING_LIBRARY_ABI, provider) - const config = await messagingLibrary.defaultAppConfig(getLayerZeroChainId(network)) + const environment = await getEnvironment(network) + const endpointV2 = await environment.getContract("EndpointV2", environment.provider) + const eid = await endpointV2.eid() + + const defaultSendLibrary = await endpointV2.defaultSendLibrary(eid) + const defaultReceiveLibrary = await endpointV2.defaultReceiveLibrary(eid) + + const maxMessageSizeEncodedData = await endpointV2.defaultConfig(defaultSendLibrary, eid, CONFIG_TYPE_MAX_MESSAGE_SIZE) + const maxMessageSize = ethers.utils.defaultAbiCoder.decode(["uint32"], maxMessageSizeEncodedData) + + const outboundConfirmationsEncodedData = await endpointV2.defaultConfig(defaultSendLibrary, eid, CONFIG_TYPE_OUTBOUND_CONFIRMATIONS) + const outboundConfirmations = ethers.utils.defaultAbiCoder.decode(["uint64"], outboundConfirmationsEncodedData) + + const executorEncodedData = await endpointV2.defaultConfig(defaultSendLibrary, eid, CONFIG_TYPE_EXECUTOR) + const executor = ethers.utils.defaultAbiCoder.decode(["address"], executorEncodedData) + + const inboundBlockConfirmationsEncodedData = await endpointV2.defaultConfig( + defaultReceiveLibrary, + eid, + CONFIG_TYPE_INBOUND_CONFIRMATIONS + ) + const inboundBlockConfirmations = ethers.utils.defaultAbiCoder.decode(["uint64"], inboundBlockConfirmationsEncodedData) + + const verifiersEncodedData = await endpointV2.defaultConfig(defaultReceiveLibrary, eid, CONFIG_TYPE_VERIFIERS) + const verifiers = ethers.utils.defaultAbiCoder.decode(["address[]"], verifiersEncodedData) + + const optionalVerifierEncodedData = await endpointV2.defaultConfig(defaultReceiveLibrary, eid, CONFIG_TYPE_OPTIONAL_VERIFIERS) + const [optionalVerifiers, optionalVerifierThreshold] = await ethers.utils.defaultAbiCoder.decode( + ["uint8", "uint8"], + optionalVerifierEncodedData + ) return { network, - sendVersion, - receiveVersion, - inboundProofLibraryVersion: config.inboundProofLibraryVersion, - inboundBlockConfirmations: config.inboundBlockConfirmations.toNumber(), - relayer: config.relayer, - outboundProofType: config.outboundProofType, - outboundBlockConfirmations: config.outboundBlockConfirmations.toNumber(), - oracle: config.oracle, + defaultSendLibrary, + defaultReceiveLibrary, + maxMessageSize, + outboundConfirmations, + executor, + inboundBlockConfirmations, + verifiers, + optionalVerifiers, + optionalVerifierThreshold, } }) ) - console.table(configByNetwork) } + +task("getDefaultConfig", "outputs the default Send and Receive Messaging Library versions and the default application config") + .addParam("networks", "comma separated list of networks") + .setAction(action) diff --git a/packages/ua-utils/src/index.ts b/packages/ua-utils/src/index.ts index ce273379d..b35900460 100644 --- a/packages/ua-utils/src/index.ts +++ b/packages/ua-utils/src/index.ts @@ -1,63 +1,2 @@ -import { task, types } from "hardhat/config" -import wireAll from "./wireAll" -import setConfig from "./setConfig" import getDefaultConfig from "./getDefaultConfig" import getConfig from "./getConfig" -import checkWireAllConfig from "./checkWireAllConfig" - -task( - "setConfig", - "sets Send and Receive Messaging Library versions and a custom application config for contracts implementing ILayerZeroUserApplicationConfig interface", - setConfig -) - .addParam("configPath", "the application config file path") - .addOptionalParam( - "name", - "name of the deployed contracts. Should be specified if the same contract deployed on different chains and the deployment information is located in the deployments folder" - ) - .addOptionalParam("address", "address of the deployed contracts. Should be specified if the contract address is the same on all chains") - .addOptionalParam("gnosisConfigPath", "the path to a file with Gnosis config. If specified, the transactions will be sent to Gnosis") - .addOptionalParam("gasLimit", "override execution gasLimit") - -task( - "getDefaultConfig", - "outputs the default Send and Receive Messaging Library versions and the default application config", - getDefaultConfig -).addParam("networks", "comma separated list of networks") - -task("getConfig", "outputs the application's Send and Receive Messaging Library versions and the config for remote networks", getConfig) - .addParam("remoteNetworks", "comma separated list of remote networks") - .addOptionalParam( - "name", - "name of the deployed contract. Should be specified only if the deployment information is located in the deployments folder" - ) - .addOptionalParam("address", "the contract address") - -task("checkWireAllConfig", "", checkWireAllConfig) - .addParam("e", "the environment ie: mainnet, testnet or sandbox") - .addFlag("u", "show use custom adapter params") - .addFlag("t", "show trusted remote lookup") - .addFlag("m", "show min destination gas lookup") - .addParam("chains", "comma separated list of networks") - .addOptionalParam("contract", "name of contract") - .addOptionalParam("addresses", "addresses of contracts in same order as chains") - .addOptionalParam("proxyContract", "name of proxy contract") - .addOptionalParam("proxyChain", "name of proxy chain") - -task("wireAll", "", wireAll) - .addParam("e", "the environment ie: mainnet, testnet or sandbox") - .addOptionalParam("noPrompt", "no prompt", false, types.boolean) - .addOptionalParam( - "configPath", - "Optional config path. Default: ./constants/wireUpConfig.json", - "./constants/wireUpConfig.json", - types.string - ) - .addOptionalParam("n", "send to gnosis", false, types.boolean) - .addOptionalParam("gasLimit", "override execution gasLimit") - .addOptionalParam( - "gnosisConfigPath", - "Optional config path. Default: ./constants/gnosisConfig.json", - "./constants/gnosisConfig.json", - types.string - ) diff --git a/packages/ua-utils/src/utils/wireAllHelpers.ts b/packages/ua-utils/src/utils/wireAllHelpers.ts index 7d81ce005..55f862846 100644 --- a/packages/ua-utils/src/utils/wireAllHelpers.ts +++ b/packages/ua-utils/src/utils/wireAllHelpers.ts @@ -1,106 +1,6 @@ import { Transaction, getLayerZeroChainId, getContractInstance } from "./crossChainHelper" - -export async function setUseCustomAdapterParams( - hre: any, - localNetwork: string, - localContractNameOrAddress: string, - useCustom: boolean -): Promise { - const localContract = await getContractInstance(hre, localNetwork, localContractNameOrAddress) - const cur = await localContract.useCustomAdapterParams() - const needChange = cur !== useCustom - - // function setUseCustomAdapterParams(bool _useCustomAdapterParams) - const functionName = "setUseCustomAdapterParams" - const params = ["bool"] - const args = [useCustom] - - const tx: any = { - needChange, - chainId: getLayerZeroChainId(localNetwork), - contractName: localContractNameOrAddress, - functionName: functionName, - args: args, - calldata: localContract.interface.encodeFunctionData(functionName, args), - } - if (tx.needChange) { - tx.diff = JSON.stringify({ useCustomAdapterParams: { oldValue: cur, newValue: useCustom } }) - } - return [tx] -} - -export async function setMinDstGas( - hre: any, - localNetwork: string, - localContractNameOrAddress: string, - minDstGasConfig: any, - remoteChainId: string -): Promise { - const txns: Transaction[] = [] - const localContract = await getContractInstance(hre, localNetwork, localContractNameOrAddress) - const packetTypes = Object.keys(minDstGasConfig) - for (const packet of packetTypes) { - const packetType = parseInt(packet.at(-1) as string) - const minGas = minDstGasConfig[packet] - const cur = (await localContract.minDstGasLookup(remoteChainId, packetType)).toNumber() - const needChange = cur !== minGas - - // function setMinDstGas(uint16 _dstChainId, uint16 _packetType, uint _minGas) - const functionName = "setMinDstGas" - const params = ["uint16", "uint16", "uint256"] - const args = [remoteChainId, packetType, minGas] - - const tx: any = { - needChange, - chainId: getLayerZeroChainId(localNetwork), - contractName: localContractNameOrAddress, - functionName, - args: args, - calldata: localContract.interface.encodeFunctionData(functionName, args), - } - if (tx.needChange) { - tx.diff = JSON.stringify({ oldValue: cur, newValue: minGas }) - } - txns.push(tx) - } - return txns -} - -export async function setTrustedRemote( - hre: any, - localNetwork: string, - localContractNameOrAddress: string, - remoteNetwork: string, - remoteContractNameOrAddress: string -): Promise { - const localContract = await getContractInstance(hre, localNetwork, localContractNameOrAddress) - const remoteContract = await getContractInstance(hre, remoteNetwork, remoteContractNameOrAddress) - - const remoteContractAddress = await remoteContract.address - const desiredTrustedRemote = hre.ethers.utils.solidityPack(["bytes"], [remoteContractAddress + localContract.address.substring(2)]) - - const remoteChainId = getLayerZeroChainId(remoteNetwork) - const cur = await localContract.trustedRemoteLookup(remoteChainId) - const needChange = cur != desiredTrustedRemote - - // function setTrustedRemote(uint16 _srcChainId, bytes calldata _path) - const functionName = "setTrustedRemote" - const params = ["uint16", "bytes"] - const args = [remoteChainId, desiredTrustedRemote] - - const tx: any = { - needChange, - chainId: getLayerZeroChainId(localNetwork), - contractName: localContractNameOrAddress, - functionName: functionName, - args: args, - calldata: localContract.interface.encodeFunctionData(functionName, args), - } - if (tx.needChange) { - tx.diff = JSON.stringify({ trustedRemote: { oldValue: cur, newValue: desiredTrustedRemote } }) - } - return [tx] -} +import OAPP_ARTIFACT from "@layerzerolabs/lz-evm-sdk-v2/artifacts/contracts/OApp.sol/OApp.json" +import { ethers } from "ethers" export function getContractNameOrAddress(chain: string, WIRE_UP_CONFIG: any) { let contractNameOrAddress @@ -122,3 +22,16 @@ export function getContractNameOrAddress(chain: string, WIRE_UP_CONFIG: any) { } return contractNameOrAddress } + +export function getAndReturnContract(contractNameOrAddress: string, environment: any) { + if (ethers.utils.isAddress(contractNameOrAddress)) { + const oappFactory = ethers.getContractFactory(OAPP_ARTIFACT.abi) + return oappFactory.attach(contractNameOrAddress).connect(environment.provider) + } else { + return await environment.getContract(contractNameOrAddress, environment.provider) + } +} + +export function getOAppContract(chain: string, environment: any, WIRE_UP_CONFIG: any) { + return getAndReturnContract(getContractNameOrAddress(chain, WIRE_UP_CONFIG), environment) +} diff --git a/packages/ua-utils/src/wireAll.ts b/packages/ua-utils/src/wireAll.ts index 895cf46ee..f2458b72c 100644 --- a/packages/ua-utils/src/wireAll.ts +++ b/packages/ua-utils/src/wireAll.ts @@ -1,5 +1,6 @@ import { Transaction, NetworkTransactions, getContractInstance, getLayerZeroChainId, executeTransactions } from "./utils/crossChainHelper" import { configExist, getConfig, logError, printTransactions } from "./utils/helpers" +import { configExist, getConfig, logError, printTransactions } from "./utils/helpers" import { setUseCustomAdapterParams, setMinDstGas, setTrustedRemote, getContractNameOrAddress } from "./utils/wireAllHelpers" export default async function (taskArgs: any, hre: any) { @@ -19,6 +20,9 @@ export default async function (taskArgs: any, hre: any) { const WIRE_UP_CONFIG = getConfig(taskArgs.configPath) const localNetworks = Object.keys(WIRE_UP_CONFIG?.chainConfig) + const localNetwork = hre.network.name + const getEnvironment = createGetNetworkEnvironment(hre) + console.log(`************************************************`) console.log(`Computing diff`) console.log(`************************************************`) @@ -29,65 +33,32 @@ export default async function (taskArgs: any, hre: any) { const transactions: Transaction[] = [] const remoteNetworks = Object.keys(WIRE_UP_CONFIG?.chainConfig?.[localNetwork]?.remoteNetworkConfig) - const localContractNameOrAddress = getContractNameOrAddress(localNetwork, WIRE_UP_CONFIG) + const localEnvironment = await getEnvironment(localNetwork) + const localContract = getOAppContract(localNetwork, localEnvironment, WIRE_UP_CONFIG) if (localContractNameOrAddress === undefined) { logError(`Invalid wire up config for localContractNameOrAddress.`) return } - // check if useCustomAdapterParams needs to be set - const useCustomAdapterParams = WIRE_UP_CONFIG?.chainConfig?.[localNetwork]?.useCustomAdapterParams - if (useCustomAdapterParams !== undefined) { - transactions.push(...(await setUseCustomAdapterParams(hre, localNetwork, localContractNameOrAddress, useCustomAdapterParams))) - } - - // check if defaultFeeBp needs to be set - const defaultFeeBp = WIRE_UP_CONFIG?.chainConfig?.[localNetwork]?.defaultFeeBp - if (defaultFeeBp !== undefined) { - transactions.push(...(await setDefaultFeeBp(hre, localNetwork, localContractNameOrAddress, defaultFeeBp))) - } - await Promise.all( remoteNetworks.map(async (remoteNetwork) => { // skip wiring itself if (localNetwork === remoteNetwork) return - const proxyChain = WIRE_UP_CONFIG?.proxyContractConfig?.chain - const remoteContractNameOrAddress = getContractNameOrAddress(remoteNetwork, WIRE_UP_CONFIG) + const remoteEnvironment = await getEnvironment(remoteNetwork) + const remoteContract = getOAppContract(remoteNetwork, remoteEnvironment, WIRE_UP_CONFIG) if (remoteContractNameOrAddress === undefined) { logError(`Invalid wire up config for remoteContractNameOrAddress.`) return } - // setTrustedRemote - transactions.push( - ...(await setTrustedRemote(hre, localNetwork, localContractNameOrAddress, remoteNetwork, remoteContractNameOrAddress)) - ) - - // setFeeBp - if (WIRE_UP_CONFIG?.chainConfig?.[localNetwork]?.remoteNetworkConfig?.[remoteNetwork]?.feeBpConfig !== undefined) { - transactions.push( - ...(await setFeeBp( - hre, - localNetwork, - localContractNameOrAddress, - WIRE_UP_CONFIG?.chainConfig?.[localNetwork]?.remoteNetworkConfig?.[remoteNetwork].feeBpConfig, - getLayerZeroChainId(remoteNetwork) - )) - ) - } + // setPeer + transactions.push(...(await setPeer(localContract, remoteContract))) - // setMinDstGas - if (WIRE_UP_CONFIG?.chainConfig?.[localNetwork]?.remoteNetworkConfig?.[remoteNetwork]?.minDstGasConfig !== undefined) { - transactions.push( - ...(await setMinDstGas( - hre, - localNetwork, - localContractNameOrAddress, - WIRE_UP_CONFIG?.chainConfig?.[localNetwork]?.remoteNetworkConfig?.[remoteNetwork].minDstGasConfig, - getLayerZeroChainId(remoteNetwork) - )) - ) + // setEnforcedOptions + const enforcedOptions = WIRE_UP_CONFIG?.chainConfig?.[localNetwork]?.remoteNetworkConfig?.[remoteNetwork].enforcedOptions + if (enforcedOptions !== undefined) { + transactions.push(...(await setEnforcedOptions(localContract, remoteContract, enforcedOptions))) } }) ) @@ -112,66 +83,36 @@ export default async function (taskArgs: any, hre: any) { await executeTransactions(hre, taskArgs, transactionByNetwork) } -async function setDefaultFeeBp( - hre: any, - localNetwork: string, - localContractNameOrAddress: string, - defaultFeeBp: number -): Promise { - const localContract = await getContractInstance(hre, localNetwork, localContractNameOrAddress) - const cur = await localContract.defaultFeeBp() - const needChange = cur !== defaultFeeBp - - // function setDefaultFeeBp(uint16 _feeBp) - const functionName = "setDefaultFeeBp" - const params = ["uint16"] - const args = [defaultFeeBp] - - const tx: any = { - needChange, - chainId: getLayerZeroChainId(localNetwork), - contractName: localContractNameOrAddress, - functionName: functionName, - args: args, - calldata: localContract.interface.encodeFunctionData(functionName, args), - } - if (tx.needChange) { - tx.diff = JSON.stringify({ defaultFeeBp: { oldValue: cur, newValue: defaultFeeBp } }) - } - return [tx] +const setPeer = async (localOApp: any, remoteOApp: any): Promise => { + const oldPeer = await localOApp.peers(await remoteOApp.endpoint.eid()) + const newPeer = await remoteOApp.address + const needChange = oldPeer !== newPeer + const contractAddress = await localOApp.address + const functionName = localOApp.setPeer.selector + const args = [newPeer] + const calldata = localOApp.interface.encodeFunctionData(functionName, args) + const diff = needChange ? { oldValue: oldPeer, newValue: newPeer } : undefined + return [{ needChange, chainId, contractAddress, functionName, args, calldata, diff }] } -async function setFeeBp( - hre: any, - localNetwork: string, - localContractNameOrAddress: string, - feeBpConfig: any, - remoteChainId: string -): Promise { - const localContract = await getContractInstance(hre, localNetwork, localContractNameOrAddress) - const feeConfig = await localContract.chainIdToFeeBps(remoteChainId) - const curFeeBp = feeConfig[0] - const curEnabled = feeConfig[1] - const needChange = curFeeBp !== feeBpConfig.feeBp || curEnabled !== feeBpConfig.enabled - - // function setFeeBp(uint16 _dstChainId, bool _enabled, uint16 _feeBp) - const functionName = "setFeeBp" - const params = ["uint16", "bool", "uint16"] - const args = [remoteChainId, feeBpConfig.enabled, feeBpConfig.feeBp] - const calldata = localContract.interface.encodeFunctionData(functionName, args) - - const tx: any = { - needChange, - chainId: getLayerZeroChainId(localNetwork), - contractName: localContractNameOrAddress, - functionName: functionName, - args: args, - calldata: localContract.interface.encodeFunctionData(functionName, args), - } - if (tx.needChange) { - tx.diff = JSON.stringify({ - feeBp: { oldFeeBpValue: curFeeBp, newFeeBpValue: feeBpConfig.feeBp, oldEnabledFee: curEnabled, newEnabledFee: feeBpConfig.enabled }, - }) +const setEnforcedOptions = async (localOApp: any, remoteOApp: any, enforcedOptions: any): Promise => { + const contractAddress = await localOApp.address + const endpointId = await localOApp.endpoint.eid() + const txns: Transaction[] = [] + const packetTypes = Object.keys(enforcedOptions) + for (const packet of packetTypes) { + const packetType = parseInt(packet.at(-1) as string) + const minGas = enforcedOptions[packet] + const remoteChainId = await remoteOApp.endpoint.eid() + const encodedOptions = await localContract.enforcedOptions(remoteChainId, packetType) + const [version, curGas] = hre.ethers.utils.defaultAbiCoder.decode(["uint16", "uint256"], encodedOptions) + const needChange = curGas !== minGas + const functionName = localOApp.setEnforcedOptions.selector + const options = hre.ethers.utils.solidityPack(["uint16", "uint256"], [3, minGas]) + const args = [remoteChainId, packetType, options] + const calldata = localOApp.interface.encodeFunctionData(functionName, args) + const diff = needChange ? { oldValue: cur, newValue: minGas } : undefined + txns.push({ needChange, endpointId, contractAddress, functionName, args, calldata, diff }) } - return [tx] + return txns }