diff --git a/packages/omnicounter-utils-evm/.eslintignore b/packages/omnicounter-utils-evm/.eslintignore new file mode 100644 index 000000000..0f295f243 --- /dev/null +++ b/packages/omnicounter-utils-evm/.eslintignore @@ -0,0 +1,3 @@ +.turbo +dist +node_modules \ No newline at end of file diff --git a/packages/omnicounter-utils-evm/.eslintrc.json b/packages/omnicounter-utils-evm/.eslintrc.json new file mode 100644 index 000000000..be97c53fb --- /dev/null +++ b/packages/omnicounter-utils-evm/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "../../.eslintrc.json" +} diff --git a/packages/omnicounter-utils-evm/README.md b/packages/omnicounter-utils-evm/README.md new file mode 100644 index 000000000..82e40cd04 --- /dev/null +++ b/packages/omnicounter-utils-evm/README.md @@ -0,0 +1,23 @@ +

+ + LayerZero + +

+ +

@layerzerolabs/omnicounter-utils-evm

+ + +

+ + NPM Version + + Downloads + + NPM License +

+ +## Installation + +```sh +$ npm install @layerzerolabs/omnicounter-utils-evm +``` diff --git a/packages/omnicounter-utils-evm/jest.config.js b/packages/omnicounter-utils-evm/jest.config.js new file mode 100644 index 000000000..16148cfb1 --- /dev/null +++ b/packages/omnicounter-utils-evm/jest.config.js @@ -0,0 +1,8 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + moduleNameMapper: { + '^@/(.*)$': '/src/$1', + }, +}; diff --git a/packages/omnicounter-utils-evm/package.json b/packages/omnicounter-utils-evm/package.json new file mode 100644 index 000000000..ef12a2f3c --- /dev/null +++ b/packages/omnicounter-utils-evm/package.json @@ -0,0 +1,55 @@ +{ + "name": "@layerzerolabs/omnicounter-utils-evm", + "version": "0.0.1", + "private": true, + "description": "Utilities for working with LayerZero OmniCounter contract", + "repository": { + "type": "git", + "url": "git+https://github.com/LayerZero-Labs/lz-utils.git", + "directory": "packages/ua-utils-evm" + }, + "license": "MIT", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "require": "./dist/index.js", + "import": "./dist/index.mjs" + } + }, + "main": "dist/index.js", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", + "files": [ + "dist/" + ], + "scripts": { + "prebuild": "tsc -noEmit", + "build": "npx tsup", + "clean": "rm -rf dist", + "lint": "npx eslint '**/*.{js,ts,json}'", + "test": "jest --passWithNoTests" + }, + "devDependencies": { + "@layerzerolabs/lz-definitions": "~1.5.70", + "@layerzerolabs/omnicounter-utils": "~0.0.1", + "@layerzerolabs/ua-utils": "~0.1.0", + "@layerzerolabs/ua-utils-evm": "~0.0.1", + "@layerzerolabs/utils-evm": "~0.0.1", + "@types/jest": "^29.5.10", + "jest": "^29.7.0", + "ts-jest": "^29.1.1", + "ts-node": "^10.9.1", + "tslib": "~2.6.2", + "tsup": "~8.0.1", + "typescript": "^5.2.2", + "zod": "^3.22.4" + }, + "peerDependencies": { + "@layerzerolabs/lz-definitions": "~1.5.70", + "@layerzerolabs/omnicounter-utils": "~0.0.1", + "@layerzerolabs/ua-utils": "~0.1.0", + "@layerzerolabs/ua-utils-evm": "~0.0.1", + "@layerzerolabs/utils-evm": "~0.0.1", + "zod": "^3.22.4" + } +} diff --git a/packages/omnicounter-utils-evm/src/index.ts b/packages/omnicounter-utils-evm/src/index.ts new file mode 100644 index 000000000..6ab4b696d --- /dev/null +++ b/packages/omnicounter-utils-evm/src/index.ts @@ -0,0 +1 @@ +export * from './omnicounter' diff --git a/packages/omnicounter-utils-evm/src/omnicounter/index.ts b/packages/omnicounter-utils-evm/src/omnicounter/index.ts new file mode 100644 index 000000000..7db67b18a --- /dev/null +++ b/packages/omnicounter-utils-evm/src/omnicounter/index.ts @@ -0,0 +1 @@ +export * from './sdk' diff --git a/packages/omnicounter-utils-evm/src/omnicounter/sdk.ts b/packages/omnicounter-utils-evm/src/omnicounter/sdk.ts new file mode 100644 index 000000000..fb8aa5feb --- /dev/null +++ b/packages/omnicounter-utils-evm/src/omnicounter/sdk.ts @@ -0,0 +1,10 @@ +import { IOmniCounterApp } from '@layerzerolabs/omnicounter-utils' +import { OApp } from '@layerzerolabs/ua-utils-evm' +import { OmniTransaction } from '@layerzerolabs/utils' + +export class OmniCounterApp extends OApp implements IOmniCounterApp { + public async increment(eid: number, type: number, options: string): Promise { + const data = this.contract.contract.interface.encodeFunctionData('increment', [eid, type, options]) + return super.createTransaction(data) + } +} diff --git a/packages/omnicounter-utils-evm/tsconfig.json b/packages/omnicounter-utils-evm/tsconfig.json new file mode 100644 index 000000000..f083b2ecb --- /dev/null +++ b/packages/omnicounter-utils-evm/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "exclude": ["dist", "node_modules"], + "include": ["src", "test"], + "compilerOptions": { + "types": ["node", "jest"], + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/packages/omnicounter-utils-evm/tsup.config.ts b/packages/omnicounter-utils-evm/tsup.config.ts new file mode 100644 index 000000000..b0e373950 --- /dev/null +++ b/packages/omnicounter-utils-evm/tsup.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'tsup' + +export default defineConfig({ + entry: ['src/index.ts'], + outDir: './dist', + clean: true, + dts: true, + sourcemap: true, + splitting: false, + treeshake: true, + format: ['esm', 'cjs'], +}) diff --git a/packages/omnicounter-utils/.eslintignore b/packages/omnicounter-utils/.eslintignore new file mode 100644 index 000000000..0f295f243 --- /dev/null +++ b/packages/omnicounter-utils/.eslintignore @@ -0,0 +1,3 @@ +.turbo +dist +node_modules \ No newline at end of file diff --git a/packages/omnicounter-utils/.eslintrc.json b/packages/omnicounter-utils/.eslintrc.json new file mode 100644 index 000000000..be97c53fb --- /dev/null +++ b/packages/omnicounter-utils/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "../../.eslintrc.json" +} diff --git a/packages/omnicounter-utils/README.md b/packages/omnicounter-utils/README.md new file mode 100644 index 000000000..e4cafafd7 --- /dev/null +++ b/packages/omnicounter-utils/README.md @@ -0,0 +1,23 @@ +

