Skip to content

Commit

Permalink
feat: options builder
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Goulding <[email protected]>
  • Loading branch information
ryandgoulding committed Dec 13, 2023
1 parent cf11969 commit ff3f51b
Show file tree
Hide file tree
Showing 6 changed files with 2,244 additions and 57 deletions.
8 changes: 8 additions & 0 deletions packages/ua-utils-evm-hardhat-test/contracts/OmniCounter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;

import { OmniCounter as OmniCounterImpl } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/examples/OmniCounter.sol";

contract OmniCounter is OmniCounterImpl {
constructor(address _endpoint, address _owner) OmniCounterImpl(_endpoint, _owner) {}
}
33 changes: 33 additions & 0 deletions packages/ua-utils-evm-hardhat-test/deploy/003_omnicounter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { formatEid } from '@layerzerolabs/utils'
import { type DeployFunction } from 'hardhat-deploy/types'
import assert from 'assert'

/**
* This deploy function will deploy and configure LayerZero OmniCounter
*
* @param env `HardhatRuntimeEnvironment`
*/
const deploy: DeployFunction = async ({ getUnnamedAccounts, deployments, network }) => {
assert(network.config.eid != null, `Missing endpoint ID for network ${network.name}`)

const [deployer] = await getUnnamedAccounts()
assert(deployer, 'Missing deployer')

await deployments.delete('OmniCounter')
const endpointV2 = await deployments.get('EndpointV2')
const omniCounterDeployment = await deployments.deploy('OmniCounter', {
contract: 'contracts/OmniCounter.sol:OmniCounter',
from: deployer,
args: [endpointV2.address, deployer],
})

console.table({
Network: `${network.name} (endpoint ${formatEid(network.config.eid)})`,
OmniCounter: omniCounterDeployment.address,
})
}

deploy.tags = ['OmniCounter']
deploy.dependencies = ['Bootstrap']

export default deploy
3 changes: 3 additions & 0 deletions packages/ua-utils-evm-hardhat-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -45,6 +47,7 @@
"hardhat": "^2.19.2",
"hardhat-deploy": "^0.11.43",
"jest": "^29.7.0",
"solidity-bytes-utils": "^0.8.0",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
Expand Down
21 changes: 21 additions & 0 deletions packages/ua-utils-evm-hardhat-test/test/__utils__/omnicounter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { EndpointId } from '@layerzerolabs/lz-definitions'
import { createNetworkEnvironmentFactory } from '@layerzerolabs/utils-evm-hardhat'

export const deployOmniCounter = async () => {
const environmentFactory = createNetworkEnvironmentFactory()
const eth = await environmentFactory(EndpointId.ETHEREUM_MAINNET)
const avax = await environmentFactory(EndpointId.AVALANCHE_MAINNET)

await Promise.all([
eth.deployments.run('OmniCounter', { writeDeploymentsToFiles: true }),
avax.deployments.run('OmniCounter', { writeDeploymentsToFiles: true }),
])
}

export const deployOmniCounterFixture = async () => {
const environmentFactory = createNetworkEnvironmentFactory()
const eth = await environmentFactory(EndpointId.ETHEREUM_MAINNET)
const avax = await environmentFactory(EndpointId.AVALANCHE_MAINNET)

await Promise.all([eth.deployments.fixture('OmniCounter'), avax.deployments.fixture('OmniCounter')])
}
128 changes: 128 additions & 0 deletions packages/ua-utils-evm-hardhat-test/test/omnicounter/options.test.ts
Original file line number Diff line number Diff line change
@@ -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[]

Check warning on line 118 in packages/ua-utils-evm-hardhat-test/test/omnicounter/options.test.ts

View workflow job for this annotation

GitHub Actions / Check code / Build, Lint & Test

Unexpected any. Specify a different type
).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())
}
})
)
})
})
Loading

0 comments on commit ff3f51b

Please sign in to comment.