From 431b7996e6951be97ccf6912d50ffa3dea83fde1 Mon Sep 17 00:00:00 2001 From: Ryan Goulding Date: Mon, 11 Dec 2023 13:06:30 -0800 Subject: [PATCH] feat: options builder Signed-off-by: Ryan Goulding --- .../ua-utils-evm-hardhat-test/package.json | 2 + .../test/omnicounter/options.test.ts | 128 ++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 packages/ua-utils-evm-hardhat-test/test/omnicounter/options.test.ts diff --git a/packages/ua-utils-evm-hardhat-test/package.json b/packages/ua-utils-evm-hardhat-test/package.json index d2b7b16f4..40fa31964 100644 --- a/packages/ua-utils-evm-hardhat-test/package.json +++ b/packages/ua-utils-evm-hardhat-test/package.json @@ -30,6 +30,8 @@ "@layerzerolabs/lz-evm-sdk-v1": "~1.5.72", "@layerzerolabs/lz-evm-sdk-v2": "~1.5.72", "@layerzerolabs/lz-utility-v2": "~1.5.72", + "@layerzerolabs/omnicounter-utils": "~0.0.1", + "@layerzerolabs/omnicounter-utils-evm": "~0.0.1", "@layerzerolabs/protocol-utils": "~0.0.1", "@layerzerolabs/protocol-utils-evm": "~0.0.1", "@layerzerolabs/toolbox-hardhat": "~0.0.1", diff --git a/packages/ua-utils-evm-hardhat-test/test/omnicounter/options.test.ts b/packages/ua-utils-evm-hardhat-test/test/omnicounter/options.test.ts new file mode 100644 index 000000000..20387805a --- /dev/null +++ b/packages/ua-utils-evm-hardhat-test/test/omnicounter/options.test.ts @@ -0,0 +1,128 @@ +import fc from 'fast-check' +import 'hardhat' +import { EventFragment } from '@ethersproject/abi/src.ts/fragments' +import { Log, TransactionReceipt } from '@ethersproject/providers' +import { EndpointId, MainnetEndpointId } from '@layerzerolabs/lz-definitions' +import { Options } from '@layerzerolabs/lz-utility-v2' +import { createOmniCounterFactory, OmniCounter } from '@layerzerolabs/omnicounter-utils-evm' +import { createEndpointFactory } from '@layerzerolabs/protocol-utils-evm' +import { configureOApp } from '@layerzerolabs/ua-utils' +import { OmniTransaction } from '@layerzerolabs/utils' +import { omniContractToPoint } from '@layerzerolabs/utils-evm' +import { + createConnectedContractFactory, + createSignerFactory, + OmniGraphBuilderHardhat, + OmniGraphHardhat, +} from '@layerzerolabs/utils-evm-hardhat' +import { utils } from 'ethers' +import { keccak256, parseEther, toUtf8Bytes } from 'ethers/lib/utils' +import { setupDefaultEndpoint } from '../__utils__/endpoint' +import { deployOmniCounter } from '../__utils__/omnicounter' + +/** + * Find matching emitted events. + * @param {TransactionReceipt} receipt + * @param {EventFragment} frag + * @param {string} contractAddress + * @returns {Log[]} + */ +const findMatchingEvents = (receipt: TransactionReceipt, frag: utils.EventFragment, contractAddress: string): Log[] => + receipt.logs + .filter((log) => log.topics.includes(keccak256(toUtf8Bytes(frag.format())))) + .filter( + (log) => + log.address && + (contractAddress === undefined || log.address.toLowerCase() === contractAddress.toLowerCase()) + ) + +/** + * Parse event logs. + * @param {Log} log + * @param {utils.Interface} context + */ +const parseArgs = (log: Log, context: utils.Interface): utils.Result => context.parseLog(log).args + +describe('oapp/options', () => { + const ethContract = { eid: EndpointId.ETHEREUM_MAINNET, contractName: 'OmniCounter' } + const avaxContract = { eid: EndpointId.AVALANCHE_MAINNET, contractName: 'OmniCounter' } + + const config: OmniGraphHardhat = { + contracts: [ + { + contract: ethContract, + }, + { + contract: avaxContract, + }, + ], + connections: [ + { + from: ethContract, + to: avaxContract, + }, + { + from: avaxContract, + to: ethContract, + }, + ], + } + + beforeEach(async () => { + await deployOmniCounter() + await setupDefaultEndpoint() + }) + + it('lzReceive option', async () => { + const contractFactory = createConnectedContractFactory() + const builder = await OmniGraphBuilderHardhat.fromConfig(config) + const sdkFactory = createOmniCounterFactory(contractFactory) + const signerFactory = createSignerFactory() + + const ethPoint = omniContractToPoint(await contractFactory(ethContract)) + const ethSdk: OmniCounter = await sdkFactory(ethPoint) + const ethSigner = await signerFactory(ethContract.eid) + + const avaxPoint = omniContractToPoint(await contractFactory(avaxContract)) + const avaxSdk = await sdkFactory(avaxPoint) + const avaxSigner = await signerFactory(avaxContract.eid) + + const transactions = await configureOApp(builder.graph, sdkFactory) + for (const transaction of transactions) { + const signer = transaction.point.eid === MainnetEndpointId.ETHEREUM_MAINNET ? ethSigner : avaxSigner + const txResponse = await signer.signAndSend(transaction) + const txReceipt: TransactionReceipt = await txResponse.wait() + expect(txReceipt.status).toBe(1) + } + + expect(await ethSdk.hasPeer(avaxPoint.eid, avaxPoint.address)).toBe(true) + expect(await avaxSdk.hasPeer(ethPoint.eid, ethPoint.address)).toBe(true) + + await fc.assert( + fc.asyncProperty(fc.integer({ min: 200000, max: 100000000000 }), async (p) => { + const options = Options.newOptions().addExecutorLzReceiveOption(p) + const incrementTx: OmniTransaction = { + ...(await ethSdk.increment(avaxPoint.eid, 2, options.toHex())), + gasLimit: 500000, + value: parseEther('0').toString(), + } + const incrementTxResponse = await ethSigner.signAndSend(incrementTx) + const incrementTxReceipt: TransactionReceipt = await incrementTxResponse.wait() + expect(incrementTxReceipt.status).toEqual(1) + + const ethEndpointContract = { eid: MainnetEndpointId.ETHEREUM_MAINNET, contractName: 'EndpointV2' } + const ethEndpointPoint = omniContractToPoint(await contractFactory(ethEndpointContract)) + const endpointSdkFactory = createEndpointFactory(contractFactory) + const ethEndpointSdk = await endpointSdkFactory(ethEndpointPoint) + const packetReceived = Object.values( + ethEndpointSdk.contract.contract.interface.events as any as EventFragment[] + ).find((frag: EventFragment) => frag.name === 'PacketSent') as EventFragment + const logs = findMatchingEvents(incrementTxReceipt, packetReceived, ethEndpointPoint.address) + if (logs && logs.length > 0) { + const eventArgs = parseArgs(logs[0]!, ethEndpointSdk.contract.contract.interface) + expect(eventArgs.options.toLowerCase() === options.toHex().toLowerCase()) + } + }) + ) + }) +})