Skip to content

Commit

Permalink
🗞️ Adding getEnforcedOptions task (#369)
Browse files Browse the repository at this point in the history
  • Loading branch information
sirarthurmoney authored Feb 8, 2024
1 parent 092b4d6 commit b2670f8
Show file tree
Hide file tree
Showing 12 changed files with 680 additions and 5 deletions.
7 changes: 7 additions & 0 deletions .changeset/big-zoos-pretend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@layerzerolabs/ua-devtools-evm-hardhat-test": patch
"@layerzerolabs/ua-devtools-evm-hardhat": patch
"@layerzerolabs/ua-devtools": patch
---

Adding getEnforcedOptions task
1 change: 1 addition & 0 deletions packages/ua-devtools-evm-hardhat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@layerzerolabs/io-devtools": "~0.1.2",
"@layerzerolabs/lz-definitions": "~2.1.4",
"@layerzerolabs/lz-evm-messagelib-v2": "~2.1.4",
"@layerzerolabs/lz-v2-utilities": "~2.1.4",
"@layerzerolabs/protocol-devtools": "~0.1.3",
"@layerzerolabs/protocol-devtools-evm": "~0.1.3",
"@layerzerolabs/ua-devtools": "~0.1.5",
Expand Down
1 change: 1 addition & 0 deletions packages/ua-devtools-evm-hardhat/src/constants/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const TASK_LZ_OAPP_CONFIG_GET_DEFAULT = 'lz:oapp:config:get:default'
export const TASK_LZ_OAPP_CONFIG_GET_EXECUTOR = 'lz:oapp:config:get:executor'
export const TASK_LZ_OAPP_CONFIG_GET = 'lz:oapp:config:get'
export const TASK_LZ_OAPP_CONFIG_CHECK = 'lz:oapp:config:check'
export const TASK_LZ_OAPP_ENFORCED_OPTIONS_GET = 'lz:oapp:enforced:options:get'
export const TASK_LZ_OAPP_CONFIG_INIT = 'lz:oapp:config:init'

export const SUBTASK_LZ_OAPP_WIRE_CONFIGURE = '::lz:oapp:wire:configure'
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { ActionType } from 'hardhat/types'
import { task } from 'hardhat/config'
import { createLogger, printCrossTable, printRecord, setDefaultLogLevel } from '@layerzerolabs/io-devtools'
import { TASK_LZ_OAPP_ENFORCED_OPTIONS_GET } from '@/constants/tasks'
import { printLogo } from '@layerzerolabs/io-devtools/swag'
import { EncodedOption, OAppOmniGraph } from '@layerzerolabs/ua-devtools'
import { createConnectedContractFactory, types } from '@layerzerolabs/devtools-evm-hardhat'
import { createOAppFactory } from '@layerzerolabs/ua-devtools-evm'
import { checkOAppEnforcedOptions } from '@layerzerolabs/ua-devtools'
import { validateAndTransformOappConfig } from '@/utils/taskHelpers'
import { getNetworkNameForEid } from '@layerzerolabs/devtools-evm-hardhat'
import { areVectorsEqual, isZero } from '@layerzerolabs/devtools'
import { Options } from '@layerzerolabs/lz-v2-utilities'

interface TaskArgs {
oappConfig: string
logLevel?: string
}

export const enforcedOptionsGet: ActionType<TaskArgs> = async ({ oappConfig: oappConfigPath, logLevel = 'info' }) => {
printLogo()

// We'll set the global logging level to get as much info as needed
setDefaultLogLevel(logLevel)

// And we'll create a logger for ourselves
const logger = createLogger()
const graph: OAppOmniGraph = await validateAndTransformOappConfig(oappConfigPath, logger)

// need points for OApp Enforced Option Matrix
const points = graph.contracts
.map(({ point }) => point)
.map((point) => ({
...point,
networkName: getNetworkNameForEid(point.eid),
}))

// At this point we are ready read data from the OApp
const contractFactory = createConnectedContractFactory()
const oAppFactory = createOAppFactory(contractFactory)

try {
const enforcedOptions = await checkOAppEnforcedOptions(graph, oAppFactory)
const enforcedOptsNetworkMatrix = points.map((row) => {
/**
* for each point in the network (referred to as 'row'), create a row in the matrix
*/
const connectionsForCurrentRow = points.reduce((tableRow, column) => {
/**
* find a peer with a vector matching the connection from 'column' to 'row'
*/
const connection = enforcedOptions.find((peer) => {
return areVectorsEqual(peer.vector, { from: column, to: row })
})
/**
* update the row with a key-value pair indicating the enforced option for the current column
*/
const enforcedOptsByMsgType: Record<string, unknown> = {}
if (connection?.enforcedOptions) {
connection.enforcedOptions.forEach((encodedEnforcedOpts) => {
if (!isZero(encodedEnforcedOpts.options)) {
enforcedOptsByMsgType['msgType: ' + encodedEnforcedOpts.msgType] =
decodeEnforcedOptions(encodedEnforcedOpts)
}
})
}

return {
...tableRow,
[column.networkName]: printRecord(enforcedOptsByMsgType),
}
}, {})

/**
* return the row representing connections for the current 'row'
*/
return connectionsForCurrentRow
})

console.log(
printCrossTable(enforcedOptsNetworkMatrix, ['from → to', ...points.map(({ networkName }) => networkName)])
)

return enforcedOptions
} catch (error) {
throw new Error(`An error occurred while getting the OApp configuration: ${error}`)
}
}

task(TASK_LZ_OAPP_ENFORCED_OPTIONS_GET, 'Outputs table of OApp enforced options using layerzero.config')
.addParam('oappConfig', 'Path to your LayerZero OApp config', undefined, types.string)
.addParam('logLevel', 'Logging level. One of: error, warn, info, verbose, debug, silly', 'info', types.logLevel)
.setAction(enforcedOptionsGet)

/**
* Decodes enforced options from the provided encoded enforced options.
* @param {EncodedOption} option - The encoded options.
* @returns {Record<string, unknown>} - The decoded enforced options.
*/
function decodeEnforcedOptions(option: EncodedOption): Record<string, unknown> {
const fromOptions = Options.fromOptions(option.options)
const lzReceiveOption = fromOptions.decodeExecutorLzReceiveOption()
const lzNativeDropOption = fromOptions.decodeExecutorNativeDropOption()
const lzComposeOption = fromOptions.decodeExecutorComposeOption()
const lzOrderedExecutionOption = fromOptions.decodeExecutorOrderedExecutionOption()

return {
...(lzReceiveOption ? { lzReceiveOption } : {}),
...(lzNativeDropOption.length ? { lzNativeDropOption: headOrEverything(lzNativeDropOption) } : {}),
...(lzComposeOption.length ? { lzComposeOption: headOrEverything(lzComposeOption) } : {}),
...(lzOrderedExecutionOption ? { lzOrderedExecutionOption } : {}),
}
}

/**
* This is used for better readability in print tables
* If array has length 1, pop from array and return the object
* Else return the array
*/
const headOrEverything = <T>(array: T[]): T | T[] => (array.length === 1 ? array[0]! : array)
1 change: 1 addition & 0 deletions packages/ua-devtools-evm-hardhat/src/tasks/oapp/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import './config.check'
import './config.get.default'
import './config.get.executor'
import './config.get'
import './enforced.options.get'
import './config.init'
34 changes: 31 additions & 3 deletions packages/ua-devtools/src/oapp/check.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import { OAppFactory, OAppOmniGraph, OAppPeers } from '@/oapp/types'
import { EncodedOption, OAppEnforcedOptions, OAppFactory, OAppOmniGraph, OAppPeers } from '@/oapp/types'
import { ExecutorOptionType } from '@layerzerolabs/lz-v2-utilities'

export type OAppRead = (graph: OAppOmniGraph, createSdk: OAppFactory) => Promise<OAppPeers[]>
export type OAppReadPeers = (graph: OAppOmniGraph, createSdk: OAppFactory) => Promise<OAppPeers[]>
export type OAppReadEnforcedOptions = (graph: OAppOmniGraph, createSdk: OAppFactory) => Promise<OAppEnforcedOptions[]>

export const checkOAppPeers: OAppRead = async (graph, createSdk): Promise<OAppPeers[]> => {
const EnforcedOptions: ExecutorOptionType[] = [
ExecutorOptionType.LZ_RECEIVE,
ExecutorOptionType.NATIVE_DROP,
ExecutorOptionType.COMPOSE,
ExecutorOptionType.ORDERED,
]

export const checkOAppPeers: OAppReadPeers = async (graph, createSdk): Promise<OAppPeers[]> => {
return await Promise.all(
graph.connections.map(async ({ vector }): Promise<OAppPeers> => {
const sdk = await createSdk(vector.from)
Expand All @@ -11,3 +20,22 @@ export const checkOAppPeers: OAppRead = async (graph, createSdk): Promise<OAppPe
})
)
}

export const checkOAppEnforcedOptions: OAppReadEnforcedOptions = async (
graph,
createSdk
): Promise<OAppEnforcedOptions[]> => {
return await Promise.all(
graph.connections.map(async ({ vector }): Promise<OAppEnforcedOptions> => {
const enforcedOptionsRead: EncodedOption[] = []
const oappSdk = await createSdk(vector.from)
for (const enforcedOption of EnforcedOptions) {
enforcedOptionsRead.push({
msgType: enforcedOption,
options: await oappSdk.getEnforcedOptions(vector.to.eid, enforcedOption),
})
}
return { vector: vector, enforcedOptions: enforcedOptionsRead }
})
)
}
6 changes: 5 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit b2670f8

Please sign in to comment.