Skip to content

Commit

Permalink
🪚 Error parser (#173)
Browse files Browse the repository at this point in the history
  • Loading branch information
janjakubnanista authored Jan 10, 2024
1 parent 7bd271e commit 5236166
Show file tree
Hide file tree
Showing 11 changed files with 355 additions and 4 deletions.
6 changes: 6 additions & 0 deletions .changeset/fair-nails-suffer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@layerzerolabs/devtools-evm-hardhat-test": patch
"@layerzerolabs/devtools-evm-hardhat": patch
---

Add a generic contract error parser for hardhat projects
2 changes: 2 additions & 0 deletions packages/devtools-evm-hardhat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"zod": "^3.22.4"
},
"devDependencies": {
"@ethersproject/abi": "^5.7.0",
"@ethersproject/abstract-signer": "^5.7.0",
"@ethersproject/contracts": "^5.7.0",
"@ethersproject/providers": "^5.7.2",
Expand All @@ -66,6 +67,7 @@
"typescript": "^5.3.3"
},
"peerDependencies": {
"@ethersproject/abi": "^5.7.0",
"@ethersproject/abstract-signer": "^5.7.0",
"@ethersproject/contracts": "^5.7.0",
"@ethersproject/providers": "^5.7.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/devtools-evm-hardhat/src/errors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './errors'
export * from './parser'
40 changes: 40 additions & 0 deletions packages/devtools-evm-hardhat/src/errors/parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { getDefaultRuntimeEnvironment } from '@/runtime'
import { Contract } from '@ethersproject/contracts'
import {
createErrorParser as createErrorParserBase,
makeZeroAddress,
type OmniContractFactory,
} from '@layerzerolabs/devtools-evm'

/**
* Helper function that combines all the available ABIs into a one giant
* interface (only containing the error fragments) used for error decoding.
*
* TODO This function is not memoized at the moment, if the performance turns out to be a bottleneck we can memoize
*
* @returns {OmniContractFactory}
*/
const createCombinedContractFactory =
(): OmniContractFactory =>
async ({ eid }) => {
// We're getting the artifacts so it does not really matter which environment we get them from
const env = getDefaultRuntimeEnvironment()

// We'll grab all the artifacts from the environment
const artifactNames = await env.artifacts.getAllFullyQualifiedNames()
const artifacts = artifactNames.map((name) => env.artifacts.readArtifactSync(name))

// Now we combine the ABIs and keep only the errors
const abi = artifacts.flatMap((artifact) => artifact.abi).filter(({ type }) => type === 'error')

// Even though duplicated fragments don't throw errors, they still pollute the interface with warning console.logs
// To prevent this, we'll run a simple deduplication algorithm - use JSON encoded values as hashes
const deduplicatedAbi = Object.values(Object.fromEntries(abi.map((abi) => [JSON.stringify(abi), abi])))

return { eid, contract: new Contract(makeZeroAddress(), deduplicatedAbi) }
}

/**
* Creates a generic error parser based on all the artifacts found in your hardhat project
*/
export const createErrorParser = () => createErrorParserBase(createCombinedContractFactory())
1 change: 1 addition & 0 deletions packages/devtools-evm-hardhat/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import './type-extensions'

// Regular exports
export * from './config'
export * from './errors'
export * from './internal'
export * from './omnigraph'
export * from './provider'
Expand Down
8 changes: 4 additions & 4 deletions packages/devtools-evm/src/omnigraph/sdk.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { OmniPoint, OmniTransaction } from '@layerzerolabs/devtools'
import { IOmniSDK, OmniContract } from './types'
import type { OmniPoint, OmniTransaction } from '@layerzerolabs/devtools'
import type { IOmniSDK, OmniContract } from './types'
import { omniContractToPoint } from './coordinates'
import { createContractErrorParser } from '@/errors/parser'
import { OmniContractErrorParser } from '@/errors/types'
import { ContractError } from '..'
import type { OmniContractErrorParser } from '@/errors/types'
import type { ContractError } from '@/errors/errors'

/**
* Base class for all EVM SDKs, providing some common functionality
Expand Down
12 changes: 12 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 75 additions & 0 deletions tests/devtools-evm-hardhat-test/contracts/Thrower.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;

contract Thrower {
error CustomErrorWithNoArguments();
error CustomErrorWithAnArgument(string message);

// This error is duplicated in the NestedThrower
error CommonErrorWithNoArguments();

// This error is duplicated in the NestedThrower but with a different argument
error CommonErrorWithAnArgument(string message);

NestedThrower private nested;

constructor() {
nested = new NestedThrower();
}

function throwWithCustomErrorAndNoArguments() external pure {
revert CustomErrorWithNoArguments();
}

function throwWithCustomErrorAndArgument(string calldata message) external pure {
revert CustomErrorWithAnArgument(message);
}

function throwWithCommonErrorAndNoArguments() external pure {
revert CommonErrorWithNoArguments();
}

function throwWithCommonErrorAndArgument(string calldata message) external pure {
revert CommonErrorWithAnArgument(message);
}

function throwNestedWithCustomErrorAndNoArguments() external view {
nested.throwWithCustomErrorAndNoArguments();
}

function throwNestedWithCustomErrorAndArgument(string calldata message) external view {
nested.throwWithCustomErrorAndArgument(message);
}

function throwNestedWithCommonErrorAndNoArguments() external view {
nested.throwWithCommonErrorAndNoArguments();
}

function throwNestedWithCommonErrorAndArgument(uint256 code) external view {
nested.throwWithCommonErrorAndArgument(code);
}
}

contract NestedThrower {
error NestedCustomErrorWithNoArguments();
error NestedCustomErrorWithAnArgument(string message);

error CommonErrorWithNoArguments();
error CommonErrorWithAnArgument(uint256 code);

function throwWithCustomErrorAndNoArguments() external pure {
revert NestedCustomErrorWithNoArguments();
}

function throwWithCustomErrorAndArgument(string calldata message) external pure {
revert NestedCustomErrorWithAnArgument(message);
}

function throwWithCommonErrorAndNoArguments() external pure {
revert CommonErrorWithNoArguments();
}

function throwWithCommonErrorAndArgument(uint256 code) external pure {
revert CommonErrorWithAnArgument(code);
}
}
3 changes: 3 additions & 0 deletions tests/devtools-evm-hardhat-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
"devDependencies": {
"@babel/core": "^7.23.7",
"@ethersproject/abstract-signer": "^5.7.0",
"@ethersproject/bignumber": "^5.7.0",
"@ethersproject/constants": "^5.7.0",
"@ethersproject/contracts": "^5.7.0",
"@ethersproject/providers": "^5.7.2",
"@ethersproject/wallet": "^5.7.0",
"@layerzerolabs/devtools": "~0.0.1",
Expand All @@ -36,6 +38,7 @@
"@layerzerolabs/omnicounter-devtools-evm": "~0.0.1",
"@layerzerolabs/protocol-devtools": "~0.0.1",
"@layerzerolabs/protocol-devtools-evm": "~0.0.1",
"@layerzerolabs/test-devtools": "~0.0.1",
"@layerzerolabs/toolbox-hardhat": "~0.0.1",
"@nomicfoundation/hardhat-ethers": "^3.0.5",
"@openzeppelin/contracts": "^4.9.5",
Expand Down
Loading

0 comments on commit 5236166

Please sign in to comment.