fix(utils): use browser compatible `deepEquals` (#4141)

- fix: use browser compatible `deepEquals`
- removes use of node-specific deepEquality check
- add a few unit tests for `deepEqual` and `deepCopy`

---------

Signed-off-by: pbio <10051819+paulbalaji@users.noreply.github.com>
Co-authored-by: J M Rossy <jm.rossy@gmail.com>
pull/4178/head
Paul Balaji 4 months ago committed by GitHub
parent ed65556aa4
commit 1474865ae1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      .changeset/twelve-seas-return.md
  2. 11
      typescript/sdk/src/hook/EvmHookModule.hardhat-test.ts
  3. 10
      typescript/sdk/src/hook/EvmHookModule.ts
  4. 6
      typescript/sdk/src/ism/EvmIsmModule.ts
  5. 4
      typescript/sdk/src/ism/utils.ts
  6. 4
      typescript/sdk/src/token/EvmERC20WarpModule.ts
  7. 2
      typescript/utils/package.json
  8. 3
      typescript/utils/src/index.ts
  9. 16
      typescript/utils/src/objects.test.ts
  10. 18
      typescript/utils/src/objects.ts
  11. 18
      yarn.lock

@ -0,0 +1,5 @@
---
'@hyperlane-xyz/utils': patch
---
Replace `configDeepEquals` with improve `deepEquals`

@ -1,10 +1,15 @@
/* eslint-disable no-console */
import assert from 'assert';
import { expect } from 'chai';
import { Signer } from 'ethers';
import hre from 'hardhat';
import { Address, eqAddress, normalizeConfig } from '@hyperlane-xyz/utils';
import {
Address,
assert,
deepEquals,
eqAddress,
normalizeConfig,
} from '@hyperlane-xyz/utils';
import { TestChainName, testChains } from '../consts/testChains.js';
import { HyperlaneAddresses, HyperlaneContracts } from '../contracts/types.js';
@ -253,7 +258,7 @@ describe('EvmHookModule', async () => {
afterEach(async () => {
const normalizedDerivedConfig = normalizeConfig(await testHook.read());
const normalizedConfig = normalizeConfig(testConfig);
assert.deepStrictEqual(normalizedDerivedConfig, normalizedConfig);
deepEquals(normalizedDerivedConfig, normalizedConfig);
});
// create a new Hook and verify that it matches the config

@ -25,7 +25,7 @@ import {
Address,
ProtocolType,
addressToBytes32,
configDeepEquals,
deepEquals,
eqAddress,
normalizeConfig,
rootLogger,
@ -142,7 +142,7 @@ export class EvmHookModule extends HyperlaneModule<
this.args.config = targetConfig;
// If configs match, no updates needed
if (configDeepEquals(currentConfig, targetConfig)) {
if (deepEquals(currentConfig, targetConfig)) {
return [];
}
@ -275,7 +275,7 @@ export class EvmHookModule extends HyperlaneModule<
// If the domain is not in the current config or the config has changed, deploy a new hook
// TODO: in-place updates per domain as a future optimization
if (!configDeepEquals(currentDomains[dest], targetDomainConfig)) {
if (!deepEquals(currentDomains[dest], targetDomainConfig)) {
const domainHook = await this.deploy({
config: targetDomainConfig,
});
@ -471,7 +471,7 @@ export class EvmHookModule extends HyperlaneModule<
}
// only update if the oracle config has changed
if (!current || !configDeepEquals(current, target)) {
if (!current || !deepEquals(current, target)) {
configsToSet.push({ remoteDomain, ...target });
// Log an example remote gas cost
@ -567,7 +567,7 @@ export class EvmHookModule extends HyperlaneModule<
// Deploy a new fallback hook if the fallback config has changed
if (
targetConfig.type === HookType.FALLBACK_ROUTING &&
!configDeepEquals(
!deepEquals(
targetConfig.fallback,
(currentConfig as FallbackRoutingHookConfig).fallback,
)

@ -20,15 +20,15 @@ import {
} from '@hyperlane-xyz/core';
import {
Address,
Domain,
ProtocolType,
assert,
configDeepEquals,
deepEquals,
eqAddress,
normalizeConfig,
objFilter,
rootLogger,
} from '@hyperlane-xyz/utils';
import { Domain } from '@hyperlane-xyz/utils';
import { attachAndConnectContracts } from '../contracts/contracts.js';
import { HyperlaneAddresses, HyperlaneContracts } from '../contracts/types.js';
@ -154,7 +154,7 @@ export class EvmIsmModule extends HyperlaneModule<
// if it's a fallback routing ISM, do a mailbox diff check
// If configs match, no updates needed
if (configDeepEquals(currentConfig, targetConfig)) {
if (deepEquals(currentConfig, targetConfig)) {
return [];
}

@ -14,7 +14,7 @@ import {
} from '@hyperlane-xyz/core';
import {
Address,
configDeepEquals,
deepEquals,
eqAddress,
formatMessage,
normalizeAddress,
@ -49,7 +49,7 @@ export function calculateDomainRoutingDelta(
if (!current.domains[origin]) {
domainsToEnroll.push(origin);
} else {
const subModuleMatches = configDeepEquals(
const subModuleMatches = deepEquals(
current.domains[origin],
target.domains[origin],
);

@ -10,7 +10,7 @@ import {
ProtocolType,
addressToBytes32,
assert,
configDeepEquals,
deepEquals,
isObjEmpty,
normalizeConfig,
rootLogger,
@ -127,7 +127,7 @@ export class EvmERC20WarpModule extends HyperlaneModule<
const { remoteRouters: actualRemoteRouters } = actualConfig;
const { remoteRouters: expectedRemoteRouters } = expectedConfig;
if (!configDeepEquals(actualRemoteRouters, expectedRemoteRouters)) {
if (!deepEquals(actualRemoteRouters, expectedRemoteRouters)) {
const contractToUpdate = TokenRouter__factory.connect(
this.args.addresses.deployedTokenRoute,
this.multiProvider.getProvider(this.domainId),

@ -7,10 +7,12 @@
"@solana/web3.js": "^1.78.0",
"bignumber.js": "^9.1.1",
"ethers": "^5.7.2",
"lodash-es": "^4.17.21",
"pino": "^8.19.0",
"yaml": "^2.4.1"
},
"devDependencies": {
"@types/lodash-es": "^4.17.12",
"@types/mocha": "^10.0.1",
"chai": "^4.3.6",
"mocha": "^10.2.0",

@ -102,6 +102,7 @@ export {
invertKeysAndValues,
isObjEmpty,
isObject,
normalizeConfig,
objFilter,
objKeys,
objLength,
@ -111,8 +112,6 @@ export {
pick,
promiseObjAll,
stringifyObject,
normalizeConfig,
configDeepEquals,
} from './objects.js';
export { difference, setEquality, symmetricDifference } from './sets.js';
export {

@ -0,0 +1,16 @@
import { expect } from 'chai';
import { deepCopy, deepEquals } from './objects.js';
describe('Object utilities', () => {
it('deepEquals', () => {
expect(deepEquals({ a: 1, b: 2 }, { a: 1, b: 2 })).to.be.true;
expect(deepEquals({ a: 1, b: 2 }, { a: 1, b: 2, c: 3 })).to.be.false;
expect(deepEquals({ a: 1, b: 2 }, { a: 1, b: 4 })).to.be.false;
});
it('deepCopy', () => {
expect(deepCopy({ a: 1, b: 2 })).to.eql({ a: 1, b: 2 });
expect(deepCopy({ a: 1, b: 2 })).to.not.eql({ a: 1, b: 3 });
});
});

@ -1,7 +1,7 @@
import { deepStrictEqual } from 'node:assert/strict';
import { cloneDeep, isEqual } from 'lodash-es';
import { stringify as yamlStringify } from 'yaml';
import { ethersBigNumberSerializer, rootLogger } from './logging.js';
import { ethersBigNumberSerializer } from './logging.js';
import { WithAddress } from './types.js';
import { assert } from './validation.js';
@ -10,11 +10,11 @@ export function isObject(item: any) {
}
export function deepEquals(v1: any, v2: any) {
return JSON.stringify(v1) === JSON.stringify(v2);
return isEqual(v1, v2);
}
export function deepCopy(v: any) {
return JSON.parse(JSON.stringify(v));
return cloneDeep(v);
}
export type ValueOf<T> = T[keyof T];
@ -175,13 +175,3 @@ export function normalizeConfig(obj: WithAddress<any>): any {
return obj;
}
export function configDeepEquals(v1: any, v2: any): boolean {
try {
deepStrictEqual(v1, v2);
return true;
} catch (error) {
rootLogger.info((error as Error).message);
return false;
}
}

@ -6002,10 +6002,12 @@ __metadata:
dependencies:
"@cosmjs/encoding": "npm:^0.31.3"
"@solana/web3.js": "npm:^1.78.0"
"@types/lodash-es": "npm:^4.17.12"
"@types/mocha": "npm:^10.0.1"
bignumber.js: "npm:^9.1.1"
chai: "npm:^4.3.6"
ethers: "npm:^5.7.2"
lodash-es: "npm:^4.17.21"
mocha: "npm:^10.2.0"
pino: "npm:^8.19.0"
prettier: "npm:^2.8.8"
@ -9734,6 +9736,22 @@ __metadata:
languageName: node
linkType: hard
"@types/lodash-es@npm:^4.17.12":
version: 4.17.12
resolution: "@types/lodash-es@npm:4.17.12"
dependencies:
"@types/lodash": "npm:*"
checksum: 56b9a433348b11c31051c6fa9028540a033a08fb80b400c589d740446c19444d73b217cf1471d4036448ef686a83e8cf2a35d1fadcb3f2105f26701f94aebb07
languageName: node
linkType: hard
"@types/lodash@npm:*":
version: 4.17.7
resolution: "@types/lodash@npm:4.17.7"
checksum: b8177f19cf962414a66989837481b13f546afc2e98e8d465bec59e6ac03a59c584eb7053ce511cde3a09c5f3096d22a5ae22cfb56b23f3b0da75b0743b6b1a44
languageName: node
linkType: hard
"@types/long@npm:^4.0.0, @types/long@npm:^4.0.1":
version: 4.0.2
resolution: "@types/long@npm:4.0.2"

Loading…
Cancel
Save