From 8789236e996ab8fcab016ed46078eec67113c957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Jakub=20Nani=C5=A1ta?= Date: Mon, 29 Jan 2024 16:34:47 -0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=AA=9A=20Move=20bytes=20helpers=20to=20de?= =?UTF-8?q?vtools,=20add=20comparison=20utility=20(#300)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/kind-rings-worry.md | 12 + packages/build-lz-options/package.json | 1 + packages/build-lz-options/src/index.tsx | 2 +- .../build-lz-options/src/utilities/prompts.ts | 2 +- packages/devtools-evm/package.json | 2 - packages/devtools-evm/src/address.ts | 49 +--- packages/devtools-evm/test/address.test.ts | 165 +------------ packages/devtools/package.json | 3 + packages/devtools/src/common/bytes.ts | 66 +++++ packages/devtools/src/common/index.ts | 1 + packages/devtools/src/types.ts | 8 + packages/devtools/test/bytes.test.ts | 231 ++++++++++++++++++ .../src/omnicounter/sdk.ts | 4 +- .../protocol-devtools-evm/src/endpoint/sdk.ts | 22 +- .../protocol-devtools-evm/src/uln302/sdk.ts | 3 +- .../test/endpoint/sdk.test.ts | 3 +- .../protocol-devtools/src/endpoint/types.ts | 27 +- .../protocol-devtools/src/uln302/types.ts | 18 +- packages/ua-devtools-evm/src/oapp/sdk.ts | 18 +- .../ua-devtools-evm/test/oapp/sdk.test.ts | 4 +- packages/ua-devtools/src/oapp/types.ts | 9 +- pnpm-lock.yaml | 13 +- .../test/omnicounter/options.test.ts | 4 +- 23 files changed, 399 insertions(+), 268 deletions(-) create mode 100644 .changeset/kind-rings-worry.md create mode 100644 packages/devtools/src/common/bytes.ts create mode 100644 packages/devtools/test/bytes.test.ts diff --git a/.changeset/kind-rings-worry.md b/.changeset/kind-rings-worry.md new file mode 100644 index 000000000..222790f9c --- /dev/null +++ b/.changeset/kind-rings-worry.md @@ -0,0 +1,12 @@ +--- +"@layerzerolabs/omnicounter-devtools-evm": patch +"@layerzerolabs/protocol-devtools-evm": patch +"@layerzerolabs/protocol-devtools": patch +"build-lz-options": patch +"@layerzerolabs/ua-devtools-evm": patch +"@layerzerolabs/devtools-evm": patch +"@layerzerolabs/ua-devtools": patch +"@layerzerolabs/devtools": patch +--- + +Move bytes utilities to devtools diff --git a/packages/build-lz-options/package.json b/packages/build-lz-options/package.json index 3d2049f3f..8db69d3b1 100644 --- a/packages/build-lz-options/package.json +++ b/packages/build-lz-options/package.json @@ -32,6 +32,7 @@ "yoga-layout-prebuilt": "^1.10.0" }, "devDependencies": { + "@layerzerolabs/devtools": "~0.0.1", "@layerzerolabs/devtools-evm": "~0.0.6", "@layerzerolabs/io-devtools": "~0.0.5", "@layerzerolabs/lz-v2-utilities": "~2.0.25", diff --git a/packages/build-lz-options/src/index.tsx b/packages/build-lz-options/src/index.tsx index 9d595eb05..3d8d9a93a 100644 --- a/packages/build-lz-options/src/index.tsx +++ b/packages/build-lz-options/src/index.tsx @@ -1,4 +1,4 @@ -import { makeBytes32 } from "@layerzerolabs/devtools-evm"; +import { makeBytes32 } from "@layerzerolabs/devtools"; import { optionsType1, optionsType2 } from "@layerzerolabs/lz-v2-utilities"; import React from "react"; import { render } from "ink"; diff --git a/packages/build-lz-options/src/utilities/prompts.ts b/packages/build-lz-options/src/utilities/prompts.ts index 31b1db2d3..87b59045c 100644 --- a/packages/build-lz-options/src/utilities/prompts.ts +++ b/packages/build-lz-options/src/utilities/prompts.ts @@ -1,6 +1,6 @@ import { EXECUTOR_OPTION_TYPE, OPTION_TYPES, WORKER_TYPE } from '@/config' import { OptionType1Summary, OptionType2Summary } from '@/types' -import { makeBytes32 } from '@layerzerolabs/devtools-evm' +import { makeBytes32 } from '@layerzerolabs/devtools' import { ExecutorOptionType, Options, WorkerId } from '@layerzerolabs/lz-v2-utilities' import prompts, { PromptObject } from 'prompts' import { handlePromptState, promptToContinue } from '@layerzerolabs/io-devtools' diff --git a/packages/devtools-evm/package.json b/packages/devtools-evm/package.json index 5c7956c34..9982e43a7 100644 --- a/packages/devtools-evm/package.json +++ b/packages/devtools-evm/package.json @@ -42,7 +42,6 @@ "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", "@ethersproject/constants": "^5.7.0", "@ethersproject/contracts": "^5.7.0", "@ethersproject/providers": "^5.7.2", @@ -66,7 +65,6 @@ "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", "@ethersproject/constants": "^5.7.0", "@ethersproject/contracts": "^5.7.0", "@ethersproject/providers": "^5.7.0", diff --git a/packages/devtools-evm/src/address.ts b/packages/devtools-evm/src/address.ts index d371b8b72..4b33bb7c9 100644 --- a/packages/devtools-evm/src/address.ts +++ b/packages/devtools-evm/src/address.ts @@ -1,53 +1,6 @@ -import type { Address, Bytes32 } from '@layerzerolabs/devtools' -import { hexZeroPad } from '@ethersproject/bytes' +import type { Address } from '@layerzerolabs/devtools' import { AddressZero } from '@ethersproject/constants' -/** - * Converts an address into Bytes32 by padding it with zeros. - * - * It will return zero bytes if passed `null`, `undefined` or an empty string. - * - * @param {Bytes32 | Address | null | undefined} address - * @returns {string} - */ -export const makeBytes32 = (address?: Bytes32 | Address | null | undefined): Bytes32 => hexZeroPad(address || '0x0', 32) - -/** - * Compares two Bytes32-like values by value (i.e. ignores casing on strings - * and string length) - * - * @param {Bytes32 | Address | null | undefined} a - * @param {Bytes32 | Address | null | undefined} b - * @returns {boolean} - */ -export const areBytes32Equal = ( - a: Bytes32 | Address | null | undefined, - b: Bytes32 | Address | null | undefined -): boolean => BigInt(makeBytes32(a)) === BigInt(makeBytes32(b)) - -/** - * Checks whether a value is a zero value. - * - * It will return true if passed `null`, `undefined`, empty bytes ('0x') or an empty string. - * - * It will throw an error if the value is not a valid numerical value. - * - * @param {Bytes32 | Address | null | undefined} value - * @returns {boolean} - */ -export const isZero = (value: Bytes32 | Address | null | undefined): boolean => - value === '0x' || BigInt(value || 0) === BigInt(0) - -/** - * Turns a potentially zero address into undefined - * - * @param {Bytes32 | Address | null | undefined} address - * - * @returns {string | undefined} - */ -export const ignoreZero = (value?: Bytes32 | Address | null | undefined): string | undefined => - isZero(value) ? undefined : value ?? undefined - /** * Turns a nullish value (`null` or `undefined`) into a zero address * diff --git a/packages/devtools-evm/test/address.test.ts b/packages/devtools-evm/test/address.test.ts index eb0017e0f..36fca1ab9 100644 --- a/packages/devtools-evm/test/address.test.ts +++ b/packages/devtools-evm/test/address.test.ts @@ -1,170 +1,9 @@ import fc from 'fast-check' import { AddressZero } from '@ethersproject/constants' -import { evmAddressArbitrary, evmBytes32Arbitrary } from '@layerzerolabs/test-devtools' -import { areBytes32Equal, ignoreZero, isZero, makeBytes32, makeZeroAddress } from '@/address' +import { evmAddressArbitrary } from '@layerzerolabs/test-devtools' +import { makeZeroAddress } from '@/address' describe('address', () => { - const ZERO_BYTES = '0x0000000000000000000000000000000000000000000000000000000000000000' - - describe('makeBytes32', () => { - it('should return zero value with empty bytes32', () => { - expect(makeBytes32(ZERO_BYTES)).toBe(ZERO_BYTES) - }) - - it('should return zero value with empty string', () => { - expect(makeBytes32('')).toBe(ZERO_BYTES) - }) - - it('should return zero value with zero address', () => { - expect(makeBytes32(AddressZero)).toBe(ZERO_BYTES) - }) - - it('should return zero value with undefined', () => { - expect(makeBytes32(undefined)).toBe(ZERO_BYTES) - }) - - it('should return zero value with null', () => { - expect(makeBytes32(null)).toBe(ZERO_BYTES) - }) - - it('should return zero value with empty bytes', () => { - expect(makeBytes32('0x')).toBe(ZERO_BYTES) - }) - - it('should return padded values for address', () => { - fc.assert( - fc.property(evmAddressArbitrary, (address) => { - const bytes = makeBytes32(address) - - expect(bytes.length).toBe(66) - expect(BigInt(bytes)).toBe(BigInt(address)) - }) - ) - }) - - it('should return identity for bytes32', () => { - fc.assert( - fc.property(evmBytes32Arbitrary, (bytes) => { - expect(makeBytes32(bytes)).toBe(bytes) - }) - ) - }) - }) - - describe('areBytes32Equal', () => { - const zeroishBytes32Arbitrary = fc.constantFrom(null, undefined, '0x', '0x0', makeZeroAddress(), ZERO_BYTES) - - it('should return true for two nullish values', () => { - fc.assert( - fc.property(zeroishBytes32Arbitrary, zeroishBytes32Arbitrary, (a, b) => { - expect(areBytes32Equal(a, b)).toBe(true) - }) - ) - }) - - it('should return true for two identical values', () => { - fc.assert( - fc.property(evmBytes32Arbitrary, (a) => { - expect(areBytes32Equal(a, a)).toBe(true) - }) - ) - }) - - it('should return true for an address and bytes', () => { - fc.assert( - fc.property(evmAddressArbitrary, (address) => { - expect(areBytes32Equal(address, makeBytes32(address))).toBe(true) - }) - ) - }) - - it('should return false for a zeroish value and a non-zeroish address', () => { - fc.assert( - fc.property(zeroishBytes32Arbitrary, evmAddressArbitrary, (bytes, address) => { - fc.pre(!isZero(address)) - - expect(areBytes32Equal(bytes, address)).toBe(false) - }) - ) - }) - - it('should return false for a zeroish value and a non-zeroish bytes', () => { - fc.assert( - fc.property(zeroishBytes32Arbitrary, evmBytes32Arbitrary, (a, b) => { - fc.pre(!isZero(b)) - - expect(areBytes32Equal(a, b)).toBe(false) - }) - ) - }) - }) - - describe('isZero', () => { - it('should return true with zero bytes32', () => { - expect(isZero(makeBytes32(AddressZero))).toBe(true) - }) - - it('should return true with zero bytes32 string', () => { - expect(isZero('0x')).toBe(true) - }) - - it('should return true with zero address', () => { - expect(isZero(AddressZero)).toBe(true) - }) - - it('should return true with undefined', () => { - expect(isZero(undefined)).toBe(true) - }) - - it('should return true with null', () => { - expect(isZero(null)).toBe(true) - }) - - it('should return false with non-zero address', () => { - fc.assert( - fc.property(evmAddressArbitrary, (address) => { - fc.pre(address !== AddressZero) - - expect(isZero(address)).toBe(false) - }) - ) - }) - - it('should return false with non-zero bytes32', () => { - fc.assert( - fc.property(evmBytes32Arbitrary, (address) => { - fc.pre(address !== ZERO_BYTES) - - expect(isZero(address)).toBe(false) - }) - ) - }) - }) - - describe('ignoreZero', () => { - it('should return address with non-zero address', () => { - fc.assert( - fc.property(evmAddressArbitrary, (address) => { - fc.pre(address !== AddressZero) - - expect(ignoreZero(address)).toBe(address) - }) - ) - }) - - it('should return undefined with zero address', () => { - expect(ignoreZero(AddressZero)).toBe(undefined) - }) - - it('should return undefined with undefined', () => { - expect(ignoreZero(undefined)).toBe(undefined) - }) - - it('should return undefined with null', () => { - expect(ignoreZero(null)).toBe(undefined) - }) - }) - describe('makeZeroAddress', () => { it('should return address with non-zero address', () => { fc.assert( diff --git a/packages/devtools/package.json b/packages/devtools/package.json index fddc4f4b3..efaa6a294 100644 --- a/packages/devtools/package.json +++ b/packages/devtools/package.json @@ -30,6 +30,8 @@ "test": "jest --ci --forceExit" }, "devDependencies": { + "@ethersproject/bytes": "~5.7.0", + "@ethersproject/constants": "~5.7.0", "@layerzerolabs/io-devtools": "~0.0.5", "@layerzerolabs/lz-definitions": "~2.0.25", "@layerzerolabs/test-devtools": "~0.0.5", @@ -46,6 +48,7 @@ "zod": "^3.22.4" }, "peerDependencies": { + "@ethersproject/bytes": "~5.7.0", "@layerzerolabs/io-devtools": "~0.0.4", "@layerzerolabs/lz-definitions": "~2.0.25", "zod": "^3.22.4" diff --git a/packages/devtools/src/common/bytes.ts b/packages/devtools/src/common/bytes.ts new file mode 100644 index 000000000..76fedc3c8 --- /dev/null +++ b/packages/devtools/src/common/bytes.ts @@ -0,0 +1,66 @@ +import type { PossiblyBigInt, PossiblyBytes } from '@/types' +import { hexZeroPad } from '@ethersproject/bytes' + +/** + * Converts an address into Bytes32 by padding it with zeros. + * + * It will return zero bytes if passed `null`, `undefined` or an empty string. + * + * @param {PossiblyBytes | null | undefined} address + * @returns {string} + */ +export const makeBytes32 = (address?: PossiblyBytes | null | undefined): PossiblyBytes => + hexZeroPad(address || '0x0', 32) + +/** + * Compares two Bytes32-like values by value (i.e. ignores casing on strings + * and string length) + * + * @param {PossiblyBytes | null | undefined} a + * @param {PossiblyBytes | null | undefined} b + * @returns {boolean} + */ +export const areBytes32Equal = (a: PossiblyBytes | null | undefined, b: PossiblyBytes | null | undefined): boolean => + BigInt(makeBytes32(a)) === BigInt(makeBytes32(b)) + +/** + * Checks whether a value is a zero value. + * + * It will return true if passed `null`, `undefined`, empty bytes ('0x') or an empty string. + * + * It will throw an error if the value is not a valid numerical value. + * + * @param {PossiblyBytes | PossiblyBigInt | null | undefined} value + * @returns {boolean} + */ +export const isZero = (value: PossiblyBytes | PossiblyBigInt | null | undefined): boolean => + value === '0x' || BigInt(value || 0) === BigInt(0) + +/** + * Turns a potentially zero address into undefined + * + * @param {PossiblyBytes | PossiblyBigInt | null | undefined} address + * + * @returns {string | undefined} + */ +export const ignoreZero = (value?: T | null | undefined): T | undefined => + isZero(value) ? undefined : value ?? undefined + +/** + * Helper function to be used when sorting of addresses is necessary. + * + * This can be used to sort arrays of addresses in ascending manner: + * + * ``` + * // The result will be ["0x000000000000000000636F6e736F6c652e6c6f67", "0xEe6cF2E1Bc7645F8439d241ce37820305F2BB3F8"] + * ["0xEe6cF2E1Bc7645F8439d241ce37820305F2BB3F8", "0x000000000000000000636F6e736F6c652e6c6f67"].sort(compareBytes32Ascending) + * ``` + * + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare} + * + * @param {PossiblyBytes} a + * @param {PossiblyBytes} b + * @returns {number} `0` when the two are interchangeable, a negative value when `a` comes before `b` and a positive value when `a` comes after `b` + */ +export const compareBytes32Ascending = (a: PossiblyBytes, b: PossiblyBytes): number => + Number(BigInt(makeBytes32(a)) - BigInt(makeBytes32(b))) diff --git a/packages/devtools/src/common/index.ts b/packages/devtools/src/common/index.ts index 27be9e943..6d31f61a9 100644 --- a/packages/devtools/src/common/index.ts +++ b/packages/devtools/src/common/index.ts @@ -1,2 +1,3 @@ export * from './assertion' +export * from './bytes' export * from './promise' diff --git a/packages/devtools/src/types.ts b/packages/devtools/src/types.ts index aae0f6e55..e1785e6a1 100644 --- a/packages/devtools/src/types.ts +++ b/packages/devtools/src/types.ts @@ -4,6 +4,14 @@ export type Address = string export type Bytes32 = string +export type Bytes = string + +export type PossiblyBigInt = string | number | bigint + +export type OmniAddress = Bytes32 | Address + +export type PossiblyBytes = Bytes | Bytes32 | Address + /** * Generic type for a hybrid (sync / async) factory * that generates an instance of `TOutput` based on arguments of type `TInput` diff --git a/packages/devtools/test/bytes.test.ts b/packages/devtools/test/bytes.test.ts new file mode 100644 index 000000000..d17023bc0 --- /dev/null +++ b/packages/devtools/test/bytes.test.ts @@ -0,0 +1,231 @@ +import fc from 'fast-check' +import { AddressZero } from '@ethersproject/constants' +import { evmAddressArbitrary, evmBytes32Arbitrary } from '@layerzerolabs/test-devtools' +import { areBytes32Equal, compareBytes32Ascending, ignoreZero, isZero, makeBytes32 } from '@/common/bytes' + +describe('bytes', () => { + const ZERO_BYTES = '0x0000000000000000000000000000000000000000000000000000000000000000' + + describe('makeBytes32', () => { + it('should return zero value with empty bytes32', () => { + expect(makeBytes32(ZERO_BYTES)).toBe(ZERO_BYTES) + }) + + it('should return zero value with empty string', () => { + expect(makeBytes32('')).toBe(ZERO_BYTES) + }) + + it('should return zero value with zero address', () => { + expect(makeBytes32(AddressZero)).toBe(ZERO_BYTES) + }) + + it('should return zero value with undefined', () => { + expect(makeBytes32(undefined)).toBe(ZERO_BYTES) + }) + + it('should return zero value with null', () => { + expect(makeBytes32(null)).toBe(ZERO_BYTES) + }) + + it('should return zero value with empty bytes', () => { + expect(makeBytes32('0x')).toBe(ZERO_BYTES) + }) + + it('should return padded values for address', () => { + fc.assert( + fc.property(evmAddressArbitrary, (address) => { + const bytes = makeBytes32(address) + + expect(bytes.length).toBe(66) + expect(BigInt(bytes)).toBe(BigInt(address)) + }) + ) + }) + + it('should return identity for bytes32', () => { + fc.assert( + fc.property(evmBytes32Arbitrary, (bytes) => { + expect(makeBytes32(bytes)).toBe(bytes) + }) + ) + }) + }) + + describe('areBytes32Equal', () => { + const zeroishBytes32Arbitrary = fc.constantFrom(null, undefined, '0x', '0x0', AddressZero, ZERO_BYTES) + + it('should return true for two nullish values', () => { + fc.assert( + fc.property(zeroishBytes32Arbitrary, zeroishBytes32Arbitrary, (a, b) => { + expect(areBytes32Equal(a, b)).toBe(true) + }) + ) + }) + + it('should return true for two identical values', () => { + fc.assert( + fc.property(evmBytes32Arbitrary, (a) => { + expect(areBytes32Equal(a, a)).toBe(true) + }) + ) + }) + + it('should return true for an address and bytes', () => { + fc.assert( + fc.property(evmAddressArbitrary, (address) => { + expect(areBytes32Equal(address, makeBytes32(address))).toBe(true) + }) + ) + }) + + it('should return false for a zeroish value and a non-zeroish address', () => { + fc.assert( + fc.property(zeroishBytes32Arbitrary, evmAddressArbitrary, (bytes, address) => { + fc.pre(!isZero(address)) + + expect(areBytes32Equal(bytes, address)).toBe(false) + }) + ) + }) + + it('should return false for a zeroish value and a non-zeroish bytes', () => { + fc.assert( + fc.property(zeroishBytes32Arbitrary, evmBytes32Arbitrary, (a, b) => { + fc.pre(!isZero(b)) + + expect(areBytes32Equal(a, b)).toBe(false) + }) + ) + }) + }) + + describe('isZero', () => { + it('should return true with zero bytes32', () => { + expect(isZero(makeBytes32(AddressZero))).toBe(true) + }) + + it('should return true with zero bytes32 string', () => { + expect(isZero('0x')).toBe(true) + }) + + it('should return true with zero address', () => { + expect(isZero(AddressZero)).toBe(true) + }) + + it('should return true with undefined', () => { + expect(isZero(undefined)).toBe(true) + }) + + it('should return true with null', () => { + expect(isZero(null)).toBe(true) + }) + + it('should return false with non-zero address', () => { + fc.assert( + fc.property(evmAddressArbitrary, (address) => { + fc.pre(address !== AddressZero) + + expect(isZero(address)).toBe(false) + }) + ) + }) + + it('should return false with non-zero bytes32', () => { + fc.assert( + fc.property(evmBytes32Arbitrary, (address) => { + fc.pre(address !== ZERO_BYTES) + + expect(isZero(address)).toBe(false) + }) + ) + }) + }) + + describe('ignoreZero', () => { + it('should return address with non-zero address', () => { + fc.assert( + fc.property(evmAddressArbitrary, (address) => { + fc.pre(address !== AddressZero) + + expect(ignoreZero(address)).toBe(address) + }) + ) + }) + + it('should return undefined with zero address', () => { + expect(ignoreZero(AddressZero)).toBe(undefined) + }) + + it('should return undefined with undefined', () => { + expect(ignoreZero(undefined)).toBe(undefined) + }) + + it('should return undefined with null', () => { + expect(ignoreZero(null)).toBe(undefined) + }) + }) + + describe('compareBytes32Ascending', () => { + it('should return 0 for two identical addresses', () => { + fc.assert( + fc.property(evmAddressArbitrary, (address) => { + expect(compareBytes32Ascending(address, address)).toBe(0) + expect(compareBytes32Ascending(address, makeBytes32(address))).toBe(0) + expect(compareBytes32Ascending(makeBytes32(address), makeBytes32(address))).toBe(0) + }) + ) + }) + + it('should return a negative value for zero address and any other address', () => { + fc.assert( + fc.property(evmAddressArbitrary, (address) => { + fc.pre(!isZero(address)) + + expect(compareBytes32Ascending(AddressZero, address)).toBeLessThan(0) + expect(compareBytes32Ascending(AddressZero, makeBytes32(address))).toBeLessThan(0) + expect(compareBytes32Ascending(makeBytes32(AddressZero), address)).toBeLessThan(0) + expect(compareBytes32Ascending(makeBytes32(AddressZero), makeBytes32(address))).toBeLessThan(0) + }) + ) + }) + + it('should return a positive value for zero address and any other address', () => { + fc.assert( + fc.property(evmAddressArbitrary, (address) => { + fc.pre(!isZero(address)) + + expect(compareBytes32Ascending(address, AddressZero)).toBeGreaterThan(0) + expect(compareBytes32Ascending(makeBytes32(address), AddressZero)).toBeGreaterThan(0) + expect(compareBytes32Ascending(address, makeBytes32(AddressZero))).toBeGreaterThan(0) + expect(compareBytes32Ascending(makeBytes32(address), makeBytes32(AddressZero))).toBeGreaterThan(0) + }) + ) + }) + + it('should return a negative if address comes before the other address', () => { + fc.assert( + fc.property(evmAddressArbitrary, evmAddressArbitrary, (addressA, addressB) => { + fc.pre(addressA.toLowerCase() < addressB.toLowerCase()) + + expect(compareBytes32Ascending(addressA, addressB)).toBeLessThan(0) + expect(compareBytes32Ascending(addressA, makeBytes32(addressB))).toBeLessThan(0) + expect(compareBytes32Ascending(makeBytes32(addressA), addressB)).toBeLessThan(0) + expect(compareBytes32Ascending(makeBytes32(addressA), makeBytes32(addressB))).toBeLessThan(0) + }) + ) + }) + + it('should return a negative if address comes after the other address', () => { + fc.assert( + fc.property(evmAddressArbitrary, evmAddressArbitrary, (addressA, addressB) => { + fc.pre(addressA.toLowerCase() > addressB.toLowerCase()) + + expect(compareBytes32Ascending(addressA, addressB)).toBeGreaterThan(0) + expect(compareBytes32Ascending(makeBytes32(addressA), addressB)).toBeGreaterThan(0) + expect(compareBytes32Ascending(addressA, makeBytes32(addressB))).toBeGreaterThan(0) + expect(compareBytes32Ascending(makeBytes32(addressA), makeBytes32(addressB))).toBeGreaterThan(0) + }) + ) + }) + }) +}) diff --git a/packages/omnicounter-devtools-evm/src/omnicounter/sdk.ts b/packages/omnicounter-devtools-evm/src/omnicounter/sdk.ts index 30b64437d..1b8940422 100644 --- a/packages/omnicounter-devtools-evm/src/omnicounter/sdk.ts +++ b/packages/omnicounter-devtools-evm/src/omnicounter/sdk.ts @@ -2,8 +2,8 @@ import { EndpointId } from '@layerzerolabs/lz-definitions' import { IncrementOutput, IncrementType, IOmniCounter } from '@layerzerolabs/omnicounter-devtools' import { EndpointFactory } from '@layerzerolabs/protocol-devtools' import { OApp } from '@layerzerolabs/ua-devtools-evm' -import { Address } from '@layerzerolabs/devtools' -import { makeBytes32, OmniContract } from '@layerzerolabs/devtools-evm' +import { type Address, makeBytes32 } from '@layerzerolabs/devtools' +import { OmniContract } from '@layerzerolabs/devtools-evm' export class OmniCounter extends OApp implements IOmniCounter { public constructor( diff --git a/packages/protocol-devtools-evm/src/endpoint/sdk.ts b/packages/protocol-devtools-evm/src/endpoint/sdk.ts index 9327d03e1..91b05b377 100644 --- a/packages/protocol-devtools-evm/src/endpoint/sdk.ts +++ b/packages/protocol-devtools-evm/src/endpoint/sdk.ts @@ -9,9 +9,17 @@ import type { Uln302SetUlnConfig, Uln302UlnConfig, } from '@layerzerolabs/protocol-devtools' -import { formatEid, type Address, type OmniTransaction, formatOmniPoint, Bytes32 } from '@layerzerolabs/devtools' +import { + formatEid, + type Address, + type OmniAddress, + type OmniTransaction, + formatOmniPoint, + isZero, + ignoreZero, +} from '@layerzerolabs/devtools' import type { EndpointId } from '@layerzerolabs/lz-definitions' -import { ignoreZero, isZero, makeZeroAddress, type OmniContract, OmniSDK } from '@layerzerolabs/devtools-evm' +import { makeZeroAddress, type OmniContract, OmniSDK } from '@layerzerolabs/devtools-evm' import { Timeout } from '@layerzerolabs/protocol-devtools' import { Uln302 } from '@/uln302' import { Uln302SetExecutorConfig } from '@layerzerolabs/protocol-devtools' @@ -89,7 +97,7 @@ export class Endpoint extends OmniSDK implements IEndpoint { return ignoreZero(await this.contract.contract.defaultSendLibrary(eid)) } - async isDefaultSendLibrary(sender: Bytes32 | Address, dstEid: EndpointId): Promise { + async isDefaultSendLibrary(sender: OmniAddress, dstEid: EndpointId): Promise { this.logger.debug( `Checking default send library for eid ${dstEid} (${formatEid(dstEid)}) and address ${sender}` ) @@ -226,7 +234,7 @@ export class Endpoint extends OmniSDK implements IEndpoint { return await this.setConfig(oapp, lib, setExecutorConfigParams) } - async getExecutorConfig(oapp: Bytes32 | Address, lib: Address, eid: EndpointId): Promise { + async getExecutorConfig(oapp: OmniAddress, lib: Address, eid: EndpointId): Promise { this.logger.debug( `Getting executor config for eid ${eid} (${formatEid(eid)}) and OApp ${oapp} and address ${lib}` ) @@ -235,7 +243,7 @@ export class Endpoint extends OmniSDK implements IEndpoint { return await uln.getExecutorConfig(eid, oapp) } - async getAppExecutorConfig(oapp: Bytes32 | Address, lib: Address, eid: EndpointId): Promise { + async getAppExecutorConfig(oapp: OmniAddress, lib: Address, eid: EndpointId): Promise { this.logger.debug( `Getting executor app config for eid ${eid} (${formatEid(eid)}) and OApp ${oapp} and address ${lib}` ) @@ -244,14 +252,14 @@ export class Endpoint extends OmniSDK implements IEndpoint { return await uln.getAppExecutorConfig(eid, oapp) } - async getUlnConfig(oapp: Bytes32 | Address, lib: Address, eid: EndpointId): Promise { + async getUlnConfig(oapp: OmniAddress, lib: Address, eid: EndpointId): Promise { this.logger.debug(`Getting ULN config for eid ${eid} (${formatEid(eid)}) and OApp ${oapp} and address ${lib}`) const uln = await this.getUln302SDK(lib) return await uln.getUlnConfig(eid, oapp) } - async getAppUlnConfig(oapp: Bytes32 | Address, lib: Address, eid: EndpointId): Promise { + async getAppUlnConfig(oapp: OmniAddress, lib: Address, eid: EndpointId): Promise { this.logger.debug( `Getting App ULN config for eid ${eid} (${formatEid(eid)}) and OApp ${oapp} and address ${lib}` ) diff --git a/packages/protocol-devtools-evm/src/uln302/sdk.ts b/packages/protocol-devtools-evm/src/uln302/sdk.ts index 28e563887..64a7ed37f 100644 --- a/packages/protocol-devtools-evm/src/uln302/sdk.ts +++ b/packages/protocol-devtools-evm/src/uln302/sdk.ts @@ -1,10 +1,11 @@ import type { EndpointId } from '@layerzerolabs/lz-definitions' import type { IUln302, Uln302ExecutorConfig, Uln302UlnConfig } from '@layerzerolabs/protocol-devtools' import { Address, formatEid, type OmniTransaction } from '@layerzerolabs/devtools' -import { isZero, makeZeroAddress, OmniSDK } from '@layerzerolabs/devtools-evm' import { Uln302ExecutorConfigSchema, Uln302UlnConfigInputSchema, Uln302UlnConfigSchema } from './schema' import assert from 'assert' import { printRecord } from '@layerzerolabs/io-devtools' +import { isZero } from '@layerzerolabs/devtools' +import { OmniSDK, makeZeroAddress } from '@layerzerolabs/devtools-evm' export class Uln302 extends OmniSDK implements IUln302 { async getUlnConfig(eid: EndpointId, address?: Address | null | undefined): Promise { diff --git a/packages/protocol-devtools-evm/test/endpoint/sdk.test.ts b/packages/protocol-devtools-evm/test/endpoint/sdk.test.ts index 7e7f012ee..3e0a05ec4 100644 --- a/packages/protocol-devtools-evm/test/endpoint/sdk.test.ts +++ b/packages/protocol-devtools-evm/test/endpoint/sdk.test.ts @@ -1,8 +1,9 @@ import fc from 'fast-check' import { endpointArbitrary, evmAddressArbitrary } from '@layerzerolabs/test-devtools' import type { Contract } from '@ethersproject/contracts' -import { isZero, makeBytes32, makeZeroAddress, type OmniContract } from '@layerzerolabs/devtools-evm' +import { makeZeroAddress, type OmniContract } from '@layerzerolabs/devtools-evm' import { Endpoint } from '@/endpoint' +import { isZero, makeBytes32 } from '@layerzerolabs/devtools' describe('endpoint/sdk', () => { describe('getUln302SDK', () => { diff --git a/packages/protocol-devtools/src/endpoint/types.ts b/packages/protocol-devtools/src/endpoint/types.ts index 06d21880b..1565f7dfb 100644 --- a/packages/protocol-devtools/src/endpoint/types.ts +++ b/packages/protocol-devtools/src/endpoint/types.ts @@ -6,6 +6,7 @@ import type { OmniTransaction, IOmniSDK, Bytes32, + PossiblyBytes, } from '@layerzerolabs/devtools' import type { EndpointId } from '@layerzerolabs/lz-definitions' import type { IUln302, Uln302ExecutorConfig, Uln302UlnConfig } from '@/uln302/types' @@ -46,7 +47,7 @@ export interface IEndpoint extends IOmniSDK { * @param {Address | Bytes32} sender Address of the OApp * @param {EndpointId} dstEid Destination endpoint ID */ - isDefaultSendLibrary(sender: Bytes32 | Address, dstEid: EndpointId): Promise + isDefaultSendLibrary(sender: PossiblyBytes, dstEid: EndpointId): Promise setReceiveLibrary(oapp: Address, eid: EndpointId, newLib: Address, gracePeriod: number): Promise setReceiveLibraryTimeout(oapp: Address, eid: EndpointId, newLib: Address, expiry: number): Promise @@ -59,11 +60,11 @@ export interface IEndpoint extends IOmniSDK { * * @see {@link getAppExecutorConfig} * - * @param {Bytes32 | Address} oapp OApp address - * @param {Bytes32 | Address} lib Library address + * @param {PossiblyBytes} oapp OApp address + * @param {PossiblyBytes} lib Library address * @param {EndpointId} eid Endpoint ID */ - getExecutorConfig(oapp: Bytes32 | Address, lib: Address, eid: EndpointId): Promise + getExecutorConfig(oapp: PossiblyBytes, lib: Address, eid: EndpointId): Promise /** * Gets the executor config for a given OApp, library and a destination @@ -74,14 +75,14 @@ export interface IEndpoint extends IOmniSDK { * * @see {@link getExecutorConfig} * - * @param {Bytes32 | Address} oapp OApp address - * @param {Bytes32 | Address} lib Library address + * @param {PossiblyBytes} oapp OApp address + * @param {PossiblyBytes} lib Library address * @param {EndpointId} eid Endpoint ID */ - getAppExecutorConfig(oapp: Bytes32 | Address, lib: Address, eid: EndpointId): Promise + getAppExecutorConfig(oapp: PossiblyBytes, lib: Address, eid: EndpointId): Promise setExecutorConfig( - oapp: Bytes32 | Address, - lib: Bytes32 | Address, + oapp: PossiblyBytes, + lib: PossiblyBytes, setExecutorConfig: Uln302SetExecutorConfig[] ): Promise @@ -94,8 +95,8 @@ export interface IEndpoint extends IOmniSDK { * * @see {@link getAppUlnConfig} * - * @param {Bytes32 | Address} oapp OApp address - * @param {Bytes32 | Address} lib Library address + * @param {PossiblyBytes} oapp OApp address + * @param {PossiblyBytes} lib Library address * @param {EndpointId} eid Endpoint ID */ getUlnConfig(oapp: Address, lib: Address, eid: EndpointId): Promise @@ -109,8 +110,8 @@ export interface IEndpoint extends IOmniSDK { * * @see {@link getUlnConfig} * - * @param {Bytes32 | Address} oapp OApp address - * @param {Bytes32 | Address} lib Library address + * @param {PossiblyBytes} oapp OApp address + * @param {PossiblyBytes} lib Library address * @param {EndpointId} eid Endpoint ID */ getAppUlnConfig(oapp: Address, lib: Address, eid: EndpointId): Promise diff --git a/packages/protocol-devtools/src/uln302/types.ts b/packages/protocol-devtools/src/uln302/types.ts index 7d2a1e06e..f5d1ff6f5 100644 --- a/packages/protocol-devtools/src/uln302/types.ts +++ b/packages/protocol-devtools/src/uln302/types.ts @@ -1,4 +1,4 @@ -import type { Address, OmniGraph, Factory, OmniTransaction, IOmniSDK, OmniPoint } from '@layerzerolabs/devtools' +import type { OmniAddress, OmniGraph, Factory, OmniTransaction, IOmniSDK, OmniPoint } from '@layerzerolabs/devtools' import type { EndpointId } from '@layerzerolabs/lz-definitions' export interface IUln302 extends IOmniSDK { @@ -11,9 +11,9 @@ export interface IUln302 extends IOmniSDK { * @see {@link getAppUlnConfig} * * @param {EndpointId} eid Endpoint ID - * @param {Bytes32 | Address} address + * @param {PossiblyBytes} address */ - getUlnConfig(eid: EndpointId, address?: Address | null | undefined): Promise + getUlnConfig(eid: EndpointId, address?: OmniAddress | null | undefined): Promise /** * Gets the ULN config for a given endpoint ID and an address. @@ -24,9 +24,9 @@ export interface IUln302 extends IOmniSDK { * @see {@link getUlnConfig} * * @param {EndpointId} eid Endpoint ID - * @param {Bytes32 | Address} address + * @param {PossiblyBytes} address */ - getAppUlnConfig(eid: EndpointId, address: Address): Promise + getAppUlnConfig(eid: EndpointId, address: OmniAddress): Promise setDefaultUlnConfig(eid: EndpointId, config: Uln302UlnConfig): Promise @@ -39,9 +39,9 @@ export interface IUln302 extends IOmniSDK { * @see {@link getAppExecutorConfig} * * @param {EndpointId} eid Endpoint ID - * @param {Bytes32 | Address | null} address + * @param {PossiblyBytes | null} address */ - getExecutorConfig(eid: EndpointId, address?: Address | null | undefined): Promise + getExecutorConfig(eid: EndpointId, address?: OmniAddress | null | undefined): Promise /** * Gets the Executor config for a given endpoint ID and an address. @@ -52,9 +52,9 @@ export interface IUln302 extends IOmniSDK { * @see {@link getExecutorConfig} * * @param {EndpointId} eid Endpoint ID - * @param {Bytes32 | Address} address + * @param {PossiblyBytes} address */ - getAppExecutorConfig(eid: EndpointId, address: Address): Promise + getAppExecutorConfig(eid: EndpointId, address: OmniAddress): Promise setDefaultExecutorConfig(eid: EndpointId, config: Uln302ExecutorConfig): Promise } diff --git a/packages/ua-devtools-evm/src/oapp/sdk.ts b/packages/ua-devtools-evm/src/oapp/sdk.ts index f6dbb3bcd..f064d0181 100644 --- a/packages/ua-devtools-evm/src/oapp/sdk.ts +++ b/packages/ua-devtools-evm/src/oapp/sdk.ts @@ -1,13 +1,15 @@ import type { IOApp, EnforcedOptions, OAppEnforcedOptionConfig } from '@layerzerolabs/ua-devtools' -import { type Bytes32, type Address, type OmniTransaction, formatEid } from '@layerzerolabs/devtools' import { - type OmniContract, + type Bytes32, + type OmniAddress, + type OmniTransaction, + formatEid, + isZero, + areBytes32Equal, ignoreZero, makeBytes32, - areBytes32Equal, - isZero, - formatOmniContract, -} from '@layerzerolabs/devtools-evm' +} from '@layerzerolabs/devtools' +import { type OmniContract, formatOmniContract } from '@layerzerolabs/devtools-evm' import type { EndpointId } from '@layerzerolabs/lz-definitions' import type { EndpointFactory, IEndpoint } from '@layerzerolabs/protocol-devtools' import { OmniSDK } from '@layerzerolabs/devtools-evm' @@ -55,11 +57,11 @@ export class OApp extends OmniSDK implements IOApp { return ignoreZero(await this.contract.contract.peers(eid)) } - async hasPeer(eid: EndpointId, address: Bytes32 | Address | null | undefined): Promise { + async hasPeer(eid: EndpointId, address: OmniAddress | null | undefined): Promise { return areBytes32Equal(await this.getPeer(eid), address) } - async setPeer(eid: EndpointId, address: Bytes32 | Address | null | undefined): Promise { + async setPeer(eid: EndpointId, address: OmniAddress | null | undefined): Promise { this.logger.debug(`Setting peer for eid ${eid} (${formatEid(eid)}) to address ${makeBytes32(address)}`) const data = this.contract.contract.interface.encodeFunctionData('setPeer', [eid, makeBytes32(address)]) diff --git a/packages/ua-devtools-evm/test/oapp/sdk.test.ts b/packages/ua-devtools-evm/test/oapp/sdk.test.ts index 45fd2caa3..c01d0da3c 100644 --- a/packages/ua-devtools-evm/test/oapp/sdk.test.ts +++ b/packages/ua-devtools-evm/test/oapp/sdk.test.ts @@ -2,8 +2,8 @@ import fc from 'fast-check' import { endpointArbitrary, evmAddressArbitrary } from '@layerzerolabs/test-devtools' import { Contract } from '@ethersproject/contracts' import { OApp } from '@/oapp/sdk' -import { OmniContract, isZero, makeZeroAddress } from '@layerzerolabs/devtools-evm' -import { makeBytes32 } from '@layerzerolabs/devtools-evm' +import { OmniContract, makeZeroAddress } from '@layerzerolabs/devtools-evm' +import { isZero, makeBytes32 } from '@layerzerolabs/devtools' import { formatEid } from '@layerzerolabs/devtools' describe('oapp/sdk', () => { diff --git a/packages/ua-devtools/src/oapp/types.ts b/packages/ua-devtools/src/oapp/types.ts index 723943c75..06dbea0fb 100644 --- a/packages/ua-devtools/src/oapp/types.ts +++ b/packages/ua-devtools/src/oapp/types.ts @@ -1,10 +1,9 @@ import type { EndpointId } from '@layerzerolabs/lz-definitions' import type { IEndpoint, Timeout, Uln302ExecutorConfig, Uln302UlnConfig } from '@layerzerolabs/protocol-devtools' import type { - Address, - Bytes32, Factory, IOmniSDK, + OmniAddress, OmniGraph, OmniPoint, OmniTransaction, @@ -14,9 +13,9 @@ import { ExecutorOptionType, Options } from '@layerzerolabs/lz-v2-utilities' export interface IOApp extends IOmniSDK { getEndpointSDK(): Promise - getPeer(eid: EndpointId): Promise - hasPeer(eid: EndpointId, address: Bytes32 | Address | null | undefined): Promise - setPeer(eid: EndpointId, peer: Bytes32 | Address | null | undefined): Promise + getPeer(eid: EndpointId): Promise + hasPeer(eid: EndpointId, address: OmniAddress | null | undefined): Promise + setPeer(eid: EndpointId, peer: OmniAddress | null | undefined): Promise getEnforcedOptions(eid: EndpointId, msgType: number): Promise setEnforcedOptions(enforcedOptions: EnforcedOptions[]): Promise encodeEnforcedOptions(enforcedOptionConfig: OAppEnforcedOptionConfig): Options diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f763ca3a0..46a305733 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -261,6 +261,9 @@ importers: specifier: ^1.10.0 version: 1.10.0 devDependencies: + '@layerzerolabs/devtools': + specifier: ~0.0.1 + version: link:../devtools '@layerzerolabs/devtools-evm': specifier: ~0.0.6 version: link:../devtools-evm @@ -385,6 +388,12 @@ importers: packages/devtools: devDependencies: + '@ethersproject/bytes': + specifier: ~5.7.0 + version: 5.7.0 + '@ethersproject/constants': + specifier: ~5.7.0 + version: 5.7.0 '@layerzerolabs/io-devtools': specifier: ~0.0.5 version: link:../io-devtools @@ -446,9 +455,6 @@ importers: '@ethersproject/bignumber': specifier: ^5.7.0 version: 5.7.0 - '@ethersproject/bytes': - specifier: ^5.7.0 - version: 5.7.0 '@ethersproject/constants': specifier: ^5.7.0 version: 5.7.0 @@ -6773,6 +6779,7 @@ packages: dependencies: is-hex-prefixed: 1.0.0 strip-hex-prefix: 1.0.0 + bundledDependencies: false /eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} diff --git a/tests/ua-devtools-evm-hardhat-test/test/omnicounter/options.test.ts b/tests/ua-devtools-evm-hardhat-test/test/omnicounter/options.test.ts index e28a456fe..173dab6ec 100644 --- a/tests/ua-devtools-evm-hardhat-test/test/omnicounter/options.test.ts +++ b/tests/ua-devtools-evm-hardhat-test/test/omnicounter/options.test.ts @@ -1,6 +1,6 @@ /// -import { makeBytes32, OmniSignerEVM, parseLogsWithName } from '@layerzerolabs/devtools-evm' +import { OmniSignerEVM, parseLogsWithName } from '@layerzerolabs/devtools-evm' import { parseEther } from 'ethers/lib/utils' import fc from 'fast-check' import 'hardhat' @@ -11,7 +11,7 @@ import { IncrementType } from '@layerzerolabs/omnicounter-devtools' import { createOmniCounterFactory, OmniCounter } from '@layerzerolabs/omnicounter-devtools-evm' import { createEndpointFactory } from '@layerzerolabs/protocol-devtools-evm' import { configureOAppPeers, OAppEdgeConfig } from '@layerzerolabs/ua-devtools' -import { createSignAndSend, OmniPoint, OmniTransaction } from '@layerzerolabs/devtools' +import { createSignAndSend, makeBytes32, OmniPoint, OmniTransaction } from '@layerzerolabs/devtools' import { omniContractToPoint } from '@layerzerolabs/devtools-evm' import { createConnectedContractFactory,