+ + LayerZero + +

+ +

@layerzerolabs/omnicounter-utils

+ + +

+ + NPM Version + + Downloads + + NPM License +

+ +## Installation + +```sh +$ npm install @layerzerolabs/omnicounter-utils +``` diff --git a/packages/omnicounter-utils/jest.config.js b/packages/omnicounter-utils/jest.config.js new file mode 100644 index 000000000..16148cfb1 --- /dev/null +++ b/packages/omnicounter-utils/jest.config.js @@ -0,0 +1,8 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + moduleNameMapper: { + '^@/(.*)$': '/src/$1', + }, +}; diff --git a/packages/omnicounter-utils/package.json b/packages/omnicounter-utils/package.json new file mode 100644 index 000000000..608da103f --- /dev/null +++ b/packages/omnicounter-utils/package.json @@ -0,0 +1,50 @@ +{ + "name": "@layerzerolabs/omnicounter-utils", + "version": "0.0.1", + "private": true, + "description": "Utilities for working with LayerZero OmniCounter contract", + "repository": { + "type": "git", + "url": "git+https://github.com/LayerZero-Labs/lz-utils.git", + "directory": "packages/omnicounter-utils" + }, + "license": "MIT", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "require": "./dist/index.js", + "import": "./dist/index.mjs" + } + }, + "main": "dist/index.js", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", + "files": [ + "dist/", + "LICENSE" + ], + "scripts": { + "prebuild": "tsc -noEmit", + "build": "npx tsup", + "clean": "rm -rf dist", + "lint": "npx eslint '**/*.{js,ts,json}'", + "test": "jest --passWithNoTests" + }, + "devDependencies": { + "@layerzerolabs/lz-definitions": "~1.5.70", + "@layerzerolabs/utils": "~0.0.1", + "@types/jest": "^29.5.10", + "jest": "^29.7.0", + "ts-jest": "^29.1.1", + "ts-node": "^10.9.1", + "tslib": "~2.6.2", + "tsup": "~8.0.1", + "typescript": "^5.2.2", + "zod": "^3.22.4" + }, + "peerDependencies": { + "@layerzerolabs/lz-definitions": "~1.5.70", + "@layerzerolabs/utils": "~0.0.1", + "zod": "^3.22.4" + } +} diff --git a/packages/omnicounter-utils/src/index.ts b/packages/omnicounter-utils/src/index.ts new file mode 100644 index 000000000..04ee4a493 --- /dev/null +++ b/packages/omnicounter-utils/src/index.ts @@ -0,0 +1 @@ +export * from './omnicounter/types' diff --git a/packages/omnicounter-utils/src/omnicounter/types.ts b/packages/omnicounter-utils/src/omnicounter/types.ts new file mode 100644 index 000000000..ffea90f87 --- /dev/null +++ b/packages/omnicounter-utils/src/omnicounter/types.ts @@ -0,0 +1,6 @@ +import { OmniTransaction } from '@layerzerolabs/utils' +import { EndpointId } from '@layerzerolabs/lz-definitions' + +export interface IOmniCounterApp { + increment(eid: EndpointId, type: number, options: string): Promise +} diff --git a/packages/omnicounter-utils/tsconfig.json b/packages/omnicounter-utils/tsconfig.json new file mode 100644 index 000000000..f083b2ecb --- /dev/null +++ b/packages/omnicounter-utils/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "exclude": ["dist", "node_modules"], + "include": ["src", "test"], + "compilerOptions": { + "types": ["node", "jest"], + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/packages/omnicounter-utils/tsup.config.ts b/packages/omnicounter-utils/tsup.config.ts new file mode 100644 index 000000000..b0e373950 --- /dev/null +++ b/packages/omnicounter-utils/tsup.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'tsup' + +export default defineConfig({ + entry: ['src/index.ts'], + outDir: './dist', + clean: true, + dts: true, + sourcemap: true, + splitting: false, + treeshake: true, + format: ['esm', 'cjs'], +}) diff --git a/packages/ua-utils-evm-hardhat-test/contracts/DefaultOApp.sol b/packages/ua-utils-evm-hardhat-test/contracts/DefaultOApp.sol index 6dce66b71..c4293381a 100644 --- a/packages/ua-utils-evm-hardhat-test/contracts/DefaultOApp.sol +++ b/packages/ua-utils-evm-hardhat-test/contracts/DefaultOApp.sol @@ -1,10 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.22; -contract DefaultOApp { - mapping(uint256 => bytes32) public peers; +import { OmniCounter as OmniCounterImpl } from "@layerzerolabs/lz-evm-oapp-v2/contracts/examples/OmniCounter.sol"; - function setPeer(uint256 eid, bytes32 peer) external { - peers[eid] = peer; - } +contract DefaultOApp is OmniCounterImpl { + constructor(address _endpoint) OmniCounterImpl(_endpoint) {} } diff --git a/packages/ua-utils-evm-hardhat-test/deploy/001_bootstrap.ts b/packages/ua-utils-evm-hardhat-test/deploy/001_bootstrap.ts index 5869d9ebc..8a28e9373 100644 --- a/packages/ua-utils-evm-hardhat-test/deploy/001_bootstrap.ts +++ b/packages/ua-utils-evm-hardhat-test/deploy/001_bootstrap.ts @@ -1,6 +1,25 @@ import { type DeployFunction } from 'hardhat-deploy/types' import assert from 'assert' import { formatEid } from '@layerzerolabs/utils' +import { createConnectedContractFactory, createSignerFactory } from '@layerzerolabs/utils-evm-hardhat' + +const DEFAULT_NATIVE_DECIMALS_RATE = '18' //ethers.utils.parseUnits('1', 18).toString() + +const deleteEndpointDeployments = (deployments): Promise => + Promise.all( + [ + ['EndpointV2'], + ['SendUln302'], + ['ReceiveUln302'], + ['DefaultProxyAdmin', 'PriceFeed_Proxy', 'PriceFeed', 'PriceFeed_Implementation'], // delete all proxy contracts for PriceFeed + ['ExecutorFeeLib'], + ['Executor_Proxy', 'Executor_Implementation', 'Executor', 'ExecutorProxyAdmin'], // delete all proxy contracts for Executor + ['DVN'], + ['DVNFeeLib'], + ] + .flat() + .map((contractName) => deployments.delete(contractName)) + ) /** * This deploy function will deploy and configure LayerZero endpoint @@ -13,29 +32,123 @@ const deploy: DeployFunction = async ({ getUnnamedAccounts, deployments, network const [deployer] = await getUnnamedAccounts() assert(deployer, 'Missing deployer') - await deployments.delete('EndpointV2') + await deleteEndpointDeployments(deployments) + const endpointV2Deployment = await deployments.deploy('EndpointV2', { from: deployer, args: [network.config.eid], }) - await deployments.delete('SendUln302') const sendUln302 = await deployments.deploy('SendUln302', { from: deployer, args: [endpointV2Deployment.address, 0, 0], }) - await deployments.delete('ReceiveUln302') const receiveUln302 = await deployments.deploy('ReceiveUln302', { from: deployer, args: [endpointV2Deployment.address], }) + const priceFeed = await deployments.deploy('PriceFeed', { + from: deployer, + proxy: { + owner: deployer, + proxyContract: 'OptimizedTransparentProxy', + execute: { + init: { + methodName: 'initialize', + args: [deployer], + }, + }, + }, + }) + + const executorFeeLib = await deployments.deploy('ExecutorFeeLib', { + from: deployer, + args: [DEFAULT_NATIVE_DECIMALS_RATE], + }) + + const executor = await deployments.deploy('Executor', { + from: deployer, + log: true, + skipIfAlreadyDeployed: true, + proxy: { + owner: deployer, + proxyContract: 'OptimizedTransparentProxy', + viaAdminContract: { name: 'ExecutorProxyAdmin', artifact: 'ProxyAdmin' }, + execute: { + init: { + methodName: 'initialize', + args: [ + endpointV2Deployment.address, // _endpoint + receiveUln302.address, // _receiveUln301 + [sendUln302.address], // _messageLibs + priceFeed.address, // _priceFeed + deployer, // _roleAdmin + [deployer], // _admins + ], + }, + onUpgrade: { + methodName: 'onUpgrade', + args: [receiveUln302.address], + }, + }, + }, + }) + + const signerFactory = createSignerFactory() + const signer = await signerFactory(network.config.eid) // local network signer + const connectedContractFactory = createConnectedContractFactory() + + const executorContract = ( + await connectedContractFactory({ + eid: network.config.eid, + contractName: 'Executor', + }) + ).contract.connect(signer.signer) + executorContract.functions.setWorkerFeeLib && + (await executorContract.functions.setWorkerFeeLib(executorFeeLib.address, { + from: await signer.signer.getAddress(), + })) + + const dvn = await deployments.deploy('DVN', { + from: deployer, + args: [ + network.config.eid, // vid + [sendUln302.address], // messageLibs + priceFeed.address, // priceFeed + [deployer], // signers + 1, // quorum + [deployer], // admins + ], + }) + + const dvnFeeLib = await deployments.deploy('DVNFeeLib', { + from: deployer, + args: [DEFAULT_NATIVE_DECIMALS_RATE], + }) + + const dvnContract = ( + await connectedContractFactory({ + eid: network.config.eid, + contractName: 'DVN', + }) + ).contract.connect(signer.signer) + dvnContract.functions.setWorkerFeeLib && + (await dvnContract.functions.setWorkerFeeLib(dvnFeeLib.address, { + from: await signer.signer.getAddress(), + })) + console.table({ Network: `${network.name} (endpoint ${formatEid(network.config.eid)})`, EndpointV2: endpointV2Deployment.address, SendUln302: sendUln302.address, ReceiveUln302: receiveUln302.address, + PriceFeed: priceFeed.address, + Executor: executor.address, + ExecutorFeeLib: executorFeeLib.address, + DVN: dvn.address, + DVNFeeLib: dvnFeeLib.address, }) } diff --git a/packages/ua-utils-evm-hardhat-test/deploy/002_oapp.ts b/packages/ua-utils-evm-hardhat-test/deploy/002_oapp.ts index b56907807..53d6453eb 100644 --- a/packages/ua-utils-evm-hardhat-test/deploy/002_oapp.ts +++ b/packages/ua-utils-evm-hardhat-test/deploy/002_oapp.ts @@ -14,8 +14,10 @@ const deploy: DeployFunction = async ({ getUnnamedAccounts, deployments, network assert(deployer, 'Missing deployer') await deployments.delete('DefaultOApp') + const endpointV2 = await deployments.get('EndpointV2') const defaultOAppDeployment = await deployments.deploy('DefaultOApp', { from: deployer, + args: [endpointV2.address], }) console.table({ diff --git a/packages/ua-utils-evm-hardhat-test/package.json b/packages/ua-utils-evm-hardhat-test/package.json index e4bad95ab..c50bfdbf5 100644 --- a/packages/ua-utils-evm-hardhat-test/package.json +++ b/packages/ua-utils-evm-hardhat-test/package.json @@ -25,8 +25,11 @@ "@gnosis.pm/safe-service-client": "1.1.1", "@layerzerolabs/io-utils": "~0.0.1", "@layerzerolabs/lz-definitions": "~1.5.70", + "@layerzerolabs/lz-evm-oapp-v2": "~1.5.70", + "@layerzerolabs/lz-evm-protocol-v2": "~1.5.70", "@layerzerolabs/lz-evm-sdk-v1": "~1.5.70", "@layerzerolabs/lz-evm-sdk-v2": "~1.5.70", + "@layerzerolabs/lz-utility-v2": "~1.5.70", "@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/__utils__/endpoint.ts b/packages/ua-utils-evm-hardhat-test/test/__utils__/endpoint.ts index f54905017..7917328c5 100644 --- a/packages/ua-utils-evm-hardhat-test/test/__utils__/endpoint.ts +++ b/packages/ua-utils-evm-hardhat-test/test/__utils__/endpoint.ts @@ -25,20 +25,40 @@ import { formatOmniPoint } from '@layerzerolabs/utils' export const ethEndpoint = { eid: EndpointId.ETHEREUM_MAINNET, contractName: 'EndpointV2' } export const ethReceiveUln = { eid: EndpointId.ETHEREUM_MAINNET, contractName: 'ReceiveUln302' } export const ethSendUln = { eid: EndpointId.ETHEREUM_MAINNET, contractName: 'SendUln302' } +export const ethExecutor = { eid: EndpointId.ETHEREUM_MAINNET, contractName: 'Executor' } +export const ethDvn = { eid: EndpointId.ETHEREUM_MAINNET, contractName: 'DVN' } export const avaxEndpoint = { eid: EndpointId.AVALANCHE_MAINNET, contractName: 'EndpointV2' } export const avaxReceiveUln = { eid: EndpointId.AVALANCHE_MAINNET, contractName: 'ReceiveUln302' } export const avaxSendUln = { eid: EndpointId.AVALANCHE_MAINNET, contractName: 'SendUln302' } +export const avaxExecutor = { eid: EndpointId.AVALANCHE_MAINNET, contractName: 'Executor' } +export const avaxDvn = { eid: EndpointId.AVALANCHE_MAINNET, contractName: 'DVN' } -export const defaultExecutorConfig: Uln302ExecutorConfig = { - maxMessageSize: 10000, - executor: '0x0000000000000000000000000000000000000001', +export const MAX_MESSAGE_SIZE = 10000 // match on-chain value + +/** + * Helper function to generate the default Uln302ExecutorConfig for a given chain. + * + * @param executorAddress The local Executor address. + */ +export const getDefaultExecutorConfig = (executorAddress: string): Uln302ExecutorConfig => { + return { + maxMessageSize: MAX_MESSAGE_SIZE, + executor: executorAddress, + } } -export const defaultUlnConfig: Uln302UlnConfig = { - confirmations: BigInt(1), - requiredDVNs: ['0x0000000000000000000000000000000000000002', '0x0000000000000000000000000000000000000003'], - optionalDVNs: [], - optionalDVNThreshold: 0, +/** + * Helper function to generate the default Uln302UlnConfig for a given chain. + * + * @param dvnAddress The local DVN address. + */ +export const getDefaultUlnConfig = (dvnAddress: string): Uln302UlnConfig => { + return { + confirmations: BigInt(1), + requiredDVNs: [dvnAddress], + optionalDVNs: [], + optionalDVNThreshold: 0, + } } /** @@ -68,6 +88,13 @@ export const setupDefaultEndpoint = async (): Promise => { const avaxSendUlnPoint = omniContractToPoint(await contractFactory(avaxSendUln)) const ethReceiveUlnPoint = omniContractToPoint(await contractFactory(ethReceiveUln)) const avaxReceiveUlnPoint = omniContractToPoint(await contractFactory(avaxReceiveUln)) + const ethExecutorPoint = omniContractToPoint(await contractFactory(ethExecutor)) + const avaxExecutorPoint = omniContractToPoint(await contractFactory(avaxExecutor)) + const ethDvnPoint = omniContractToPoint(await contractFactory(ethDvn)) + const avaxDvnPoint = omniContractToPoint(await contractFactory(avaxDvn)) + + const ethUlnConfig: Uln302UlnConfig = getDefaultUlnConfig(ethDvnPoint.address) + const avaxUlnConfig: Uln302UlnConfig = getDefaultUlnConfig(avaxDvnPoint.address) // This is the graph for SendUln302 const sendUlnConfig: OmniGraphHardhat = { @@ -75,15 +102,19 @@ export const setupDefaultEndpoint = async (): Promise => { { contract: ethSendUln, config: { - defaultUlnConfigs: [[EndpointId.AVALANCHE_MAINNET, defaultUlnConfig]], - defaultExecutorConfigs: [[EndpointId.AVALANCHE_MAINNET, defaultExecutorConfig]], + defaultUlnConfigs: [[EndpointId.AVALANCHE_MAINNET, ethUlnConfig]], + defaultExecutorConfigs: [ + [EndpointId.AVALANCHE_MAINNET, getDefaultExecutorConfig(ethExecutorPoint.address)], + ], }, }, { contract: avaxSendUln, config: { - defaultUlnConfigs: [[EndpointId.ETHEREUM_MAINNET, defaultUlnConfig]], - defaultExecutorConfigs: [[EndpointId.ETHEREUM_MAINNET, defaultExecutorConfig]], + defaultUlnConfigs: [[EndpointId.ETHEREUM_MAINNET, avaxUlnConfig]], + defaultExecutorConfigs: [ + [EndpointId.ETHEREUM_MAINNET, getDefaultExecutorConfig(avaxExecutorPoint.address)], + ], }, }, ], @@ -96,14 +127,14 @@ export const setupDefaultEndpoint = async (): Promise => { { contract: ethReceiveUln, config: { - defaultUlnConfigs: [[EndpointId.AVALANCHE_MAINNET, defaultUlnConfig]], + defaultUlnConfigs: [[EndpointId.AVALANCHE_MAINNET, ethUlnConfig]], defaultExecutorConfigs: [], }, }, { contract: avaxReceiveUln, config: { - defaultUlnConfigs: [[EndpointId.ETHEREUM_MAINNET, defaultUlnConfig]], + defaultUlnConfigs: [[EndpointId.ETHEREUM_MAINNET, avaxUlnConfig]], defaultExecutorConfigs: [], }, }, diff --git a/packages/ua-utils-evm-hardhat-test/test/endpoint/config.test.ts b/packages/ua-utils-evm-hardhat-test/test/endpoint/config.test.ts index 73dc83694..4533a2b2b 100644 --- a/packages/ua-utils-evm-hardhat-test/test/endpoint/config.test.ts +++ b/packages/ua-utils-evm-hardhat-test/test/endpoint/config.test.ts @@ -3,16 +3,18 @@ import { createConnectedContractFactory } from '@layerzerolabs/utils-evm-hardhat import type { OmniPoint } from '@layerzerolabs/utils' import { omniContractToPoint } from '@layerzerolabs/utils-evm' import { EndpointId } from '@layerzerolabs/lz-definitions' -import { defaultUlnConfig, setupDefaultEndpoint } from '../__utils__/endpoint' +import { getDefaultUlnConfig, setupDefaultEndpoint } from '../__utils__/endpoint' import { Endpoint, Uln302 } from '@layerzerolabs/protocol-utils-evm' describe('endpoint/config', () => { const ethEndpoint = { eid: EndpointId.ETHEREUM_MAINNET, contractName: 'EndpointV2' } const ethReceiveUln = { eid: EndpointId.ETHEREUM_MAINNET, contractName: 'ReceiveUln302' } const ethSendUln = { eid: EndpointId.ETHEREUM_MAINNET, contractName: 'SendUln302' } + const ethDvn = { eid: EndpointId.ETHEREUM_MAINNET, contractName: 'DVN' } const avaxEndpoint = { eid: EndpointId.AVALANCHE_MAINNET, contractName: 'EndpointV2' } const avaxReceiveUln = { eid: EndpointId.AVALANCHE_MAINNET, contractName: 'ReceiveUln302' } const avaxSendUln = { eid: EndpointId.AVALANCHE_MAINNET, contractName: 'SendUln302' } + const avaxDvn = { eid: EndpointId.AVALANCHE_MAINNET, contractName: 'DVN' } beforeEach(async () => { await setupDefaultEndpoint() @@ -68,8 +70,11 @@ describe('endpoint/config', () => { const ethConfig = await ethSendUlnSdk.getUlnConfig(avaxSendUlnPoint.eid, avaxSendUlnPoint.address) const avaxConfig = await avaxSendUlnSdk.getUlnConfig(ethSendUlnPoint.eid, ethSendUlnPoint.address) - expect(ethConfig).toEqual(defaultUlnConfig) - expect(avaxConfig).toEqual(defaultUlnConfig) + const ethDvnPoint = omniContractToPoint(await connectedContractFactory(ethDvn)) + const avaxDvnPoint = omniContractToPoint(await connectedContractFactory(avaxDvn)) + + expect(ethConfig).toBe(getDefaultUlnConfig(ethDvnPoint.address)) + expect(avaxConfig).toBe(getDefaultUlnConfig(avaxDvnPoint.address)) }) }) }) diff --git a/packages/ua-utils-evm-hardhat-test/test/oapp/options.test.ts b/packages/ua-utils-evm-hardhat-test/test/oapp/options.test.ts new file mode 100644 index 000000000..a501f7f35 --- /dev/null +++ b/packages/ua-utils-evm-hardhat-test/test/oapp/options.test.ts @@ -0,0 +1,134 @@ +import { EndpointId } from '@layerzerolabs/lz-definitions' +import { OmniCounterApp } from '@layerzerolabs/omnicounter-utils-evm' +import { OmniPoint, OmniTransaction } from '@layerzerolabs/utils' +import { omniContractToPoint } from '@layerzerolabs/utils-evm' +import { + createConnectedContractFactory, + createContractFactory, + createSignerFactory, + OmniGraphBuilderHardhat, + OmniGraphHardhat, +} from '@layerzerolabs/utils-evm-hardhat' + +import { Options, optionsType1 } from '@layerzerolabs/lz-utility-v2' +import { avaxEndpoint, ethEndpoint, setupDefaultEndpoint } from '../__utils__/endpoint' +import { deployOApp } from '../__utils__/oapp' +import { configureOApp } from '@layerzerolabs/ua-utils' +import { parseEther } from 'ethers/lib/utils' +import { Endpoint } from '@layerzerolabs/protocol-utils-evm' + +describe('options', () => { + beforeEach(async () => { + await setupDefaultEndpoint() + await deployOApp() + }) + + it('should be tested', async () => { + const opt = Options.newOptions().addExecutorLzReceiveOption(100, 100) + expect(opt.toHex()).toEqual('0x0003010021010000000000000000000000000000006400000000000000000000000000000064') + }) + ;[ + { + it: 'addExecutorLzReceiveOption without amount', + options: { + gas: 10, + amount: 0, + }, + expected: '0x0003010011010000000000000000000000000000000a', + }, + { + it: 'addExecutorLzReceiveOption with 11 as amount', + options: { + gas: 10, + amount: 11, + }, + expected: '0x0003010021010000000000000000000000000000000a0000000000000000000000000000000b', + }, + ].forEach((test) => { + it(test.it, async () => { + const opt = Options.newOptions() + opt.addExecutorLzReceiveOption(test.options.gas, test.options.amount) + expect(opt.toHex()).toEqual(test.expected) + }) + }) + + const ethContract = { eid: EndpointId.ETHEREUM_MAINNET, contractName: 'DefaultOApp' } + const avaxContract = { eid: EndpointId.AVALANCHE_MAINNET, contractName: 'DefaultOApp' } + + // This is the OApp config that we want to use against our contracts + const config: OmniGraphHardhat = { + contracts: [ + { + contract: ethContract, + config: undefined, + }, + { + contract: avaxContract, + config: undefined, + }, + ], + connections: [ + { + from: ethContract, + to: avaxContract, + config: undefined, + }, + { + from: avaxContract, + to: ethContract, + config: undefined, + }, + ], + } + + it('increments', async () => { + const contractFactory = createContractFactory() + const connectedContractFactory = createConnectedContractFactory(contractFactory) + const sdkFactory = async (point: OmniPoint) => new OmniCounterApp(await connectedContractFactory(point)) + + const ethPoint = omniContractToPoint(await contractFactory(ethContract)) + const avaxPoint = omniContractToPoint(await contractFactory(avaxContract)) + + const builder = await OmniGraphBuilderHardhat.fromConfig(config) + await configureOApp(builder.graph, sdkFactory) + const signerFactory = createSignerFactory() + const ethSigner = await signerFactory(ethContract.eid) + const avaxSigner = await signerFactory(avaxContract.eid) + + const ethSdk = await sdkFactory(ethPoint) + const avaxSdk = await sdkFactory(avaxPoint) + { + const ethTransaction = { + ...(await ethSdk.setPeer(avaxPoint.eid, avaxPoint.address)), + gasLimit: '1000000', + } + const ethResponse = await ethSigner.signAndSend(ethTransaction) + const ethReceipt = await ethResponse.wait() + expect(ethReceipt.from).toEqual(await ethSigner.signer.getAddress()) + } + + { + const tx = { + ...(await avaxSdk.setPeer(ethEndpoint.eid, ethPoint.address)), + gasLimit: '1000000', + } + const ethResponse = await avaxSigner.signAndSend(tx) + await ethResponse.wait() + } + + const opt1 = Options.newOptions().addExecutorLzReceiveOption(200000) + const tx1: OmniTransaction = { + ...(await ethSdk.increment(avaxPoint.eid, 1, opt1.toHex())), + gasLimit: 2000001, + value: parseEther('1').toString(), + } + console.dir({ tx1 }, { depth: null }) + + const ethResponse = await ethSigner.signAndSend(tx1) + console.dir(ethResponse, { depth: null }) + const ethReceipt = await ethResponse.wait() + expect(ethReceipt.from).toEqual(await ethSigner.signer.getAddress()) + + console.dir(ethResponse, { depth: null }) + }) +}) diff --git a/packages/ua-utils-evm-hardhat-test/test/task/getDefaultConfig.test.ts b/packages/ua-utils-evm-hardhat-test/test/task/getDefaultConfig.test.ts index 59ae0006d..6d63518aa 100644 --- a/packages/ua-utils-evm-hardhat-test/test/task/getDefaultConfig.test.ts +++ b/packages/ua-utils-evm-hardhat-test/test/task/getDefaultConfig.test.ts @@ -1,7 +1,9 @@ -import { defaultExecutorConfig, defaultUlnConfig, setupDefaultEndpoint } from '../__utils__/endpoint' +import { describe } from 'mocha' +import { getDefaultExecutorConfig, getDefaultUlnConfig, setupDefaultEndpoint } from '../__utils__/endpoint' import { createContractFactory, getEidForNetworkName } from '@layerzerolabs/utils-evm-hardhat' import hre from 'hardhat' import { TASK_LZ_GET_DEFAULT_CONFIG } from '@layerzerolabs/ua-utils-evm-hardhat' +import { omniContractToPoint } from '@layerzerolabs/utils-evm' describe('task: getDefaultConfig', () => { beforeEach(async () => { @@ -20,12 +22,16 @@ describe('task: getDefaultConfig', () => { const sendUln302 = await contractFactory({ contractName: 'SendUln302', eid: localEid }) const receiveUln302 = await contractFactory({ contractName: 'ReceiveUln302', eid: localEid }) + const executor = await contractFactory({ contractName: 'Executor', eid: localEid }) + const executorPoint = await omniContractToPoint(executor) + const dvn = await contractFactory({ contractName: 'DVN', eid: localEid }) + const dvnPoint = await omniContractToPoint(dvn) expect(defaultConfig.defaultSendLibrary).toEqual(sendUln302.contract.address) expect(defaultConfig.defaultReceiveLibrary).toEqual(receiveUln302.contract.address) - expect(defaultConfig.sendExecutorConfig).toEqual(defaultExecutorConfig) - expect(defaultConfig.sendUlnConfig).toEqual(defaultUlnConfig) - expect(defaultConfig.receiveUlnConfig).toEqual(defaultUlnConfig) + expect(defaultConfig.sendExecutorConfig).toEqual(getDefaultExecutorConfig(executorPoint.address)) + expect(defaultConfig.sendUlnConfig).toEqual(getDefaultUlnConfig(dvnPoint.address)) + expect(defaultConfig.receiveUlnConfig).toEqual(getDefaultUlnConfig(dvnPoint.address)) } } }) diff --git a/packages/ua-utils-evm/src/oapp/sdk.ts b/packages/ua-utils-evm/src/oapp/sdk.ts index f919d9848..dbcdcfe77 100644 --- a/packages/ua-utils-evm/src/oapp/sdk.ts +++ b/packages/ua-utils-evm/src/oapp/sdk.ts @@ -16,7 +16,6 @@ export class OApp implements IOApp { async setPeer(eid: EndpointId, address: Bytes32 | Address | null | undefined): Promise { const data = this.contract.contract.interface.encodeFunctionData('setPeer', [eid, makeBytes32(address)]) - return this.createTransaction(data) } diff --git a/packages/utils-evm/package.json b/packages/utils-evm/package.json index 2ab707c15..2ccfd1a75 100644 --- a/packages/utils-evm/package.json +++ b/packages/utils-evm/package.json @@ -65,6 +65,7 @@ "@ethersproject/contracts": "^5.7.0", "@ethersproject/providers": "^5.7.0", "@layerzerolabs/lz-definitions": "~1.5.70", + "@layerzerolabs/ua-utils": "~0.1.0", "@layerzerolabs/utils": "~0.0.1", "zod": "^3.22.4" } diff --git a/packages/utils-evm/src/signer/sdk.ts b/packages/utils-evm/src/signer/sdk.ts index 444e0771b..48faf8a49 100644 --- a/packages/utils-evm/src/signer/sdk.ts +++ b/packages/utils-evm/src/signer/sdk.ts @@ -53,11 +53,9 @@ export class OmniSignerEVM implements OmniSigner { // from?: string, // nonce?: BigNumberish, - // gasLimit?: BigNumberish, // gasPrice?: BigNumberish, // data?: BytesLike, - // value?: BigNumberish, // chainId?: number // type?: number; @@ -67,8 +65,13 @@ export class OmniSignerEVM implements OmniSigner { // maxFeePerGas?: BigNumberish; return { + // mandatory to: transaction.point.address, data: transaction.data, + + // optional + ...(transaction.gasLimit && { gasLimit: transaction.gasLimit }), + ...(transaction.value && { value: transaction.value }), } } } diff --git a/packages/utils/src/transactions/types.ts b/packages/utils/src/transactions/types.ts index a89ad5ae7..6b1ed7a11 100644 --- a/packages/utils/src/transactions/types.ts +++ b/packages/utils/src/transactions/types.ts @@ -5,6 +5,8 @@ export interface OmniTransaction { point: OmniPoint data: string description?: string + gasLimit?: string | bigint | number + value?: string | bigint | number } export interface OmniTransactionResponse { diff --git a/yarn.lock b/yarn.lock index 39f8c6ef6..59b2ab9ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1673,6 +1673,13 @@ dependencies: tiny-invariant "^1.3.1" +"@layerzerolabs/lz-definitions@^1.5.71": + version "1.5.71" + resolved "https://registry.yarnpkg.com/@layerzerolabs/lz-definitions/-/lz-definitions-1.5.71.tgz#dc143d7569e5c9e8e4a16cf3b746d636784f56e3" + integrity sha512-xVuGDMxhctWYIxIDGj+Op+pYgLZ8NnxUvFjSg7frCy7P2bMGZ6lFhNOYiHQGKawP7+696RBpsZcNq3i9AMznHQ== + dependencies: + tiny-invariant "^1.3.1" + "@layerzerolabs/lz-evm-messagelib-v2@^1.5.70": version "1.5.70" resolved "https://registry.yarnpkg.com/@layerzerolabs/lz-evm-messagelib-v2/-/lz-evm-messagelib-v2-1.5.70.tgz#43164baaa747632676dd7378a5ff331a0cdbaf81" @@ -1710,6 +1717,17 @@ lodash "^4.17.21" solidity-bytes-utils "^0.8.0" +"@layerzerolabs/lz-evm-protocol-v2@~1.5.70": + version "1.5.71" + resolved "https://registry.yarnpkg.com/@layerzerolabs/lz-evm-protocol-v2/-/lz-evm-protocol-v2-1.5.71.tgz#26c7d077a60fc812baf8fae48a9348583df0679c" + integrity sha512-3tCCl1VnjGpdiRHJ99CJ589DB7ACk/mZXCjomdoTLd/UfWYAwhsgfFXCkIKNP01Ksm0RMnfWJ3+VNzv5CPnjnQ== + dependencies: + "@layerzerolabs/ops-plugin-core" "^1.5.71" + dotenv "^16.3.1" + ethers "^5.7.2" + lodash "^4.17.21" + zksync-web3 "^0.16.0" + "@layerzerolabs/lz-evm-sdk-v1@^1.5.70": version "1.5.71" resolved "https://registry.yarnpkg.com/@layerzerolabs/lz-evm-sdk-v1/-/lz-evm-sdk-v1-1.5.71.tgz#b6c89358c09e21e6931d47b1a8c8ce48b3dced0b" @@ -1728,7 +1746,7 @@ "@ethersproject/providers" "^5.7.0" ethers "^5.7.2" -"@layerzerolabs/lz-evm-sdk-v2@^1.5.70": +"@layerzerolabs/lz-evm-sdk-v2@^1.5.70", "@layerzerolabs/lz-evm-sdk-v2@^1.5.71": version "1.5.71" resolved "https://registry.yarnpkg.com/@layerzerolabs/lz-evm-sdk-v2/-/lz-evm-sdk-v2-1.5.71.tgz#8496638a43ecec9593989cb73346c98703c1de01" integrity sha512-S076L4kSuS1x3vfSdIe5y4hcf1QplTg/0hMJfSzoMD/epJEvFPy6h7bzIQ5JtusuuyE6qa3IqsVD+3s9k+eveQ== @@ -1771,6 +1789,34 @@ tree-kill "^1.2.2" winston "^3.11.0" +"@layerzerolabs/lz-utilities@^1.5.71": + version "1.5.71" + resolved "https://registry.yarnpkg.com/@layerzerolabs/lz-utilities/-/lz-utilities-1.5.71.tgz#3d14448177ea65cd180cca18b5eafec5d7350f90" + integrity sha512-M2kwQNJIa4YOV4gUPjwTGORonlajzGOk10+YSu2IheytgvuqH1AAyyfy+Ofme2GR+N+pCKf2r353/pZG35RnSA== + dependencies: + "@ethersproject/providers" "^5.7.0" + "@layerzerolabs/lz-definitions" "^1.5.71" + "@noble/hashes" "^1.3.2" + "@solana/web3.js" "^1.87.6" + aptos "^1.20.0" + bip39 "^3.1.0" + ed25519-hd-key "^1.3.0" + ethers "^5.7.2" + find-up "^5.0.0" + glob "^10.3.10" + tree-kill "^1.2.2" + winston "^3.11.0" + +"@layerzerolabs/lz-utility-v2@~1.5.70": + version "1.5.71" + resolved "https://registry.yarnpkg.com/@layerzerolabs/lz-utility-v2/-/lz-utility-v2-1.5.71.tgz#27a72ce1ec31e11350b2254c51dd8c887d6162e0" + integrity sha512-u5qQL+qRvMJ54McU3jC3m4D2/oRaeegLRLcTk10r8mksnMsmuEwkbfBfa6l/wvo6OZSO2O426X62EmLPIWjCoQ== + dependencies: + "@layerzerolabs/lz-evm-sdk-v2" "^1.5.71" + "@solana/web3.js" "^1.87.6" + ethers "^5.7.2" + tiny-invariant "^1.3.1" + "@layerzerolabs/ops-core@^1.5.70": version "1.5.70" resolved "https://registry.yarnpkg.com/@layerzerolabs/ops-core/-/ops-core-1.5.70.tgz#c2d7eac8cc86c220e13df0c667a917bfdabcef98" @@ -1791,6 +1837,24 @@ tiny-invariant "^1.3.1" ts-node "^10.9.1" +"@layerzerolabs/ops-core@^1.5.71": + version "1.5.71" + resolved "https://registry.yarnpkg.com/@layerzerolabs/ops-core/-/ops-core-1.5.71.tgz#5bb7b5b0faab4301e274e7bdf8a6796db2f5946f" + integrity sha512-jv55jYJaByPD7J3XnT3kMv1R97BGA8rtWxh7Z80F/Uf4p4YfQzdq2cwYpOqmrLf+rG2GGO5eNZo8FXE7lJFXdQ== + dependencies: + "@layerzerolabs/lz-definitions" "^1.5.71" + "@layerzerolabs/lz-utilities" "^1.5.71" + "@solana/web3.js" "^1.87.6" + aptos "^1.20.0" + bip39 "^3.1.0" + commander "^11.1.0" + ed25519-hd-key "^1.3.0" + ethers "^5.7.2" + find-up "^5.0.0" + lodash "^4.17.21" + stacktrace-parser "^0.1.10" + tiny-invariant "^1.3.1" + "@layerzerolabs/ops-plugin-core@^1.5.70": version "1.5.70" resolved "https://registry.yarnpkg.com/@layerzerolabs/ops-plugin-core/-/ops-plugin-core-1.5.70.tgz#e689bc6413f00222df8c2547e15da3806b2d5b16" @@ -1809,6 +1873,24 @@ papaparse "^5.4.1" winston "^3.11.0" +"@layerzerolabs/ops-plugin-core@^1.5.71": + version "1.5.71" + resolved "https://registry.yarnpkg.com/@layerzerolabs/ops-plugin-core/-/ops-plugin-core-1.5.71.tgz#30eee6205dd4c3520ae4b04229da8d3738729596" + integrity sha512-5jQTWckN0d+slxAAtKPP4QqSFtFYdWey7VLXjOzrPGZPKDbr4qiq6lZSDN1Fb/Z0I5M7Z3hwK8wvzxw2aebxgA== + dependencies: + "@inquirer/confirm" "^2.0.15" + "@inquirer/prompts" "^3.3.0" + "@layerzerolabs/lz-definitions" "^1.5.71" + "@layerzerolabs/lz-utilities" "^1.5.71" + "@layerzerolabs/ops-core" "^1.5.71" + "@solana/web3.js" "^1.87.6" + aptos "^1.20.0" + commander "^11.1.0" + ethers "^5.7.2" + lodash "^4.17.21" + papaparse "^5.4.1" + winston "^3.11.0" + "@layerzerolabs/prettier-config-next@^1.5.70": version "1.5.70" resolved "https://registry.yarnpkg.com/@layerzerolabs/prettier-config-next/-/prettier-config-next-1.5.70.tgz#a2309f21592d5e1d8ddd2509934fd4dcd3a2a333" @@ -5848,7 +5930,7 @@ ethereumjs-vm@^2.3.4: rustbn.js "~0.2.0" safe-buffer "^5.1.1" -ethers@^5.7.0, ethers@^5.7.1, ethers@^5.7.2: +ethers@^5.7.0, ethers@^5.7.1, ethers@^5.7.2, ethers@~5.7.0: version "5.7.2" resolved "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -12497,6 +12579,13 @@ zksync-web3@^0.14.3: resolved "https://registry.npmjs.org/zksync-web3/-/zksync-web3-0.14.3.tgz" integrity sha512-hT72th4AnqyLW1d5Jlv8N2B/qhEnl2NePK2A3org7tAa24niem/UAaHMkEvmWI3SF9waYUPtqAtjpf+yvQ9zvQ== +zksync-web3@^0.16.0: + version "0.16.0" + resolved "https://registry.yarnpkg.com/zksync-web3/-/zksync-web3-0.16.0.tgz#407b258e61923d104864cff284bb54dc8b6af753" + integrity sha512-ER/qDpuRkoHrqwi2f4RCP6HXCQP1KB9o7Ih2K7h+QzfCSyDRL0apPMT9LkVQspeIeqRoXhl+1tit3vQdDIGe4w== + dependencies: + ethers "~5.7.0" + zod@^3.22.4: version "3.22.4" resolved "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz"