From d00edb8de04056db5c7aa58a232ea3194da4d0ce Mon Sep 17 00:00:00 2001 From: Amine E Date: Wed, 17 Apr 2024 19:36:28 +0200 Subject: [PATCH] Ccip/add hex error messages (#1886) * add error selectors * add error selectors * errors * errors * errors --- package-lock.json | 12 ++ package.json | 1 + src/config/data/ccip/data.ts | 15 +++ src/config/data/ccip/errors/erc20.json | 10 ++ src/config/data/ccip/errors/onramp.json | 114 ++++++++++++++++++ .../data/ccip/errors/priceregistry.json | 62 ++++++++++ src/config/data/ccip/errors/ratelimiter.json | 87 +++++++++++++ src/config/data/ccip/errors/router.json | 25 ++++ src/config/data/ccip/types.ts | 10 ++ src/content/ccip/api-reference/errors.mdx | 42 ++----- .../components/api-reference/Errors.astro | 110 +++++++++++++++++ .../ccip/components/api-reference/index.ts | 1 + 12 files changed, 454 insertions(+), 35 deletions(-) create mode 100644 src/config/data/ccip/errors/erc20.json create mode 100644 src/config/data/ccip/errors/onramp.json create mode 100644 src/config/data/ccip/errors/priceregistry.json create mode 100644 src/config/data/ccip/errors/ratelimiter.json create mode 100644 src/config/data/ccip/errors/router.json create mode 100644 src/features/ccip/components/api-reference/Errors.astro create mode 100644 src/features/ccip/components/api-reference/index.ts diff --git a/package-lock.json b/package-lock.json index 1aae9176adf..4fc015e9534 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "focus-trap-react": "^10.2.3", "github-slugger": "^2.0.0", "lodash": "^4.17.21", + "marked": "^12.0.1", "nanostores": "^0.9.5", "preact": "^10.20.1", "react-instantsearch": "^7.7.0", @@ -17724,6 +17725,17 @@ "dev": true, "peer": true }, + "node_modules/marked": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.1.tgz", + "integrity": "sha512-Y1/V2yafOcOdWQCX0XpAKXzDakPOpn6U0YLxTJs3cww6VxOzZV1BTOOYWLvH3gX38cq+iLwljHHTnMtlDfg01Q==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", diff --git a/package.json b/package.json index 89f578a9d83..75e9c415ed9 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "focus-trap-react": "^10.2.3", "github-slugger": "^2.0.0", "lodash": "^4.17.21", + "marked": "^12.0.1", "nanostores": "^0.9.5", "preact": "^10.20.1", "react-instantsearch": "^7.7.0", diff --git a/src/config/data/ccip/data.ts b/src/config/data/ccip/data.ts index a11224a5378..ff338d3c88e 100644 --- a/src/config/data/ccip/data.ts +++ b/src/config/data/ccip/data.ts @@ -4,6 +4,7 @@ import { TokensConfig, Environment, Version, + CCIPSendErrorEntry, SupportedTokenConfig, determineTokenMechanism, TokenMechanism, @@ -21,12 +22,26 @@ import chainsTestnetv120 from "@config/data/ccip/v1_2_0/testnet/chains.json" import lanesTestnetv120 from "@config/data/ccip/v1_2_0/testnet/lanes.json" import tokensTestnetv120 from "@config/data/ccip/v1_2_0/testnet/tokens.json" +// errors + +import erc20CCIPSendErrors from "@config/data/ccip/errors/erc20.json" +import routerCCIPSendErrors from "@config/data/ccip/errors/router.json" +import onrampCCIPSendErrors from "@config/data/ccip/errors/onramp.json" +import ratelimiterCCIPSendErrors from "@config/data/ccip/errors/ratelimiter.json" +import priceregistryCCIPSendErrors from "@config/data/ccip/errors/priceregistry.json" + import { SupportedChain } from "@config/types" import { directoryToSupportedChain, supportedChainToChainInRdd } from "@features/utils" export const getAllEnvironments = () => [Environment.Mainnet, Environment.Testnet] export const getAllVersions = () => [Version.V1_2_0] +export const erc20Errors: CCIPSendErrorEntry[] = erc20CCIPSendErrors +export const routerErrors: CCIPSendErrorEntry[] = routerCCIPSendErrors +export const onrampErrors: CCIPSendErrorEntry[] = onrampCCIPSendErrors +export const ratelimiterErrors: CCIPSendErrorEntry[] = ratelimiterCCIPSendErrors +export const priceRegistryErrors: CCIPSendErrorEntry[] = priceregistryCCIPSendErrors + export const networkFees: NetworkFees = { tokenTransfers: { [TokenMechanism.LockAndUnlock]: { diff --git a/src/config/data/ccip/errors/erc20.json b/src/config/data/ccip/errors/erc20.json new file mode 100644 index 00000000000..43ea19415c2 --- /dev/null +++ b/src/config/data/ccip/errors/erc20.json @@ -0,0 +1,10 @@ +[ + { + "error": "ERC20: burn amount exceeds balance", + "description": "Thrown when the amount to be burned exceeds the pool balance." + }, + { + "error": "ERC20: transfer amount exceeds allowance", + "description": "Thrown when the transfer amount exceeds the allowance." + } +] diff --git a/src/config/data/ccip/errors/onramp.json b/src/config/data/ccip/errors/onramp.json new file mode 100644 index 00000000000..ab2bf1797a2 --- /dev/null +++ b/src/config/data/ccip/errors/onramp.json @@ -0,0 +1,114 @@ +[ + { + "error": "CannotSendZeroTokens", + "parameters": [], + "errorSelector": "0x5cf04449", + "description": "Thrown when the user tries to send a zero amount of tokens." + }, + { + "error": "InvalidAddress", + "parameters": [ + { + "type": "bytes", + "name": "encodedAddress" + } + ], + "errorSelector": "0x370d875f", + "description": "Thrown when the receiver address is invalid." + }, + { + "error": "InvalidChainSelector", + "parameters": [ + { + "type": "uint64", + "name": "chainSelector" + } + ], + "errorSelector": "0xd9a9cd68", + "description": "Thrown when an invalid destination chain selector is used." + }, + { + "error": "InvalidExtraArgsTag", + "parameters": [], + "errorSelector": "0x5247fdce", + "description": "Thrown when an invalid extra arguments tag is used." + }, + { + "error": "MaxFeeBalanceReached", + "parameters": [], + "errorSelector": "0xe5c7a491", + "description": "Thrown when the onRamp has reached its maximum fee storage capacity. If it is full, it cannot process new transactions." + }, + { + "error": "MessageGasLimitTooHigh", + "parameters": [], + "errorSelector": "0x4c4fc93a", + "description": "Thrown when the gas limit is too high." + }, + { + "error": "MessageTooLarge", + "parameters": [ + { + "type": "uint256", + "name": "maxSize" + }, + { + "type": "uint256", + "name": "actualSize" + } + ], + "errorSelector": "0x86933789", + "description": "Thrown when the message size exceeds the maximum allowed size." + }, + { + "error": "MustBeCalledByRouter", + "parameters": [], + "errorSelector": "0x1c0a3529", + "description": "This error should never be thrown as the router always makes the call." + }, + { + "error": "NotAFeeToken", + "parameters": [ + { + "type": "address", + "name": "token" + } + ], + "errorSelector": "0xa7499d20", + "description": "Thrown when an unsupported fee token is used." + }, + { + "error": "RouterMustSetOriginalSender", + "parameters": [], + "errorSelector": "0xa4ec7479", + "description": "This error should never be thrown as the router always sets the sender." + }, + { + "error": "SenderNotAllowed", + "parameters": [ + { + "type": "address", + "name": "sender" + } + ], + "errorSelector": "0xd0d25976", + "description": "Thrown when the sender is not allowlisted." + }, + { + "error": "UnsupportedNumberOfTokens", + "parameters": [], + "errorSelector": "0x4c056b6a", + "description": "Thrown when too many tokens are involved in the transfer." + }, + { + "error": "UnsupportedToken", + "parameters": [ + { + "type": "IERC20", + "name": "token" + } + ], + "errorSelector": "0xbf16aab6", + "description": "Thrown when an unsupported transfer token is used." + } +] diff --git a/src/config/data/ccip/errors/priceregistry.json b/src/config/data/ccip/errors/priceregistry.json new file mode 100644 index 00000000000..921014ec370 --- /dev/null +++ b/src/config/data/ccip/errors/priceregistry.json @@ -0,0 +1,62 @@ +[ + { + "error": "ChainNotSupported", + "parameters": [ + { + "type": "uint64", + "name": "chain" + } + ], + "errorSelector": "0x2e59db3a", + "description": "Thrown when a chain is not supported." + }, + { + "error": "StaleGasPrice", + "parameters": [ + { + "type": "uint64", + "name": "destChainSelector" + }, + { + "type": "uint256", + "name": "threshold" + }, + { + "type": "uint256", + "name": "timePassed" + } + ], + "errorSelector": "0xf08bcb3e", + "description": "Thrown when the gas price is stale." + }, + { + "error": "TokenNotSupported", + "parameters": [ + { + "type": "address", + "name": "token" + } + ], + "errorSelector": "0x06439c6b", + "description": "Thrown when a token is not supported." + }, + { + "error": "StaleTokenPrice", + "parameters": [ + { + "type": "address", + "name": "token" + }, + { + "type": "uint256", + "name": "threshold" + }, + { + "type": "uint256", + "name": "timePassed" + } + ], + "errorSelector": "0xc65fdfca", + "description": "Thrown when the price of a token is stale." + } +] diff --git a/src/config/data/ccip/errors/ratelimiter.json b/src/config/data/ccip/errors/ratelimiter.json new file mode 100644 index 00000000000..edeeff5e13e --- /dev/null +++ b/src/config/data/ccip/errors/ratelimiter.json @@ -0,0 +1,87 @@ +[ + { + "error": "AggregateValueMaxCapacityExceeded", + "parameters": [ + { + "type": "uint256", + "name": "capacity" + }, + { + "type": "uint256", + "name": "requested" + } + ], + "errorSelector": "0xf94ebcd1", + "description": "Thrown when the user requests to transfer more value than the capacity of the aggregate rate limit bucket." + }, + { + "error": "AggregateValueRateLimitReached", + "parameters": [ + { + "type": "uint256", + "name": "minWaitInSeconds" + }, + { + "type": "uint256", + "name": "available" + } + ], + "errorSelector": "0x15279c08", + "description": "Thrown when the user requests to transfer more value than currently available in the bucket. The user might have to wait for at least `minWaitInSeconds` for enough availability or transfer the currently `available` amount." + }, + { + "error": "BucketOverfilled", + "parameters": [], + "errorSelector": "0x9725942a", + "description": "This error should never be thrown as it indicates an invalid bucket state." + }, + { + "error": "PriceNotFoundForToken", + "parameters": [ + { + "type": "address", + "name": "token" + } + ], + "errorSelector": "0x9a655f7b", + "description": "Thrown when a price cannot be found for a specific token." + }, + { + "error": "TokenMaxCapacityExceeded", + "parameters": [ + { + "type": "uint256", + "name": "capacity" + }, + { + "type": "uint256", + "name": "requested" + }, + { + "type": "address", + "name": "tokenAddress" + } + ], + "errorSelector": "0x1a76572a", + "description": "Thrown when the user requests to transfer more of a token than the capacity of the bucket." + }, + { + "error": "TokenRateLimitReached", + "parameters": [ + { + "type": "uint256", + "name": "minWaitInSeconds" + }, + { + "type": "uint256", + "name": "available" + }, + { + "type": "address", + "name": "tokenAddress" + } + ], + "errorSelector": "0xd0c8d23a", + "description": "Thrown when the user requests to transfer more of a token than currently available in the bucket. The user might have to wait at least `minWaitInSeconds` for enough availability, or transfer the currently `available` amount." + } +] diff --git a/src/config/data/ccip/errors/router.json b/src/config/data/ccip/errors/router.json new file mode 100644 index 00000000000..6a92b759228 --- /dev/null +++ b/src/config/data/ccip/errors/router.json @@ -0,0 +1,25 @@ +[ + { + "error": "UnsupportedDestinationChain", + "parameters": [ + { + "type": "uint64", + "name": "destChainSelector" + } + ], + "errorSelector": "0xae236d9c", + "description": "Thrown when the destination chain is not supported." + }, + { + "error": "InsufficientFeeTokenAmount", + "parameters": [], + "errorSelector": "0x07da6ee6", + "description": "Thrown when the CCIP fees are paid with native tokens, but not enough is sent with the transaction." + }, + { + "error": "InvalidMsgValue", + "parameters": [], + "errorSelector": "0x1841b4e1", + "description": "Thrown when the CCIP fees are _not_ paid in native tokens, but `msg.value` is non-zero." + } +] diff --git a/src/config/data/ccip/types.ts b/src/config/data/ccip/types.ts index de52eff11b6..8c634d874d8 100644 --- a/src/config/data/ccip/types.ts +++ b/src/config/data/ccip/types.ts @@ -98,3 +98,13 @@ export enum Environment { export enum Version { V1_2_0 = "1.2.0", } + +export interface CCIPSendErrorEntry { + error: string + parameters?: Array<{ + type: string + name: string + }> + errorSelector?: string + description: string +} diff --git a/src/content/ccip/api-reference/errors.mdx b/src/content/ccip/api-reference/errors.mdx index 4e56e14f8c4..768f804b8df 100644 --- a/src/content/ccip/api-reference/errors.mdx +++ b/src/content/ccip/api-reference/errors.mdx @@ -5,6 +5,8 @@ title: "Errors API Reference" --- import CcipCommon from "@features/ccip/CcipCommon.astro" +import { CCIPSendError } from "@features/ccip/components/api-reference" +import { Aside, CopyText } from "@components" @@ -12,50 +14,20 @@ When invoking the `ccipSend` [function](/ccip/api-reference/i-router-client#ccip ## Router -| Error | Parameters | Description | -| --------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------- | -| UnsupportedDestinationChain | | Thrown when the destination chain is not supported. | -| InsufficientFeeTokenAmount | - | Thrown when the CCIP fees are paid with native tokens, but not enough is sent with the transaction. | -| InvalidMsgValue | - | Thrown when the CCIP fees are _not_ paid in native tokens, but `msg.value` is non-zero. | + ## Onramp -| Error | Parameters | Description | -| --------------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -| NotAFeeToken |
  • address token
| Thrown when an unsupported fee token is used. | -| UnsupportedToken |
  • IERC20 token
| Thrown when an unsupported transfer token is used. | -| InvalidAddress |
  • bytes encodedAddress
| Thrown when the receiver address is invalid. | -| InvalidExtraArgsTag | - | Thrown when an invalid extra arguments tag is used. | -| RouterMustSetOriginalSender | - | This error should never be thrown as the router always sets the sender. | -| MustBeCalledByRouter | - | This error should never be thrown as the router always makes the call. | -| MessageGasLimitTooHigh | - | Thrown when the gas limit is too high. | -| UnsupportedNumberOfTokens | - | Thrown when too many tokens are involved in the transfer. | -| SenderNotAllowed |
  • address sender
| Thrown when the sender is not allowlisted. | -| MaxFeeBalanceReached | - | Thrown when the onRamp has reached its maximum fee storage capacity. If it is full, it cannot process new transactions. | + ## RateLimiter -| Error | Parameters | Description | -| --------------------------------- | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| PriceNotFoundForToken |
  • address token
| Thrown when a price cannot be found for a specific token. | -| BucketOverfilled | - | This error should never be thrown as it indicates an invalid bucket state. | -| AggregateValueMaxCapacityExceeded |
  • uint256 capacity
  • uint256 requested
| Thrown when the user requests to transfer more value than the capacity of the aggregate rate limit bucket. | -| TokenMaxCapacityExceeded |
  • uint256 capacity
  • uint256 requested
  • address tokenAddress
| Thrown when the user requests to transfer more of a token than the capacity of the bucket. | -| AggregateValueRateLimitReached |
  • uint256 minWaitInSeconds
  • uint256 available
| Thrown when the user requests to transfer more value than currently available in the bucket. The user might have to wait for at least `minWaitInSeconds` for enough availability or transfer the currently `available` amount. | -| TokenRateLimitReached |
  • uint256 minWaitInSeconds
  • uint256 available
  • address tokenAddress
| Thrown when the user requests to transfer more of a token than currently available in the bucket. The user might have to wait at least `minWaitInSeconds` for enough availability, or transfer the currently `available` amount. | + ## ERC20 -| Error | Description | -| ---------------------------------------- | ------------------------------------------------------------- | -| ERC20: burn amount exceeds balance | Thrown when the amount to be burned exceeds the pool balance. | -| ERC20: transfer amount exceeds allowance | Thrown when the transfer amount exceeds the allowance. | + ## PriceRegistry -| Error | Parameters | Description | -| ----------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------ | -| ChainNotSupported |
  • uint64 chain
| Thrown when a chain is not supported. | -| StaleGasPrice |
  • uint64 destChainSelector
  • uint256 threshold
  • uint256 timePassed
| Thrown when the gas price is stale. | -| TokenNotSupported |
  • address token
| Thrown when a token is not supported. | -| StaleTokenPrice |
  • address token
  • uint256 threshold
  • uint256 timePassed
| Thrown when the price of a token is stale. | + diff --git a/src/features/ccip/components/api-reference/Errors.astro b/src/features/ccip/components/api-reference/Errors.astro new file mode 100644 index 00000000000..81d0b42d6a3 --- /dev/null +++ b/src/features/ccip/components/api-reference/Errors.astro @@ -0,0 +1,110 @@ +--- +// Importing necessary modules and error data +import { + erc20Errors, + routerErrors, + onrampErrors, + ratelimiterErrors, + priceRegistryErrors, + CCIPSendErrorEntry, +} from "@config/data/ccip/" +import { CopyText } from "@components" +import { marked } from "marked" + +// Get the prop type and determine which error data to use +const { type } = Astro.props +let errors: CCIPSendErrorEntry[] = [] + +switch (type) { + case "erc20": + errors = erc20Errors + break + case "router": + errors = routerErrors + break + case "onramp": + errors = onrampErrors + break + case "rate-limiter": + errors = ratelimiterErrors + break + case "price-registry": + errors = priceRegistryErrors + break + default: + throw new Error(`Invalid error type: ${type}`) +} + +// Determine if any errors have parameters or an error selector +const hasParameters = errors.some((error) => error.parameters && error.parameters.length > 0) +const hasErrorSelector = errors.some((error) => error.errorSelector) + +const renderMarkdown = (text: string) => { + return marked.parse(text) +} +--- + +
+ + + + + {hasParameters ? : null} + {hasErrorSelector ? : null} + + + + + { + errors.map((error) => { + const params = error.parameters || [] + const paramsLength = params.length + return ( + + + {hasParameters ? ( + + ) : null} + {hasErrorSelector ? ( + + ) : null} + + ) + }) + } + +
ErrorParametersError SelectorDescription
{error.error} + {paramsLength > 0 + ? params.map((param, index) => ( + <> + + {param.type} {param.name} + + {index < paramsLength - 1 ?
: null} + + )) + : "-"} +
{error.errorSelector ? : "-"} +
+
+ + diff --git a/src/features/ccip/components/api-reference/index.ts b/src/features/ccip/components/api-reference/index.ts new file mode 100644 index 00000000000..4015c58ef62 --- /dev/null +++ b/src/features/ccip/components/api-reference/index.ts @@ -0,0 +1 @@ +export { default as CCIPSendError } from "./Errors.astro"