diff --git a/.eslintrc.js b/.eslintrc.js index 8280d78075..5e03bd7274 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -25,8 +25,11 @@ module.exports = { "@typescript-eslint/no-use-before-define": "off", "@typescript-eslint/no-empty-function": "warn", "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/no-loss-of-precision": "off", - "@typescript-eslint/camelcase": "off", + "@typescript-eslint/no-unused-vars": [ + "warn", + { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }, + ], + "no-loss-of-precision": "off", "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "warn", "unicorn/filename-case": [ diff --git a/apps/extension/noop-keplr-wallet-private/build/index.d.ts b/apps/extension/noop-keplr-wallet-private/build/index.d.ts index e35be1589a..212e25a7c8 100644 --- a/apps/extension/noop-keplr-wallet-private/build/index.d.ts +++ b/apps/extension/noop-keplr-wallet-private/build/index.d.ts @@ -14,7 +14,7 @@ export declare const onGoogleSignInClick: ((sceneTransition: { push(name: string, props?: Record): void; replace(name: string, props?: Record): void; }) => void) | undefined; -export declare const exportGenerateQRCodeDataByInterval: (_data: string, _setQRCodeData: (data: string) => void) => NodeJS.Timer; +export declare const exportGenerateQRCodeDataByInterval: (_data: string, _setQRCodeData: (data: string) => void) => ReturnType; export declare const exportUpload: (_encryptedData: string) => Promise<{ otp: string; } | null>; diff --git a/apps/extension/noop-keplr-wallet-private/index.ts b/apps/extension/noop-keplr-wallet-private/index.ts index 8ec3e16094..50f732feda 100644 --- a/apps/extension/noop-keplr-wallet-private/index.ts +++ b/apps/extension/noop-keplr-wallet-private/index.ts @@ -19,7 +19,7 @@ export const onGoogleSignInClick: export const exportGenerateQRCodeDataByInterval = ( _data: string, _setQRCodeData: (data: string) => void -): NodeJS.Timer => { +): ReturnType => { throw new Error("Method not implemented."); }; diff --git a/apps/extension/package.json b/apps/extension/package.json index 63862a4c37..50dc33ebe6 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -23,8 +23,6 @@ }, "dependencies": { "@amplitude/analytics-browser": "^1.10.3", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", "@floating-ui/react": "^0.23.0", "@floating-ui/react-dom": "^1.3.0", "@keplr-wallet/analytics": "0.13.19", @@ -83,6 +81,7 @@ "long": "^4.0.0", "lottie-web": "^5.10.2", "os-browserify": "^0.3.0", + "ox": "^0.14.6", "p-queue": "^6.6.2", "process": "^0.11.10", "qrcode.react": "^3.1.0", @@ -143,13 +142,13 @@ "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.7.4", "deepmerge": "^4.2.2", - "fork-ts-checker-webpack-plugin": "^7.2.13", + "fork-ts-checker-webpack-plugin": "^9.1.0", "html-webpack-plugin": "^5.5.0", "identity-obj-proxy": "^3.0.0", "serialize-javascript": ">=3.1.0", "storybook": "^7.6.18", "style-loader": "^3.3.3", - "ts-loader": "^9.4.2", + "ts-loader": "^9.5.4", "webpack": "^5.74.0", "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "^5.0.1" diff --git a/apps/extension/src/config.ts b/apps/extension/src/config.ts index faea046894..86e5d9c82e 100644 --- a/apps/extension/src/config.ts +++ b/apps/extension/src/config.ts @@ -1833,7 +1833,7 @@ export const EmbedChainInfos: (ChainInfo | ModularChainInfo)[] = [ "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/eip155:1/chain.png", }, ], - features: [], + features: ["eip-7702"], }, { rpc: "https://evm-8453.keplr.app", @@ -1870,7 +1870,7 @@ export const EmbedChainInfos: (ChainInfo | ModularChainInfo)[] = [ "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/eip155:1/chain.png", }, ], - features: ["op-stack-l1-data-fee"], + features: ["op-stack-l1-data-fee", "eip-7702"], }, { rpc: "https://evm-10.keplr.app", @@ -1907,7 +1907,7 @@ export const EmbedChainInfos: (ChainInfo | ModularChainInfo)[] = [ "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/eip155:1/chain.png", }, ], - features: ["op-stack-l1-data-fee"], + features: ["op-stack-l1-data-fee", "eip-7702"], }, { rpc: "https://evm-42161.keplr.app", @@ -1944,7 +1944,7 @@ export const EmbedChainInfos: (ChainInfo | ModularChainInfo)[] = [ "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/eip155:1/chain.png", }, ], - features: ["eth-address-gen", "eth-key-sign"], + features: ["eth-address-gen", "eth-key-sign", "eip-7702"], }, { rpc: "https://evm-137.keplr.app", @@ -1981,7 +1981,7 @@ export const EmbedChainInfos: (ChainInfo | ModularChainInfo)[] = [ "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/eip155:137/chain.png", }, ], - features: [], + features: ["eip-7702"], }, { rpc: "https://evm-56.keplr.app", @@ -2018,7 +2018,7 @@ export const EmbedChainInfos: (ChainInfo | ModularChainInfo)[] = [ "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/eip155:56/chain.png", }, ], - features: [], + features: ["eip-7702"], }, { rpc: "https://evm-43114.keplr.app", @@ -2741,7 +2741,7 @@ export const EmbedChainInfos: (ChainInfo | ModularChainInfo)[] = [ "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/eip155:80094/berachain-native.png", }, ], - features: [], + features: ["eip-7702"], }, { rpc: "https://evm-1514.keplr.app", @@ -2813,7 +2813,7 @@ export const EmbedChainInfos: (ChainInfo | ModularChainInfo)[] = [ coinGeckoId: "ethereum", }, ], - features: ["op-stack-l1-data-fee"], + features: ["op-stack-l1-data-fee", "eip-7702"], }, { isV2: true, @@ -3383,7 +3383,7 @@ export const EmbedChainInfos: (ChainInfo | ModularChainInfo)[] = [ "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/eip155:57073/ink-native.png", }, ], - features: ["op-stack-l1-data-fee"], + features: ["op-stack-l1-data-fee", "eip-7702"], }, { rpc: "https://evm-59144.keplr.app", @@ -3428,7 +3428,7 @@ export const EmbedChainInfos: (ChainInfo | ModularChainInfo)[] = [ "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/eip155:59144/linea-native.png", }, ], - features: [], + features: ["eip-7702"], }, { chainId: "union-1", @@ -3577,7 +3577,7 @@ export const EmbedChainInfos: (ChainInfo | ModularChainInfo)[] = [ "https://raw.githubusercontent.com/chainapsis/keplr-chain-registry/main/images/eip155:143/monad-native.png", }, ], - features: [], + features: ["eip-7702"], }, { chainId: "zigchain-1", diff --git a/apps/extension/src/index.tsx b/apps/extension/src/index.tsx index a8304a8968..9c73689805 100644 --- a/apps/extension/src/index.tsx +++ b/apps/extension/src/index.tsx @@ -66,6 +66,8 @@ import { WalletDeletePage, WalletSelectPage, WalletShowSensitivePage, + SmartAccountPage, + SmartAccountConfirmPage, } from "./pages/wallet"; import { SuggestChainPage } from "./pages/suggest-chain"; import { ModalRootProvider } from "./components/modal"; @@ -549,6 +551,14 @@ const RoutesAfterReady: FunctionComponent = observer(() => { path="/wallet/show-sensitive" element={} /> + } + /> + } + /> } /> } /> ` @@ -145,6 +146,7 @@ export const AccountItemSwitchModal = observer( const icnsPrimaryName = useGetIcnsName(bech32Address); const paragraph = useGetKeyInfoParagraph(keyInfo, true); + const eip7702Chains = useEip7702Chains(); const dropdownItems = (() => { const defaults = [ { @@ -186,6 +188,20 @@ export const AccountItemSwitchModal = observer( } } + // Smart Account menu — only for software wallets with at least one EIP-7702 chain + if ( + (keyInfo.type === "mnemonic" || keyInfo.type === "private-key") && + eip7702Chains.length > 0 + ) { + defaults.splice(defaults.length - 1, 0, { + key: "smart-account", + label: intl.formatMessage({ + id: "page.wallet.keyring-item.dropdown.smart-account-title", + }), + onSelect: () => navigate(`/wallet/smart-account?id=${keyInfo.id}`), + }); + } + return defaults; })(); diff --git a/apps/extension/src/pages/send/amount/evm/hooks/use-evm-transfer-tx-submit.ts b/apps/extension/src/pages/send/amount/evm/hooks/use-evm-transfer-tx-submit.ts index 3e942ccaf8..fa50427695 100644 --- a/apps/extension/src/pages/send/amount/evm/hooks/use-evm-transfer-tx-submit.ts +++ b/apps/extension/src/pages/send/amount/evm/hooks/use-evm-transfer-tx-submit.ts @@ -70,9 +70,9 @@ export function useEvmTransferTxSubmit({ amount: sendConfigs.amountConfig.amount[0].toDec().toString(), to: sendConfigs.recipientConfig.recipient, gasLimit: sendConfigs.gasConfig.gas, - maxFeePerGas: maxFeePerGas?.toString(), - maxPriorityFeePerGas: maxPriorityFeePerGas?.toString(), - gasPrice: gasPrice?.toString(), + maxFeePerGas: maxFeePerGas?.truncate().toString(), + maxPriorityFeePerGas: maxPriorityFeePerGas?.truncate().toString(), + gasPrice: gasPrice?.truncate().toString(), }); await ethereumAccount.sendEthereumTx( sender, @@ -133,7 +133,7 @@ export function useEvmTransferTxSubmit({ historyType, chainId, sendConfigs.recipientConfig.chainId, - signedTx, + new Uint8Array(signedTx), sendConfigs.senderConfig.sender, sendConfigs.recipientConfig.recipient, sendConfigs.amountConfig.amount.map((amount) => { diff --git a/apps/extension/src/pages/send/amount/index.tsx b/apps/extension/src/pages/send/amount/index.tsx index 7665f2e152..b431f34336 100644 --- a/apps/extension/src/pages/send/amount/index.tsx +++ b/apps/extension/src/pages/send/amount/index.tsx @@ -669,9 +669,9 @@ export const SendAmountPage: FunctionComponent = observer(() => { amount: sendConfigs.amountConfig.amount[0].toDec().toString(), to: sendConfigs.recipientConfig.recipient, gasLimit: sendConfigs.gasConfig.gas, - maxFeePerGas: maxFeePerGas?.toString(), - maxPriorityFeePerGas: maxPriorityFeePerGas?.toString(), - gasPrice: gasPrice?.toString(), + maxFeePerGas: maxFeePerGas?.truncate().toString(), + maxPriorityFeePerGas: maxPriorityFeePerGas?.truncate().toString(), + gasPrice: gasPrice?.truncate().toString(), }); const l1DataFee = await ethereumAccount.simulateOpStackL1Fee({ diff --git a/apps/extension/src/pages/setting/general/link-keplr-mobile/index.tsx b/apps/extension/src/pages/setting/general/link-keplr-mobile/index.tsx index eaf742499d..0f7400e107 100644 --- a/apps/extension/src/pages/setting/general/link-keplr-mobile/index.tsx +++ b/apps/extension/src/pages/setting/general/link-keplr-mobile/index.tsx @@ -279,7 +279,9 @@ const QRCodeView: FunctionComponent<{ }, [confirm, intl]); useEffect(() => { - let intervalId: NodeJS.Timer | undefined; + let intervalId: + | ReturnType + | undefined; try { (async () => { diff --git a/apps/extension/src/pages/sign/components/eth-tx/registry.tsx b/apps/extension/src/pages/sign/components/eth-tx/registry.tsx index 443135a977..797cd173ec 100644 --- a/apps/extension/src/pages/sign/components/eth-tx/registry.tsx +++ b/apps/extension/src/pages/sign/components/eth-tx/registry.tsx @@ -1,8 +1,8 @@ import React, { FunctionComponent, PropsWithChildren } from "react"; import { useTheme } from "styled-components"; import { ColorPalette } from "../../../../styles"; +import { UnsignedEVMTransaction } from "@keplr-wallet/stores-eth"; import { IEthTxRenderRegistry, IEthTxRenderer } from "./types"; -import { UnsignedTransaction } from "@ethersproject/transactions"; import { EthSendTokenTx } from "./render"; import { EthExecuteContractTx } from "./render/execute-contract"; @@ -15,7 +15,7 @@ export class EthTxRenderRegistry implements IEthTxRenderRegistry { render( chainId: string, - unsignedTx: UnsignedTransaction + unsignedTx: UnsignedEVMTransaction ): { icon?: React.ReactElement; title?: string | React.ReactElement; diff --git a/apps/extension/src/pages/sign/components/eth-tx/render/send-token.tsx b/apps/extension/src/pages/sign/components/eth-tx/render/send-token.tsx index 95d5ce8987..4d8617aee9 100644 --- a/apps/extension/src/pages/sign/components/eth-tx/render/send-token.tsx +++ b/apps/extension/src/pages/sign/components/eth-tx/render/send-token.tsx @@ -2,8 +2,8 @@ import React from "react"; import { observer } from "mobx-react-lite"; import { useStore } from "../../../../../stores"; import { CoinPretty, Dec } from "@keplr-wallet/unit"; -import { erc20ContractInterface } from "@keplr-wallet/stores-eth"; -import { BigNumber } from "@ethersproject/bignumber"; +import { erc20TransferFunction } from "@keplr-wallet/stores-eth"; +import { AbiFunction } from "ox"; import { IEthTxRenderer } from "../types"; import { ItemLogo } from "../../../../main/token-detail/msg-items/logo"; import { ColorPalette } from "../../../../../styles"; @@ -15,13 +15,22 @@ import { Stack } from "../../../../../components/stack"; import { useTheme } from "styled-components"; import { FormattedMessage } from "react-intl"; +function normalizeDisplayAmount(amount: string): string { + return amount.startsWith("0x") ? BigInt(amount).toString() : amount; +} + export const EthSendTokenTx: IEthTxRenderer = { process(chainId, unsignedTx) { if (unsignedTx.data && unsignedTx.data !== "0x" && unsignedTx.to) { try { - const dataDecodedValues = erc20ContractInterface.decodeFunctionData( - "transfer", - unsignedTx.data + const selector = unsignedTx.data.slice(0, 10).toLowerCase(); + if (selector !== AbiFunction.getSelector(erc20TransferFunction)) { + return undefined; + } + + const dataDecodedValues = AbiFunction.decodeData( + erc20TransferFunction, + unsignedTx.data as `0x${string}` ); const erc20ContractAddress = unsignedTx.to; const recipient = dataDecodedValues[0]; @@ -32,8 +41,7 @@ export const EthSendTokenTx: IEthTxRenderer = { typeof erc20ContractAddress !== "string" || !recipient || typeof recipient !== "string" || - !amount || - amount instanceof BigNumber === false + typeof amount !== "bigint" ) { return undefined; } @@ -69,13 +77,16 @@ export const EthSendTokenTx: IEthTxRenderer = { ), }; } catch (e) { - // Fallback to other renderers if unsingedTx.data can't be decoded with ERC20 transfer method. + console.warn( + "ERC20 transfer selector matched but data decoding failed:", + e + ); return undefined; } } else { @@ -122,7 +133,7 @@ export const EthSendTokenTx: IEthTxRenderer = { ), }; @@ -152,7 +163,10 @@ export const EthSendTokenTxPretty: React.FunctionComponent<{ `Unexpected chain type "${u.type}" for EthSendTokenTxPretty (${mcInfo2.chainId})` ); })(); - const amountCoinPretty = new CoinPretty(currency, new Dec(Number(amount))); + const amountCoinPretty = new CoinPretty( + currency, + new Dec(normalizeDisplayAmount(amount)) + ); const theme = useTheme(); diff --git a/apps/extension/src/pages/sign/components/eth-tx/types.ts b/apps/extension/src/pages/sign/components/eth-tx/types.ts index fd2debf282..2cdc3a36b4 100644 --- a/apps/extension/src/pages/sign/components/eth-tx/types.ts +++ b/apps/extension/src/pages/sign/components/eth-tx/types.ts @@ -1,10 +1,10 @@ import React from "react"; -import { UnsignedTransaction } from "@ethersproject/transactions"; +import { UnsignedEVMTransaction } from "@keplr-wallet/stores-eth"; export interface IEthTxRenderer { process( chainId: string, - unsignedTx: UnsignedTransaction + unsignedTx: UnsignedEVMTransaction ): | { icon?: React.ReactElement; @@ -19,7 +19,7 @@ export interface IEthTxRenderRegistry { render( chainId: string, - unsignedTx: UnsignedTransaction + unsignedTx: UnsignedEVMTransaction ): { icon?: React.ReactElement; title?: string | React.ReactElement; diff --git a/apps/extension/src/pages/sign/ethereum/views/sign-tx-view.tsx b/apps/extension/src/pages/sign/ethereum/views/sign-tx-view.tsx index 2591f17e41..b9864d722b 100644 --- a/apps/extension/src/pages/sign/ethereum/views/sign-tx-view.tsx +++ b/apps/extension/src/pages/sign/ethereum/views/sign-tx-view.tsx @@ -30,7 +30,7 @@ import { KeystoneSign } from "../../components/keystone"; import styled, { useTheme } from "styled-components"; import SimpleBar from "simplebar-react"; import { ViewDataButton } from "../../components/view-data-button"; -import { UnsignedTransaction } from "@ethersproject/transactions"; +import { UnsignedEVMTransaction } from "@keplr-wallet/stores-eth"; import { defaultRegistry } from "../../components/eth-tx/registry"; import { ChainImageFallback } from "../../../../components/image"; import { Gutter } from "../../../../components/gutter"; @@ -373,7 +373,7 @@ export const EthereumSignTxView: FunctionComponent<{ useEffect(() => { (async () => { if (chainInfo.hasFeature("op-stack-l1-data-fee")) { - const { to, gasLimit, value, data, chainId }: UnsignedTransaction = + const { to, gasLimit, value, data, chainId }: UnsignedEVMTransaction = JSON.parse(Buffer.from(message).toString("utf8")); const l1DataFee = await ethereumAccount.simulateOpStackL1Fee({ @@ -829,7 +829,7 @@ export const EthereumSignTxView: FunctionComponent<{ interactionData.data.chainId, JSON.parse( Buffer.from(interactionData.data.message).toString() - ) as UnsignedTransaction + ) as UnsignedEVMTransaction ); if (icon !== undefined && title !== undefined) { diff --git a/apps/extension/src/pages/sign/ethereum/wrapper.tsx b/apps/extension/src/pages/sign/ethereum/wrapper.tsx index a58b560337..cd78c13727 100644 --- a/apps/extension/src/pages/sign/ethereum/wrapper.tsx +++ b/apps/extension/src/pages/sign/ethereum/wrapper.tsx @@ -43,6 +43,9 @@ export const SignEthereumTxPage: FunctionComponent = observer(() => { interactionData={signEthereumInteractionStore.waitingData} /> ); + case EthSignType.EIP5792: + // TODO: Implement EIP-5792 batch sign view + throw new Error("EIP-5792 batch sign view is not yet implemented"); default: throw new Error( `Unknown sign type: ${signEthereumInteractionStore.waitingData.data.signType}` diff --git a/apps/extension/src/pages/sign/utils/handle-eth-sign.ts b/apps/extension/src/pages/sign/utils/handle-eth-sign.ts index 0ee6c27290..8b1e4fa1df 100644 --- a/apps/extension/src/pages/sign/utils/handle-eth-sign.ts +++ b/apps/extension/src/pages/sign/utils/handle-eth-sign.ts @@ -23,7 +23,7 @@ import { EIP712MessageValidator, messageHash, } from "@keplr-wallet/background"; -import { serialize, TransactionTypes } from "@ethersproject/transactions"; +import { serializeEVMTransaction } from "@keplr-wallet/stores-eth"; import TransportWebHID from "@ledgerhq/hw-transport-webhid"; import { KeystoneKeys, @@ -277,9 +277,9 @@ export const connectAndSignEthWithLedger = async ( const isEIP1559 = !!tx.maxFeePerGas || !!tx.maxPriorityFeePerGas; if (isEIP1559) { - tx.type = TransactionTypes.eip1559; + tx.type = 2; } - const rlpArray = serialize(tx).replace("0x", ""); + const rlpArray = serializeEVMTransaction(tx).replace("0x", ""); return ethSignatureToBytes( await ethApp.signTransaction( @@ -303,6 +303,8 @@ export const connectAndSignEthWithLedger = async ( ) ); } + case EthSignType.EIP5792: + throw new Error("EIP-5792 batch signing is not supported on Ledger"); default: throw new Error("Invalid sign type"); } diff --git a/apps/extension/src/pages/sign/utils/keystone.ts b/apps/extension/src/pages/sign/utils/keystone.ts index 1821f0f7df..246347cc0a 100644 --- a/apps/extension/src/pages/sign/utils/keystone.ts +++ b/apps/extension/src/pages/sign/utils/keystone.ts @@ -1,4 +1,4 @@ -import { serialize, TransactionTypes } from "@ethersproject/transactions"; +import { serializeEVMTransaction } from "@keplr-wallet/stores-eth"; import { EthSignType } from "@keplr-wallet/types"; import { KeystoneEthereumSDK } from "@keystonehq/keystone-sdk"; @@ -40,7 +40,7 @@ export function getEthDataTypeFromSignType( const msg = JSON.parse(Buffer.from(message).toString()); const isEIP1559 = !!msg.maxFeePerGas || !!msg.maxPriorityFeePerGas; if (isEIP1559) { - msg.type = TransactionTypes.eip1559; + msg.type = 2; } if (!msg.type) { return KeystoneEthereumSDK.DataType.transaction; @@ -52,6 +52,8 @@ export function getEthDataTypeFromSignType( return KeystoneEthereumSDK.DataType.personalMessage; case EthSignType.EIP712: return KeystoneEthereumSDK.DataType.typedData; + case EthSignType.EIP5792: + throw new Error("EIP-5792 batch signing is not supported on Keystone"); } } @@ -64,15 +66,17 @@ export function encodeEthMessage( const tx = JSON.parse(Buffer.from(message).toString()); const isEIP1559 = !!tx.maxFeePerGas || !!tx.maxPriorityFeePerGas; if (isEIP1559) { - tx.type = TransactionTypes.eip1559; + tx.type = 2; } if (typeof tx.type === "string") { tx.type = +tx.type.replace(/^0x/, ""); } - return Buffer.from(serialize(tx).replace(/^0x/, ""), "hex"); + return Buffer.from(serializeEVMTransaction(tx).replace(/^0x/, ""), "hex"); case EthSignType.MESSAGE: case EthSignType.EIP712: return Buffer.from(message); + case EthSignType.EIP5792: + throw new Error("EIP-5792 batch signing is not supported on Keystone"); } } diff --git a/apps/extension/src/pages/wallet/index.ts b/apps/extension/src/pages/wallet/index.ts index 364bdccb21..0ed97118e9 100644 --- a/apps/extension/src/pages/wallet/index.ts +++ b/apps/extension/src/pages/wallet/index.ts @@ -2,3 +2,4 @@ export * from "./select"; export * from "./delete"; export * from "./change-name"; export * from "./show-sensitive"; +export { SmartAccountPage, SmartAccountConfirmPage } from "./smart-account"; diff --git a/apps/extension/src/pages/wallet/smart-account/confirm/components/card.tsx b/apps/extension/src/pages/wallet/smart-account/confirm/components/card.tsx new file mode 100644 index 0000000000..e084df6448 --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/confirm/components/card.tsx @@ -0,0 +1,8 @@ +import styled from "styled-components"; +import { DSColor } from "@keplr-wallet/design-system"; + +export const Card = styled.div` + border-radius: 0.375rem; + background-color: ${DSColor.background.surface.elevated}; + padding: 1rem; +`; diff --git a/apps/extension/src/pages/wallet/smart-account/confirm/components/detail-card.tsx b/apps/extension/src/pages/wallet/smart-account/confirm/components/detail-card.tsx new file mode 100644 index 0000000000..99f4731e76 --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/confirm/components/detail-card.tsx @@ -0,0 +1,136 @@ +import React, { FunctionComponent } from "react"; +import { useIntl } from "react-intl"; +import styled from "styled-components"; +import { DSColor, DSTypography } from "@keplr-wallet/design-system"; +import { XAxis, YAxis } from "../../../../../components/axis"; +import { ChainImageFallback } from "../../../../../components/image"; +import { DELEGATOR_DISPLAY } from "../../constants"; +import { truncateAddress } from "../../utils"; +import type { IModularChainInfoImpl } from "@keplr-wallet/stores"; +import { Card } from "./card"; + +export const DetailCard: FunctionComponent<{ + accountName: string; + hexAddress: string; + isUpgrade: boolean; + chainName: string; + chainInfo?: IModularChainInfoImpl; +}> = ({ accountName, hexAddress, isUpgrade, chainName, chainInfo }) => { + const intl = useIntl(); + + return ( + + + + + + + {accountName} + + {hexAddress && ( + + {truncateAddress(hexAddress)} + + )} + + + + + + + + {intl.formatMessage({ + id: isUpgrade + ? "page.wallet.smart-account.confirm.current.eoa" + : "page.wallet.smart-account.confirm.current.smart", + })} + + + + + + + + {intl.formatMessage({ + id: isUpgrade + ? "page.wallet.smart-account.confirm.current.smart" + : "page.wallet.smart-account.confirm.current.eoa", + })} + + + + + + + + {DELEGATOR_DISPLAY} + + + + + + + + {chainInfo && ( + + )} + + {chainName} + + + + + + ); +}; + +const Label: FunctionComponent<{ children: React.ReactNode }> = ({ + children, +}) => ( + + {children} + +); + +const InfoRow = styled(XAxis)` + justify-content: space-between; + align-items: center; +`; + +const Divider = styled.div` + height: 1px; + background-color: ${DSColor.stroke.separator.primary}; +`; diff --git a/apps/extension/src/pages/wallet/smart-account/confirm/components/fee-card.tsx b/apps/extension/src/pages/wallet/smart-account/confirm/components/fee-card.tsx new file mode 100644 index 0000000000..f4c96046c9 --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/confirm/components/fee-card.tsx @@ -0,0 +1,111 @@ +import React, { Fragment, FunctionComponent } from "react"; +import { useIntl } from "react-intl"; +import styled from "styled-components"; +import { DSColor, DSTypography } from "@keplr-wallet/design-system"; +import { Card } from "./card"; +import { XAxis, YAxis } from "../../../../../components/axis"; +import { Gutter } from "../../../../../components/gutter"; +import { Skeleton } from "../../../../../components/skeleton"; + +export const FeeCard: FunctionComponent<{ + feeDisplay: string | null; + feeUsd: string | null; + isEstimating: boolean; + isFailed: boolean; + insufficientBalance: boolean; + onRetry: () => void; +}> = ({ + feeDisplay, + feeUsd, + isEstimating, + isFailed, + insufficientBalance, + onRetry, +}) => { + const intl = useIntl(); + + return ( + + + + {intl.formatMessage({ + id: "page.wallet.smart-account.confirm.fee", + })} + +
+ + + + {feeUsd + ? feeUsd + : feeDisplay === null + ? intl.formatMessage({ + id: "page.wallet.smart-account.confirm.fee.failed", + }) + : feeDisplay} + + {feeUsd && feeDisplay && ( + + {feeDisplay} + + )} + + + + + {insufficientBalance && ( + + + + {intl.formatMessage({ + id: "page.wallet.smart-account.confirm.fee.insufficient", + })} + + + )} + + {isFailed && ( + + + + {intl.formatMessage({ + id: "page.wallet.smart-account.confirm.fee.retry", + })} + + + )} + + ); +}; + +const FeeCardContainer = styled(Card)` + padding: 0.875rem 1rem; + margin-bottom: 0.75rem; +`; diff --git a/apps/extension/src/pages/wallet/smart-account/confirm/components/summary-card.tsx b/apps/extension/src/pages/wallet/smart-account/confirm/components/summary-card.tsx new file mode 100644 index 0000000000..4d07752df6 --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/confirm/components/summary-card.tsx @@ -0,0 +1,66 @@ +import React, { FunctionComponent } from "react"; +import { useIntl } from "react-intl"; +import styled from "styled-components"; +import { + DSColor, + DSTypography, + CheckmarkCircleIcon, + XCloseIcon, +} from "@keplr-wallet/design-system"; +import { XAxis, YAxis } from "../../../../../components/axis"; +import { Gutter } from "../../../../../components/gutter"; +import { Card } from "./card"; + +export const SummaryCard: FunctionComponent<{ isUpgrade: boolean }> = ({ + isUpgrade, +}) => { + const intl = useIntl(); + + return ( + + + + {isUpgrade ? ( + + ) : ( + + )} + + + + + {intl.formatMessage({ + id: isUpgrade + ? "page.wallet.smart-account.confirm.summary.upgrade" + : "page.wallet.smart-account.confirm.summary.downgrade", + })} + + + + {intl.formatMessage({ + id: isUpgrade + ? "page.wallet.smart-account.confirm.summary.upgrade.desc" + : "page.wallet.smart-account.confirm.summary.downgrade.desc", + })} + + + + + ); +}; + +const IconCircle = styled.div` + width: 2.75rem; + min-width: 2.75rem; + height: 2.75rem; + border-radius: 50%; + background-color: ${DSColor.button.primaryTransparent}; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +`; diff --git a/apps/extension/src/pages/wallet/smart-account/confirm/confirm.tsx b/apps/extension/src/pages/wallet/smart-account/confirm/confirm.tsx new file mode 100644 index 0000000000..224c6aa18d --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/confirm/confirm.tsx @@ -0,0 +1,194 @@ +import React, { + FunctionComponent, + useCallback, + useMemo, + useRef, + useState, +} from "react"; +import { observer } from "mobx-react-lite"; +import { useIntl } from "react-intl"; +import { + UpgradeSmartAccountMsg, + DowngradeSmartAccountMsg, +} from "@keplr-wallet/background"; +import { InExtensionMessageRequester } from "@keplr-wallet/router-extension"; +import { BACKGROUND_PORT } from "@keplr-wallet/router"; +import { DSColor, DSTypography } from "@keplr-wallet/design-system"; +import { BackButton } from "../../../../layouts/header/components"; +import { HeaderLayout } from "../../../../layouts/header"; +import { CancelIcon } from "../../../../components/button"; +import { Gutter } from "../../../../components/gutter"; +import { Box } from "../../../../components/box"; +import { useStore } from "../../../../stores"; +import { useNotification } from "../../../../hooks/notification"; +import { useRedirectIfInvalid } from "../hooks/use-redirect-if-invalid"; +import { useVaultHexAddress } from "../hooks/use-vault-hex-address"; +import { useConfirmRoute } from "./hooks/use-confirm-route"; +import { useSmartAccountFee } from "./hooks/use-smart-account-fee"; +import { SummaryCard } from "./components/summary-card"; +import { DetailCard } from "./components/detail-card"; +import { FeeCard } from "./components/fee-card"; + +export const SmartAccountConfirmPage: FunctionComponent = observer(() => { + const intl = useIntl(); + const notification = useNotification(); + const { chainStore, keyRingStore } = useStore(); + + const { + vaultId, + chainId, + chainName, + isValid, + isUpgrade, + goBack, + goBackAfterApprove, + } = useConfirmRoute(); + + useRedirectIfInvalid(isValid); + + const hexAddress = useVaultHexAddress(chainId, vaultId); + + const accountName = useMemo(() => { + const keyInfo = keyRingStore.keyInfos.find((info) => info.id === vaultId); + return keyInfo?.name || "Account"; + }, [keyRingStore.keyInfos, vaultId]); + + const chainInfo = useMemo(() => { + try { + return chainStore.getModularChain(chainId); + } catch { + return undefined; + } + }, [chainStore, chainId]); + + const { + feeDisplay, + feeUsd, + isEstimating, + isFailed, + insufficientBalance, + balanceLoaded, + retry, + } = useSmartAccountFee(chainId, hexAddress, isValid); + + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + const submittingRef = useRef(false); + + const handleApprove = useCallback(async () => { + if (submittingRef.current) return; + submittingRef.current = true; + setIsLoading(true); + setError(null); + try { + const requester = new InExtensionMessageRequester(); + const Msg = isUpgrade ? UpgradeSmartAccountMsg : DowngradeSmartAccountMsg; + await requester.sendMessage(BACKGROUND_PORT, new Msg(chainId, vaultId)); + notification.show( + "success", + intl.formatMessage({ id: "notification.transaction-success" }), + "" + ); + goBackAfterApprove(); + } catch (e) { + notification.show( + "failed", + intl.formatMessage({ id: "error.transaction-failed" }), + "" + ); + setError(intl.formatMessage({ id: "error.transaction-failed" })); + setIsLoading(false); + submittingRef.current = false; + } + }, [isUpgrade, chainId, vaultId, goBackAfterApprove, notification, intl]); + + if (!isValid) return null; + + const approveDisabled = + isLoading || + insufficientBalance || + isFailed || + !balanceLoaded || + isEstimating || + !feeDisplay; + + return ( + } + bottomButtons={[ + { + textOverrideIcon: , + color: "secondary", + size: "large", + style: { width: "3.25rem" }, + onClick: goBack, + disabled: isLoading, + }, + { + isSpecial: true, + text: intl.formatMessage({ id: "button.approve" }), + size: "large", + isLoading, + disabled: approveDisabled, + onClick: handleApprove, + }, + ]} + > + + + + {intl.formatMessage({ + id: "page.wallet.smart-account.confirm.section-title", + })} + + + + + + + +
+ + + + {error && ( + + + {error} + + + )} + + + ); +}); diff --git a/apps/extension/src/pages/wallet/smart-account/confirm/hooks/use-confirm-route.ts b/apps/extension/src/pages/wallet/smart-account/confirm/hooks/use-confirm-route.ts new file mode 100644 index 0000000000..22bc199aa3 --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/confirm/hooks/use-confirm-route.ts @@ -0,0 +1,51 @@ +import { useCallback } from "react"; +import { useSearchParams } from "react-router-dom"; +import { useNavigate } from "react-router"; + +export function useConfirmRoute() { + const [searchParams] = useSearchParams(); + const navigate = useNavigate(); + + const vaultId = searchParams.get("id") ?? ""; + const chainId = searchParams.get("chainId") ?? ""; + const chainName = searchParams.get("chainName") ?? ""; + const direction = searchParams.get("direction"); + + const isValid = + !!vaultId && + !!chainId && + (direction === "upgrade" || direction === "downgrade"); + + const isUpgrade = direction === "upgrade"; + + const goBack = useCallback( + () => + navigate(`/wallet/smart-account?id=${encodeURIComponent(vaultId)}`, { + replace: true, + }), + [navigate, vaultId] + ); + + const goBackAfterApprove = useCallback( + () => + navigate( + `/wallet/smart-account?id=${encodeURIComponent( + vaultId + )}&updatedChainId=${encodeURIComponent( + chainId + )}&updatedDirection=${direction}`, + { replace: true } + ), + [navigate, vaultId, chainId, direction] + ); + + return { + vaultId, + chainId, + chainName, + isValid, + isUpgrade, + goBack, + goBackAfterApprove, + }; +} diff --git a/apps/extension/src/pages/wallet/smart-account/confirm/hooks/use-smart-account-fee.ts b/apps/extension/src/pages/wallet/smart-account/confirm/hooks/use-smart-account-fee.ts new file mode 100644 index 0000000000..470571fedf --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/confirm/hooks/use-smart-account-fee.ts @@ -0,0 +1,177 @@ +import { useCallback, useEffect, useMemo, useState } from "react"; +import { + ALLOWED_DELEGATORS, + buildDummyAuthorizationList, +} from "@keplr-wallet/background"; +import { computeEIP1559TxFees } from "@keplr-wallet/hooks-evm"; +import { CoinPretty, Dec, Int } from "@keplr-wallet/unit"; +import { useStore } from "../../../../../stores"; +import { formatFee } from "../../utils"; + +type FeeState = + | { status: "loading" } + | { status: "success"; gasUsed: number; l1DataFee?: Dec } + | { status: "error" }; + +export function useSmartAccountFee( + chainId: string, + hexAddress: string, + isValid: boolean +) { + const { chainStore, queriesStore, priceStore, ethereumAccountStore } = + useStore(); + + const nativeCurrency = useMemo(() => { + try { + const unwrapped = chainStore.getModularChain(chainId).unwrapped; + if (unwrapped.type === "evm") return unwrapped.evm.nativeCurrency; + if (unwrapped.type === "ethermint") return unwrapped.evm.nativeCurrency; + return undefined; + } catch { + return undefined; + } + }, [chainStore, chainId]); + + const evmChainId = useMemo(() => { + const unwrapped = chainStore.getModularChain(chainId).unwrapped; + if (unwrapped.type === "evm") return unwrapped.evm.chainId; + if (unwrapped.type === "ethermint") return unwrapped.evm.chainId; + return 0; + }, [chainStore, chainId]); + + const nativeSymbol = nativeCurrency?.coinDenom ?? "ETH"; + + const [feeState, setFeeState] = useState({ status: "loading" }); + const [retryCount, setRetryCount] = useState(0); + + useEffect(() => { + if (!isValid || !hexAddress || !evmChainId) return; + let cancelled = false; + setFeeState({ status: "loading" }); + + const ethereumAccount = ethereumAccountStore.getAccount(chainId); + + const modularChainInfo = chainStore.getModularChain(chainId); + const hasOpStackFee = modularChainInfo.hasFeature("op-stack-l1-data-fee"); + + ethereumAccount + .simulateGas(hexAddress, { + to: hexAddress, + value: "0x0", + data: "0x", + authorizationList: buildDummyAuthorizationList( + ALLOWED_DELEGATORS[0], + evmChainId + ), + }) + .then(async (result) => { + if (cancelled) return; + + let l1DataFee: Dec | undefined; + if (hasOpStackFee) { + const gasLimit = Math.ceil(result.gasUsed * 1.3); + const l1Fee = await ethereumAccount.simulateOpStackL1Fee({ + to: hexAddress, + value: "0x0", + data: "0x", + gasLimit, + }); + l1DataFee = new Dec(BigInt(l1Fee)); + } + + if (!cancelled) { + setFeeState({ + status: "success", + gasUsed: result.gasUsed, + l1DataFee, + }); + } + }) + .catch(() => { + if (!cancelled) setFeeState({ status: "error" }); + }); + + return () => { + cancelled = true; + }; + }, [ + chainId, + chainStore, + hexAddress, + evmChainId, + isValid, + retryCount, + ethereumAccountStore, + ]); + + // Fee from reactive queries (feeHistory percentile + baseFee margin, fillUnsignedEVMTx와 동일 로직) + const ethereumQueries = queriesStore.get(chainId).ethereum; + const txFees = ethereumQueries + ? computeEIP1559TxFees(ethereumQueries, "average", chainId) + : undefined; + + const estimatedFeeWei = useMemo(() => { + if (feeState.status !== "success") return null; + const feePerGas = txFees?.maxFeePerGas ?? txFees?.gasPrice; + if (!feePerGas || feePerGas.isZero()) return null; + const gasLimit = Math.ceil(feeState.gasUsed * 1.3); + let fee = feePerGas.mul(new Dec(gasLimit)).truncate(); + if (feeState.l1DataFee) { + fee = fee.add(feeState.l1DataFee.truncate()); + } + return "0x" + BigInt(fee.toString()).toString(16); + }, [feeState, txFees]); + + const isEstimating = feeState.status === "loading"; + const isFailed = feeState.status === "error"; + + const feeDisplay = useMemo( + () => (estimatedFeeWei ? formatFee(estimatedFeeWei, nativeSymbol) : null), + [estimatedFeeWei, nativeSymbol] + ); + + const feeUsd = useMemo(() => { + if (!estimatedFeeWei || !nativeCurrency) return null; + try { + const feeCoin = new CoinPretty( + nativeCurrency, + new Int(BigInt(estimatedFeeWei).toString()) + ); + const price = priceStore.calculatePrice(feeCoin); + return price ? price.toString() : null; + } catch { + return null; + } + }, [estimatedFeeWei, nativeCurrency, priceStore]); + + const balance = + nativeCurrency && hexAddress + ? queriesStore + .get(chainId) + .queryBalances.getQueryEthereumHexAddress(hexAddress) + .getBalance(nativeCurrency) + : undefined; + + const balanceLoaded = !!balance?.response; + + const insufficientBalance = + balance && balanceLoaded && estimatedFeeWei + ? new Int(balance.balance.toCoin().amount).lt( + new Int(BigInt(estimatedFeeWei).toString()) + ) + : false; + + const retry = useCallback(() => { + setRetryCount((prev) => prev + 1); + }, []); + + return { + feeDisplay, + feeUsd, + isEstimating, + isFailed, + insufficientBalance, + balanceLoaded, + retry, + }; +} diff --git a/apps/extension/src/pages/wallet/smart-account/confirm/index.ts b/apps/extension/src/pages/wallet/smart-account/confirm/index.ts new file mode 100644 index 0000000000..70afd3ae7b --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/confirm/index.ts @@ -0,0 +1 @@ +export { SmartAccountConfirmPage } from "./confirm"; diff --git a/apps/extension/src/pages/wallet/smart-account/constants.ts b/apps/extension/src/pages/wallet/smart-account/constants.ts new file mode 100644 index 0000000000..47a0164bff --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/constants.ts @@ -0,0 +1,9 @@ +import { ALLOWED_DELEGATORS } from "@keplr-wallet/background"; +import { truncateAddress } from "./utils"; + +export const TOGGLE_ANIMATION_DELAY_MS = 200; +export const STATUS_UPDATE_DELAY_MS = 100; + +export const DELEGATOR_DISPLAY = ALLOWED_DELEGATORS[0] + ? truncateAddress(ALLOWED_DELEGATORS[0]) + : ""; diff --git a/apps/extension/src/pages/wallet/smart-account/hooks/use-eip7702-chains.ts b/apps/extension/src/pages/wallet/smart-account/hooks/use-eip7702-chains.ts new file mode 100644 index 0000000000..dceb7db3a3 --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/hooks/use-eip7702-chains.ts @@ -0,0 +1,28 @@ +import { useMemo } from "react"; +import { useStore } from "../../../../stores"; + +export function useEip7702Chains() { + const { chainStore } = useStore(); + + return useMemo( + () => + chainStore.modularChainInfos + .map((info) => { + const unwrapped = info.unwrapped; + if (unwrapped.type === "evm") { + if (unwrapped.evm.features?.includes("eip-7702")) { + return { chainId: info.chainId, chainName: info.chainName }; + } + } else if (unwrapped.type === "ethermint") { + if (unwrapped.cosmos.features?.includes("eip-7702")) { + return { chainId: info.chainId, chainName: info.chainName }; + } + } + return null; + }) + .filter( + (item): item is { chainId: string; chainName: string } => item != null + ), + [chainStore.modularChainInfos] + ); +} diff --git a/apps/extension/src/pages/wallet/smart-account/hooks/use-redirect-if-invalid.ts b/apps/extension/src/pages/wallet/smart-account/hooks/use-redirect-if-invalid.ts new file mode 100644 index 0000000000..43dd19f764 --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/hooks/use-redirect-if-invalid.ts @@ -0,0 +1,12 @@ +import { useEffect } from "react"; +import { useNavigate } from "react-router"; + +export function useRedirectIfInvalid(isValid: boolean, to = "/") { + const navigate = useNavigate(); + + useEffect(() => { + if (!isValid) { + navigate(to, { replace: true }); + } + }, [isValid, navigate, to]); +} diff --git a/apps/extension/src/pages/wallet/smart-account/hooks/use-vault-hex-address.ts b/apps/extension/src/pages/wallet/smart-account/hooks/use-vault-hex-address.ts new file mode 100644 index 0000000000..87181040a7 --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/hooks/use-vault-hex-address.ts @@ -0,0 +1,29 @@ +import { useEffect, useState } from "react"; +import { GetEthereumAddressForVaultMsg } from "@keplr-wallet/background"; +import { InExtensionMessageRequester } from "@keplr-wallet/router-extension"; +import { BACKGROUND_PORT } from "@keplr-wallet/router"; + +export function useVaultHexAddress(chainId: string, vaultId: string): string { + const [hexAddress, setHexAddress] = useState(""); + + useEffect(() => { + if (!chainId || !vaultId) return; + let cancelled = false; + + new InExtensionMessageRequester() + .sendMessage( + BACKGROUND_PORT, + new GetEthereumAddressForVaultMsg(chainId, vaultId) + ) + .then((addr) => { + if (!cancelled) setHexAddress(addr); + }) + .catch(() => {}); + + return () => { + cancelled = true; + }; + }, [chainId, vaultId]); + + return hexAddress; +} diff --git a/apps/extension/src/pages/wallet/smart-account/index.ts b/apps/extension/src/pages/wallet/smart-account/index.ts new file mode 100644 index 0000000000..ea51c5e54a --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/index.ts @@ -0,0 +1,2 @@ +export { SmartAccountPage } from "./network-list"; +export { SmartAccountConfirmPage } from "./confirm"; diff --git a/apps/extension/src/pages/wallet/smart-account/network-list/components/chain-row-item.tsx b/apps/extension/src/pages/wallet/smart-account/network-list/components/chain-row-item.tsx new file mode 100644 index 0000000000..e494d88a3b --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/network-list/components/chain-row-item.tsx @@ -0,0 +1,86 @@ +import React, { FunctionComponent } from "react"; +import { useIntl } from "react-intl"; +import styled, { css } from "styled-components"; +import { observer } from "mobx-react-lite"; +import type { DelegationStatus } from "@keplr-wallet/types"; +import { DSColor, DSTypography } from "@keplr-wallet/design-system"; +import { XAxis } from "../../../../../components/axis"; +import { Gutter } from "../../../../../components/gutter"; +import { ChainImageFallback } from "../../../../../components/image"; +import { Toggle } from "../../../../../components/toggle"; +import { useStore } from "../../../../../stores"; + +export const ChainRowItem: FunctionComponent<{ + chainId: string; + chainName: string; + status: DelegationStatus; + isAnimating: boolean; + disabled?: boolean; + onToggle: () => void; +}> = observer( + ({ chainId, chainName, status, isAnimating, disabled, onToggle }) => { + const intl = useIntl(); + const { chainStore } = useStore(); + + let chainInfo; + try { + chainInfo = chainStore.getModularChain(chainId); + } catch { + // noop + } + + return ( + + + {chainInfo && ( + + )} + + + {chainName} + + {status === "unsupported" && ( + + + + {intl.formatMessage({ + id: "page.wallet.smart-account.status.unsupported", + })} + + + )} + + + + + + ); + } +); + +const ChainRow = styled(XAxis)` + padding: 0.75rem 0; + align-items: center; + justify-content: space-between; +`; + +const ToggleTransitionWrapper = styled.div<{ + $enableTransition: boolean; +}>` + ${(props) => + !props.$enableTransition && + css` + * { + transition: none !important; + } + `} +`; diff --git a/apps/extension/src/pages/wallet/smart-account/network-list/hooks/use-chain-statuses.ts b/apps/extension/src/pages/wallet/smart-account/network-list/hooks/use-chain-statuses.ts new file mode 100644 index 0000000000..164d6d9bb3 --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/network-list/hooks/use-chain-statuses.ts @@ -0,0 +1,58 @@ +import { useEffect, useRef, useState } from "react"; +import { useSearchParams } from "react-router-dom"; +import type { DelegationStatus } from "@keplr-wallet/types"; +import { useStore } from "../../../../../stores"; +import { useEip7702Chains } from "../../hooks/use-eip7702-chains"; +import { STATUS_UPDATE_DELAY_MS } from "../../constants"; + +export interface ChainStatus { + chainId: string; + chainName: string; + status: DelegationStatus; + isLoading: boolean; + hasError: boolean; +} + +export function useChainStatuses(hexAddress: string) { + const [searchParams] = useSearchParams(); + const { queriesStore } = useStore(); + const eip7702Chains = useEip7702Chains(); + + const updatedChainId = searchParams.get("updatedChainId"); + const updatedDirection = searchParams.get("updatedDirection"); + + const chainStatuses: ChainStatus[] = eip7702Chains.map((chain) => { + const query = queriesStore + .get(chain.chainId) + .ethereum?.querySmartAccountDelegationStatus?.getQueryByAddress( + hexAddress + ); + return { + chainId: chain.chainId, + chainName: chain.chainName, + status: query?.delegationStatus ?? "ready", + isLoading: !!(!query?.response && !query?.error), + hasError: !!query?.error, + }; + }); + + const [animatingChainId, setAnimatingChainId] = useState(null); + const appliedRef = useRef(null); + + useEffect(() => { + if ( + !updatedChainId || + !updatedDirection || + appliedRef.current === updatedChainId + updatedDirection + ) + return; + appliedRef.current = updatedChainId + updatedDirection; + const timer = setTimeout( + () => setAnimatingChainId(updatedChainId), + STATUS_UPDATE_DELAY_MS + ); + return () => clearTimeout(timer); + }, [updatedChainId, updatedDirection]); + + return { chainStatuses, animatingChainId }; +} diff --git a/apps/extension/src/pages/wallet/smart-account/network-list/index.ts b/apps/extension/src/pages/wallet/smart-account/network-list/index.ts new file mode 100644 index 0000000000..eca81b93e1 --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/network-list/index.ts @@ -0,0 +1 @@ +export { SmartAccountPage } from "./network-list"; diff --git a/apps/extension/src/pages/wallet/smart-account/network-list/network-list.tsx b/apps/extension/src/pages/wallet/smart-account/network-list/network-list.tsx new file mode 100644 index 0000000000..0fc6434e32 --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/network-list/network-list.tsx @@ -0,0 +1,103 @@ +import React, { FunctionComponent, useCallback, useRef, useState } from "react"; +import { observer } from "mobx-react-lite"; +import { useSearchParams } from "react-router-dom"; +import { useNavigate } from "react-router"; +import { useIntl } from "react-intl"; +import type { DelegationStatus } from "@keplr-wallet/types"; +import { DSColor, DSTypography } from "@keplr-wallet/design-system"; +import { BackButton } from "../../../../layouts/header/components"; +import { HeaderLayout } from "../../../../layouts/header"; +import { Box } from "../../../../components/box"; +import { useRedirectIfInvalid } from "../hooks/use-redirect-if-invalid"; +import { useEip7702Chains } from "../hooks/use-eip7702-chains"; +import { useVaultHexAddress } from "../hooks/use-vault-hex-address"; +import { TOGGLE_ANIMATION_DELAY_MS } from "../constants"; +import { useChainStatuses } from "./hooks/use-chain-statuses"; +import { ChainRowItem } from "./components/chain-row-item"; + +export const SmartAccountPage: FunctionComponent = observer(() => { + const [searchParams] = useSearchParams(); + const navigate = useNavigate(); + const intl = useIntl(); + const vaultId = searchParams.get("id"); + + useRedirectIfInvalid(!!vaultId); + + const eip7702Chains = useEip7702Chains(); + const firstChainId = eip7702Chains[0]?.chainId ?? ""; + const hexAddress = useVaultHexAddress(firstChainId, vaultId ?? ""); + + const { chainStatuses, animatingChainId } = useChainStatuses(hexAddress); + + const navigatingRef = useRef(false); + const [pendingToggleChainId, setPendingToggleChainId] = useState< + string | null + >(null); + + const handleToggle = useCallback( + (chainId: string, chainName: string, currentStatus: DelegationStatus) => { + if (currentStatus === "unsupported" || navigatingRef.current) return; + navigatingRef.current = true; + setPendingToggleChainId(chainId); + const direction = currentStatus === "ready" ? "upgrade" : "downgrade"; + setTimeout(() => { + navigatingRef.current = false; + setPendingToggleChainId(null); + navigate( + `/wallet/smart-account/confirm?id=${vaultId}&chainId=${encodeURIComponent( + chainId + )}&chainName=${encodeURIComponent(chainName)}&direction=${direction}`, + { replace: true } + ); + }, TOGGLE_ANIMATION_DELAY_MS); + }, + [navigate, vaultId] + ); + + if (!vaultId) return null; + + return ( + } + > + + + {intl.formatMessage({ + id: "page.wallet.smart-account.description", + })} + + + + {chainStatuses.map((chain) => { + const isPending = pendingToggleChainId === chain.chainId; + const displayStatus = isPending + ? chain.status === "ready" + ? "supported" + : "ready" + : chain.status; + + return ( + + handleToggle(chain.chainId, chain.chainName, chain.status) + } + /> + ); + })} + + + + ); +}); diff --git a/apps/extension/src/pages/wallet/smart-account/utils.ts b/apps/extension/src/pages/wallet/smart-account/utils.ts new file mode 100644 index 0000000000..1de3de96f0 --- /dev/null +++ b/apps/extension/src/pages/wallet/smart-account/utils.ts @@ -0,0 +1,18 @@ +export const truncateAddress = (addr: string): string => + addr ? `${addr.slice(0, 10)}...${addr.slice(-8)}` : ""; + +export const formatFee = ( + weiStr: string, + symbol: string, + decimals = 18 +): string => { + const wei = BigInt(weiStr); + const divisor = BigInt(10) ** BigInt(decimals); + const whole = wei / divisor; + const frac = wei % divisor; + const fracStr = frac.toString().padStart(decimals, "0").slice(0, 6); + if (whole === BigInt(0) && frac === BigInt(0)) return `0 ${symbol}`; + if (whole === BigInt(0) && BigInt(fracStr) === BigInt(0)) + return `< 0.000001 ${symbol}`; + return `~${whole}.${fracStr} ${symbol}`; +}; diff --git a/apps/extension/src/stores/root.tsx b/apps/extension/src/stores/root.tsx index 020a5b4264..14a39c8e73 100644 --- a/apps/extension/src/stores/root.tsx +++ b/apps/extension/src/stores/root.tsx @@ -101,6 +101,7 @@ import { setInteractionDataHref } from "../utils"; import { InteractionIdPingMsg, InteractionPingMsg, + ALLOWED_DELEGATORS, } from "@keplr-wallet/background"; import { StarknetAccountStore, @@ -396,6 +397,7 @@ export class RootStore { EthereumQueries.use({ coingeckoAPIBaseURL: CoinGeckoAPIEndPoint, coingeckoAPIURI: CoinGeckoCoinDataByTokenAddress, + allowedDelegators: ALLOWED_DELEGATORS, forceNativeERC20Query: ( chainId, _chainGetter, diff --git a/package.json b/package.json index 7eba7a1f3a..6072b3f3c6 100644 --- a/package.json +++ b/package.json @@ -51,36 +51,30 @@ "prettier --check" ] }, - "remarkConfig": { - "plugins": [ - "@1stg/remark-preset" - ] - }, "keywords": [], "author": "chainapsis", "license": "Apache-2.0", "devDependencies": { - "@1stg/remark-preset": "^2.0.0", "@octokit/core": "^3.5.1", "@types/filesystem": "^0.0.32", "@types/jest": "^29.4.0", - "@types/node": "^18.13.0", + "@types/node": "^22.0.0", "@types/react": "^18.2.19", "@types/react-dom": "^18.2.7", "@types/react-is": "^18.2.1", - "@typescript-eslint/eslint-plugin": "^5.52.0", - "@typescript-eslint/parser": "^5.52.0", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", "bitcoinjs-lib": "^6.1.7", "cross-env": "^5.2.0", - "eslint": "^8.34.0", + "eslint": "^8.56.0", "eslint-config-prettier": "^8.6.0", "eslint-plugin-import": "^2.27.5", - "eslint-plugin-mdx": "^2.0.5", + "eslint-plugin-mdx": "^3.7.0", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-unicorn": "^45.0.2", - "eslint-plugin-unused-imports": "^2.0.0", + "eslint-plugin-unused-imports": "^4.0.0", "folder-hash": "^4.0.2", "husky": "^9.1.7", "jest": "^29.4.3", @@ -97,7 +91,7 @@ "semver": "^7.6.0", "starknet": "^8.9.1", "ts-jest": "^29.0.5", - "typescript": "5.0.4", + "typescript": "^5.7.0", "zx": "^4.2.0" }, "resolutions": { diff --git a/packages/background/package.json b/packages/background/package.json index f520d1c113..a207d7888b 100644 --- a/packages/background/package.json +++ b/packages/background/package.json @@ -29,10 +29,6 @@ "dependencies": { "@ethereumjs/common": "^2.6.5", "@ethereumjs/tx": "^3.5.2", - "@ethersproject/address": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wallet": "^5.7.0", "@keplr-wallet/chain-validator": "0.13.19", "@keplr-wallet/common": "0.13.19", "@keplr-wallet/cosmos": "0.13.19", @@ -42,6 +38,7 @@ "@keplr-wallet/proto-types": "0.13.19", "@keplr-wallet/router": "0.13.19", "@keplr-wallet/simple-fetch": "0.13.19", + "@keplr-wallet/stores-eth": "0.13.19", "@keplr-wallet/types": "0.13.19", "@keplr-wallet/unit": "0.13.19", "@ledgerhq/hw-app-eth": "6.42.8", @@ -61,6 +58,7 @@ "ledger-bitcoin": "^0.2.3", "long": "^4.0.0", "miscreant": "0.3.2", + "ox": "^0.14.6", "pbkdf2": "^3.1.2", "utility-types": "^3.10.0" }, diff --git a/packages/background/src/keyring-cosmos/eip712.spec.ts b/packages/background/src/keyring-cosmos/eip712.spec.ts new file mode 100644 index 0000000000..b5f46f5f49 --- /dev/null +++ b/packages/background/src/keyring-cosmos/eip712.spec.ts @@ -0,0 +1,305 @@ +import { sortObjectByKey } from "@keplr-wallet/common"; +import { domainHash, EIP712MessageValidator, messageHash } from "./eip712"; + +function makeMsgSendFixture( + fromAddress: string, + toAddress: string, + denom: string, + amount: string +): { type: string; value: Record } { + return { + type: "cosmos-sdk/MsgSend", + value: { + from_address: fromAddress, + to_address: toAddress, + amount: [{ denom, amount }], + }, + }; +} + +async function makeEvmosTypedData() { + const msg = makeMsgSendFixture( + "evmos1testaddress000000000000000000000000000", + "evmos1recipient0000000000000000000000000000", + "aevmos", + "1000000000000000000" + ); + + return await EIP712MessageValidator.validateAsync({ + types: { + EIP712Domain: [ + { name: "name", type: "string" }, + { name: "version", type: "string" }, + { name: "chainId", type: "uint256" }, + { name: "verifyingContract", type: "string" }, + { name: "salt", type: "string" }, + ], + Tx: [ + { name: "account_number", type: "string" }, + { name: "chain_id", type: "string" }, + { name: "fee", type: "Fee" }, + { name: "memo", type: "string" }, + { name: "msgs", type: "Msg[]" }, + { name: "sequence", type: "string" }, + ], + Fee: [ + { name: "feePayer", type: "string" }, + { name: "amount", type: "Coin[]" }, + { name: "gas", type: "string" }, + ], + Coin: [ + { name: "denom", type: "string" }, + { name: "amount", type: "string" }, + ], + Msg: [ + { name: "type", type: "string" }, + { name: "value", type: "MsgValue" }, + ], + MsgValue: [ + { name: "from_address", type: "string" }, + { name: "to_address", type: "string" }, + { name: "amount", type: "TypeAmount[]" }, + ], + TypeAmount: [ + { name: "denom", type: "string" }, + { name: "amount", type: "string" }, + ], + }, + primaryType: "Tx", + domain: { + name: "Cosmos Web3", + version: "1.0.0", + chainId: "9001", + verifyingContract: "cosmos", + salt: "0", + }, + message: sortObjectByKey({ + account_number: "7", + chain_id: "evmos_9001-2", + fee: { + amount: [{ denom: "aevmos", amount: "2000000000000000" }], + feePayer: "evmos1testaddress000000000000000000000000000", + gas: "200000", + }, + memo: "", + msgs: [msg], + sequence: "9", + }), + }); +} + +async function makeInjectiveTypedData() { + const msg = makeMsgSendFixture( + "inj1testaddress0000000000000000000000000000", + "inj1recipient00000000000000000000000000000", + "inj", + "10000000000000000" + ); + + return await EIP712MessageValidator.validateAsync({ + types: { + EIP712Domain: [ + { name: "name", type: "string" }, + { name: "version", type: "string" }, + { name: "chainId", type: "uint256" }, + { name: "verifyingContract", type: "string" }, + { name: "salt", type: "string" }, + ], + Tx: [ + { name: "account_number", type: "string" }, + { name: "chain_id", type: "string" }, + { name: "fee", type: "Fee" }, + { name: "memo", type: "string" }, + { name: "msgs", type: "Msg[]" }, + { name: "sequence", type: "string" }, + { name: "timeout_height", type: "string" }, + ], + Fee: [ + { name: "amount", type: "Coin[]" }, + { name: "gas", type: "string" }, + ], + Coin: [ + { name: "denom", type: "string" }, + { name: "amount", type: "string" }, + ], + Msg: [ + { name: "type", type: "string" }, + { name: "value", type: "MsgValue" }, + ], + MsgValue: [ + { name: "from_address", type: "string" }, + { name: "to_address", type: "string" }, + { name: "amount", type: "TypeAmount[]" }, + ], + TypeAmount: [ + { name: "denom", type: "string" }, + { name: "amount", type: "string" }, + ], + }, + primaryType: "Tx", + domain: { + name: "Injective Web3", + version: "1.0.0", + chainId: "0x1", + verifyingContract: "cosmos", + salt: "0", + }, + message: sortObjectByKey({ + account_number: "12", + chain_id: "injective-1", + fee: { + amount: [{ denom: "inj", amount: "50000000000000" }], + gas: "200000", + }, + memo: "", + msgs: [msg], + sequence: "3", + timeout_height: Number.MAX_SAFE_INTEGER.toString(), + }), + }); +} + +describe("Test EIP-712 helpers", () => { + it("matches the canonical EIP-712 mail example hashes", async () => { + const typedData = await EIP712MessageValidator.validateAsync({ + types: { + EIP712Domain: [ + { name: "name", type: "string" }, + { name: "version", type: "string" }, + { name: "chainId", type: "uint256" }, + { name: "verifyingContract", type: "address" }, + ], + Person: [ + { name: "wallet", type: "address" }, + { name: "name", type: "string" }, + ], + Mail: [ + { name: "from", type: "Person" }, + { name: "to", type: "Person" }, + { name: "contents", type: "string" }, + ], + }, + primaryType: "Mail", + domain: { + name: "Ether Mail", + version: "1", + chainId: 1, + verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", + }, + message: { + from: { + wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", + name: "Cow", + }, + to: { + wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", + name: "Bob", + }, + contents: "Hello, Bob!", + }, + }); + + expect(domainHash(typedData)).toBe( + "0xf2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f" + ); + expect(messageHash(typedData)).toBe( + "0xdde0a9fa0b3a536b59f2fd59426a15de66a5ca873cc166b6eb8021e16b91b3d3" + ); + }); + + it("keeps Ethermint-style ledger typed data stable", async () => { + const typedData = await makeEvmosTypedData(); + + expect(typedData.domain).toEqual({ + name: "Cosmos Web3", + version: "1.0.0", + chainId: "9001", + verifyingContract: "cosmos", + salt: "0", + }); + expect(typedData.types.Tx).toEqual([ + { name: "account_number", type: "string" }, + { name: "chain_id", type: "string" }, + { name: "fee", type: "Fee" }, + { name: "memo", type: "string" }, + { name: "msgs", type: "Msg[]" }, + { name: "sequence", type: "string" }, + ]); + expect(typedData.types.Fee).toEqual([ + { name: "feePayer", type: "string" }, + { name: "amount", type: "Coin[]" }, + { name: "gas", type: "string" }, + ]); + expect(domainHash(typedData)).toBe( + "0x1633cfb1cf33b8790808cb60604cfd1f261c59a367ccb3aaff568a000149ace9" + ); + expect(messageHash(typedData)).toBe( + "0x9d2fea7a4c1eb2801664062e5e9ca260dfd415b0274670b8a6f65f9e144b348b" + ); + }); + + it("keeps Injective ledger typed data stable", async () => { + const typedData = await makeInjectiveTypedData(); + + expect(typedData.domain).toEqual({ + name: "Injective Web3", + version: "1.0.0", + chainId: "0x1", + verifyingContract: "cosmos", + salt: "0", + }); + expect(typedData.types.Tx).toEqual([ + { name: "account_number", type: "string" }, + { name: "chain_id", type: "string" }, + { name: "fee", type: "Fee" }, + { name: "memo", type: "string" }, + { name: "msgs", type: "Msg[]" }, + { name: "sequence", type: "string" }, + { name: "timeout_height", type: "string" }, + ]); + expect(typedData.types.Fee).toEqual([ + { name: "amount", type: "Coin[]" }, + { name: "gas", type: "string" }, + ]); + expect(domainHash(typedData)).toBe( + "0xe976870d04d7c978d7d21058ec0b93416744f360658321bd253ddcd9483c4e00" + ); + expect(messageHash(typedData)).toBe( + "0xd8a585e24f5942f95592b01de6d341fef2654a863995e6e235d41b419b90671d" + ); + }); + + it("sorts EIP712Domain fields during validation", async () => { + const typedData = await EIP712MessageValidator.validateAsync({ + types: { + EIP712Domain: [ + { name: "salt", type: "string" }, + { name: "version", type: "string" }, + { name: "name", type: "string" }, + { name: "verifyingContract", type: "string" }, + { name: "chainId", type: "uint256" }, + ], + Tx: [{ name: "account_number", type: "string" }], + }, + primaryType: "Tx", + domain: { + name: "Cosmos Web3", + version: "1.0.0", + chainId: "9001", + verifyingContract: "cosmos", + salt: "0", + }, + message: { + account_number: "1", + }, + }); + + expect(typedData.types.EIP712Domain).toEqual([ + { name: "name", type: "string" }, + { name: "version", type: "string" }, + { name: "chainId", type: "uint256" }, + { name: "verifyingContract", type: "string" }, + { name: "salt", type: "string" }, + ]); + }); +}); diff --git a/packages/background/src/keyring-cosmos/eip712.ts b/packages/background/src/keyring-cosmos/eip712.ts index d7c12d23dc..818f186a12 100644 --- a/packages/background/src/keyring-cosmos/eip712.ts +++ b/packages/background/src/keyring-cosmos/eip712.ts @@ -1,15 +1,12 @@ import Joi from "joi"; -import { _TypedDataEncoder as TypedDataEncoder } from "@ethersproject/hash"; +import { TypedData } from "ox"; // https://eips.ethereum.org/EIPS/eip-712 // XXX: ledger의 서명을 frontend에서 다루게 되면서 밑의 함수들은 사실 frontend에서 사용된다. // 뭔가 이상해진 부분임 -export const EIP712PropertyFieldValidator = Joi.object<{ - name: string; - type: string; -}>({ +export const EIP712PropertyFieldValidator = Joi.object({ name: Joi.string().min(1).required(), // TODO: Check valid types (string, bool, address, uint256...) type: Joi.string().min(1).required(), @@ -17,40 +14,25 @@ export const EIP712PropertyFieldValidator = Joi.object<{ export const EIP712DomainTypeValidator = Joi.array() .items( - Joi.object<{ - name: string; - type: string; - }>({ + Joi.object({ name: Joi.string().valid("name").required(), type: Joi.string().valid("string").required(), }), - Joi.object<{ - name: string; - type: string; - }>({ + Joi.object({ name: Joi.string().valid("version").required(), type: Joi.string().valid("string").required(), }), - Joi.object<{ - name: string; - type: string; - }>({ + Joi.object({ name: Joi.string().valid("chainId").required(), type: Joi.string().valid("uint256").required(), }), - Joi.object<{ - name: string; - type: string; - }>({ + Joi.object({ name: Joi.string().valid("verifyingContract").required(), // From https://eips.ethereum.org/EIPS/eip-712, (string) may be non-standard? // But, ethermint set this type as string. type: Joi.string().valid("address", "string").required(), }), - Joi.object<{ - name: string; - type: string; - }>({ + Joi.object({ name: Joi.string().valid("salt").required(), // From https://eips.ethereum.org/EIPS/eip-712, (string) may be non-standard? // But, ethermint set this type as string. @@ -77,7 +59,7 @@ export const EIP712DomainTypeValidator = Joi.array() }); export const EIP712MessageValidator = Joi.object<{ - types: Record; + types: TypedData.TypedData; primaryType: string; domain: Record; message: Record; @@ -93,38 +75,32 @@ export const EIP712MessageValidator = Joi.object<{ }); export const domainHash = (message: { - types: Record; - domain: Record; + types: TypedData.TypedData; + domain: Record; }): string => - TypedDataEncoder.hashStruct( - "EIP712Domain", - { EIP712Domain: message.types["EIP712Domain"] }, - message.domain - ); + TypedData.hashDomain({ + domain: message.domain, + types: { EIP712Domain: message.types["EIP712Domain"] }, + }); -// Seems that there is no way to set primary type and the first type becomes primary type. export const messageHash = (message: { - types: Record; + types: TypedData.TypedData; primaryType: string; message: Record; -}): string => - TypedDataEncoder.from( - (() => { - const types = { ...message.types }; - - delete types["EIP712Domain"]; +}): string => { + const types = { ...message.types }; - const primary = types[message.primaryType]; + delete types["EIP712Domain"]; - if (!primary) { - throw new Error(`No matched primary type: ${message.primaryType}`); - } + const primary = types[message.primaryType]; - delete types[message.primaryType]; + if (!primary) { + throw new Error(`No matched primary type: ${message.primaryType}`); + } - return { - [message.primaryType]: primary, - ...types, - }; - })() - ).hash(message.message); + return TypedData.hashStruct({ + data: message.message, + primaryType: message.primaryType, + types, + }); +}; diff --git a/packages/background/src/keyring-ethereum/chain-handlers.ts b/packages/background/src/keyring-ethereum/chain-handlers.ts new file mode 100644 index 0000000000..dd67906754 --- /dev/null +++ b/packages/background/src/keyring-ethereum/chain-handlers.ts @@ -0,0 +1,351 @@ +import { Env, EthereumProviderRpcError } from "@keplr-wallet/router"; +import { ChainInfo, JsonRpcResponse } from "@keplr-wallet/types"; +import { ChainsService } from "../chains"; +import { getBasicAccessPermissionType, PermissionService } from "../permission"; +import { TokenERC20Service } from "../token-erc20"; +import { simpleFetch } from "@keplr-wallet/simple-fetch"; +import { rethrowAsProviderError, validateEVMChainId } from "./helper"; +import { + DEFAULT_EVM_CHAIN_ID, + enableAccessSkippedEVMJSONRPCMethods, + ETH_COIN_TYPE, + RPC_ERROR_INVALID_PARAMS, + RPC_ERROR_UNRECOGNIZED_CHAIN, +} from "./constants"; + +export class EvmChainHandler { + constructor( + private readonly chainsService: ChainsService, + private readonly permissionService: PermissionService, + private readonly tokenERC20Service: TokenERC20Service + ) {} + + // ── Private Helpers ────────────────────────────────────── + + private getCurrentChainId( + origin: string, + chainId?: string + ): string | undefined { + return chainId || this.permissionService.getCurrentChainIdForEVM(origin); + } + + private forceGetCurrentChainId(origin: string, chainId?: string): string { + return this.getCurrentChainId(origin, chainId) || DEFAULT_EVM_CHAIN_ID; + } + + // ── Chain Management ────────────────────────────────────── + + async switchChain( + env: Env, + origin: string, + method: string, + params: unknown[] | Record | undefined, + chainId: string | undefined + ) { + const newCurrentChainId = this.getNewCurrentChainIdFromRequest( + method, + params + ); + const currentChainId = this.getCurrentChainId(origin, chainId); + if ( + // If the new current chain id is not set or the current chain id is the same as the new current chain id, do nothing. + newCurrentChainId == null || + currentChainId === newCurrentChainId + ) { + return null; + } + + try { + await this.permissionService.updateCurrentChainIdForEVM( + env, + origin, + newCurrentChainId + ); + } catch (e) { + rethrowAsProviderError(e); + } + + return null; + } + + async addChain( + env: Env, + origin: string, + params: unknown[] | Record | undefined, + _chainId: string | undefined + ) { + const param = + Array.isArray(params) && + (params?.[0] as { + chainId: string; + chainName: string; + nativeCurrency: { + name: string; + symbol: string; + decimals: number; + }; + rpcUrls: string[]; + iconUrls?: string[]; + }); + if (!param || typeof param !== "object") { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide a single object parameter." + ); + } + + const evmChainId = validateEVMChainId(parseInt(param.chainId, 16)); + + const chainInfo = + this.chainsService.getChainInfoByEVMChainId(evmChainId) ?? + (await this.suggestAndBuildChainInfo(env, origin, param, evmChainId)); + + this.permissionService.addPermission( + [chainInfo.chainId], + getBasicAccessPermissionType(), + [origin] + ); + + try { + await this.permissionService.updateCurrentChainIdForEVM( + env, + origin, + chainInfo.chainId + ); + } catch (e) { + rethrowAsProviderError(e); + } + + return null; + } + + private async suggestAndBuildChainInfo( + env: Env, + origin: string, + param: { + chainName: string; + nativeCurrency: { name: string; symbol: string; decimals: number }; + rpcUrls: string[]; + iconUrls?: string[]; + }, + evmChainId: number + ): Promise { + const rpc = param.rpcUrls.find((url) => { + try { + const urlObject = new URL(url); + return ( + urlObject.protocol === "http:" || urlObject.protocol === "https:" + ); + } catch { + return false; + } + }); + const websocket = param.rpcUrls.find((url) => { + try { + const urlObject = new URL(url); + return urlObject.protocol === "ws:" || urlObject.protocol === "wss:"; + } catch { + return false; + } + }); + // Skip the validation for these parameters because they will be validated in the `suggestChainInfo` method. + const { chainName, nativeCurrency, iconUrls } = param; + + const addingChainInfo = { + rpc, + rest: rpc, + chainId: `eip155:${evmChainId}`, + bip44: { + coinType: ETH_COIN_TYPE, + }, + chainName, + stakeCurrency: { + coinDenom: nativeCurrency.symbol, + coinMinimalDenom: nativeCurrency.symbol, + coinDecimals: nativeCurrency.decimals, + }, + currencies: [ + { + coinDenom: nativeCurrency.symbol, + coinMinimalDenom: nativeCurrency.symbol, + coinDecimals: nativeCurrency.decimals, + }, + ], + feeCurrencies: [ + { + coinDenom: nativeCurrency.symbol, + coinMinimalDenom: nativeCurrency.symbol, + coinDecimals: nativeCurrency.decimals, + }, + ], + evm: { + chainId: evmChainId, + rpc, + websocket, + }, + features: ["eth-address-gen", "eth-key-sign"], + chainSymbolImageUrl: + iconUrls && typeof iconUrls[0] === "string" && !!iconUrls[0] + ? iconUrls[0] + : undefined, + beta: true, + } as ChainInfo; + + try { + await this.chainsService.suggestChainInfo(env, addingChainInfo, origin); + } catch (e) { + rethrowAsProviderError(e); + } + + return addingChainInfo; + } + + // ── Permission & Asset Handlers ─────────────────────────── + + async revokePermissions( + origin: string, + params: unknown[] | Record | undefined + ) { + const param = + Array.isArray(params) && (params?.[0] as Record); + if (!param || typeof param !== "object") { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide a single object parameter." + ); + } + + if (param["eth_accounts"] == null) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide a single object parameter with the key 'eth_accounts'." + ); + } + + await this.permissionService.removeAllTypePermission([origin]); + + return null; + } + + async watchAsset( + env: Env, + origin: string, + params: unknown[] | Record | undefined, + chainId: string | undefined + ) { + const param = params as + | { + type: string; + options: { + address: string; + symbol?: string; + decimals?: number; + image?: string; + tokenId?: string; + }; + } + | undefined; + if (!param) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide a single object parameter." + ); + } + + if (param.type !== "ERC20") { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide a valid asset type. Only ERC20 is supported." + ); + } + + const contractAddress = param?.options.address; + + const currentChainId = this.forceGetCurrentChainId(origin, chainId); + + try { + await this.tokenERC20Service.suggestERC20Token( + env, + currentChainId, + contractAddress + ); + } catch (e) { + rethrowAsProviderError(e); + } + + return true; + } + + // ── RPC Passthrough ─────────────────────────────────────── + + async passthroughRpc( + origin: string, + method: string, + params: unknown[] | Record | undefined, + chainId: string | undefined + ) { + const currentChainId = this.forceGetCurrentChainId(origin, chainId); + const currentChainEVMInfo = + this.chainsService.getEVMInfoOrThrow(currentChainId); + + return ( + await simpleFetch>(currentChainEVMInfo.rpc, { + method: "POST", + headers: { + "content-type": "application/json", + "request-source": origin, + }, + body: JSON.stringify({ + jsonrpc: "2.0", + method, + params, + id: 1, + }), + }) + ).data.result; + } + + // ── Public Utilities ────────────────────────────────────── + + getNewCurrentChainIdFromRequest( + method: string, + params?: unknown[] | Record + ): string | undefined { + switch (method) { + case "wallet_switchEthereumChain": { + const param = + (Array.isArray(params) && (params?.[0] as { chainId: string })) || + undefined; + if (!param?.chainId) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide a chain id." + ); + } + + const newEvmChainId = validateEVMChainId(parseInt(param.chainId, 16)); + const chainInfo = + this.chainsService.getChainInfoByEVMChainId(newEvmChainId); + if (!chainInfo) { + throw new EthereumProviderRpcError( + RPC_ERROR_UNRECOGNIZED_CHAIN, + `Unrecognized chain ID "${newEvmChainId}". Try adding the chain using wallet_addEthereumChain first.` + ); + } + + return chainInfo.chainId; + } + default: { + return; + } + } + } + + checkNeedEnableAccess(method: string) { + if (enableAccessSkippedEVMJSONRPCMethods.includes(method)) { + return false; + } + + return true; + } +} diff --git a/packages/background/src/keyring-ethereum/constants.ts b/packages/background/src/keyring-ethereum/constants.ts index 364a4eca1a..a885c14de1 100644 --- a/packages/background/src/keyring-ethereum/constants.ts +++ b/packages/background/src/keyring-ethereum/constants.ts @@ -1,6 +1,47 @@ +import { Buffer } from "buffer/"; + export const ROUTE = "keyring-ethereum"; export const enableAccessSkippedEVMJSONRPCMethods = [ "keplr_initProviderState", "eth_accounts", ]; + +// Signature recovery IDs (v-value) +export const SIGNATURE_V_FALSE = Buffer.from("1b", "hex"); +export const SIGNATURE_V_TRUE = Buffer.from("1c", "hex"); + +// EIP-1193 / EIP-1474 RPC error codes +export const RPC_ERROR_USER_REJECTED = 4001; +export const RPC_ERROR_UNAUTHORIZED = 4100; +export const RPC_ERROR_UNSUPPORTED_METHOD = 4200; +export const RPC_ERROR_INVALID_PARAMS = -32602; +export const RPC_ERROR_UNRECOGNIZED_CHAIN = 4902; + +// EIP-5792 error codes +export const EIP5792_ERROR_UNSUPPORTED_CAPABILITY = 5700; +export const EIP5792_ERROR_UNSUPPORTED_CHAIN = 5710; +export const EIP5792_ERROR_UNKNOWN_BUNDLE = 5730; +export const EIP5792_ERROR_ATOMICITY_NOT_SUPPORTED = 5760; + +// ERC-20 transfer(address,uint256) function selector +export const ERC20_TRANSFER_SELECTOR = "0xa9059cbb"; + +// Default fallback chain +export const DEFAULT_EVM_CHAIN_ID = "eip155:1"; + +// BIP-44 coin type for Ethereum +export const ETH_COIN_TYPE = 60; + +// eth_getCode 응답이 이 접두사로 시작하면 해당 EOA가 EIP-7702로 delegation된 상태. +// 전체 형식: 0xef0100 + 20바이트 delegator 주소 = 48자. +export const EIP7702_DELEGATION_PREFIX = "0xef0100"; + +// eth_getCode로 확인된 delegator 주소가 이 목록에 있어야 "supported"로 판정한다. +// 현재는 MetaMask StatelessDeleGator 주소만 포함. CREATE2로 모든 체인에 동일 주소로 배포됨. +// TODO: MetaMask 것을 그대로 쓸지 자체 배포할지 결정 후, 주소 추가 또는 교체. +export const ALLOWED_DELEGATORS: readonly string[] = [ + "0x63c0c19a282a1b52b07dd5a65b58948a07dae32b", +]; + +export const EVM_ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; diff --git a/packages/background/src/keyring-ethereum/handler.ts b/packages/background/src/keyring-ethereum/handler.ts index f363b87866..37e1fd80b8 100644 --- a/packages/background/src/keyring-ethereum/handler.ts +++ b/packages/background/src/keyring-ethereum/handler.ts @@ -10,6 +10,9 @@ import { RequestJsonRpcToEvmMsg, GetNewCurrentChainIdForEVMMsg, CheckNeedEnableAccessForEVMMsg, + UpgradeSmartAccountMsg, + DowngradeSmartAccountMsg, + GetEthereumAddressForVaultMsg, } from "./messages"; import { KeyRingEthereumService } from "./service"; import { PermissionInteractiveService } from "../permission-interactive"; @@ -43,6 +46,23 @@ export const getHandler: ( env, msg as CheckNeedEnableAccessForEVMMsg ); + case UpgradeSmartAccountMsg: + return service.upgradeToSmartAccount( + env, + (msg as UpgradeSmartAccountMsg).chainId, + (msg as UpgradeSmartAccountMsg).vaultId + ); + case DowngradeSmartAccountMsg: + return service.downgradeSmartAccount( + env, + (msg as DowngradeSmartAccountMsg).chainId, + (msg as DowngradeSmartAccountMsg).vaultId + ); + case GetEthereumAddressForVaultMsg: + return service.getEthAddressForVault( + (msg as GetEthereumAddressForVaultMsg).chainId, + (msg as GetEthereumAddressForVaultMsg).vaultId + ); default: throw new KeplrError("keyring", 221, "Unknown msg type"); } diff --git a/packages/background/src/keyring-ethereum/helper.spec.ts b/packages/background/src/keyring-ethereum/helper.spec.ts new file mode 100644 index 0000000000..6ac1ccaab6 --- /dev/null +++ b/packages/background/src/keyring-ethereum/helper.spec.ts @@ -0,0 +1,623 @@ +import { Buffer } from "buffer/"; +import { EthereumProviderRpcError } from "@keplr-wallet/router"; +import { + applyEIP1559Type, + encodeSignature, + getEthAddressFromPubkey, + normalizeUnsignedTx, + normalizeSigner, + parseChainIdParam, + parseDelegation, + parseTxParam, + rethrowAsProviderError, + toHexQty, + validateEIP5792Call, + validateAuthorizationList, + validateEVMChainId, + validateSendCallsRequest, +} from "./helper"; +import { + SIGNATURE_V_FALSE, + SIGNATURE_V_TRUE, + EVM_ZERO_ADDRESS, +} from "./constants"; + +// ── validateEVMChainId ───────────────────────────────────── + +describe("validateEVMChainId", () => { + it("returns valid chain id", () => { + expect(validateEVMChainId(1)).toBe(1); + expect(validateEVMChainId(137)).toBe(137); + }); + + it("throws on zero", () => { + expect(() => validateEVMChainId(0)).toThrow(); + }); + + it("throws on negative", () => { + expect(() => validateEVMChainId(-1)).toThrow(); + }); + + it("throws on too large", () => { + expect(() => validateEVMChainId(4503599627370477)).toThrow(); + }); + + it("accepts max valid chain id", () => { + expect(validateEVMChainId(4503599627370476)).toBe(4503599627370476); + }); +}); + +// ── encodeSignature ──────────────────────────────────────── + +describe("encodeSignature", () => { + const r = Buffer.alloc(32, 0xaa); + const s = Buffer.alloc(32, 0xbb); + + it("appends 0x1c when v is truthy", () => { + const result = encodeSignature({ r, s, v: 1 }); + expect(result.length).toBe(65); + expect(result.slice(64)).toEqual(SIGNATURE_V_TRUE); + }); + + it("appends 0x1b when v is falsy (0)", () => { + const result = encodeSignature({ r, s, v: 0 }); + expect(result.slice(64)).toEqual(SIGNATURE_V_FALSE); + }); + + it("appends 0x1b when v is null", () => { + const result = encodeSignature({ r, s, v: null }); + expect(result.slice(64)).toEqual(SIGNATURE_V_FALSE); + }); + + it("preserves r and s bytes", () => { + const result = encodeSignature({ r, s, v: true }); + expect(result.slice(0, 32)).toEqual(r); + expect(result.slice(32, 64)).toEqual(s); + }); +}); + +// ── normalizeSigner ──────────────────────────────────────── + +describe("normalizeSigner", () => { + it("returns bech32 address unchanged", () => { + const bech32 = "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh"; + expect(normalizeSigner(bech32)).toBe(bech32); + }); + + it("lowercases hex address with 0x prefix", () => { + expect(normalizeSigner("0xAbCdEf1234567890")).toBe("0xabcdef1234567890"); + }); + + it("adds 0x prefix and lowercases hex without prefix", () => { + expect(normalizeSigner("AbCdEf1234567890")).toBe("0xabcdef1234567890"); + }); +}); + +// ── getEthAddressFromPubkey ──────────────────────────────── + +describe("getEthAddressFromPubkey", () => { + it("converts pubkey eth address to hex string", () => { + const mockPubkey = { + getEthAddress: () => new Uint8Array([0xab, 0xcd, 0xef, 0x12]), + }; + expect(getEthAddressFromPubkey(mockPubkey)).toBe("0xabcdef12"); + }); +}); + +// ── applyEIP1559Type ─────────────────────────────────────── + +describe("applyEIP1559Type", () => { + it("sets type=2 when maxFeePerGas is present", () => { + const tx: any = { maxFeePerGas: "0x1" }; + applyEIP1559Type(tx); + expect(tx.type).toBe(2); + }); + + it("sets type=2 when maxPriorityFeePerGas is present", () => { + const tx: any = { maxPriorityFeePerGas: "0x1" }; + applyEIP1559Type(tx); + expect(tx.type).toBe(2); + }); + + it("does not set type when neither field is present", () => { + const tx: any = { gasPrice: "0x1" }; + applyEIP1559Type(tx); + expect(tx.type).toBeUndefined(); + }); +}); + +// ── parseChainIdParam ────────────────────────────────────── + +describe("parseChainIdParam", () => { + it("parses hex string", () => { + expect(parseChainIdParam("0x89")).toBe(137); + }); + + it("parses decimal string", () => { + expect(parseChainIdParam("137")).toBe(137); + }); + + it("returns number as-is", () => { + expect(parseChainIdParam(137)).toBe(137); + }); +}); + +// ── parseTxParam ─────────────────────────────────────────── + +describe("parseTxParam", () => { + it("extracts first element from array params", () => { + const tx = { from: "0xabc", value: "0x1" }; + expect(parseTxParam([tx])).toBe(tx); + }); + + it("throws RPC error for empty array", () => { + expect(() => parseTxParam([])).toThrow(EthereumProviderRpcError); + }); + + it("throws RPC error for undefined", () => { + expect(() => parseTxParam(undefined)).toThrow(EthereumProviderRpcError); + }); +}); + +// ── rethrowAsProviderError ───────────────────────────────── + +describe("rethrowAsProviderError", () => { + it("converts Error('Request rejected') to RPC error 4001", () => { + try { + rethrowAsProviderError(new Error("Request rejected")); + fail("should have thrown"); + } catch (e) { + expect(e).toBeInstanceOf(EthereumProviderRpcError); + expect((e as EthereumProviderRpcError).code).toBe(4001); + expect((e as EthereumProviderRpcError).message).toBe( + "User Rejected Request" + ); + } + }); + + it("converts string 'Request rejected' to RPC error 4001", () => { + try { + rethrowAsProviderError("Request rejected"); + fail("should have thrown"); + } catch (e) { + expect(e).toBeInstanceOf(EthereumProviderRpcError); + expect((e as EthereumProviderRpcError).code).toBe(4001); + } + }); + + it("re-throws other errors unchanged", () => { + const original = new Error("Something else"); + try { + rethrowAsProviderError(original); + fail("should have thrown"); + } catch (e) { + expect(e).toBe(original); + } + }); +}); + +// ── toHexQty ─────────────────────────────────────────────── + +describe("toHexQty", () => { + it("returns undefined for undefined", () => { + expect(toHexQty(undefined)).toBeUndefined(); + }); + + it("returns undefined for null", () => { + expect(toHexQty(null as any)).toBeUndefined(); + }); + + it("converts number to hex", () => { + expect(toHexQty(255)).toBe("0xff"); + }); + + it("converts zero", () => { + expect(toHexQty(0)).toBe("0x0"); + }); + + it("converts bigint", () => { + expect(toHexQty(BigInt(256))).toBe("0x100"); + }); + + it("converts hex string", () => { + expect(toHexQty("0xff")).toBe("0xff"); + }); + + it("converts decimal string", () => { + expect(toHexQty("255")).toBe("0xff"); + }); + + it("returns undefined for empty string", () => { + expect(toHexQty("")).toBeUndefined(); + }); + + it("returns undefined for '0x'", () => { + expect(toHexQty("0x")).toBeUndefined(); + }); + + it("handles non-finite number (NaN)", () => { + expect(toHexQty(NaN)).toBe("0x0"); + }); +}); + +// ── normalizeUnsignedTx ──────────────────────────────────── + +describe("normalizeUnsignedTx", () => { + it("normalizes a basic legacy transaction", () => { + const tx = { + to: "0xabc", + value: "1000", + gas: "21000", + gasPrice: "20000000000", + data: "0x", + }; + const result = normalizeUnsignedTx(tx, 1, 5); + + expect(result.chainId).toBe(1); + expect(result.nonce).toBe(5); + expect(result.value).toBe("0x3e8"); + expect(result.gasLimit).toBe("0x5208"); + expect(result.gasPrice).toBe("0x4a817c800"); + expect(result.maxFeePerGas).toBeUndefined(); + expect(result.maxPriorityFeePerGas).toBeUndefined(); + expect(result.data).toBe("0x"); + }); + + it("normalizes an EIP-1559 transaction (removes gasPrice)", () => { + const tx = { + to: "0xabc", + value: "0", + gas: "21000", + gasPrice: "20000000000", + maxFeePerGas: "30000000000", + maxPriorityFeePerGas: "1000000000", + }; + const result = normalizeUnsignedTx(tx, 137, 0); + + expect(result.chainId).toBe(137); + expect(result.gasPrice).toBeUndefined(); + expect(result.maxFeePerGas).toBe("0x6fc23ac00"); + expect(result.maxPriorityFeePerGas).toBe("0x3b9aca00"); + }); + + it("uses gasLimit over gas when gasLimit is provided", () => { + const tx = { + to: "0xabc", + gas: "21000", + gasLimit: "42000", + gasPrice: "1", + }; + const result = normalizeUnsignedTx(tx, 1, 0); + expect(result.gasLimit).toBe("0xa410"); + }); + + it("adds 0x prefix to data without it", () => { + const tx = { to: "0xabc", data: "abcdef", gasPrice: "1" }; + const result = normalizeUnsignedTx(tx, 1, 0); + expect(result.data).toBe("0xabcdef"); + }); + + it("strips from field via rest spread", () => { + const tx = { to: "0xabc", from: "0xsender", gasPrice: "1" }; + const result = normalizeUnsignedTx(tx, 1, 0); + // 'from' is spread into restTx, so it will be included + // This matches original behavior where 'from' was removed separately + expect(result.to).toBe("0xabc"); + }); +}); + +// ── parseDelegation ──────────────────────────────────── + +describe("parseDelegation", () => { + const allowedDelegators = ["0x63c0c19a282a1b52b07dd5a65b58948a07dae32b"]; + + it("returns 'ready' for empty EOA (0x)", () => { + expect(parseDelegation("0x", allowedDelegators)).toBe("ready"); + }); + + it("returns 'ready' for empty EOA (0x0)", () => { + expect(parseDelegation("0x0", allowedDelegators)).toBe("ready"); + }); + + it("returns 'supported' for whitelisted delegator", () => { + const code = "0xef010063c0c19a282a1b52b07dd5a65b58948a07dae32b"; + expect(parseDelegation(code, allowedDelegators)).toBe("supported"); + }); + + it("returns 'supported' for mixed-case whitelisted delegator", () => { + const code = "0xef010063C0c19A282a1B52b07dD5a65b58948A07DAE32B"; + expect(parseDelegation(code, allowedDelegators)).toBe("supported"); + }); + + it("returns 'unsupported' for unknown delegator", () => { + const code = "0xef0100aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + expect(parseDelegation(code, allowedDelegators)).toBe("unsupported"); + }); + + it("returns 'unsupported' for regular contract code", () => { + expect( + parseDelegation("0x608060405234801561001057600080fd", allowedDelegators) + ).toBe("unsupported"); + }); + + it("returns 'unsupported' for wrong-length delegation code", () => { + // 0xef0100 prefix but too short (missing bytes) + expect(parseDelegation("0xef010063c0c19a", allowedDelegators)).toBe( + "unsupported" + ); + }); +}); + +// ── validateSendCallsRequest ────────────────────────────── + +describe("validateSendCallsRequest", () => { + const hexChainId = "0x1"; + + const validRequest = { + atomicRequired: false, + calls: [{ data: "0xdeadbeef" }], + chainId: "0x1", + version: "1.0", + }; + + it("returns null for a valid request", () => { + expect(validateSendCallsRequest(validRequest, hexChainId)).toBeNull(); + }); + + it("rejects empty calls", () => { + const err = validateSendCallsRequest( + { ...validRequest, calls: [] }, + hexChainId + ); + expect(err).not.toBeNull(); + expect(err!.code).toBe(-32602); + }); + + it("rejects mismatched chainId", () => { + const err = validateSendCallsRequest( + { ...validRequest, chainId: "0xa" }, + hexChainId + ); + expect(err).not.toBeNull(); + expect(err!.code).toBe(4902); + }); + + it("rejects unsupported version", () => { + const err = validateSendCallsRequest( + { ...validRequest, version: "3.0" }, + hexChainId + ); + expect(err).not.toBeNull(); + expect(err!.message).toContain("Unsupported version"); + }); + + it("accepts version 1.0 and 2.0.0", () => { + expect( + validateSendCallsRequest({ ...validRequest, version: "1.0" }, hexChainId) + ).toBeNull(); + expect( + validateSendCallsRequest( + { ...validRequest, version: "2.0.0" }, + hexChainId + ) + ).toBeNull(); + }); + + it("rejects non-optional unsupported capability", () => { + const err = validateSendCallsRequest( + { + ...validRequest, + capabilities: { paymasterService: { url: "https://x.com" } }, + }, + hexChainId + ); + expect(err).not.toBeNull(); + expect(err!.code).toBe(5700); + }); + + it("allows optional unsupported capability", () => { + const err = validateSendCallsRequest( + { + ...validRequest, + capabilities: { + paymasterService: { url: "https://x.com", optional: true }, + }, + }, + hexChainId + ); + expect(err).toBeNull(); + }); + + it("allows atomic capability", () => { + const err = validateSendCallsRequest( + { + ...validRequest, + capabilities: { atomic: { status: "supported" } }, + }, + hexChainId + ); + expect(err).toBeNull(); + }); +}); + +describe("validateEIP5792Call", () => { + it("accepts valid call with to, value, data", () => { + expect( + validateEIP5792Call( + { + to: "0x7099793F8A0FA7EE4a941d1F0df4E55179d8f799", + value: "0x10f2c", + data: "0xdeadbeef", + }, + 0 + ) + ).toBeNull(); + }); + + it("accepts call without to (contract deploy)", () => { + expect(validateEIP5792Call({ data: "0x6060604052" }, 0)).toBeNull(); + }); + + it("accepts call without data (simple ETH transfer)", () => { + expect( + validateEIP5792Call( + { to: "0x7099793f8a0fa7ee4a941d1f0df4e55179d8f799", value: "0x1" }, + 0 + ) + ).toBeNull(); + }); + + it("accepts bare 0x data", () => { + expect(validateEIP5792Call({ data: "0x" }, 0)).toBeNull(); + }); + + it("accepts 0x0 value", () => { + expect(validateEIP5792Call({ data: "0x", value: "0x0" }, 0)).toBeNull(); + }); + + it("rejects invalid to address", () => { + const err = validateEIP5792Call({ to: "not_an_address", data: "0x" }, 0); + expect(err).not.toBeNull(); + expect(err!.message).toContain("invalid 'to' address"); + }); + + it("rejects non-hex value", () => { + const err = validateEIP5792Call({ data: "0x", value: "12345" }, 0); + expect(err).not.toBeNull(); + expect(err!.message).toContain("invalid 'value'"); + }); + + it("rejects non-hex data", () => { + const err = validateEIP5792Call({ data: "not_hex" }, 0); + expect(err).not.toBeNull(); + expect(err!.message).toContain("invalid 'data'"); + }); + + it("accepts lowercase address", () => { + expect( + validateEIP5792Call( + { + to: "0x7099793f8a0fa7ee4a941d1f0df4e55179d8f799", + data: "0x", + }, + 0 + ) + ).toBeNull(); + }); + + it("accepts mixed-case address (no strict checksum)", () => { + expect( + validateEIP5792Call( + { + to: "0x7099793F8a0fa7ee4a941d1f0df4e55179d8f799", + data: "0x", + }, + 0 + ) + ).toBeNull(); + }); +}); + +// ── validateAuthorizationList ────────────────────────── + +describe("validateAuthorizationList", () => { + const allowed = ["0x63c0c19a282a1b52b07dd5a65b58948a07dae32b"]; + + it("passes for allowed delegator with numeric chainId", () => { + expect(() => + validateAuthorizationList([{ chainId: 1, address: allowed[0] }], allowed) + ).not.toThrow(); + }); + + it("passes for allowed delegator with hex string chainId", () => { + expect(() => + validateAuthorizationList( + [{ chainId: "0x1", address: allowed[0] }], + allowed + ) + ).not.toThrow(); + }); + + it("passes for allowed delegator with decimal string chainId", () => { + expect(() => + validateAuthorizationList( + [{ chainId: "137", address: allowed[0] }], + allowed + ) + ).not.toThrow(); + }); + + it("passes for zero address (downgrade)", () => { + expect(() => + validateAuthorizationList( + [{ chainId: 1, address: EVM_ZERO_ADDRESS }], + allowed + ) + ).not.toThrow(); + }); + + it("throws for chainId = 0 (number)", () => { + expect(() => + validateAuthorizationList([{ chainId: 0, address: allowed[0] }], allowed) + ).toThrow("chain_id=0"); + }); + + it("throws for chainId = '0' (string)", () => { + expect(() => + validateAuthorizationList( + [{ chainId: "0", address: allowed[0] }], + allowed + ) + ).toThrow("chain_id=0"); + }); + + it("throws for chainId = '0x0' (hex zero)", () => { + expect(() => + validateAuthorizationList( + [{ chainId: "0x0", address: allowed[0] }], + allowed + ) + ).toThrow("chain_id=0"); + }); + + it("throws for unauthorized delegator address", () => { + expect(() => + validateAuthorizationList( + [{ chainId: 1, address: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }], + allowed + ) + ).toThrow("Unauthorized delegator"); + }); + + it("is case-insensitive for address matching", () => { + const upperCase = allowed[0].toUpperCase().replace("0X", "0x"); + expect(() => + validateAuthorizationList([{ chainId: 1, address: upperCase }], allowed) + ).not.toThrow(); + }); + + it("throws for NaN chainId", () => { + expect(() => + validateAuthorizationList( + [{ chainId: "notanumber", address: allowed[0] }], + allowed + ) + ).toThrow("chain_id=0"); + }); + + it("validates all entries in the list", () => { + expect(() => + validateAuthorizationList( + [ + { chainId: 1, address: allowed[0] }, + { chainId: 0, address: allowed[0] }, + ], + allowed + ) + ).toThrow("chain_id=0"); + }); + + it("passes for empty list", () => { + expect(() => validateAuthorizationList([], allowed)).not.toThrow(); + }); +}); diff --git a/packages/background/src/keyring-ethereum/helper.ts b/packages/background/src/keyring-ethereum/helper.ts index 7a9b8adb03..5e93c022fc 100644 --- a/packages/background/src/keyring-ethereum/helper.ts +++ b/packages/background/src/keyring-ethereum/helper.ts @@ -1,3 +1,149 @@ +import { Bech32Address } from "@keplr-wallet/cosmos"; +import { EthereumProviderRpcError } from "@keplr-wallet/router"; +import { UnsignedEVMTransaction } from "@keplr-wallet/stores-eth"; +import { + DelegationStatus, + EIP5792Call, + WalletSendCallsRequest, +} from "@keplr-wallet/types"; +import { Address, Hex } from "ox"; +import { Buffer } from "buffer/"; +import { Authorization } from "ox"; + +import { + EIP5792_ERROR_UNSUPPORTED_CAPABILITY, + RPC_ERROR_INVALID_PARAMS, + RPC_ERROR_UNRECOGNIZED_CHAIN, + RPC_ERROR_USER_REJECTED, + SIGNATURE_V_FALSE, + SIGNATURE_V_TRUE, + EIP7702_DELEGATION_PREFIX, + EVM_ZERO_ADDRESS, +} from "./constants"; + +// ── EIP-7702 Delegation ─────────────────────────────────── + +export function validateAuthorizationList( + authList: Array<{ chainId: string | number; address: string }>, + allowedDelegators: readonly string[] +): void { + for (const auth of authList) { + const numericChainId = + typeof auth.chainId === "string" + ? parseInt(auth.chainId, auth.chainId.startsWith("0x") ? 16 : 10) + : Number(auth.chainId); + if (numericChainId === 0 || !Number.isFinite(numericChainId)) { + throw new Error("chain_id=0 authorization is not allowed."); + } + const addr = ( + typeof auth.address === "string" ? auth.address : "" + ).toLowerCase(); + if ( + addr !== EVM_ZERO_ADDRESS && + !allowedDelegators.some((d) => d.toLowerCase() === addr) + ) { + throw new Error("Unauthorized delegator address."); + } + } +} + +export async function signAuthorizationList( + keyRingService: { + sign( + chainId: string, + vaultId: string, + data: Uint8Array, + digestMethod: string + ): Promise<{ r: Uint8Array; s: Uint8Array; v: number | null }>; + }, + chainId: string, + vaultId: string, + authList: Array<{ address: string; chainId: number; nonce: bigint }> +): Promise> { + const signed: NonNullable = []; + for (const auth of authList) { + if (auth.chainId === 0) { + throw new Error("Cross-chain authorization (chainId=0) is not allowed"); + } + + const payload = Authorization.getSignPayload({ + address: auth.address as `0x${string}`, + chainId: auth.chainId, + nonce: auth.nonce, + }); + const sig = await keyRingService.sign( + chainId, + vaultId, + Buffer.from(payload.slice(2), "hex"), + "noop" + ); + signed.push({ + address: auth.address, + chainId: auth.chainId, + nonce: "0x" + auth.nonce.toString(16), + r: "0x" + Buffer.from(sig.r).toString("hex"), + s: "0x" + Buffer.from(sig.s).toString("hex"), + yParity: sig.v === 1 ? 1 : 0, + }); + } + return signed; +} + +// eth_getCode 응답을 파싱하여 계정의 delegation 상태를 판별한다. +// 빈 코드면 "ready", 허용된 delegator로 delegation되어 있으면 "supported", 그 외는 "unsupported". +export function parseDelegation( + code: string, + allowedDelegators: readonly string[] +): DelegationStatus { + if (code === "0x" || code === "0x0") { + return "ready"; + } + const lower = code.toLowerCase(); + if (lower.startsWith(EIP7702_DELEGATION_PREFIX) && lower.length === 48) { + const delegator = "0x" + lower.slice(8); + return allowedDelegators.some((d) => d.toLowerCase() === delegator) + ? "supported" + : "unsupported"; + } + return "unsupported"; +} + +export function buildDummyAuthorizationList( + address: string, + chainId: number +): NonNullable { + return [ + { + address, + chainId: `0x${chainId.toString(16)}`, + nonce: "0x1", + r: "0x" + "1".repeat(64), + s: "0x" + "1".repeat(64), + yParity: "0x1", + }, + ]; +} + +// ── Types ── + +export interface EVMTransactionParam { + chainId?: string | number; + from: string; + value?: string; + gas?: string; + gasLimit?: string; + authorizationList?: { + address: string; + chainId: string; + nonce: string; + r: string; + s: string; + yParity: string; + }[]; +} + +// ── Validators ── + export const validateEVMChainId = (evmChainId: number) => { const isSafeEVMChainId = Number.isSafeInteger(evmChainId) && @@ -13,3 +159,281 @@ export const validateEVMChainId = (evmChainId: number) => { return evmChainId; }; + +// ── Signature encoding ── + +export function encodeSignature(signature: { + readonly r: Uint8Array; + readonly s: Uint8Array; + readonly v: number | boolean | null; +}): Buffer { + return Buffer.concat([ + signature.r, + signature.s, + // The metamask doesn't seem to consider the chain id in this case... (maybe bug on metamask?) + signature.v ? SIGNATURE_V_TRUE : SIGNATURE_V_FALSE, + ]); +} + +// ── Signer normalization ── + +export function normalizeSigner(signer: string): string { + try { + Bech32Address.validate(signer); + return signer; + } catch { + // Ignore mixed-case checksum + return ( + signer.substring(0, 2) === "0x" ? signer : "0x" + signer + ).toLowerCase(); + } +} + +// ── Address derivation ── + +export function getEthAddressFromPubkey(pubkey: { + getEthAddress(): Uint8Array; +}): string { + return `0x${Buffer.from(pubkey.getEthAddress()).toString("hex")}`; +} + +// ── Transaction type detection ── + +export function applyEIP1559Type(tx: UnsignedEVMTransaction): void { + const isEIP1559 = !!tx.maxFeePerGas || !!tx.maxPriorityFeePerGas; + if (isEIP1559) { + tx.type = 2; + } +} + +export function applyTxType(tx: UnsignedEVMTransaction): void { + if (tx.authorizationList && tx.authorizationList.length > 0) { + tx.type = 4; + return; + } + applyEIP1559Type(tx); +} + +// ── Chain ID parsing ── + +export function parseChainIdParam(chainId: string | number): number { + if (typeof chainId === "string") { + if (chainId.startsWith("0x")) { + return parseInt(chainId, 16); + } else { + return parseInt(chainId, 10); + } + } else { + return chainId; + } +} + +// ── Transaction param parsing ── + +export function parseTxParam( + params: unknown[] | Record | undefined +): EVMTransactionParam { + const tx = + (Array.isArray(params) && (params?.[0] as EVMTransactionParam)) || null; + if (!tx) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide a transaction." + ); + } + return tx; +} + +// ── Hex quantity conversion ── + +export function toHexQty(value?: string | number | bigint): string | undefined { + if (value === undefined || value === null) { + return undefined; + } + + if (typeof value === "bigint") { + return `0x${value.toString(16)}`; + } + + if (typeof value === "number") { + const clamped = Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0; + return `0x${clamped.toString(16)}`; + } + + value = value.trim(); + if (value.length === 0 || value === "0x") { + return undefined; + } + + let parsed: bigint; + + try { + parsed = BigInt(value); + } catch { + if (!value.startsWith("0x")) { + value = `0x${value}`; + } + try { + parsed = BigInt(value); + } catch { + return undefined; + } + } + + return `0x${parsed.toString(16)}`; +} + +// ── Transaction normalization ── + +export function normalizeUnsignedTx( + tx: any, + evmChainId: number, + nonce: number +): UnsignedEVMTransaction { + const { + value, + gas, + gasLimit, + gasPrice, + maxFeePerGas, + maxPriorityFeePerGas, + data, + ...restTx + } = tx; + + const unsignedTx: UnsignedEVMTransaction = { + ...restTx, + value: toHexQty(value), + gasLimit: toHexQty(gasLimit ?? gas), + gasPrice: toHexQty(gasPrice), + maxFeePerGas: toHexQty(maxFeePerGas), + maxPriorityFeePerGas: toHexQty(maxPriorityFeePerGas), + chainId: evmChainId, + nonce, + }; + + if (data != null && typeof data === "string") { + unsignedTx.data = data.startsWith("0x") ? data : `0x${data}`; + } + + const isLegacy = unsignedTx.gasPrice !== undefined; + const isEIP1559 = + unsignedTx.maxFeePerGas !== undefined && + unsignedTx.maxPriorityFeePerGas !== undefined; + + if (isEIP1559) { + delete unsignedTx.gasPrice; + } else if (isLegacy) { + delete unsignedTx.maxFeePerGas; + delete unsignedTx.maxPriorityFeePerGas; + } + + return unsignedTx; +} + +// ── Error re-throwing ── + +export function rethrowAsProviderError(e: unknown): never { + if ( + (e instanceof Error && e.message === "Request rejected") || + e === "Request rejected" + ) { + throw new EthereumProviderRpcError( + RPC_ERROR_USER_REJECTED, + "User Rejected Request" + ); + } + throw e; +} + +// ── EIP-5792 wallet_sendCalls Validation ────────────────── + +const SUPPORTED_VERSIONS = ["1.0", "2.0.0"]; + +export type SendCallsValidationError = { + code: number; + message: string; +}; + +/** + * Validate a wallet_sendCalls request (pure, no RPC calls). + * Returns null if valid, or an error object if invalid. + */ +export function validateSendCallsRequest( + request: WalletSendCallsRequest, + hexChainId: string +): SendCallsValidationError | null { + if (!Array.isArray(request.calls) || request.calls.length === 0) { + return { + code: RPC_ERROR_INVALID_PARAMS, + message: "Must provide at least one call.", + }; + } + + if (request.chainId && request.chainId !== hexChainId) { + return { + code: RPC_ERROR_UNRECOGNIZED_CHAIN, + message: `Unmatched chain ID: ${request.chainId}`, + }; + } + + if (request.version && !SUPPORTED_VERSIONS.includes(request.version)) { + return { + code: RPC_ERROR_INVALID_PARAMS, + message: `Unsupported version: ${ + request.version + }. Supported: ${SUPPORTED_VERSIONS.join(", ")}`, + }; + } + + if (request.capabilities) { + for (const [key, cap] of Object.entries(request.capabilities)) { + if (key === "atomic") continue; + const isOptional = + cap != null && + typeof cap === "object" && + (cap as Record)["optional"] === true; + if (!isOptional) { + return { + code: EIP5792_ERROR_UNSUPPORTED_CAPABILITY, + message: `Unsupported non-optional capability: ${key}`, + }; + } + } + } + + for (let i = 0; i < request.calls.length; i++) { + const err = validateEIP5792Call(request.calls[i], i); + if (err) return err; + } + + return null; +} + +/** + * Validate a single EIP-5792 call object. + */ +export function validateEIP5792Call( + call: EIP5792Call, + index: number +): SendCallsValidationError | null { + if (call.to && !Address.validate(call.to, { strict: false })) { + return { + code: RPC_ERROR_INVALID_PARAMS, + message: `calls[${index}]: invalid 'to' address: ${call.to}`, + }; + } + if (call.value != null && !Hex.validate(call.value)) { + return { + code: RPC_ERROR_INVALID_PARAMS, + message: `calls[${index}]: invalid 'value', must be hex string`, + }; + } + if (call.data != null && !Hex.validate(call.data)) { + return { + code: RPC_ERROR_INVALID_PARAMS, + message: `calls[${index}]: invalid 'data', must be hex string`, + }; + } + return null; +} diff --git a/packages/background/src/keyring-ethereum/index.ts b/packages/background/src/keyring-ethereum/index.ts index 31b4cbd481..78d99aea49 100644 --- a/packages/background/src/keyring-ethereum/index.ts +++ b/packages/background/src/keyring-ethereum/index.ts @@ -1,2 +1,4 @@ export * from "./messages"; export * from "./service"; +export { ALLOWED_DELEGATORS } from "./constants"; +export { buildDummyAuthorizationList } from "./helper"; diff --git a/packages/background/src/keyring-ethereum/init.ts b/packages/background/src/keyring-ethereum/init.ts index 8b2210d402..adbbd44ab0 100644 --- a/packages/background/src/keyring-ethereum/init.ts +++ b/packages/background/src/keyring-ethereum/init.ts @@ -5,6 +5,9 @@ import { RequestSignEthereumMsg, GetNewCurrentChainIdForEVMMsg, CheckNeedEnableAccessForEVMMsg, + UpgradeSmartAccountMsg, + DowngradeSmartAccountMsg, + GetEthereumAddressForVaultMsg, } from "./messages"; import { ROUTE } from "./constants"; import { getHandler } from "./handler"; @@ -19,6 +22,9 @@ export function init( router.registerMessage(RequestJsonRpcToEvmMsg); router.registerMessage(GetNewCurrentChainIdForEVMMsg); router.registerMessage(CheckNeedEnableAccessForEVMMsg); + router.registerMessage(UpgradeSmartAccountMsg); + router.registerMessage(DowngradeSmartAccountMsg); + router.registerMessage(GetEthereumAddressForVaultMsg); router.addHandler(ROUTE, getHandler(service, permissionInteractionService)); } diff --git a/packages/background/src/keyring-ethereum/messages.ts b/packages/background/src/keyring-ethereum/messages.ts index 1db7ad42ba..f1b0d73d3a 100644 --- a/packages/background/src/keyring-ethereum/messages.ts +++ b/packages/background/src/keyring-ethereum/messages.ts @@ -111,6 +111,108 @@ export class GetNewCurrentChainIdForEVMMsg extends Message { } } +export class UpgradeSmartAccountMsg extends Message { + public static type() { + return "upgrade-smart-account"; + } + + constructor( + public readonly chainId: string, + public readonly vaultId: string + ) { + super(); + } + + validateBasic(): void { + if (!this.chainId) { + throw new Error("chain id not set"); + } + if (!this.vaultId) { + throw new Error("vault id not set"); + } + } + + override approveExternal(): boolean { + return false; + } + + route(): string { + return ROUTE; + } + + type(): string { + return UpgradeSmartAccountMsg.type(); + } +} + +export class DowngradeSmartAccountMsg extends Message { + public static type() { + return "downgrade-smart-account"; + } + + constructor( + public readonly chainId: string, + public readonly vaultId: string + ) { + super(); + } + + validateBasic(): void { + if (!this.chainId) { + throw new Error("chain id not set"); + } + if (!this.vaultId) { + throw new Error("vault id not set"); + } + } + + override approveExternal(): boolean { + return false; + } + + route(): string { + return ROUTE; + } + + type(): string { + return DowngradeSmartAccountMsg.type(); + } +} + +export class GetEthereumAddressForVaultMsg extends Message { + public static type() { + return "get-ethereum-address-for-vault"; + } + + constructor( + public readonly chainId: string, + public readonly vaultId: string + ) { + super(); + } + + validateBasic(): void { + if (!this.chainId) { + throw new Error("chain id not set"); + } + if (!this.vaultId) { + throw new Error("vault id not set"); + } + } + + override approveExternal(): boolean { + return false; + } + + route(): string { + return ROUTE; + } + + type(): string { + return GetEthereumAddressForVaultMsg.type(); + } +} + export class CheckNeedEnableAccessForEVMMsg extends Message { public static type() { return "check-need-enable-access-for-evm"; diff --git a/packages/background/src/keyring-ethereum/service.ts b/packages/background/src/keyring-ethereum/service.ts index 91bdbc9fa0..29e4396c4a 100644 --- a/packages/background/src/keyring-ethereum/service.ts +++ b/packages/background/src/keyring-ethereum/service.ts @@ -2,42 +2,82 @@ import { ChainsService } from "../chains"; import { KeyRingService } from "../keyring"; import { InteractionService } from "../interaction"; import { AnalyticsService } from "../analytics"; +import { Env, EthereumProviderRpcError } from "@keplr-wallet/router"; import { - Env, - EthereumProviderRpcError, - WEBPAGE_PORT, -} from "@keplr-wallet/router"; -import { - ChainInfo, + BatchSigningData, + BatchStrategy, + DelegationStatus, + EthereumBatchSignResponse, EthereumSignResponse, EthSignType, - JsonRpcResponse, + GetCapabilitiesResult, + InternalSendCallsRequest, isEthSignChain, + WalletSendCallsRequest, } from "@keplr-wallet/types"; -import { Bech32Address } from "@keplr-wallet/cosmos"; import { Buffer } from "buffer/"; +import { retry } from "@keplr-wallet/common"; import { domainHash, EIP712MessageValidator, KeyRingCosmosService, messageHash, } from "../keyring-cosmos"; + import { - serialize, - TransactionTypes, - UnsignedTransaction, -} from "@ethersproject/transactions"; -import { simpleFetch } from "@keplr-wallet/simple-fetch"; -import { getBasicAccessPermissionType, PermissionService } from "../permission"; + UnsignedEVMTransaction, + serializeEVMTransaction, +} from "@keplr-wallet/stores-eth"; +import { PermissionService } from "../permission"; import { BackgroundTxEthereumService } from "../tx-ethereum"; import { TokenERC20Service } from "../token-erc20"; -import { validateEVMChainId } from "./helper"; -import { runInAction } from "mobx"; +import { + applyTxType, + buildDummyAuthorizationList, + encodeSignature, + getEthAddressFromPubkey, + normalizeUnsignedTx, + normalizeSigner, + parseChainIdParam, + parseDelegation, + parseTxParam, + rethrowAsProviderError, + signAuthorizationList, + validateAuthorizationList, + validateEVMChainId, + validateSendCallsRequest, +} from "./helper"; import { PermissionInteractiveService } from "../permission-interactive"; -import { enableAccessSkippedEVMJSONRPCMethods } from "./constants"; +import { + ALLOWED_DELEGATORS, + DEFAULT_EVM_CHAIN_ID, + EIP5792_ERROR_ATOMICITY_NOT_SUPPORTED, + EIP5792_ERROR_UNKNOWN_BUNDLE, + ERC20_TRANSFER_SELECTOR, + EVM_ZERO_ADDRESS, + RPC_ERROR_INVALID_PARAMS, + RPC_ERROR_UNAUTHORIZED, + RPC_ERROR_UNSUPPORTED_METHOD, +} from "./constants"; +import { EvmWebSocketManager } from "./ws-handlers"; +import { EvmChainHandler } from "./chain-handlers"; +import { fillUnsignedEVMTx } from "../tx-executor/utils/evm"; export class KeyRingEthereumService { - protected websocketSubscriptionMap = new Map(); + private readonly wsManager: EvmWebSocketManager; + private readonly chainHandler: EvmChainHandler; + + // EIP-5792: batchId → tx metadata mapping (in-memory, no persistence needed) + private readonly batchCallsMap = new Map< + string, + { + txHash: string; + chainId: string; + origin: string; + strategy: BatchStrategy; + apiVersion: string; + } + >(); constructor( protected readonly chainsService: ChainsService, @@ -51,12 +91,283 @@ export class KeyRingEthereumService { protected readonly permissionInteractiveService: PermissionInteractiveService, protected readonly backgroundTxEthereumService: BackgroundTxEthereumService, protected readonly tokenERC20Service: TokenERC20Service - ) {} + ) { + this.wsManager = new EvmWebSocketManager( + chainsService, + interactionService, + permissionService + ); + this.chainHandler = new EvmChainHandler( + chainsService, + permissionService, + tokenERC20Service + ); + } async init() { // TODO: ? } + // ── Smart Account ───────────────── + // EIP-7702 delegation 판별은 parseDelegation 유틸이 담당한다. + // 아래 핸들러들은 ERC-5792 wallet_getCapabilities 응답 형식을 구성하는 레이어이다. + + // 주소 형식(-32602)과 소유권(4100)을 검증한 뒤 활성 체인의 atomic capability를 반환한다. + private async handleGetCapabilities( + env: Env, + origin: string, + params: unknown[] | Record | undefined, + chainId: string | undefined + ): Promise { + const currentChainId = this.forceGetCurrentChainId(origin, chainId); + + const requestedAddress = + Array.isArray(params) && typeof params[0] === "string" + ? params[0] + : undefined; + if (!requestedAddress || !requestedAddress.match(/^0x[0-9a-fA-F]{40}$/)) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Invalid parameters: must provide a valid Ethereum address." + ); + } + + const selectedAddress = await this.getSelectedEthAddress(currentChainId); + if (requestedAddress.toLowerCase() !== selectedAddress.toLowerCase()) { + throw new EthereumProviderRpcError( + RPC_ERROR_UNAUTHORIZED, + "Unauthorized" + ); + } + + return this.getAtomicCapability( + env, + origin, + currentChainId, + selectedAddress + ); + } + + // EIP-7702 delegation 상태를 판별하고 ERC-5792 atomic capability 응답 형식으로 반환한다. + // 미지원 체인은 키를 생략한다 (https://eips.ethereum.org/EIPS/eip-5792#wallet_getcapabilities). + async getAtomicCapability( + env: Env, + origin: string, + chainId: string, + address: string + ): Promise { + const evmInfo = this.chainsService.getEVMInfoOrThrow(chainId); + const hexChainId = `0x${evmInfo.chainId.toString(16)}`; + + if (!this.getChainFeatures(chainId)?.includes("eip-7702")) { + return {}; + } + + let code: string | undefined; + try { + code = await this.request( + env, + origin, + "eth_getCode", + [address, "latest"], + undefined, + chainId + ); + } catch { + return {}; + } + + if (!code) { + return {}; + } + + const status: DelegationStatus = parseDelegation(code, ALLOWED_DELEGATORS); + return { [hexChainId]: { atomic: { status } } }; + } + + // ── Smart Account Upgrade/Downgrade ───────────────────── + + async upgradeToSmartAccount( + env: Env, + chainId: string, + vaultId: string + ): Promise { + return this.sendEip7702Tx( + env, + chainId, + ALLOWED_DELEGATORS[0], + "ready", + vaultId + ); + } + + async downgradeSmartAccount( + env: Env, + chainId: string, + vaultId: string + ): Promise { + return this.sendEip7702Tx( + env, + chainId, + EVM_ZERO_ADDRESS, + "supported", + vaultId + ); + } + + private async sendEip7702Tx( + env: Env, + chainId: string, + delegatorAddress: string, + requiredStatus: "ready" | "supported", + vaultId: string + ): Promise { + // 1. Chain validation + const evmInfo = this.chainsService.getEVMInfoOrThrow(chainId); + if (!this.getChainFeatures(chainId)?.includes("eip-7702")) { + throw new Error("This chain does not support EIP-7702."); + } + + // 2. Key type validation + const keyInfo = this.keyRingService.getKeyInfo(vaultId); + if (!keyInfo) { + throw new Error("No key selected."); + } + if (keyInfo.type === "ledger" || keyInfo.type === "keystone") { + throw new Error("Smart Account is not supported for hardware wallets."); + } + + // 3. Check current delegation status + const selectedAddress = await this.getEthAddressForVault(chainId, vaultId); + let code: string; + try { + code = await this.request( + env, + "", + "eth_getCode", + [selectedAddress, "latest"], + undefined, + chainId + ); + } catch { + throw new Error("Failed to check account delegation status."); + } + const status = parseDelegation(code ?? "0x", ALLOWED_DELEGATORS); + if (status !== requiredStatus) { + if (requiredStatus === "ready") { + throw new Error( + status === "supported" + ? "Account is already upgraded." + : "Account has an unsupported delegation." + ); + } else { + throw new Error( + status === "ready" + ? "Account is not upgraded." + : "Account has an unsupported delegation." + ); + } + } + + const evmChainId = evmInfo.chainId; + + // 4. Estimate gas + fee + nonce in one batch (dummy auth for estimation) + const filled = await fillUnsignedEVMTx("", evmInfo, selectedAddress, { + to: selectedAddress, + value: "0x0", + data: "0x", + authorizationList: buildDummyAuthorizationList( + delegatorAddress, + evmChainId + ), + }); + + const txNonce = Number(filled.nonce); + + // 5. Sign authorization with real nonce (self-sponsoring: auth nonce = tx nonce + 1) + const signedAuthList = await signAuthorizationList( + this.keyRingService, + chainId, + keyInfo.id, + [ + { + address: delegatorAddress, + chainId: evmChainId, + nonce: BigInt(txNonce + 1), + }, + ] + ); + + // 6. Construct unsigned tx (gas+fee from fillUnsignedEVMTx, real auth from step 5) + const unsignedTx: UnsignedEVMTransaction = { + ...filled, + from: selectedAddress, + chainId: evmChainId, + type: 4, + authorizationList: signedAuthList, + }; + + // 7. Sign tx (pre-authorized — UI confirm page serves as user consent) + const { signature } = await this.signEthereumPreAuthorized( + vaultId, + chainId, + selectedAddress, + Buffer.from(JSON.stringify(unsignedTx)), + EthSignType.TRANSACTION + ); + + // 8. Serialize + broadcast + delete unsignedTx.from; + const signedTxHex = serializeEVMTransaction(unsignedTx, signature); + const signedTx = Buffer.from(signedTxHex.replace("0x", ""), "hex"); + + const txHash = await this.backgroundTxEthereumService.sendEthereumTx( + "", + chainId, + signedTx, + { skipTracingTxResult: true } + ); + + // 9. Poll for confirmation (same pattern as BackgroundTxEthereumService) + let reverted = false; + try { + await retry( + async () => { + const receipt = await this.request<{ status?: string } | null>( + env, + "", + "eth_getTransactionReceipt", + [txHash], + undefined, + chainId + ); + if (receipt) { + if (receipt.status === "0x0") { + reverted = true; + } + return; + } + throw new Error("No tx receipt yet"); + }, + { + maxRetries: 50, + waitMsAfterError: 500, + maxWaitMsAfterError: 15000, + } + ); + } catch { + // Timeout — return hash without confirmation + } + + if (reverted) { + throw new Error("EIP-7702 transaction reverted on chain."); + } + + return txHash; + } + + // ── Signing ────────────────────────────────────────────── + async signEthereumSelected( env: Env, origin: string, @@ -124,7 +435,13 @@ export class KeyRingEthereumService { if (signType === EthSignType.TRANSACTION) { const unsignedTx = JSON.parse(Buffer.from(message).toString()); if (unsignedTx.authorizationList) { - throw new Error("EIP-7702 transactions are not supported."); + if (!env.isInternalMsg) { + throw new Error("External EIP-7702 transactions are not supported."); + } + validateAuthorizationList( + unsignedTx.authorizationList, + ALLOWED_DELEGATORS + ); } const hasRequiredErc20Approvals = @@ -139,19 +456,12 @@ export class KeyRingEthereumService { } } - try { - Bech32Address.validate(signer); - } catch { - // Ignore mixed-case checksum - signer = ( - signer.substring(0, 2) === "0x" ? signer : "0x" + signer - ).toLowerCase(); - } + const normalizedSigner = normalizeSigner(signer); const key = await this.keyRingCosmosService.getKey(vaultId, chainId); if ( - signer !== key.bech32Address && - signer !== key.ethereumHexAddress.toLowerCase() + normalizedSigner !== key.bech32Address && + normalizedSigner !== key.ethereumHexAddress.toLowerCase() ) { throw new Error("Signer mismatched"); } @@ -163,7 +473,7 @@ export class KeyRingEthereumService { { origin, chainId, - signer, + signer: normalizedSigner, pubKey: key.pubKey, message, signType, @@ -197,14 +507,7 @@ export class KeyRingEthereumService { return { signingData: res.signingData, - signature: Buffer.concat([ - signature.r, - signature.s, - // The metamask doesn't seem to consider the chain id in this case... (maybe bug on metamask?) - signature.v - ? Buffer.from("1c", "hex") - : Buffer.from("1b", "hex"), - ]), + signature: encodeSignature(signature), }; } case EthSignType.TRANSACTION: { @@ -212,40 +515,31 @@ export class KeyRingEthereumService { Buffer.from(res.signingData).toString() ); - const isEIP1559 = - !!unsignedTx.maxFeePerGas || - !!unsignedTx.maxPriorityFeePerGas; - if (isEIP1559) { - unsignedTx.type = TransactionTypes.eip1559; - } + applyTxType(unsignedTx); delete unsignedTx.from; const signature = await this.keyRingService.sign( chainId, vaultId, - Buffer.from(serialize(unsignedTx).replace("0x", ""), "hex"), + Buffer.from( + serializeEVMTransaction(unsignedTx).replace("0x", ""), + "hex" + ), "keccak256" ); return { signingData: res.signingData, - signature: Buffer.concat([ - signature.r, - signature.s, - // The metamask doesn't seem to consider the chain id in this case... (maybe bug on metamask?) - signature.v - ? Buffer.from("1c", "hex") - : Buffer.from("1b", "hex"), - ]), + signature: encodeSignature(signature), }; } case EthSignType.EIP712: { const data = await EIP712MessageValidator.validateAsync( JSON.parse(Buffer.from(res.signingData).toString()) ); - // Since ethermint eip712 tx uses non-standard format, it cannot pass validation of ethersjs. - // Therefore, it should be handled at a slightly lower level. + // Since ethermint eip712 tx uses non-standard format, we construct + // the signing hash manually rather than using a typed data signing helper. const signature = await this.keyRingService.sign( chainId, vaultId, @@ -262,14 +556,7 @@ export class KeyRingEthereumService { return { signingData: res.signingData, - signature: Buffer.concat([ - signature.r, - signature.s, - // The metamask doesn't seem to consider the chain id in this case... (maybe bug on metamask?) - signature.v - ? Buffer.from("1c", "hex") - : Buffer.from("1b", "hex"), - ]), + signature: encodeSignature(signature), }; } default: @@ -278,61 +565,14 @@ export class KeyRingEthereumService { } })(); - try { - const tx = - signType === EthSignType.TRANSACTION - ? JSON.parse(Buffer.from(signingData).toString()) - : undefined; - const ethTxType = await (async () => { - if (signType !== EthSignType.TRANSACTION) { - return; - } - - if (tx.to == null || tx.to === "0x") { - return "deploy-contract"; - } - - const contractBytecode = await this.request( - env, - origin, - "eth_getCode", - [tx.to, "latest"], - undefined, - chainId - ); - if ( - (tx.data == null || tx.data === "0x") && - BigInt(tx.value) > 0 && - contractBytecode === "0x" - ) { - return "send-native"; - } - - if (tx.data?.startsWith("0xa9059cbb")) { - return "execute-contract/send-erc20"; - } - - return "execute-contract"; - })(); - - this.analyticsService.logEventIgnoreError("evm_tx_signed", { - chainId, - isInternal: env.isInternalMsg, - origin, - keyType: keyInfo.type, - ethSignType: signType, - ...(signType === EthSignType.TRANSACTION && { - ethTxType, - }), - ...(ethTxType && - ethTxType.startsWith("execute-contract") && - tx && { - contractAddress: tx.to, - }), - }); - } catch (e) { - console.log(e); - } + await this.logSignedTransaction( + env, + origin, + chainId, + signingData, + signType, + keyInfo.type + ); return { signingData, @@ -342,6 +582,71 @@ export class KeyRingEthereumService { ); } + private async logSignedTransaction( + env: Env, + origin: string, + chainId: string, + signingData: Uint8Array, + signType: EthSignType, + keyType: string + ): Promise { + try { + const tx = + signType === EthSignType.TRANSACTION + ? JSON.parse(Buffer.from(signingData).toString()) + : undefined; + const ethTxType = await (async () => { + if (signType !== EthSignType.TRANSACTION) { + return; + } + + if (tx.to == null || tx.to === "0x") { + return "deploy-contract"; + } + + const contractBytecode = await this.request( + env, + origin, + "eth_getCode", + [tx.to, "latest"], + undefined, + chainId + ); + if ( + (tx.data == null || tx.data === "0x") && + BigInt(tx.value) > 0 && + contractBytecode === "0x" + ) { + return "send-native"; + } + + if (tx.data?.startsWith(ERC20_TRANSFER_SELECTOR)) { + return "execute-contract/send-erc20"; + } + + return "execute-contract"; + })(); + + this.analyticsService.logEventIgnoreError("evm_tx_signed", { + chainId, + isInternal: env.isInternalMsg, + origin, + keyType, + ethSignType: signType, + ...(signType === EthSignType.TRANSACTION && { + ethTxType, + }), + ...(ethTxType && + ethTxType.startsWith("execute-contract") && + tx && { + contractAddress: tx.to, + }), + }); + } catch (e) { + console.log(e); + } + } + /** * Sign an Ethereum transaction with pre-authorization * @dev only sign the transaction, not simulate or broadcast @@ -370,26 +675,12 @@ export class KeyRingEthereumService { ); } - if (signType === EthSignType.TRANSACTION) { - const unsignedTx = JSON.parse(Buffer.from(message).toString()); - if (unsignedTx.authorizationList) { - throw new Error("EIP-7702 transactions are not supported."); - } - } - - try { - Bech32Address.validate(signer); - } catch { - // Ignore mixed-case checksum - signer = ( - signer.substring(0, 2) === "0x" ? signer : "0x" + signer - ).toLowerCase(); - } + const normalizedSigner = normalizeSigner(signer); const key = await this.keyRingCosmosService.getKey(vaultId, chainId); if ( - signer !== key.bech32Address && - signer !== key.ethereumHexAddress.toLowerCase() + normalizedSigner !== key.bech32Address && + normalizedSigner !== key.ethereumHexAddress.toLowerCase() ) { throw new Error("Signer mismatched"); } @@ -400,33 +691,166 @@ export class KeyRingEthereumService { ); } - const unsignedTx: UnsignedTransaction = JSON.parse( + const unsignedTx: UnsignedEVMTransaction = JSON.parse( Buffer.from(message).toString() ); - const isEIP1559 = - !!unsignedTx.maxFeePerGas || !!unsignedTx.maxPriorityFeePerGas; - if (isEIP1559) { - unsignedTx.type = TransactionTypes.eip1559; + + if (unsignedTx.authorizationList) { + validateAuthorizationList( + unsignedTx.authorizationList, + ALLOWED_DELEGATORS + ); } + applyTxType(unsignedTx); + const signature = await this.keyRingService.sign( chainId, vaultId, - Buffer.from(serialize(unsignedTx).replace("0x", ""), "hex"), + Buffer.from(serializeEVMTransaction(unsignedTx).replace("0x", ""), "hex"), "keccak256" ); return { signingData: Buffer.from(JSON.stringify(unsignedTx), "utf8"), - signature: Buffer.concat([ - signature.r, - signature.s, - // The metamask doesn't seem to consider the chain id in this case... (maybe bug on metamask?) - signature.v ? Buffer.from("1c", "hex") : Buffer.from("1b", "hex"), - ]), + signature: encodeSignature(signature), }; } + private async signEthereumBatch( + env: Env, + origin: string, + vaultId: string, + chainId: string, + signer: string, + message: Uint8Array + ): Promise { + const modularChainInfo = + this.chainsService.getModularChainInfoOrThrow(chainId); + if (modularChainInfo.hideInUI) { + throw new Error("Can't sign for hidden chain"); + } + if (!isEthSignChain(modularChainInfo)) { + throw new Error("Not ethermint like and EVM chain"); + } + + const keyInfo = this.keyRingService.getKeyInfo(vaultId); + if (!keyInfo) { + throw new Error("Null key info"); + } + + if (keyInfo.type === "ledger" || keyInfo.type === "keystone") { + throw new Error( + "Ledger and Keystone are not supported for batch transactions" + ); + } + + const normalizedSigner = normalizeSigner(signer); + + const key = await this.keyRingCosmosService.getKey(vaultId, chainId); + if ( + normalizedSigner !== key.bech32Address && + normalizedSigner !== key.ethereumHexAddress.toLowerCase() + ) { + throw new Error("Signer mismatched"); + } + + return await this.interactionService.waitApproveV2( + env, + "/sign-ethereum", + "request-sign-ethereum", + { + origin, + chainId, + signer: normalizedSigner, + pubKey: key.pubKey, + message, + signType: EthSignType.EIP5792, + keyType: keyInfo.type, + keyInsensitive: keyInfo.insensitive, + }, + async (res: { signingData: Uint8Array }) => { + const batchData: BatchSigningData = JSON.parse( + Buffer.from(res.signingData).toString() + ); + + // Cross-verify batchId with original request + const originalRequest: InternalSendCallsRequest = JSON.parse( + Buffer.from(message).toString() + ); + if (batchData.batchId !== originalRequest.batchId) { + throw new Error("Batch ID mismatch between request and signing data"); + } + + // Without sequential strategy, atomic and single both produce exactly one tx. + if (batchData.unsignedTxs.length !== 1) { + throw new Error( + `Expected exactly 1 unsigned tx, got ${batchData.unsignedTxs.length}` + ); + } + + const tx = batchData.unsignedTxs[0] as UnsignedEVMTransaction; + + // Sign EIP-7702 authorization if present (exactly one delegation per tx) + if (tx.authorizationList && tx.authorizationList.length > 0) { + if (tx.authorizationList.length !== 1) { + throw new Error( + `Expected exactly 1 authorization, got ${tx.authorizationList.length}` + ); + } + const auth = tx.authorizationList[0]; + tx.authorizationList = await signAuthorizationList( + this.keyRingService, + chainId, + vaultId, + [ + { + address: auth.address, + chainId: + typeof auth.chainId === "string" + ? parseInt( + auth.chainId, + auth.chainId.startsWith("0x") ? 16 : 10 + ) + : Number(auth.chainId), + nonce: BigInt(auth.nonce), + }, + ] + ); + } + applyTxType(tx); + delete tx.from; + + const serializedUnsigned = serializeEVMTransaction(tx); + + const sig = await this.keyRingService.sign( + chainId, + vaultId, + Buffer.from(serializedUnsigned.replace("0x", ""), "hex"), + "keccak256" + ); + + const signedTxHex = serializeEVMTransaction(tx, encodeSignature(sig)); + + this.analyticsService.logEventIgnoreError("evm_batch_tx_signed", { + chainId, + isInternal: env.isInternalMsg, + origin, + keyType: keyInfo.type, + strategy: batchData.strategy, + }); + + return { + strategy: batchData.strategy, + batchId: batchData.batchId, + signedTxs: [signedTxHex], + }; + } + ); + } + + // ── RPC Dispatcher ─────────────────────────────────────── + async request( env: Env, origin: string, @@ -443,57 +867,12 @@ export class KeyRingEthereumService { const result = (await (async () => { switch (method) { - case "keplr_initProviderState": { - const currentChainId = this.getCurrentChainId(origin, chainId); - if (currentChainId == null) { - return { - currentEvmChainId: null, - currentChainId: null, - selectedAddress: null, - } as T; - } - - try { - const pubkey = await this.keyRingService.getPubKeySelected( - currentChainId - ); - const selectedAddress = `0x${Buffer.from( - pubkey.getEthAddress() - ).toString("hex")}`; - - return { - currentEvmChainId: this.getEVMChainId(currentChainId), - currentChainId: currentChainId, - selectedAddress, - }; - } catch (e) { - console.error(e); - return null; - } - } - case "keplr_connect": { - try { - const currentChainId = this.forceGetCurrentChainId(origin, chainId); - const pubkey = await this.keyRingService.getPubKeySelected( - currentChainId - ); - const selectedAddress = `0x${Buffer.from( - pubkey.getEthAddress() - ).toString("hex")}`; - - return { - currentEvmChainId: this.getEVMChainId(currentChainId), - currentChainId: currentChainId, - selectedAddress, - }; - } catch (e) { - console.error(e); - return null; - } - } - case "keplr_disconnect": { + case "keplr_initProviderState": + return this.handleInitProviderState(origin, chainId); + case "keplr_connect": + return this.handleConnect(origin, chainId); + case "keplr_disconnect": return this.permissionService.removeAllTypePermission([origin]); - } case "eth_chainId": { const currentChainId = this.forceGetCurrentChainId(origin, chainId); return `0x${this.getEVMChainId(currentChainId).toString(16)}`; @@ -502,783 +881,86 @@ export class KeyRingEthereumService { const currentChainId = this.forceGetCurrentChainId(origin, chainId); return this.getEVMChainId(currentChainId).toString(); } - case "eth_accounts": { - const currentChainId = this.getCurrentChainId(origin, chainId); - if (currentChainId == null) { - return [] as T; - } - - const pubkey = await this.keyRingService.getPubKeySelected( - currentChainId - ); - const selectedAddress = `0x${Buffer.from( - pubkey.getEthAddress() - ).toString("hex")}`; - - return [selectedAddress]; - } + case "eth_accounts": + return this.handleEthAccounts(origin, chainId); case "eth_requestAccounts": { const currentChainId = this.forceGetCurrentChainId(origin, chainId); - const pubkey = await this.keyRingService.getPubKeySelected( - currentChainId - ); - const selectedAddress = `0x${Buffer.from( - pubkey.getEthAddress() - ).toString("hex")}`; - - return [selectedAddress]; + return [await this.getSelectedEthAddress(currentChainId)]; } - case "eth_sendTransaction": { - const tx = - (Array.isArray(params) && - (params?.[0] as { - chainId?: string | number; - from: string; - value?: string; - gas?: string; - gasLimit?: string; - authorizationList?: { - address: string; - chainId: string; - nonce: string; - r: string; - s: string; - yParity: string; - }[]; - })) || - null; - if (!tx) { - throw new EthereumProviderRpcError( - -32602, - "Must provide a transaction." - ); - } - - const currentChainId = this.forceGetCurrentChainId(origin, chainId); - - const { from: sender, authorizationList, ...restTx } = tx; - - if (authorizationList) { - throw new Error("EIP-7702 transactions are not supported."); - } - - if (tx.chainId) { - const evmChainIdFromTx: number = validateEVMChainId( - (() => { - if (typeof tx.chainId === "string") { - if (tx.chainId.startsWith("0x")) { - return parseInt(tx.chainId, 16); - } else { - return parseInt(tx.chainId, 10); - } - } else { - return tx.chainId; - } - })() - ); - if (evmChainIdFromTx !== this.getEVMChainId(currentChainId)) { - throw new Error( - "The current active chain id does not match the one in the transaction." - ); - } - } - - const pubkey = await this.keyRingService.getPubKeySelected( - currentChainId - ); - const selectedAddress = `0x${Buffer.from( - pubkey.getEthAddress() - ).toString("hex")}`; - - const transactionCount = await this.request( + case "eth_sendTransaction": + return this.handleSendTransaction( env, origin, - "eth_getTransactionCount", - [selectedAddress, "pending"], + params, providerId, chainId ); - const nonce = parseInt(transactionCount, 16); - - const unsignedTx = this.normalizeUnsignedTx( - restTx, - currentChainId, - nonce - ); - - try { - const { signingData, signature } = await this.signEthereumSelected( - env, - origin, - currentChainId, - sender, - Buffer.from(JSON.stringify(unsignedTx)), - EthSignType.TRANSACTION - ); - - const signingTx = JSON.parse(Buffer.from(signingData).toString()); - - const isEIP1559 = - !!signingTx.maxFeePerGas || !!signingTx.maxPriorityFeePerGas; - if (isEIP1559) { - signingTx.type = TransactionTypes.eip1559; - } - - const signedTx = Buffer.from( - serialize(signingTx, signature).replace("0x", ""), - "hex" - ); - - const txHash = - await this.backgroundTxEthereumService.sendEthereumTx( - origin, - currentChainId, - signedTx, - {} - ); - - return txHash; - } catch (e) { - if ( - (e instanceof Error && e.message === "Request rejected") || - e === "Request rejected" - ) { - throw new EthereumProviderRpcError(4001, "User Rejected Request"); - } - throw e; - } - } - case "eth_signTransaction": { - const tx = - (Array.isArray(params) && - (params?.[0] as { - chainId?: string | number; - from: string; - value?: string; - gas?: string; - gasLimit?: string; - authorizationList?: { - address: string; - chainId: string; - nonce: string; - r: string; - s: string; - yParity: string; - }[]; - })) || - null; - if (!tx) { - throw new EthereumProviderRpcError( - -32602, - "Must provide a transaction." - ); - } - - const currentChainId = this.forceGetCurrentChainId(origin, chainId); - - const { from: sender, authorizationList, ...restTx } = tx; - - if (authorizationList) { - throw new Error("EIP-7702 transactions are not supported."); - } - - if (tx.chainId) { - const evmChainIdFromTx: number = validateEVMChainId( - (() => { - if (typeof tx.chainId === "string") { - if (tx.chainId.startsWith("0x")) { - return parseInt(tx.chainId, 16); - } else { - return parseInt(tx.chainId, 10); - } - } else { - return tx.chainId; - } - })() - ); - if (evmChainIdFromTx !== this.getEVMChainId(currentChainId)) { - throw new Error( - "The current active chain id does not match the one in the transaction." - ); - } - } - - const pubkey = await this.keyRingService.getPubKeySelected( - currentChainId - ); - const selectedAddress = `0x${Buffer.from( - pubkey.getEthAddress() - ).toString("hex")}`; - - const transactionCount = await this.request( + case "eth_signTransaction": + return this.handleSignTransaction( env, origin, - "eth_getTransactionCount", - [selectedAddress, "pending"], + params, providerId, chainId ); - const nonce = parseInt(transactionCount, 16); - - const unsignedTx = this.normalizeUnsignedTx( - restTx, - currentChainId, - nonce - ); - - try { - const { signingData, signature } = await this.signEthereumSelected( - env, - origin, - currentChainId, - sender, - Buffer.from(JSON.stringify(unsignedTx)), - EthSignType.TRANSACTION - ); - - const signingTx = JSON.parse(Buffer.from(signingData).toString()); - - const isEIP1559 = - !!signingTx.maxFeePerGas || !!signingTx.maxPriorityFeePerGas; - if (isEIP1559) { - signingTx.type = TransactionTypes.eip1559; - } - - const signedTx = serialize(signingTx, signature); - - return signedTx; - } catch (e) { - if ( - (e instanceof Error && e.message === "Request rejected") || - e === "Request rejected" - ) { - throw new EthereumProviderRpcError(4001, "User Rejected Request"); - } - throw e; - } - } - case "personal_sign": { - const message = - (Array.isArray(params) && (params?.[0] as string)) || undefined; - if (!message) { - throw new EthereumProviderRpcError( - -32602, - "Must provide a stringified message." - ); - } - - const signer = - (Array.isArray(params) && (params?.[1] as string)) || undefined; - if (!signer || (signer && !signer.match(/^0x[0-9A-Fa-f]*$/))) { - throw new EthereumProviderRpcError( - -32602, - "Must provide an Ethereum address." - ); - } - - const currentChainId = this.forceGetCurrentChainId(origin, chainId); - try { - const { signature } = await this.signEthereumSelected( - env, - origin, - currentChainId, - signer, - message.startsWith("0x") - ? Buffer.from(message.slice(2), "hex") - : Buffer.from(message, "utf8"), - EthSignType.MESSAGE - ); - - return `0x${Buffer.from(signature).toString("hex")}`; - } catch (e) { - if ( - (e instanceof Error && e.message === "Request rejected") || - e === "Request rejected" - ) { - throw new EthereumProviderRpcError(4001, "User Rejected Request"); - } - throw e; - } - } + case "personal_sign": + return this.handlePersonalSign(env, origin, params, chainId); case "eth_signTypedData_v3": // NOTE: v3 is deprecated - case "eth_signTypedData_v4": { - const signer = - (Array.isArray(params) && (params?.[0] as string)) || undefined; - if (!signer || (signer && !signer.match(/^0x[0-9A-Fa-f]*$/))) { - throw new EthereumProviderRpcError( - -32602, - "Must provide an Ethereum address." - ); - } - - const typedData = - (Array.isArray(params) && (params?.[1] as any)) || undefined; - - const currentChainId = this.forceGetCurrentChainId(origin, chainId); - - const { value: validatedTypedData, error } = - EIP712MessageValidator.validate( - typeof typedData === "string" ? JSON.parse(typedData) : typedData - ); - if (error) { - throw new EthereumProviderRpcError( - -32602, - "Must provide a valid EIP712 data format" - ); - } - - const chainIdFromDomain = validatedTypedData.domain["chainId"] as - | string - | number - | undefined; - if (chainIdFromDomain !== undefined) { - const chainIdFromDomainNumber = validateEVMChainId( - typeof chainIdFromDomain === "string" - ? parseInt(chainIdFromDomain) - : chainIdFromDomain - ); - const currentChainIdNumber = this.getEVMChainId(currentChainId); - - if (chainIdFromDomainNumber !== currentChainIdNumber) { - throw new EthereumProviderRpcError( - -32602, - `The current active chain id ${currentChainIdNumber} does not match the one in the domain ${chainIdFromDomainNumber}.` - ); - } - } - - try { - const { signature } = await this.signEthereumSelected( - env, - origin, - currentChainId, - signer, - Buffer.from( - typeof typedData === "string" - ? typedData - : JSON.stringify(typedData) - ), - EthSignType.EIP712 - ); - - return `0x${Buffer.from(signature).toString("hex")}`; - } catch (e) { - if ( - (e instanceof Error && e.message === "Request rejected") || - e === "Request rejected" - ) { - throw new EthereumProviderRpcError(4001, "User Rejected Request"); - } - throw e; - } - } - case "eth_subscribe": { - const currentChainId = this.forceGetCurrentChainId(origin, chainId); - const currentChainEVMInfo = - this.chainsService.getEVMInfoOrThrow(currentChainId); - if (!currentChainEVMInfo.websocket) { - throw new Error( - `WebSocket endpoint for current chain has not been provided to Keplr.` - ); - } - - const ws = new WebSocket(currentChainEVMInfo.websocket); - const subscriptionId: string = await new Promise( - (resolve, reject) => { - const handleOpen = () => { - ws.send( - JSON.stringify({ - jsonrpc: "2.0", - id: 1, - method, - params, - }) - ); - }; - const handleMessage = (event: MessageEvent) => { - const eventData = JSON.parse(event.data); - if (eventData.error) { - ws.close(); - - reject(eventData.error); - } else { - if (eventData.method === "eth_subscription") { - this.interactionService.dispatchEvent( - WEBPAGE_PORT, - "keplr_ethSubscription", - { - origin, - providerId, - data: { - subscription: eventData.params.subscription, - result: eventData.params.result, - }, - } - ); - } else { - resolve(eventData.result); - } - } - }; - const handleError = () => { - ws.close(); - - reject( - new Error( - "Something went wrong with the WebSocket connection" - ) - ); - }; - - ws.addEventListener("open", handleOpen); - ws.addEventListener("message", handleMessage); - ws.addEventListener("error", handleError); - ws.addEventListener( - "close", - () => { - ws.removeEventListener("open", handleOpen); - ws.removeEventListener("message", handleMessage); - ws.removeEventListener("error", handleError); - }, - { once: true } - ); - } + case "eth_signTypedData_v4": + return this.handleSignTypedData(env, origin, params, chainId); + case "eth_subscribe": + return this.wsManager.subscribe( + origin, + method, + params, + providerId, + chainId ); - runInAction(() => { - const key = `${subscriptionId}/${providerId}`; - this.websocketSubscriptionMap.set(key, ws); - }); - - return subscriptionId; - } - case "eth_unsubscribe": { - const subscriptionId = - (Array.isArray(params) && (params?.[0] as string)) || undefined; - if (!subscriptionId) { - throw new EthereumProviderRpcError( - -32602, - "Must provide a subscription id." - ); - } - - const currentChainId = this.forceGetCurrentChainId(origin, chainId); - const currentChainEVMInfo = - this.chainsService.getEVMInfoOrThrow(currentChainId); - if (!currentChainEVMInfo.websocket) { - throw new Error( - `WebSocket endpoint for current chain has not been provided to Keplr.` - ); - } - - const subscribedWs = - this.websocketSubscriptionMap.get(subscriptionId); - if (!subscribedWs) { - return false; - } - - const ws = new WebSocket(currentChainEVMInfo.websocket); - const result = await new Promise((resolve, reject) => { - const handleOpen = () => { - ws.send( - JSON.stringify({ - jsonrpc: "2.0", - id: 1, - method, - params, - }) - ); - }; - const handleMessage = (event: MessageEvent) => { - ws.close(); - - const eventData = JSON.parse(event.data); - if (eventData.error) { - reject(eventData.error); - } else { - subscribedWs.close(); - runInAction(() => { - const key = `${subscriptionId}/${providerId}`; - this.websocketSubscriptionMap.delete(key); - }); - resolve(eventData.result); - } - }; - const handleError = () => { - ws.close(); - - reject( - new Error("Something went wrong with the WebSocket connection") - ); - }; - - ws.addEventListener("open", handleOpen); - ws.addEventListener("message", handleMessage); - ws.addEventListener("error", handleError); - ws.addEventListener( - "close", - () => { - ws.removeEventListener("open", handleOpen); - ws.removeEventListener("message", handleMessage); - ws.removeEventListener("error", handleError); - }, - { once: true } - ); - }); - - return result; - } - case "wallet_switchEthereumChain": { - const newCurrentChainId = this.getNewCurrentChainIdFromRequest( + case "eth_unsubscribe": + return this.wsManager.unsubscribe( + origin, method, - params + params, + providerId, + chainId ); - const currentChainId = this.getCurrentChainId(origin, chainId); - if ( - // If the new current chain id is not set or the current chain id is the same as the new current chain id, do nothing. - newCurrentChainId == null || - currentChainId === newCurrentChainId - ) { - return null; - } - - try { - await this.permissionService.updateCurrentChainIdForEVM( - env, - origin, - newCurrentChainId - ); - } catch (e) { - if ( - (e instanceof Error && e.message === "Request rejected") || - e === "Request rejected" - ) { - throw new EthereumProviderRpcError(4001, "User Rejected Request"); - } - throw e; - } - - return null; - } - case "wallet_addEthereumChain": { - const param = - Array.isArray(params) && - (params?.[0] as { - chainId: string; - chainName: string; - nativeCurrency: { - name: string; - symbol: string; - decimals: number; - }; - rpcUrls: string[]; - iconUrls?: string[]; - }); - if (!param || typeof param !== "object") { - throw new EthereumProviderRpcError( - -32602, - "Must provide a single object parameter." - ); - } - - const evmChainId = validateEVMChainId(parseInt(param.chainId, 16)); - - const chainInfo = - this.chainsService.getChainInfoByEVMChainId(evmChainId) ?? - (await (async () => { - const rpc = param.rpcUrls.find((url) => { - try { - const urlObject = new URL(url); - return ( - urlObject.protocol === "http:" || - urlObject.protocol === "https:" - ); - } catch { - return false; - } - }); - const websocket = param.rpcUrls.find((url) => { - try { - const urlObject = new URL(url); - return ( - urlObject.protocol === "ws:" || - urlObject.protocol === "wss:" - ); - } catch { - return false; - } - }); - // Skip the validation for these parameters because they will be validated in the `suggestChainInfo` method. - const { chainName, nativeCurrency, iconUrls } = param; - - const addingChainInfo = { - rpc, - rest: rpc, - chainId: `eip155:${evmChainId}`, - bip44: { - coinType: 60, - }, - chainName, - stakeCurrency: { - coinDenom: nativeCurrency.symbol, - coinMinimalDenom: nativeCurrency.symbol, - coinDecimals: nativeCurrency.decimals, - }, - currencies: [ - { - coinDenom: nativeCurrency.symbol, - coinMinimalDenom: nativeCurrency.symbol, - coinDecimals: nativeCurrency.decimals, - }, - ], - feeCurrencies: [ - { - coinDenom: nativeCurrency.symbol, - coinMinimalDenom: nativeCurrency.symbol, - coinDecimals: nativeCurrency.decimals, - }, - ], - evm: { - chainId: evmChainId, - rpc, - websocket, - }, - features: ["eth-address-gen", "eth-key-sign"], - chainSymbolImageUrl: - iconUrls && typeof iconUrls[0] === "string" && !!iconUrls[0] - ? iconUrls[0] - : undefined, - beta: true, - } as ChainInfo; - - try { - await this.chainsService.suggestChainInfo( - env, - addingChainInfo, - origin - ); - } catch (e) { - if ( - (e instanceof Error && e.message === "Request rejected") || - e === "Request rejected" - ) { - throw new EthereumProviderRpcError( - 4001, - "User Rejected Request" - ); - } - throw e; - } - - return addingChainInfo; - })()); - - this.permissionService.addPermission( - [chainInfo.chainId], - getBasicAccessPermissionType(), - [origin] + case "wallet_switchEthereumChain": + return this.chainHandler.switchChain( + env, + origin, + method, + params, + chainId ); - - try { - await this.permissionService.updateCurrentChainIdForEVM( - env, - origin, - chainInfo.chainId - ); - } catch (e) { - if ( - (e instanceof Error && e.message === "Request rejected") || - e === "Request rejected" - ) { - throw new EthereumProviderRpcError(4001, "User Rejected Request"); - } - throw e; - } - - return null; - } + case "wallet_addEthereumChain": + return this.chainHandler.addChain(env, origin, params, chainId); case "wallet_getPermissions": // This `request` method can be executed if the basic access permission is granted. // So, it's not necessary to check or grant the permission here. - case "wallet_requestPermissions": { + case "wallet_requestPermissions": return [{ parentCapability: "eth_accounts" }]; - } - case "wallet_revokePermissions": { - const param = - Array.isArray(params) && (params?.[0] as Record); - if (!param || typeof param !== "object") { - throw new EthereumProviderRpcError( - -32602, - "Must provide a single object parameter." - ); - } - - if (param["eth_accounts"] == null) { - throw new EthereumProviderRpcError( - -32602, - "Must provide a single object parameter with the key 'eth_accounts'." - ); - } - - await this.permissionService.removeAllTypePermission([origin]); - - return null; - } - case "wallet_watchAsset": { - const param = params as - | { - type: string; - options: { - address: string; - symbol?: string; - decimals?: number; - image?: string; - tokenId?: string; - }; - } - | undefined; - if (!param) { - throw new EthereumProviderRpcError( - -32602, - "Must provide a single object parameter." - ); - } - - if (param.type !== "ERC20") { - throw new EthereumProviderRpcError( - -32602, - "Must provide a valid asset type. Only ERC20 is supported." - ); - } - - const contractAddress = param?.options.address; - - const currentChainId = this.forceGetCurrentChainId(origin, chainId); - - try { - await this.tokenERC20Service.suggestERC20Token( - env, - currentChainId, - contractAddress - ); - } catch (e) { - if ( - (e instanceof Error && e.message === "Request rejected") || - e === "Request rejected" - ) { - throw new EthereumProviderRpcError(4001, "User Rejected Request"); - } - throw e; - } - - return true; - } + case "wallet_revokePermissions": + return this.chainHandler.revokePermissions(origin, params); + case "wallet_watchAsset": + return this.chainHandler.watchAsset(env, origin, params, chainId); + // TODO: ERC-5792 스펙은 모든 지원 체인의 capabilities를 한 번에 반환해야 하지만, 현재는 활성 체인만 반환. + case "wallet_getCapabilities": + return this.handleGetCapabilities(env, origin, params, chainId); + case "wallet_sendCalls": + return this.handleSendCalls(env, origin, params, providerId, chainId); + case "wallet_getCallsStatus": + return this.handleGetCallsStatus(env, origin, params, chainId); + case "wallet_showCallsStatus": + throw new EthereumProviderRpcError( + RPC_ERROR_UNSUPPORTED_METHOD, + "Not implemented" + ); case "eth_call": case "eth_estimateGas": case "eth_getTransactionCount": case "eth_getTransactionByHash": case "eth_getTransactionByBlockHashAndIndex": case "eth_getTransactionByBlockNumberAndIndex": - case "eth_getTransactionByHash": case "eth_getTransactionReceipt": case "eth_sendRawTransaction": case "eth_protocolVersion": @@ -1293,78 +975,257 @@ export class KeyRingEthereumService { case "eth_getBlockByNumber": case "eth_gasPrice": case "eth_feeHistory": - case "eth_maxPriorityFeePerGas": { - const currentChainId = this.forceGetCurrentChainId(origin, chainId); - const currentChainEVMInfo = - this.chainsService.getEVMInfoOrThrow(currentChainId); - - return ( - await simpleFetch>(currentChainEVMInfo.rpc, { - method: "POST", - headers: { - "content-type": "application/json", - "request-source": origin, - }, - body: JSON.stringify({ - jsonrpc: "2.0", - method, - params, - id: 1, - }), - }) - ).data.result; - } - default: { - throw new EthereumProviderRpcError(4200, `Unsupported Method`); - } + case "eth_maxPriorityFeePerGas": + return this.chainHandler.passthroughRpc( + origin, + method, + params, + chainId + ); + default: + throw new EthereumProviderRpcError( + RPC_ERROR_UNSUPPORTED_METHOD, + `Unsupported Method` + ); } })()) as T; return result; } - getNewCurrentChainIdFromRequest( - method: string, - params?: unknown[] | Record - ): string | undefined { - switch (method) { - case "wallet_switchEthereumChain": { - const param = - (Array.isArray(params) && (params?.[0] as { chainId: string })) || - undefined; - if (!param?.chainId) { - throw new EthereumProviderRpcError( - -32602, - "Must provide a chain id." - ); - } + // ── RPC Handlers ───────────────────────────────────────── - const newEvmChainId = validateEVMChainId(parseInt(param.chainId, 16)); - const chainInfo = - this.chainsService.getChainInfoByEVMChainId(newEvmChainId); - if (!chainInfo) { - throw new EthereumProviderRpcError( - 4902, - `Unrecognized chain ID "${newEvmChainId}". Try adding the chain using wallet_addEthereumChain first.` - ); - } + private async handleInitProviderState(origin: string, chainId?: string) { + const currentChainId = this.getCurrentChainId(origin, chainId); + if (currentChainId == null) { + return { + currentEvmChainId: null, + currentChainId: null, + selectedAddress: null, + }; + } - return chainInfo.chainId; - } - default: { - return; - } + try { + const selectedAddress = await this.getSelectedEthAddress(currentChainId); + + return { + currentEvmChainId: this.getEVMChainId(currentChainId), + currentChainId: currentChainId, + selectedAddress, + }; + } catch (e) { + console.error(e); + return null; } } - checkNeedEnableAccess(method: string) { - if (enableAccessSkippedEVMJSONRPCMethods.includes(method)) { - return false; + private async handleConnect(origin: string, chainId?: string) { + try { + const currentChainId = this.forceGetCurrentChainId(origin, chainId); + const selectedAddress = await this.getSelectedEthAddress(currentChainId); + + return { + currentEvmChainId: this.getEVMChainId(currentChainId), + currentChainId: currentChainId, + selectedAddress, + }; + } catch (e) { + console.error(e); + return null; } + } + + private async handleEthAccounts(origin: string, chainId?: string) { + const currentChainId = this.getCurrentChainId(origin, chainId); + if (currentChainId == null) { + return []; + } + + const selectedAddress = await this.getSelectedEthAddress(currentChainId); + + return [selectedAddress]; + } + + private async handleSendTransaction( + env: Env, + origin: string, + params: unknown[] | Record | undefined, + providerId: string | undefined, + chainId: string | undefined + ) { + try { + const { signedTxHex } = await this.prepareAndSignTransaction( + env, + origin, + params, + providerId, + chainId + ); + + const currentChainId = this.forceGetCurrentChainId(origin, chainId); + const signedTx = Buffer.from(signedTxHex.replace("0x", ""), "hex"); + + return await this.backgroundTxEthereumService.sendEthereumTx( + origin, + currentChainId, + signedTx, + {} + ); + } catch (e) { + rethrowAsProviderError(e); + } + } + + private async handleSignTransaction( + env: Env, + origin: string, + params: unknown[] | Record | undefined, + providerId: string | undefined, + chainId: string | undefined + ) { + try { + const { signedTxHex } = await this.prepareAndSignTransaction( + env, + origin, + params, + providerId, + chainId + ); + return signedTxHex; + } catch (e) { + rethrowAsProviderError(e); + } + } + + private async handlePersonalSign( + env: Env, + origin: string, + params: unknown[] | Record | undefined, + chainId: string | undefined + ) { + const message = + (Array.isArray(params) && (params?.[0] as string)) || undefined; + if (!message) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide a stringified message." + ); + } + + const signer = + (Array.isArray(params) && (params?.[1] as string)) || undefined; + if (!signer || (signer && !signer.match(/^0x[0-9A-Fa-f]*$/))) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide an Ethereum address." + ); + } + + const currentChainId = this.forceGetCurrentChainId(origin, chainId); + try { + const { signature } = await this.signEthereumSelected( + env, + origin, + currentChainId, + signer, + message.startsWith("0x") + ? Buffer.from(message.slice(2), "hex") + : Buffer.from(message, "utf8"), + EthSignType.MESSAGE + ); + + return `0x${Buffer.from(signature).toString("hex")}`; + } catch (e) { + rethrowAsProviderError(e); + } + } + + private async handleSignTypedData( + env: Env, + origin: string, + params: unknown[] | Record | undefined, + chainId: string | undefined + ) { + const signer = + (Array.isArray(params) && (params?.[0] as string)) || undefined; + if (!signer || (signer && !signer.match(/^0x[0-9A-Fa-f]*$/))) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide an Ethereum address." + ); + } + + const typedData = + (Array.isArray(params) && + (params?.[1] as string | Record)) || + undefined; + + const currentChainId = this.forceGetCurrentChainId(origin, chainId); + + const { value: validatedTypedData, error } = + EIP712MessageValidator.validate( + typeof typedData === "string" ? JSON.parse(typedData) : typedData + ); + if (error) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide a valid EIP712 data format" + ); + } + + const chainIdFromDomain = validatedTypedData.domain["chainId"] as + | string + | number + | undefined; + if (chainIdFromDomain !== undefined) { + const chainIdFromDomainNumber = validateEVMChainId( + typeof chainIdFromDomain === "string" + ? parseInt(chainIdFromDomain) + : chainIdFromDomain + ); + const currentChainIdNumber = this.getEVMChainId(currentChainId); + + if (chainIdFromDomainNumber !== currentChainIdNumber) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + `The current active chain id ${currentChainIdNumber} does not match the one in the domain ${chainIdFromDomainNumber}.` + ); + } + } + + try { + const { signature } = await this.signEthereumSelected( + env, + origin, + currentChainId, + signer, + Buffer.from( + typeof typedData === "string" ? typedData : JSON.stringify(typedData) + ), + EthSignType.EIP712 + ); + + return `0x${Buffer.from(signature).toString("hex")}`; + } catch (e) { + rethrowAsProviderError(e); + } + } + + // ── Public Utilities (delegated to chainHandler) ────────── + + getNewCurrentChainIdFromRequest( + method: string, + params?: unknown[] | Record + ): string | undefined { + return this.chainHandler.getNewCurrentChainIdFromRequest(method, params); + } - return true; + checkNeedEnableAccess(method: string) { + return this.chainHandler.checkNeedEnableAccess(method); } + // ── Private Helpers ─────────────────────────────────────── + private getCurrentChainId(origin: string, chainId?: string) { return chainId || this.permissionService.getCurrentChainIdForEVM(origin); } @@ -1373,7 +1234,7 @@ export class KeyRingEthereumService { return ( this.getCurrentChainId(origin, chainId) || // If the current chain id is not set, use Ethereum mainnet as the default chain id. - "eip155:1" + DEFAULT_EVM_CHAIN_ID ); } @@ -1383,86 +1244,286 @@ export class KeyRingEthereumService { return evmInfo.chainId; } - private toHexQty(x?: string | number | bigint): string | undefined { - if (x === undefined || x === null) { - return undefined; + private async getSelectedEthAddress(chainId: string): Promise { + const pubkey = await this.keyRingService.getPubKeySelected(chainId); + return getEthAddressFromPubkey(pubkey); + } + + private async prepareAndSignTransaction( + env: Env, + origin: string, + params: unknown[] | Record | undefined, + providerId: string | undefined, + chainId: string | undefined + ): Promise<{ signedTxHex: string }> { + const tx = parseTxParam(params); + + const currentChainId = this.forceGetCurrentChainId(origin, chainId); + + const { from: sender, authorizationList, ...restTx } = tx; + + if (authorizationList) { + throw new Error("EIP-7702 transactions are not supported."); } - if (typeof x === "bigint") { - return `0x${x.toString(16)}`; + if (tx.chainId) { + const evmChainIdFromTx: number = validateEVMChainId( + parseChainIdParam(tx.chainId) + ); + if (evmChainIdFromTx !== this.getEVMChainId(currentChainId)) { + throw new Error( + "The current active chain id does not match the one in the transaction." + ); + } } - if (typeof x === "number") { - const n = Number.isFinite(x) ? Math.max(0, Math.floor(x)) : 0; - return `0x${n.toString(16)}`; + const selectedAddress = await this.getSelectedEthAddress(currentChainId); + + const transactionCount = await this.request( + env, + origin, + "eth_getTransactionCount", + [selectedAddress, "pending"], + providerId, + chainId + ); + const nonce = parseInt(transactionCount, 16); + + const unsignedTx = normalizeUnsignedTx( + restTx, + this.getEVMChainId(currentChainId), + nonce + ); + + const { signingData, signature } = await this.signEthereumSelected( + env, + origin, + currentChainId, + sender, + Buffer.from(JSON.stringify(unsignedTx)), + EthSignType.TRANSACTION + ); + + const signingTx = JSON.parse(Buffer.from(signingData).toString()); + + applyTxType(signingTx); + + const signedTxHex = serializeEVMTransaction(signingTx, signature); + + return { signedTxHex }; + } + + // ── EIP-5792: wallet_sendCalls ────────────────────────────── + + private async handleSendCalls( + env: Env, + origin: string, + params: unknown[] | Record | undefined, + providerId: string | undefined, + chainId: string | undefined + ) { + const currentChainId = this.forceGetCurrentChainId(origin, chainId); + const evmInfo = this.chainsService.getEVMInfoOrThrow(currentChainId); + const hexChainId = `0x${evmInfo.chainId.toString(16)}`; + + const request = (Array.isArray(params) ? params[0] : undefined) as + | WalletSendCallsRequest + | undefined; + + if (!request) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide request params." + ); } - x = x.trim(); - if (x.length === 0 || x === "0x") { - return undefined; + const validationError = validateSendCallsRequest(request, hexChainId); + if (validationError) { + throw new EthereumProviderRpcError( + validationError.code, + validationError.message + ); } - let q: bigint; + // Validate sender address + const selectedAddress = await this.getSelectedEthAddress(currentChainId); + if ( + request.from && + request.from.toLowerCase() !== selectedAddress.toLowerCase() + ) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + `Unmatched from address: ${request.from}` + ); + } + // Query capabilities and validate atomicRequired + const capabilities = await this.getAtomicCapability( + env, + origin, + currentChainId, + selectedAddress + ); + const chainCapabilities = capabilities[hexChainId] as + | { atomic: { status: DelegationStatus } } + | undefined; + + // Absent capability = chain does not support batching (EIP-5792 spec) + if (!chainCapabilities) { + throw new EthereumProviderRpcError( + EIP5792_ERROR_ATOMICITY_NOT_SUPPORTED, + "Batch calls are not supported on this chain." + ); + } + + if ( + request.atomicRequired && + chainCapabilities.atomic.status === "unsupported" + ) { + throw new EthereumProviderRpcError( + EIP5792_ERROR_ATOMICITY_NOT_SUPPORTED, + "Atomic batch is not supported on this chain." + ); + } + + // Fetch nonce + const transactionCount = await this.request( + env, + origin, + "eth_getTransactionCount", + [selectedAddress, "pending"], + providerId, + currentChainId + ); + + const batchId = crypto.randomUUID(); + + const internalRequest: InternalSendCallsRequest = { + batchId, + calls: request.calls.map((call) => ({ + ...call, + data: call.data ?? "0x", + })), + apiVersion: request.version || "1.0", + nonce: parseInt(transactionCount, 16), + chainCapabilities, + }; + + // Sign batch via interaction + const batchResponse = await this.signEthereumBatch( + env, + origin, + this.keyRingService.selectedVaultId, + currentChainId, + selectedAddress, + Buffer.from(JSON.stringify(internalRequest)) + ); + + // Post-signing atomicRequired enforcement + if (request.atomicRequired && batchResponse.strategy !== "atomic") { + throw new EthereumProviderRpcError( + EIP5792_ERROR_ATOMICITY_NOT_SUPPORTED, + "Atomic execution was required but could not be fulfilled." + ); + } + + // Broadcast signed tx and store mapping try { - q = BigInt(x); - } catch { - if (!x.startsWith("0x")) { - x = `0x${x}`; - } - try { - q = BigInt(x); - } catch { - return undefined; - } + const txHash = await this.backgroundTxEthereumService.sendEthereumTx( + origin, + currentChainId, + Buffer.from(batchResponse.signedTxs[0].replace("0x", ""), "hex"), + {} + ); + + this.batchCallsMap.set(batchId, { + txHash, + chainId: currentChainId, + origin, + strategy: batchResponse.strategy, + apiVersion: request.version || "1.0", + }); + } catch (error) { + console.error(`Batch broadcast failed for ${batchId}:`, error); + rethrowAsProviderError(error); } - return `0x${q.toString(16)}`; + return { id: batchId }; } - private normalizeUnsignedTx( - tx: any, - chainId: string, - nonce: number - ): UnsignedTransaction { - const { - value, - gas, - gasLimit, - gasPrice, - maxFeePerGas, - maxPriorityFeePerGas, - data, - ...restTx - } = tx; - - const unsignedTx: UnsignedTransaction = { - ...restTx, - value: this.toHexQty(value), - gasLimit: this.toHexQty(gasLimit ?? gas), - gasPrice: this.toHexQty(gasPrice), - maxFeePerGas: this.toHexQty(maxFeePerGas), - maxPriorityFeePerGas: this.toHexQty(maxPriorityFeePerGas), - chainId: this.getEVMChainId(chainId), - nonce, - }; + // ── EIP-5792: wallet_getCallsStatus ──────────────────────── + + private async handleGetCallsStatus( + env: Env, + origin: string, + params: unknown[] | Record | undefined, + _chainId: string | undefined + ) { + const batchId = + (Array.isArray(params) && (params[0] as string)) || undefined; + if (!batchId) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide a batch ID." + ); + } - if (data != null && typeof data === "string") { - unsignedTx.data = data.startsWith("0x") ? data : `0x${data}`; + const entry = this.batchCallsMap.get(batchId); + if (!entry || entry.origin !== origin) { + throw new EthereumProviderRpcError( + EIP5792_ERROR_UNKNOWN_BUNDLE, + "Unknown bundle ID" + ); } - const isLegacy = unsignedTx.gasPrice !== undefined; - const isEIP1559 = - unsignedTx.maxFeePerGas !== undefined && - unsignedTx.maxPriorityFeePerGas !== undefined; + const evmInfo = this.chainsService.getEVMInfoOrThrow(entry.chainId); - if (isEIP1559) { - delete unsignedTx.gasPrice; - } else if (isLegacy) { - delete unsignedTx.maxFeePerGas; - delete unsignedTx.maxPriorityFeePerGas; + // Fetch receipt to determine status + let status = 100; // pending + const receipts: unknown[] = []; + + try { + const receipt = await this.request( + env, + origin, + "eth_getTransactionReceipt", + [entry.txHash], + undefined, + entry.chainId + ); + if (receipt) { + const txStatus = (receipt as Record)["status"]; + status = txStatus === "0x1" ? 200 : 500; + receipts.push(receipt); + } + } catch { + // Receipt not yet available — stays pending } - return unsignedTx; + return { + version: entry.apiVersion, + chainId: `0x${evmInfo.chainId.toString(16)}`, + id: batchId, + status, + atomic: entry.strategy === "atomic", + receipts, + }; + } + + // ── Private Helpers ──────────────────────────────────── + + private getChainFeatures(chainId: string): string[] | undefined { + const info = this.chainsService.getModularChainInfoOrThrow(chainId); + if (info.type === "evm") return info.evm.features; + if (info.type === "ethermint") return info.cosmos.features; + return undefined; + } + + async getEthAddressForVault( + chainId: string, + vaultId: string + ): Promise { + const pubkey = await this.keyRingService.getPubKey(chainId, vaultId); + return getEthAddressFromPubkey(pubkey); } } diff --git a/packages/background/src/keyring-ethereum/ws-handlers.ts b/packages/background/src/keyring-ethereum/ws-handlers.ts new file mode 100644 index 0000000000..9d7c2f67b0 --- /dev/null +++ b/packages/background/src/keyring-ethereum/ws-handlers.ts @@ -0,0 +1,189 @@ +import { EthereumProviderRpcError, WEBPAGE_PORT } from "@keplr-wallet/router"; +import { ChainsService } from "../chains"; +import { InteractionService } from "../interaction"; +import { PermissionService } from "../permission"; +import { runInAction } from "mobx"; +import { DEFAULT_EVM_CHAIN_ID, RPC_ERROR_INVALID_PARAMS } from "./constants"; + +export class EvmWebSocketManager { + protected subscriptionMap = new Map(); + + constructor( + private readonly chainsService: ChainsService, + private readonly interactionService: InteractionService, + private readonly permissionService: PermissionService + ) {} + + // ── Private Helpers ────────────────────────────────────── + + private forceGetCurrentChainId(origin: string, chainId?: string): string { + return ( + chainId || + this.permissionService.getCurrentChainIdForEVM(origin) || + DEFAULT_EVM_CHAIN_ID + ); + } + + // ── Subscription Handlers ───────────────────────────────── + + async subscribe( + origin: string, + method: string, + params: unknown[] | Record | undefined, + providerId: string | undefined, + chainId: string | undefined + ) { + const currentChainId = this.forceGetCurrentChainId(origin, chainId); + const currentChainEVMInfo = + this.chainsService.getEVMInfoOrThrow(currentChainId); + if (!currentChainEVMInfo.websocket) { + throw new Error( + `WebSocket endpoint for current chain has not been provided to Keplr.` + ); + } + + const ws = new WebSocket(currentChainEVMInfo.websocket); + const subscriptionId: string = await new Promise((resolve, reject) => { + const handleOpen = () => { + ws.send( + JSON.stringify({ + jsonrpc: "2.0", + id: 1, + method, + params, + }) + ); + }; + const handleMessage = (event: MessageEvent) => { + const eventData = JSON.parse(event.data); + if (eventData.error) { + ws.close(); + + reject(eventData.error); + } else { + if (eventData.method === "eth_subscription") { + this.interactionService.dispatchEvent( + WEBPAGE_PORT, + "keplr_ethSubscription", + { + origin, + providerId, + data: { + subscription: eventData.params.subscription, + result: eventData.params.result, + }, + } + ); + } else { + resolve(eventData.result); + } + } + }; + const handleError = () => { + ws.close(); + + reject(new Error("Something went wrong with the WebSocket connection")); + }; + + ws.addEventListener("open", handleOpen); + ws.addEventListener("message", handleMessage); + ws.addEventListener("error", handleError); + ws.addEventListener( + "close", + () => { + ws.removeEventListener("open", handleOpen); + ws.removeEventListener("message", handleMessage); + ws.removeEventListener("error", handleError); + }, + { once: true } + ); + }); + runInAction(() => { + const key = `${subscriptionId}/${providerId}`; + this.subscriptionMap.set(key, ws); + }); + + return subscriptionId; + } + + async unsubscribe( + origin: string, + method: string, + params: unknown[] | Record | undefined, + providerId: string | undefined, + chainId: string | undefined + ) { + const subscriptionId = + (Array.isArray(params) && (params?.[0] as string)) || undefined; + if (!subscriptionId) { + throw new EthereumProviderRpcError( + RPC_ERROR_INVALID_PARAMS, + "Must provide a subscription id." + ); + } + + const currentChainId = this.forceGetCurrentChainId(origin, chainId); + const currentChainEVMInfo = + this.chainsService.getEVMInfoOrThrow(currentChainId); + if (!currentChainEVMInfo.websocket) { + throw new Error( + `WebSocket endpoint for current chain has not been provided to Keplr.` + ); + } + + const key = `${subscriptionId}/${providerId}`; + const subscribedWs = this.subscriptionMap.get(key); + if (!subscribedWs) { + return false; + } + + const ws = new WebSocket(currentChainEVMInfo.websocket); + const result = await new Promise((resolve, reject) => { + const handleOpen = () => { + ws.send( + JSON.stringify({ + jsonrpc: "2.0", + id: 1, + method, + params, + }) + ); + }; + const handleMessage = (event: MessageEvent) => { + ws.close(); + + const eventData = JSON.parse(event.data); + if (eventData.error) { + reject(eventData.error); + } else { + subscribedWs.close(); + runInAction(() => { + const key = `${subscriptionId}/${providerId}`; + this.subscriptionMap.delete(key); + }); + resolve(eventData.result); + } + }; + const handleError = () => { + ws.close(); + + reject(new Error("Something went wrong with the WebSocket connection")); + }; + + ws.addEventListener("open", handleOpen); + ws.addEventListener("message", handleMessage); + ws.addEventListener("error", handleError); + ws.addEventListener( + "close", + () => { + ws.removeEventListener("open", handleOpen); + ws.removeEventListener("message", handleMessage); + ws.removeEventListener("error", handleError); + }, + { once: true } + ); + }); + + return result; + } +} diff --git a/packages/background/src/keyring-mnemonic/service.ts b/packages/background/src/keyring-mnemonic/service.ts index d85a8a87f6..95ac92de4e 100644 --- a/packages/background/src/keyring-mnemonic/service.ts +++ b/packages/background/src/keyring-mnemonic/service.ts @@ -140,7 +140,7 @@ export class KeyRingMnemonicService { } { const privKey = this.getPrivKey(vault, purpose, coinType); - let digest = new Uint8Array(); + let digest: Uint8Array; switch (digestMethod) { case "sha256": digest = Hash.sha256(data); diff --git a/packages/background/src/keyring-private-key/service.ts b/packages/background/src/keyring-private-key/service.ts index c26d923c37..e0e85e957c 100644 --- a/packages/background/src/keyring-private-key/service.ts +++ b/packages/background/src/keyring-private-key/service.ts @@ -69,7 +69,7 @@ export class KeyRingPrivateKeyService { ] as string; const privateKey = new PrivKeySecp256k1(Buffer.from(privateKeyText, "hex")); - let digest = new Uint8Array(); + let digest: Uint8Array; switch (digestMethod) { case "sha256": digest = Hash.sha256(data); diff --git a/packages/background/src/recent-send-history/service.ts b/packages/background/src/recent-send-history/service.ts index ce622a9461..1e3902252a 100644 --- a/packages/background/src/recent-send-history/service.ts +++ b/packages/background/src/recent-send-history/service.ts @@ -36,7 +36,7 @@ import { ModularChainInfo, } from "@keplr-wallet/types"; import { CoinPretty } from "@keplr-wallet/unit"; -import { id } from "@ethersproject/hash"; +import { Hash, Hex } from "ox"; import { EventBusPublisher } from "@keplr-wallet/common"; import { TxExecutionEvent } from "../tx-executor/types"; import { @@ -1267,10 +1267,14 @@ export class RecentSendHistoryService { params; const logs = txReceipt.logs; - const transferTopic = id("Transfer(address,address,uint256)"); - const withdrawTopic = id("Withdrawal(address,uint256)"); - const hyperlaneReceiveTopic = id( - "ReceivedTransferRemote(uint32,bytes32,uint256)" + const transferTopic = Hash.keccak256( + Hex.fromString("Transfer(address,address,uint256)") + ); + const withdrawTopic = Hash.keccak256( + Hex.fromString("Withdrawal(address,uint256)") + ); + const hyperlaneReceiveTopic = Hash.keccak256( + Hex.fromString("ReceivedTransferRemote(uint32,bytes32,uint256)") ); for (const log of logs) { diff --git a/packages/background/src/tx-executor/service.ts b/packages/background/src/tx-executor/service.ts index 48a2dd3eba..57053a0a5f 100644 --- a/packages/background/src/tx-executor/service.ts +++ b/packages/background/src/tx-executor/service.ts @@ -34,7 +34,8 @@ import { EthSignType, EthTxStatus, } from "@keplr-wallet/types"; -import { TransactionTypes, serialize } from "@ethersproject/transactions"; +import { serializeEVMTransaction } from "@keplr-wallet/stores-eth"; +import { applyTxType } from "../keyring-ethereum/helper"; import { BaseAccount } from "@keplr-wallet/cosmos"; import { Any } from "@keplr-wallet/proto-types/google/protobuf/any"; import { TxRaw } from "@keplr-wallet/proto-types/cosmos/tx/v1beta1/tx"; @@ -607,15 +608,10 @@ export class BackgroundTxExecutorService { ); const signedTxData = JSON.parse(Buffer.from(result.signingData).toString()); - const isEIP1559 = - !!signedTxData.maxFeePerGas || !!signedTxData.maxPriorityFeePerGas; - if (isEIP1559) { - signedTxData.type = TransactionTypes.eip1559; - } - + applyTxType(signedTxData); delete signedTxData.from; - return serialize(signedTxData, result.signature); + return serializeEVMTransaction(signedTxData, result.signature); } private async signCosmosTx( diff --git a/packages/background/src/tx-executor/types.ts b/packages/background/src/tx-executor/types.ts index dae13821ca..95b1284710 100644 --- a/packages/background/src/tx-executor/types.ts +++ b/packages/background/src/tx-executor/types.ts @@ -1,4 +1,4 @@ -import { UnsignedTransaction } from "@ethersproject/transactions"; +import { UnsignedEVMTransaction } from "@keplr-wallet/stores-eth"; import { StdFee } from "@keplr-wallet/types"; import { Any } from "@keplr-wallet/proto-types/google/protobuf/any"; import { Msg } from "@keplr-wallet/types"; @@ -50,7 +50,7 @@ interface EVMBackgroundTxBase extends Omit { export interface EVMBackgroundTx extends EVMBackgroundTxBase { readonly type: BackgroundTxType.EVM; - txData: UnsignedTransaction; + txData: UnsignedEVMTransaction; customPriorityFee?: string; customGasPrice?: string; } diff --git a/packages/background/src/tx-executor/utils/evm.ts b/packages/background/src/tx-executor/utils/evm.ts index 7c91e36992..a1865ea141 100644 --- a/packages/background/src/tx-executor/utils/evm.ts +++ b/packages/background/src/tx-executor/utils/evm.ts @@ -1,6 +1,6 @@ import { EVMInfo } from "@keplr-wallet/types"; import { simpleFetch } from "@keplr-wallet/simple-fetch"; -import { UnsignedTransaction } from "@ethersproject/transactions"; +import { UnsignedEVMTransaction } from "@keplr-wallet/stores-eth"; import { Dec } from "@keplr-wallet/unit"; import { BackgroundTxFeeType, EVMBackgroundTxFeeType } from "../types"; import { JsonRpcResponse } from "@keplr-wallet/types"; @@ -60,11 +60,11 @@ export async function fillUnsignedEVMTx( origin: string, evmInfo: EVMInfo, signer: string, - tx: UnsignedTransaction, + tx: UnsignedEVMTransaction, feeType: EVMBackgroundTxFeeType = "average", customPriorityFee?: string, customGasPrice?: string -): Promise { +): Promise { const hasProvidedPriorityFee = tx.maxPriorityFeePerGas != null; const hasProvidedGasLimit = tx.gasLimit != null; const innerFeeType: BackgroundTxFeeType = @@ -104,6 +104,9 @@ export async function fillUnsignedEVMTx( to: tx.to, value: tx.value, data: tx.data, + ...(tx.authorizationList + ? { authorizationList: tx.authorizationList } + : {}), }, ], id: ESTIMATE_GAS_ID, @@ -193,7 +196,7 @@ export async function fillUnsignedEVMTx( ? undefined : getResult(ESTIMATE_GAS_ID, true); - let finalGasLimit: UnsignedTransaction["gasLimit"]; + let finalGasLimit: UnsignedEVMTransaction["gasLimit"]; if (tx.gasLimit != null) { finalGasLimit = tx.gasLimit; } else if (gasLimitHex) { @@ -358,7 +361,7 @@ export async function fillUnsignedEVMTx( .toBigNumber() .toString(16)}`; - const newUnsignedTx: UnsignedTransaction = { + const newUnsignedTx: UnsignedEVMTransaction = { ...tx, nonce: finalNonce, maxFeePerGas: maxFeePerGasHex, diff --git a/packages/chain-validator/package.json b/packages/chain-validator/package.json index ebf2dbacbd..0dac87d95b 100644 --- a/packages/chain-validator/package.json +++ b/packages/chain-validator/package.json @@ -21,7 +21,6 @@ "typecheck": "npx tsc -p tsconfig.check.json" }, "dependencies": { - "@ethersproject/abi": "^5.7.0", "@keplr-wallet/cosmos": "0.13.19", "@keplr-wallet/simple-fetch": "0.13.19", "@keplr-wallet/types": "0.13.19", diff --git a/packages/chain-validator/src/feature.ts b/packages/chain-validator/src/feature.ts index c5368f861d..31214494f6 100644 --- a/packages/chain-validator/src/feature.ts +++ b/packages/chain-validator/src/feature.ts @@ -32,6 +32,10 @@ export const SupportedChainFeatures = [ "eth-secp256k1-initia", "eth-secp256k1-cosmos", "/cosmos.evm.types.v1.ExtensionOptionsWeb3Tx", + // EIP-7702 Smart Account 지원. delegator 컨트랙트가 배포된 체인에만 추가해야 한다. + // TODO: MetaMask delegator를 그대로 쓸지 자체 배포할지 결정 후, + // 그대로 쓴다면 @metamask/delegation-deployments 패키지에서 지원 체인을 읽어오는 방식으로 전환하여 이 플래그는 제거할 수 있다. + "eip-7702", ]; /** diff --git a/packages/cosmos/package.json b/packages/cosmos/package.json index e671fa0c37..5ac06659a3 100644 --- a/packages/cosmos/package.json +++ b/packages/cosmos/package.json @@ -21,7 +21,6 @@ "typecheck": "npx tsc -p tsconfig.check.json" }, "dependencies": { - "@ethersproject/address": "^5.6.0", "@keplr-wallet/common": "0.13.19", "@keplr-wallet/crypto": "0.13.19", "@keplr-wallet/proto-types": "0.13.19", @@ -31,6 +30,7 @@ "bech32": "^1.1.4", "buffer": "^6.0.3", "long": "^4.0.0", + "ox": "^0.14.6", "protobufjs": "^6.11.2", "utility-types": "^3.10.0" } diff --git a/packages/cosmos/src/bech32/index.ts b/packages/cosmos/src/bech32/index.ts index a213c85dd9..925dfe72b7 100644 --- a/packages/cosmos/src/bech32/index.ts +++ b/packages/cosmos/src/bech32/index.ts @@ -1,7 +1,7 @@ import bech32, { fromWords } from "bech32"; import { Bech32Config } from "@keplr-wallet/types"; import { Buffer } from "buffer/"; -import { getAddress as getEthAddress } from "@ethersproject/address"; +import { Address } from "ox"; export class Bech32Address { static shortenAddress(bech32: string, maxCharacters: number): string { @@ -92,7 +92,7 @@ export class Bech32Address { } if (mixedCaseChecksum) { - return getEthAddress("0x" + hex); + return Address.checksum(`0x${hex}`); } else { return "0x" + hex; } diff --git a/packages/design-system/src/foundation/typography/typography.tsx b/packages/design-system/src/foundation/typography/typography.tsx index 143c65dcb4..64bb669905 100644 --- a/packages/design-system/src/foundation/typography/typography.tsx +++ b/packages/design-system/src/foundation/typography/typography.tsx @@ -1,6 +1,7 @@ import React from "react"; import { dsTypographyTokens } from "./typography-tokens"; import type { DSTypographySize } from "./typography-tokens"; +import { DSColor } from "../color"; type Weight = "semibold" | "medium" | "regular"; @@ -17,7 +18,7 @@ export interface DSTypographyProps extends React.HTMLAttributes { weight?: Weight; /** Override token font size (px) */ fontSize?: number; - /** Text color — `DSColor.typography.primary`, `DSColor.blue400`, or any CSS color */ + /** Text color — defaults to `DSColor.typography.primary`. Accepts any CSS color. */ color?: string; /** HTML element to render as — `"span"`, `"p"`, `"h1"`, `"div"`, `"label"`, etc. */ as?: React.ElementType; @@ -47,7 +48,7 @@ export const DSTypography = React.forwardRef( lineHeight: token?.lineHeight, letterSpacing: token?.letterSpacing, fontWeight: WEIGHT_VALUE[weight], - color, + color: color ?? DSColor.typography.primary, ...style, }} {...rest} diff --git a/packages/hooks-evm/jest.config.js b/packages/hooks-evm/jest.config.js new file mode 100644 index 0000000000..42eb6623c3 --- /dev/null +++ b/packages/hooks-evm/jest.config.js @@ -0,0 +1,5 @@ +module.exports = { + preset: "ts-jest", + testEnvironment: "node", + testMatch: ["**/src/**/?(*.)+(spec|test).[jt]s?(x)"], +}; diff --git a/packages/hooks-evm/package.json b/packages/hooks-evm/package.json index b062b8ec9f..d6ff36bad2 100644 --- a/packages/hooks-evm/package.json +++ b/packages/hooks-evm/package.json @@ -21,8 +21,6 @@ "typecheck": "npx tsc -p tsconfig.check.json" }, "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/providers": "^5.7.0", "@keplr-wallet/common": "0.13.19", "@keplr-wallet/cosmos": "0.13.19", "@keplr-wallet/simple-fetch": "0.13.19", @@ -30,7 +28,8 @@ "@keplr-wallet/stores-eth": "0.13.19", "@keplr-wallet/types": "0.13.19", "@keplr-wallet/unit": "0.13.19", - "buffer": "^6.0.3" + "buffer": "^6.0.3", + "ox": "^0.14.6" }, "peerDependencies": { "mobx": "^6", diff --git a/packages/hooks-evm/src/tx/name-service-ens.spec.ts b/packages/hooks-evm/src/tx/name-service-ens.spec.ts new file mode 100644 index 0000000000..cf1a36de7d --- /dev/null +++ b/packages/hooks-evm/src/tx/name-service-ens.spec.ts @@ -0,0 +1,108 @@ +import { AbiFunction, Ens, Hex } from "ox"; +import { resolveENSWithEthCall } from "./name-service-ens"; + +const resolverAbi = AbiFunction.from( + "function resolver(bytes32 node) view returns (address)" +); +const multicoinAddrAbi = AbiFunction.from( + "function addr(bytes32 node, uint256 coinType) view returns (bytes)" +); + +describe("resolveENSWithEthCall", () => { + it("normalizes mixed-case ENS names before computing the node", async () => { + const normalizedNode = Ens.namehash("alice.eth"); + const resolver = "0x1234567890123456789012345678901234567890"; + const address = "0x1111111111111111111111111111111111111111"; + + const result = await resolveENSWithEthCall( + "Alice.eth", + async (_to, data) => { + if (data.startsWith(AbiFunction.getSelector(resolverAbi))) { + expect(data).toBe( + AbiFunction.encodeData(resolverAbi, [normalizedNode]) + ); + return AbiFunction.encodeResult(resolverAbi, resolver); + } + + expect(data).toBe( + AbiFunction.encodeData(multicoinAddrAbi, [normalizedNode, BigInt(60)]) + ); + return AbiFunction.encodeResult(multicoinAddrAbi, address as Hex.Hex); + } + ); + + expect(result).toBe(address); + }); + + it("resolves the ENSIP-9 multicoin ETH record", async () => { + const calls: Array<{ to: string; data: string }> = []; + const node = Ens.namehash("alice.eth"); + const resolver = "0x1234567890123456789012345678901234567890"; + const address = "0x1111111111111111111111111111111111111111"; + + const result = await resolveENSWithEthCall( + "alice.eth", + async (to, data) => { + calls.push({ to, data }); + + if (calls.length === 1) { + expect(data).toBe(AbiFunction.encodeData(resolverAbi, [node])); + return AbiFunction.encodeResult(resolverAbi, resolver); + } + + expect(data).toBe( + AbiFunction.encodeData(multicoinAddrAbi, [node, BigInt(60)]) + ); + return AbiFunction.encodeResult(multicoinAddrAbi, address as Hex.Hex); + } + ); + + expect(result).toBe(address); + expect(calls).toHaveLength(2); + }); + + it("returns undefined if the resolver address is unset", async () => { + const result = await resolveENSWithEthCall("alice.eth", async () => { + return AbiFunction.encodeResult( + resolverAbi, + "0x0000000000000000000000000000000000000000" + ); + }); + + expect(result).toBeUndefined(); + }); + + it("returns undefined if the multicoin record is not a 20-byte ETH address", async () => { + const resolver = "0x1234567890123456789012345678901234567890"; + + const result = await resolveENSWithEthCall( + "alice.eth", + async (_to, data) => { + if (data.startsWith(AbiFunction.getSelector(resolverAbi))) { + return AbiFunction.encodeResult(resolverAbi, resolver); + } + + return AbiFunction.encodeResult(multicoinAddrAbi, "0x1234"); + } + ); + + expect(result).toBeUndefined(); + }); + + it("returns undefined if the multicoin record is empty", async () => { + const resolver = "0x1234567890123456789012345678901234567890"; + + const result = await resolveENSWithEthCall( + "alice.eth", + async (_to, data) => { + if (data.startsWith(AbiFunction.getSelector(resolverAbi))) { + return AbiFunction.encodeResult(resolverAbi, resolver); + } + + return AbiFunction.encodeResult(multicoinAddrAbi, "0x"); + } + ); + + expect(result).toBeUndefined(); + }); +}); diff --git a/packages/hooks-evm/src/tx/name-service-ens.ts b/packages/hooks-evm/src/tx/name-service-ens.ts index f31e17ffc4..994fc005d9 100644 --- a/packages/hooks-evm/src/tx/name-service-ens.ts +++ b/packages/hooks-evm/src/tx/name-service-ens.ts @@ -1,9 +1,85 @@ import { action, autorun, makeObservable, observable, runInAction } from "mobx"; import { ChainGetter } from "@keplr-wallet/stores"; import { FetchDebounce, NameService } from "./name-service"; -import { JsonRpcProvider } from "@ethersproject/providers"; +import { simpleFetch } from "@keplr-wallet/simple-fetch"; +import { AbiFunction, Address, Ens, Hex } from "ox"; import { ITxChainSetter } from "./types"; +const ENS_REGISTRY: Hex.Hex = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"; +const resolverAbi = AbiFunction.from( + "function resolver(bytes32 node) view returns (address)" +); +const addrAbi = AbiFunction.from( + "function addr(bytes32 node, uint256 coinType) view returns (bytes)" +); + +async function resolveENS( + rpcUrl: string, + name: string +): Promise { + return resolveENSWithEthCall(name, (to, data) => ethCall(rpcUrl, to, data)); +} + +export async function resolveENSWithEthCall( + name: string, + ethCallFn: (to: string, data: string) => Promise +): Promise { + const node = Ens.namehash(Ens.normalize(name)); + + const resolverCalldata = AbiFunction.encodeData(resolverAbi, [node]); + const resolverResult = await ethCallFn(ENS_REGISTRY, resolverCalldata); + const resolverAddress = AbiFunction.decodeResult(resolverAbi, resolverResult); + + if ( + !resolverAddress || + resolverAddress === "0x0000000000000000000000000000000000000000" + ) { + return undefined; + } + + // Resolve ETH addresses through ENSIP-9 multicoin records only. + // We intentionally do not fall back to legacy addr(bytes32), since Keplr + // treats ENS resolution here as a modern mainnet resolver integration. + const addrCalldata = AbiFunction.encodeData(addrAbi, [node, BigInt(60)]); + const addrResult = await ethCallFn(resolverAddress, addrCalldata); + const addrBytes = AbiFunction.decodeResult(addrAbi, addrResult); + + if (!addrBytes || Hex.size(addrBytes as Hex.Hex) !== 20) { + return undefined; + } + + return Address.checksum(addrBytes as `0x${string}`); +} + +async function ethCall( + rpcUrl: string, + to: string, + data: string +): Promise { + const res = await simpleFetch<{ + result?: string; + error?: { message: string }; + }>(rpcUrl, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: 1, + method: "eth_call", + params: [{ to, data }, "latest"], + }), + }); + + if (res.data.error) { + throw new Error(res.data.error.message); + } + if (!res.data.result) { + throw new Error("No result from eth_call"); + } + + return res.data.result as Hex.Hex; +} + export class ENSNameService implements NameService { readonly type = "ens"; @@ -162,15 +238,7 @@ export class ENSNameService implements NameService { const domain = this.value; const username = domain + "." + suffix; - const resolver = await new JsonRpcProvider(ensU.evm.rpc).getResolver( - username - ); - - if (!resolver) { - throw new Error("Can't find resolver"); - } - - const res = await resolver.getAddress(60); + const res = await resolveENS(ensU.evm.rpc, username); if (this.value === prevValue) { if (res) { diff --git a/packages/hooks-starknet/package.json b/packages/hooks-starknet/package.json index 6c2cb91bec..639a044490 100644 --- a/packages/hooks-starknet/package.json +++ b/packages/hooks-starknet/package.json @@ -21,8 +21,6 @@ "typecheck": "npx tsc -p tsconfig.check.json" }, "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/providers": "^5.7.0", "@keplr-wallet/background": "0.13.19", "@keplr-wallet/common": "0.13.19", "@keplr-wallet/cosmos": "0.13.19", diff --git a/packages/hooks/package.json b/packages/hooks/package.json index 47ca190a7a..c63f1aeed2 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -21,8 +21,6 @@ "typecheck": "npx tsc -p tsconfig.check.json" }, "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/providers": "^5.7.0", "@keplr-wallet/background": "0.13.19", "@keplr-wallet/common": "0.13.19", "@keplr-wallet/cosmos": "0.13.19", @@ -36,6 +34,7 @@ "@keplr-wallet/unit": "0.13.19", "buffer": "^6.0.3", "long": "^4.0.0", + "ox": "^0.14.6", "utility-types": "^3.10.0" }, "peerDependencies": { diff --git a/packages/hooks/src/tx/name-service-ens.spec.ts b/packages/hooks/src/tx/name-service-ens.spec.ts new file mode 100644 index 0000000000..cf1a36de7d --- /dev/null +++ b/packages/hooks/src/tx/name-service-ens.spec.ts @@ -0,0 +1,108 @@ +import { AbiFunction, Ens, Hex } from "ox"; +import { resolveENSWithEthCall } from "./name-service-ens"; + +const resolverAbi = AbiFunction.from( + "function resolver(bytes32 node) view returns (address)" +); +const multicoinAddrAbi = AbiFunction.from( + "function addr(bytes32 node, uint256 coinType) view returns (bytes)" +); + +describe("resolveENSWithEthCall", () => { + it("normalizes mixed-case ENS names before computing the node", async () => { + const normalizedNode = Ens.namehash("alice.eth"); + const resolver = "0x1234567890123456789012345678901234567890"; + const address = "0x1111111111111111111111111111111111111111"; + + const result = await resolveENSWithEthCall( + "Alice.eth", + async (_to, data) => { + if (data.startsWith(AbiFunction.getSelector(resolverAbi))) { + expect(data).toBe( + AbiFunction.encodeData(resolverAbi, [normalizedNode]) + ); + return AbiFunction.encodeResult(resolverAbi, resolver); + } + + expect(data).toBe( + AbiFunction.encodeData(multicoinAddrAbi, [normalizedNode, BigInt(60)]) + ); + return AbiFunction.encodeResult(multicoinAddrAbi, address as Hex.Hex); + } + ); + + expect(result).toBe(address); + }); + + it("resolves the ENSIP-9 multicoin ETH record", async () => { + const calls: Array<{ to: string; data: string }> = []; + const node = Ens.namehash("alice.eth"); + const resolver = "0x1234567890123456789012345678901234567890"; + const address = "0x1111111111111111111111111111111111111111"; + + const result = await resolveENSWithEthCall( + "alice.eth", + async (to, data) => { + calls.push({ to, data }); + + if (calls.length === 1) { + expect(data).toBe(AbiFunction.encodeData(resolverAbi, [node])); + return AbiFunction.encodeResult(resolverAbi, resolver); + } + + expect(data).toBe( + AbiFunction.encodeData(multicoinAddrAbi, [node, BigInt(60)]) + ); + return AbiFunction.encodeResult(multicoinAddrAbi, address as Hex.Hex); + } + ); + + expect(result).toBe(address); + expect(calls).toHaveLength(2); + }); + + it("returns undefined if the resolver address is unset", async () => { + const result = await resolveENSWithEthCall("alice.eth", async () => { + return AbiFunction.encodeResult( + resolverAbi, + "0x0000000000000000000000000000000000000000" + ); + }); + + expect(result).toBeUndefined(); + }); + + it("returns undefined if the multicoin record is not a 20-byte ETH address", async () => { + const resolver = "0x1234567890123456789012345678901234567890"; + + const result = await resolveENSWithEthCall( + "alice.eth", + async (_to, data) => { + if (data.startsWith(AbiFunction.getSelector(resolverAbi))) { + return AbiFunction.encodeResult(resolverAbi, resolver); + } + + return AbiFunction.encodeResult(multicoinAddrAbi, "0x1234"); + } + ); + + expect(result).toBeUndefined(); + }); + + it("returns undefined if the multicoin record is empty", async () => { + const resolver = "0x1234567890123456789012345678901234567890"; + + const result = await resolveENSWithEthCall( + "alice.eth", + async (_to, data) => { + if (data.startsWith(AbiFunction.getSelector(resolverAbi))) { + return AbiFunction.encodeResult(resolverAbi, resolver); + } + + return AbiFunction.encodeResult(multicoinAddrAbi, "0x"); + } + ); + + expect(result).toBeUndefined(); + }); +}); diff --git a/packages/hooks/src/tx/name-service-ens.ts b/packages/hooks/src/tx/name-service-ens.ts index dcafa474dc..13b5845614 100644 --- a/packages/hooks/src/tx/name-service-ens.ts +++ b/packages/hooks/src/tx/name-service-ens.ts @@ -1,9 +1,85 @@ import { action, autorun, makeObservable, observable, runInAction } from "mobx"; import { ChainGetter } from "@keplr-wallet/stores"; import { FetchDebounce, NameService } from "./name-service"; -import { JsonRpcProvider } from "@ethersproject/providers"; +import { simpleFetch } from "@keplr-wallet/simple-fetch"; +import { AbiFunction, Address, Ens, Hex } from "ox"; import { ITxChainSetter } from "./types"; +const ENS_REGISTRY: Hex.Hex = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"; +const resolverAbi = AbiFunction.from( + "function resolver(bytes32 node) view returns (address)" +); +const addrAbi = AbiFunction.from( + "function addr(bytes32 node, uint256 coinType) view returns (bytes)" +); + +async function resolveENS( + rpcUrl: string, + name: string +): Promise { + return resolveENSWithEthCall(name, (to, data) => ethCall(rpcUrl, to, data)); +} + +export async function resolveENSWithEthCall( + name: string, + ethCallFn: (to: string, data: string) => Promise +): Promise { + const node = Ens.namehash(Ens.normalize(name)); + + const resolverCalldata = AbiFunction.encodeData(resolverAbi, [node]); + const resolverResult = await ethCallFn(ENS_REGISTRY, resolverCalldata); + const resolverAddress = AbiFunction.decodeResult(resolverAbi, resolverResult); + + if ( + !resolverAddress || + resolverAddress === "0x0000000000000000000000000000000000000000" + ) { + return undefined; + } + + // Resolve ETH addresses through ENSIP-9 multicoin records only. + // We intentionally do not fall back to legacy addr(bytes32), since Keplr + // treats ENS resolution here as a modern mainnet resolver integration. + const addrCalldata = AbiFunction.encodeData(addrAbi, [node, BigInt(60)]); + const addrResult = await ethCallFn(resolverAddress, addrCalldata); + const addrBytes = AbiFunction.decodeResult(addrAbi, addrResult); + + if (!addrBytes || Hex.size(addrBytes as Hex.Hex) !== 20) { + return undefined; + } + + return Address.checksum(addrBytes as `0x${string}`); +} + +async function ethCall( + rpcUrl: string, + to: string, + data: string +): Promise { + const res = await simpleFetch<{ + result?: string; + error?: { message: string }; + }>(rpcUrl, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: 1, + method: "eth_call", + params: [{ to, data }, "latest"], + }), + }); + + if (res.data.error) { + throw new Error(res.data.error.message); + } + if (!res.data.result) { + throw new Error("No result from eth_call"); + } + + return res.data.result as Hex.Hex; +} + export class ENSNameService implements NameService { readonly type = "ens"; @@ -142,7 +218,7 @@ export class ENSNameService implements NameService { const prevValue = this.value; try { if (!this._ens) { - throw new Error("ENS or is not set"); + throw new Error("ENS is not set"); } runInAction(() => { @@ -164,15 +240,7 @@ export class ENSNameService implements NameService { throw new Error("ENS chain must be an EVM chain"); } - const resolver = await new JsonRpcProvider(ensU.evm.rpc).getResolver( - username - ); - - if (!resolver) { - throw new Error("Can't find resolver"); - } - - const res = await resolver.getAddress(60); + const res = await resolveENS(ensU.evm.rpc, username); if (this.value === prevValue) { if (res) { diff --git a/packages/provider/src/core.ts b/packages/provider/src/core.ts index 26b43ff150..2eb4a1079b 100644 --- a/packages/provider/src/core.ts +++ b/packages/provider/src/core.ts @@ -1712,6 +1712,7 @@ const sidePanelOpenNeededJSONRPCMethods = [ "wallet_addEthereumChain", "wallet_switchEthereumChain", "wallet_watchAsset", + "wallet_sendCalls", ]; class EthereumProvider extends EventEmitter implements IEthereumProvider { diff --git a/packages/provider/src/inject.ts b/packages/provider/src/inject.ts index cc1e0571a6..636039923f 100644 --- a/packages/provider/src/inject.ts +++ b/packages/provider/src/inject.ts @@ -286,7 +286,10 @@ export class InjectedKeplr implements IKeplr, KeplrCoreTypes { if (method === "ethereum") { const ethereumProviderMethod = message.ethereumProviderMethod; - if (ethereumProviderMethod?.startsWith("protected")) { + if ( + typeof ethereumProviderMethod === "string" && + ethereumProviderMethod.startsWith("protected") + ) { throw new Error("Rejected"); } @@ -315,7 +318,9 @@ export class InjectedKeplr implements IKeplr, KeplrCoreTypes { typeof keplr.ethereum[ethereumProviderMethod] !== "function" ) { throw new Error( - `${message.ethereumProviderMethod} is not function or invalid Ethereum provider method` + `${String( + message.ethereumProviderMethod + )} is not function or invalid Ethereum provider method` ); } @@ -410,7 +415,10 @@ export class InjectedKeplr implements IKeplr, KeplrCoreTypes { if (method === "bitcoin") { const bitcoinProviderMethod = message.bitcoinProviderMethod; - if (bitcoinProviderMethod?.startsWith("protected")) { + if ( + typeof bitcoinProviderMethod === "string" && + bitcoinProviderMethod.startsWith("protected") + ) { throw new Error("Rejected"); } @@ -419,7 +427,9 @@ export class InjectedKeplr implements IKeplr, KeplrCoreTypes { typeof keplr.bitcoin?.[bitcoinProviderMethod] !== "function" ) { throw new Error( - `${message.bitcoinProviderMethod} is not function or invalid Bitcoin provider method` + `${String( + message.bitcoinProviderMethod + )} is not function or invalid Bitcoin provider method` ); } diff --git a/packages/stores-etc/package.json b/packages/stores-etc/package.json index 68eed71122..201a2b819d 100644 --- a/packages/stores-etc/package.json +++ b/packages/stores-etc/package.json @@ -21,12 +21,12 @@ "typecheck": "npx tsc -p tsconfig.check.json" }, "dependencies": { - "@ethersproject/abi": "^5.6.0", "@keplr-wallet/common": "0.13.19", "@keplr-wallet/simple-fetch": "0.13.19", "@keplr-wallet/stores": "0.13.19", "@keplr-wallet/types": "0.13.19", "@keplr-wallet/unit": "0.13.19", + "ox": "^0.14.6", "utility-types": "^3.10.0" }, "peerDependencies": { diff --git a/packages/stores-etc/src/erc20/query/index.ts b/packages/stores-etc/src/erc20/query/index.ts index 4a5926f2bd..8474819265 100644 --- a/packages/stores-etc/src/erc20/query/index.ts +++ b/packages/stores-etc/src/erc20/query/index.ts @@ -3,53 +3,18 @@ import { ObservableJsonRPCQuery, QuerySharedContext, } from "@keplr-wallet/stores"; -import { Interface } from "@ethersproject/abi"; +import { AbiFunction } from "ox"; import { computed, makeObservable } from "mobx"; -const erc20MetadataInterface: Interface = new Interface([ - { - constant: true, - inputs: [], - name: "name", - outputs: [ - { - name: "", - type: "string", - }, - ], - payable: false, - stateMutability: "view", - type: "function", - }, - { - constant: true, - inputs: [], - name: "symbol", - outputs: [ - { - name: "", - type: "string", - }, - ], - payable: false, - stateMutability: "view", - type: "function", - }, - { - constant: true, - inputs: [], - name: "decimals", - outputs: [ - { - name: "", - type: "uint8", - }, - ], - payable: false, - stateMutability: "view", - type: "function", - }, -]); +const erc20NameFunction = AbiFunction.from( + "function name() view returns (string)" +); +const erc20SymbolFunction = AbiFunction.from( + "function symbol() view returns (string)" +); +const erc20DecimalsFunction = AbiFunction.from( + "function decimals() view returns (uint8)" +); export class ObservableQueryERC20MetadataName extends ObservableJsonRPCQuery { constructor( @@ -60,7 +25,7 @@ export class ObservableQueryERC20MetadataName extends ObservableJsonRPCQuery { + const unsignedTx: UnsignedEVMTransaction = (() => { switch (denomHelper.type) { case "erc20": return { to: denomHelper.contractAddress, value: "0x0", - data: erc20ContractInterface.encodeFunctionData("transfer", [ - tempRecipient, - hexValue(parsedAmount), + data: AbiFunction.encodeData(erc20TransferFunction, [ + tempRecipient as `0x${string}`, + parsedAmount, ]), }; default: return { to: tempRecipient, - value: hexValue(parsedAmount), + value: Hex.fromNumber(parsedAmount), }; } })(); @@ -238,9 +233,9 @@ export class EthereumAccountBase { return { to: approval.tokenAddress, value: "0x0", - data: erc20ContractInterface.encodeFunctionData("approve", [ - approval.spender, - hexValue(BigInt(approval.amount)), + data: AbiFunction.encodeData(erc20ApproveFunction, [ + approval.spender as `0x${string}`, + BigInt(approval.amount), ]), }; }); @@ -317,7 +312,9 @@ export class EthereumAccountBase { } } - async simulateOpStackL1Fee(unsignedTx: UnsignedTransaction): Promise { + async simulateOpStackL1Fee( + unsignedTx: UnsignedEVMTransaction + ): Promise { const mcInfo = this.chainGetter.getModularChain(this.chainId); if (!mcInfo.hasFeature("op-stack-l1-data-fee")) { throw new Error("The chain isn't built with OP Stack"); @@ -331,8 +328,8 @@ export class EthereumAccountBase { params: [ { to: opStackGasPriceOracleProxyAddress, - data: opStackGasPriceOracleABI.encodeFunctionData("getL1Fee", [ - serialize(unsignedTx), + data: AbiFunction.encodeData(opStackGetL1FeeFunction, [ + serializeEVMTransaction(unsignedTx) as `0x${string}`, ]), }, "latest", @@ -357,7 +354,7 @@ export class EthereumAccountBase { } const evmInfo = u.evm; - const txsToSimulate: UnsignedTransaction[] = [ + const txsToSimulate: UnsignedEVMTransaction[] = [ { to: unsignedTx.to, gasLimit: unsignedTx.gasLimit, @@ -372,9 +369,9 @@ export class EthereumAccountBase { if (erc20Approval != null) { txsToSimulate.push({ to: erc20Approval.tokenAddress, - data: erc20ContractInterface.encodeFunctionData("approve", [ - erc20Approval.spender, - hexValue(BigInt(erc20Approval.amount)), + data: AbiFunction.encodeData(erc20ApproveFunction, [ + erc20Approval.spender as `0x${string}`, + BigInt(erc20Approval.amount), ]), chainId: unsignedTx.chainId, }); @@ -386,8 +383,8 @@ export class EthereumAccountBase { params: [ { to: opStackGasPriceOracleProxyAddress, - data: opStackGasPriceOracleABI.encodeFunctionData("getL1Fee", [ - serialize(tx), + data: AbiFunction.encodeData(opStackGetL1FeeFunction, [ + serializeEVMTransaction(tx) as `0x${string}`, ]), }, "latest", @@ -430,39 +427,39 @@ export class EthereumAccountBase { maxFeePerGas?: string; maxPriorityFeePerGas?: string; gasPrice?: string; - }): UnsignedTransaction { - const parsedAmount = parseUnits(amount, currency.coinDecimals); + }): UnsignedEVMTransaction { + const parsedAmount = Value.from(amount, currency.coinDecimals); const denomHelper = new DenomHelper(currency.coinMinimalDenom); const feeObject = maxFeePerGas && maxPriorityFeePerGas ? { - maxFeePerGas: hexValue(Number(maxFeePerGas)), - maxPriorityFeePerGas: hexValue(Number(maxPriorityFeePerGas)), - gasLimit: hexValue(gasLimit), + maxFeePerGas: Hex.fromNumber(BigInt(maxFeePerGas)), + maxPriorityFeePerGas: Hex.fromNumber(BigInt(maxPriorityFeePerGas)), + gasLimit: Hex.fromNumber(gasLimit), } : { - gasPrice: hexValue(Number(gasPrice ?? "0")), - gasLimit: hexValue(gasLimit), + gasPrice: Hex.fromNumber(BigInt(gasPrice ?? "0")), + gasLimit: Hex.fromNumber(gasLimit), }; // Support EIP-1559 transaction only. - const unsignedTx: UnsignedTransaction = (() => { + const unsignedTx: UnsignedEVMTransaction = (() => { switch (denomHelper.type) { case "erc20": return { ...this.makeTx( denomHelper.contractAddress, "0x0", - erc20ContractInterface.encodeFunctionData("transfer", [ - to, - hexValue(parsedAmount), + AbiFunction.encodeData(erc20TransferFunction, [ + to as `0x${string}`, + parsedAmount, ]) ), ...feeObject, }; default: return { - ...this.makeTx(to, hexValue(parsedAmount)), + ...this.makeTx(to, Hex.fromNumber(parsedAmount)), ...feeObject, }; } @@ -475,20 +472,20 @@ export class EthereumAccountBase { currency: ERC20Currency, spender: string, amount: string - ): UnsignedTransaction { - const parsedAmount = parseUnits(amount, currency.coinDecimals); + ): UnsignedEVMTransaction { + const parsedAmount = Value.from(amount, currency.coinDecimals); return this.makeTx( currency.contractAddress, "0x0", - erc20ContractInterface.encodeFunctionData("approve", [ - spender, - hexValue(parsedAmount), + AbiFunction.encodeData(erc20ApproveFunction, [ + spender as `0x${string}`, + parsedAmount, ]) ); } - makeTx(to: string, value: string, data?: string): UnsignedTransaction { + makeTx(to: string, value: string, data?: string): UnsignedEVMTransaction { const u = this.chainGetter.getModularChain(this.chainId).unwrapped; if (u.type !== "evm" && u.type !== "ethermint") { throw new Error("No EVM chain info provided"); @@ -553,15 +550,15 @@ export class EthereumAccountBase { const isEIP1559 = !!unsignedTx.maxFeePerGas || !!unsignedTx.maxPriorityFeePerGas; if (isEIP1559) { - unsignedTx.type = TransactionTypes.eip1559; + unsignedTx.type = 2; } - return serialize(unsignedTx, signature); + return serializeEVMTransaction(unsignedTx, signature); } async sendEthereumTx( sender: string, - unsignedTx: UnsignedTransaction, + unsignedTx: UnsignedEVMTransaction, onTxEvents?: { onBroadcastFailed?: (e?: Error) => void; onBroadcasted?: (txHash: string) => void; @@ -603,11 +600,11 @@ export class EthereumAccountBase { const isEIP1559 = !!unsignedTx.maxFeePerGas || !!unsignedTx.maxPriorityFeePerGas; if (isEIP1559) { - unsignedTx.type = TransactionTypes.eip1559; + unsignedTx.type = 2; } const signedTx = Buffer.from( - serialize(unsignedTx, signature).replace("0x", ""), + serializeEVMTransaction(unsignedTx, signature).replace("0x", ""), "hex" ); @@ -666,7 +663,7 @@ export class EthereumAccountBase { return false; } - const checksumHexAddress = getEthAddress(hexAddress.toLowerCase()); + const checksumHexAddress = Address.checksum(hexAddress.toLowerCase()); if (isChecksumAddress && checksumHexAddress !== hexAddress) { return false; } diff --git a/packages/stores-eth/src/batch.ts b/packages/stores-eth/src/batch.ts new file mode 100644 index 0000000000..55bcf5f835 --- /dev/null +++ b/packages/stores-eth/src/batch.ts @@ -0,0 +1,51 @@ +import { Execute } from "ox/erc7821"; +import type { UnsignedEVMTransaction } from "./types"; + +const EIP7702_DELEGATION_PREFIX = "0xef0100"; + +/** + * EIP-5792 calls 배열을 StatelessDeleGator의 execute(bytes32,bytes) calldata로 변환. + * ox/erc7821 Execute.encodeData를 사용하여 ERC-7579 표준 준수를 보장. + */ +export function createAtomicBatchTransaction( + calls: { to?: string; data?: string; value?: string }[], + selectedAddress: string, + authorizationList?: UnsignedEVMTransaction["authorizationList"] +): UnsignedEVMTransaction { + const data = Execute.encodeData( + calls.map((call, i) => { + if (!call.to) { + throw new Error( + `Call at index ${i}: contract deployment is not supported in batch execution` + ); + } + return { + to: call.to as `0x${string}`, + value: BigInt(call.value ?? "0x0"), + data: (call.data ?? "0x") as `0x${string}`, + }; + }) + ); + + return { + to: selectedAddress, + data, + value: "0x0", + ...(authorizationList ? { authorizationList } : {}), + }; +} + +/** + * 미업그레이드 계정의 가스 추정을 위한 stateOverride 생성. + * eth_estimateGas 3번째 파라미터로 전달하여 delegation 코드를 주입. + */ +export function buildDelegationStateOverride( + address: string, + delegatorAddress: string +): Record { + return { + [address]: { + code: EIP7702_DELEGATION_PREFIX + delegatorAddress.toLowerCase().slice(2), + }, + }; +} diff --git a/packages/stores-eth/src/constants.ts b/packages/stores-eth/src/constants.ts index 888847996b..22fe6da270 100644 --- a/packages/stores-eth/src/constants.ts +++ b/packages/stores-eth/src/constants.ts @@ -1,272 +1,38 @@ -import { Interface } from "@ethersproject/abi"; +import { AbiFunction } from "ox"; -export const erc20ContractInterface: Interface = new Interface([ - { inputs: [], stateMutability: "nonpayable", type: "constructor" }, +const erc20Abi = [ { - anonymous: false, inputs: [ - { - indexed: true, - internalType: "address", - name: "owner", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "spender", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "value", - type: "uint256", - }, - ], - name: "Approval", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "usr", - type: "address", - }, - ], - name: "Deny", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "usr", - type: "address", - }, - ], - name: "Rely", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "from", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "to", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "value", - type: "uint256", - }, - ], - name: "Transfer", - type: "event", - }, - { - inputs: [], - name: "DOMAIN_SEPARATOR", - outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "PERMIT_TYPEHASH", - outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "address", name: "", type: "address" }, - { internalType: "address", name: "", type: "address" }, - ], - name: "allowance", - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "address", name: "spender", type: "address" }, - { internalType: "uint256", name: "value", type: "uint256" }, + { name: "spender", type: "address" }, + { name: "value", type: "uint256" }, ], name: "approve", - outputs: [{ internalType: "bool", name: "", type: "bool" }], + outputs: [{ name: "", type: "bool" }], stateMutability: "nonpayable", type: "function", }, { - inputs: [{ internalType: "address", name: "", type: "address" }], + inputs: [{ name: "owner", type: "address" }], name: "balanceOf", - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "address", name: "from", type: "address" }, - { internalType: "uint256", name: "value", type: "uint256" }, - ], - name: "burn", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "decimals", - outputs: [{ internalType: "uint8", name: "", type: "uint8" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "address", name: "spender", type: "address" }, - { - internalType: "uint256", - name: "subtractedValue", - type: "uint256", - }, - ], - name: "decreaseAllowance", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [{ internalType: "address", name: "usr", type: "address" }], - name: "deny", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "deploymentChainId", - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + outputs: [{ name: "", type: "uint256" }], stateMutability: "view", type: "function", }, { inputs: [ - { internalType: "address", name: "spender", type: "address" }, - { internalType: "uint256", name: "addedValue", type: "uint256" }, - ], - name: "increaseAllowance", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { internalType: "address", name: "to", type: "address" }, - { internalType: "uint256", name: "value", type: "uint256" }, - ], - name: "mint", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "name", - outputs: [{ internalType: "string", name: "", type: "string" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [{ internalType: "address", name: "", type: "address" }], - name: "nonces", - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "address", name: "owner", type: "address" }, - { internalType: "address", name: "spender", type: "address" }, - { internalType: "uint256", name: "value", type: "uint256" }, - { internalType: "uint256", name: "deadline", type: "uint256" }, - { internalType: "uint8", name: "v", type: "uint8" }, - { internalType: "bytes32", name: "r", type: "bytes32" }, - { internalType: "bytes32", name: "s", type: "bytes32" }, - ], - name: "permit", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [{ internalType: "address", name: "usr", type: "address" }], - name: "rely", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "symbol", - outputs: [{ internalType: "string", name: "", type: "string" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "totalSupply", - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { internalType: "address", name: "to", type: "address" }, - { internalType: "uint256", name: "value", type: "uint256" }, + { name: "to", type: "address" }, + { name: "value", type: "uint256" }, ], name: "transfer", - outputs: [{ internalType: "bool", name: "", type: "bool" }], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { internalType: "address", name: "from", type: "address" }, - { internalType: "address", name: "to", type: "address" }, - { internalType: "uint256", name: "value", type: "uint256" }, - ], - name: "transferFrom", - outputs: [{ internalType: "bool", name: "", type: "bool" }], + outputs: [{ name: "", type: "bool" }], stateMutability: "nonpayable", type: "function", }, - { - inputs: [], - name: "version", - outputs: [{ internalType: "string", name: "", type: "string" }], - stateMutability: "view", - type: "function", - }, - { - inputs: [{ internalType: "address", name: "", type: "address" }], - name: "wards", - outputs: [{ internalType: "uint256", name: "", type: "uint256" }], - stateMutability: "view", - type: "function", - }, -]); +] as const; + +export const erc20TransferFunction = AbiFunction.fromAbi(erc20Abi, "transfer"); +export const erc20ApproveFunction = AbiFunction.fromAbi(erc20Abi, "approve"); +export const erc20BalanceOfFunction = AbiFunction.fromAbi( + erc20Abi, + "balanceOf" +); diff --git a/packages/stores-eth/src/index.ts b/packages/stores-eth/src/index.ts index 059a3ffdea..553512ecb0 100644 --- a/packages/stores-eth/src/index.ts +++ b/packages/stores-eth/src/index.ts @@ -3,3 +3,5 @@ export * from "./account"; export * from "./constants"; export * from "./currency-registrar"; export * from "./types"; +export * from "./serialize"; +export * from "./batch"; diff --git a/packages/stores-eth/src/queries/coingecko-token-info.ts b/packages/stores-eth/src/queries/coingecko-token-info.ts index 796ceb9c30..65e90f17a4 100644 --- a/packages/stores-eth/src/queries/coingecko-token-info.ts +++ b/packages/stores-eth/src/queries/coingecko-token-info.ts @@ -4,7 +4,7 @@ import { ObservableQuery, QuerySharedContext, } from "@keplr-wallet/stores"; -import { parseBytes32String } from "@ethersproject/strings"; +import { Hex } from "ox"; import { makeObservable } from "mobx"; /** @@ -16,7 +16,10 @@ function decodeBytes32IfNeeded(value: string | undefined): string | undefined { if (!value) return value; if (value.length === 64 && /^[0-9a-fA-F]+$/.test(value)) { try { - return parseBytes32String("0x" + value); + const bytes = Hex.toBytes(`0x${value}` as `0x${string}`); + const end = bytes.indexOf(0); + const trimmed = bytes.slice(0, end === -1 ? bytes.length : end); + return new TextDecoder().decode(trimmed); } catch { // noop } diff --git a/packages/stores-eth/src/queries/delegation-status.ts b/packages/stores-eth/src/queries/delegation-status.ts new file mode 100644 index 0000000000..699f8691c8 --- /dev/null +++ b/packages/stores-eth/src/queries/delegation-status.ts @@ -0,0 +1,76 @@ +import { + ChainGetter, + HasMapStore, + QuerySharedContext, +} from "@keplr-wallet/stores"; +import type { DelegationStatus } from "@keplr-wallet/types"; +import { computed, makeObservable } from "mobx"; +import { ObservableEvmChainJsonRpcQuery } from "./evm-chain-json-rpc"; + +const EIP7702_DELEGATION_PREFIX = "0xef0100"; + +function parseDelegation( + code: string, + allowedDelegators: readonly string[] +): DelegationStatus { + if (code === "0x" || code === "0x0") return "ready"; + const lower = code.toLowerCase(); + if (lower.startsWith(EIP7702_DELEGATION_PREFIX) && lower.length === 48) { + const delegator = "0x" + lower.slice(8); + return allowedDelegators.some((d) => d.toLowerCase() === delegator) + ? "supported" + : "unsupported"; + } + return "unsupported"; +} + +export class ObservableQuerySmartAccountDelegationStatusInner extends ObservableEvmChainJsonRpcQuery { + constructor( + sharedContext: QuerySharedContext, + chainId: string, + chainGetter: ChainGetter, + protected readonly ethereumHexAddress: string, + protected readonly allowedDelegators: readonly string[] + ) { + super(sharedContext, chainId, chainGetter, "eth_getCode", [ + ethereumHexAddress, + "latest", + ]); + makeObservable(this); + } + + protected override canFetch(): boolean { + return this.ethereumHexAddress.length > 0; + } + + @computed + get delegationStatus(): DelegationStatus { + if (!this.response || !this.response.data) return "ready"; + return parseDelegation(this.response.data, this.allowedDelegators); + } +} + +export class ObservableQuerySmartAccountDelegationStatus extends HasMapStore { + constructor( + protected readonly sharedContext: QuerySharedContext, + protected readonly chainId: string, + protected readonly chainGetter: ChainGetter, + protected readonly allowedDelegators: readonly string[] + ) { + super((ethereumHexAddress: string) => { + return new ObservableQuerySmartAccountDelegationStatusInner( + sharedContext, + chainId, + chainGetter, + ethereumHexAddress, + allowedDelegators + ); + }); + } + + getQueryByAddress( + ethereumHexAddress: string + ): ObservableQuerySmartAccountDelegationStatusInner { + return this.get(ethereumHexAddress); + } +} diff --git a/packages/stores-eth/src/queries/erc20-balance.ts b/packages/stores-eth/src/queries/erc20-balance.ts index 858c84f694..7f47bdbcfc 100644 --- a/packages/stores-eth/src/queries/erc20-balance.ts +++ b/packages/stores-eth/src/queries/erc20-balance.ts @@ -8,8 +8,9 @@ import { AppCurrency } from "@keplr-wallet/types"; import { CoinPretty, Int } from "@keplr-wallet/unit"; import { computed, makeObservable } from "mobx"; import bigInteger from "big-integer"; -import { erc20ContractInterface } from "../constants"; +import { erc20BalanceOfFunction } from "../constants"; import { DenomHelper } from "@keplr-wallet/common"; +import { AbiFunction } from "ox"; import { EthereumAccountBase } from "../account"; import { ObservableEvmChainJsonRpcQuery } from "./evm-chain-json-rpc"; @@ -28,8 +29,8 @@ export class ObservableQueryEthereumERC20BalanceImpl super(sharedContext, chainId, chainGetter, "eth_call", [ { to: contractAddress, - data: erc20ContractInterface.encodeFunctionData("balanceOf", [ - ethereumHexAddress, + data: AbiFunction.encodeData(erc20BalanceOfFunction, [ + ethereumHexAddress as `0x${string}`, ]), }, "latest", diff --git a/packages/stores-eth/src/queries/erc20-metadata.ts b/packages/stores-eth/src/queries/erc20-metadata.ts index a88c9d9545..a0ef5efcda 100644 --- a/packages/stores-eth/src/queries/erc20-metadata.ts +++ b/packages/stores-eth/src/queries/erc20-metadata.ts @@ -5,7 +5,14 @@ import { } from "@keplr-wallet/stores"; import { computed, makeObservable } from "mobx"; import { ObservableEvmChainJsonRpcQuery } from "./evm-chain-json-rpc"; -import { erc20ContractInterface } from "../constants"; +import { AbiFunction } from "ox"; + +const erc20SymbolFunction = AbiFunction.from( + "function symbol() view returns (string)" +); +const erc20DecimalsFunction = AbiFunction.from( + "function decimals() view returns (uint8)" +); export class ObservableQueryEVMChainERC20MetadataSymbol extends ObservableEvmChainJsonRpcQuery { constructor( @@ -17,7 +24,7 @@ export class ObservableQueryEVMChainERC20MetadataSymbol extends ObservableEvmCha super(sharedContext, chainId, chainGetter, "eth_call", [ { to: contractAddress, - data: erc20ContractInterface.encodeFunctionData("symbol"), + data: AbiFunction.encodeData(erc20SymbolFunction), }, "latest", ]); @@ -36,10 +43,10 @@ export class ObservableQueryEVMChainERC20MetadataSymbol extends ObservableEvmCha } try { - return erc20ContractInterface.decodeFunctionResult( - "symbol", - this.response.data - )[0]; + return AbiFunction.decodeResult( + erc20SymbolFunction, + this.response.data as `0x${string}` + ); } catch (e) { console.log(e); } @@ -57,7 +64,7 @@ export class ObservableQueryEVMChainERC20MetadataDecimals extends ObservableEvmC super(sharedContext, chainId, chainGetter, "eth_call", [ { to: contractAddress, - data: erc20ContractInterface.encodeFunctionData("decimals"), + data: AbiFunction.encodeData(erc20DecimalsFunction), }, "latest", ]); @@ -76,10 +83,10 @@ export class ObservableQueryEVMChainERC20MetadataDecimals extends ObservableEvmC } try { - return erc20ContractInterface.decodeFunctionResult( - "decimals", - this.response.data - )[0]; + return AbiFunction.decodeResult( + erc20DecimalsFunction, + this.response.data as `0x${string}` + ); } catch (e) { console.log(e); } diff --git a/packages/stores-eth/src/queries/index.ts b/packages/stores-eth/src/queries/index.ts index 7427220f5f..f52936b0c7 100644 --- a/packages/stores-eth/src/queries/index.ts +++ b/packages/stores-eth/src/queries/index.ts @@ -15,6 +15,7 @@ import { ObservableQueryCoingeckoTokenInfo } from "./coingecko-token-info"; import { ObservableQueryEthereumERC20BalanceRegistry } from "./erc20-balance"; import { ObservableQueryEthereumGasPrice } from "./gas-price"; import { ObservableQueryEthereumTxReceipt } from "./tx-receipt"; +import { ObservableQuerySmartAccountDelegationStatus } from "./delegation-status"; export interface EthereumQueries { ethereum: EthereumQueriesImpl; @@ -24,6 +25,7 @@ export const EthereumQueries = { use(options: { coingeckoAPIBaseURL: string; coingeckoAPIURI: string; + allowedDelegators?: readonly string[]; forceNativeERC20Query: ( chainId: string, chainGetter: ChainGetter, @@ -50,7 +52,8 @@ export const EthereumQueries = { chainId, chainGetter, options.coingeckoAPIBaseURL, - options.coingeckoAPIURI + options.coingeckoAPIURI, + options.allowedDelegators ?? [] ), }; }; @@ -66,6 +69,7 @@ export class EthereumQueriesImpl { public readonly queryEthereumCoingeckoTokenInfo: DeepReadonly; public readonly queryEthereumGasPrice: DeepReadonly; public readonly queryEthereumTxReceipt: DeepReadonly; + public readonly querySmartAccountDelegationStatus: DeepReadonly; constructor( base: QueriesSetBase, @@ -79,7 +83,8 @@ export class EthereumQueriesImpl { protected chainId: string, protected chainGetter: ChainGetter, protected coingeckoAPIBaseURL: string, - protected coingeckoAPIURI: string + protected coingeckoAPIURI: string, + protected allowedDelegators: readonly string[] ) { base.queryBalances.addBalanceRegistry( new ObservableQueryEthereumERC20BalanceRegistry(sharedContext) @@ -145,5 +150,13 @@ export class EthereumQueriesImpl { chainId, chainGetter ); + + this.querySmartAccountDelegationStatus = + new ObservableQuerySmartAccountDelegationStatus( + sharedContext, + chainId, + chainGetter, + allowedDelegators + ); } } diff --git a/packages/stores-eth/src/serialize.spec.ts b/packages/stores-eth/src/serialize.spec.ts new file mode 100644 index 0000000000..29a7b55992 --- /dev/null +++ b/packages/stores-eth/src/serialize.spec.ts @@ -0,0 +1,175 @@ +import { serializeEVMTransaction } from "./serialize"; +import { UnsignedEVMTransaction } from "./types"; + +// Test vectors adapted from viem's official transaction serialization tests: +// https://github.com/wevm/viem/blob/main/src/utils/transaction/serializeTransaction.test.ts + +const SIGNATURE = { + r: `0x${"60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe"}`, + s: `0x${"60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe"}`, + v: 27, +}; + +const SIGNATURE_BYTES = Uint8Array.from([ + ...Buffer.from( + "60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe", + "hex" + ), + ...Buffer.from( + "60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe", + "hex" + ), + 0x1b, +]); + +describe("serializeEVMTransaction", () => { + it("documents chainId handling for legacy transactions", () => { + const baseTx: UnsignedEVMTransaction = { + nonce: 0, + gasPrice: "2000000000", + to: "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + value: "1000000000000000000", + data: "0x", + }; + + expect(serializeEVMTransaction(baseTx)).toBe( + "0xe6808477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080" + ); + expect(() => + serializeEVMTransaction({ + ...baseTx, + chainId: 0, + }) + ).toThrow('Chain ID "0" is invalid.'); + expect( + serializeEVMTransaction({ + ...baseTx, + chainId: 1, + }) + ).toBe( + "0xe9808477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080018080" + ); + }); + + it("documents chainId handling for EIP-1559 transactions", () => { + const baseTx: UnsignedEVMTransaction = { + type: 2, + nonce: 0, + maxFeePerGas: "2000000000", + maxPriorityFeePerGas: "2000000000", + to: "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + value: "1000000000000000000", + data: "0x", + }; + + expect(() => serializeEVMTransaction(baseTx)).toThrow( + "Typed EVM transactions require chainId" + ); + expect(() => + serializeEVMTransaction({ + ...baseTx, + chainId: 0, + }) + ).toThrow('Chain ID "0" is invalid.'); + expect( + serializeEVMTransaction({ + ...baseTx, + chainId: 1, + }) + ).toBe( + "0x02ed018084773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0" + ); + }); + + it("serializes legacy transactions using the viem legacy vector", () => { + const tx: UnsignedEVMTransaction = { + chainId: 69, + nonce: 785, + gasPrice: "2000000000", + to: "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + value: "1000000000000000000", + data: "0x", + }; + + expect(serializeEVMTransaction(tx)).toBe( + "0xeb8203118477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080458080" + ); + }); + + it("serializes EIP-1559 transactions using the viem access-list vector", () => { + const tx: UnsignedEVMTransaction = { + type: 2, + chainId: 1, + nonce: 785, + maxFeePerGas: "2000000000", + maxPriorityFeePerGas: "2000000000", + to: "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + value: "1000000000000000000", + data: "0x", + accessList: [ + { + address: "0x0000000000000000000000000000000000000000", + storageKeys: [ + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe", + ], + }, + ], + }; + + expect(serializeEVMTransaction(tx)).toBe( + "0x02f88b0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080f85bf859940000000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000001a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe" + ); + }); + + it("accepts 65-byte signatures with legacy-style v values", () => { + const tx: UnsignedEVMTransaction = { + type: 2, + chainId: 1, + nonce: 785, + maxFeePerGas: "2000000000", + maxPriorityFeePerGas: "2000000000", + to: "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + value: "1000000000000000000", + data: "0x", + }; + + expect(serializeEVMTransaction(tx, SIGNATURE_BYTES)).toBe( + "0x02f8720182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c080a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe" + ); + expect(serializeEVMTransaction(tx, SIGNATURE)).toBe( + "0x02f8720182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c080a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe" + ); + }); + + it("documents the current mismatch against viem's EIP-2930 vector", () => { + const tx: UnsignedEVMTransaction = { + type: 1, + chainId: 1, + nonce: 785, + gasPrice: "2000000000", + to: "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + value: "1000000000000000000", + data: "0x", + accessList: [ + { + address: "0x1234512345123451234512345123451234512345", + storageKeys: [ + "0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe", + ], + }, + ], + }; + + const viemExpected = + "0x01f863018203118477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080f838f7941234512345123451234512345123451234512345e1a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe"; + + expect(viemExpected).toBe( + "0x01f863018203118477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080f838f7941234512345123451234512345123451234512345e1a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe" + ); + expect(serializeEVMTransaction(tx)).toBe( + "0xeb8203118477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080018080" + ); + expect(serializeEVMTransaction(tx)).not.toBe(viemExpected); + }); +}); diff --git a/packages/stores-eth/src/serialize.ts b/packages/stores-eth/src/serialize.ts new file mode 100644 index 0000000000..62e42cc222 --- /dev/null +++ b/packages/stores-eth/src/serialize.ts @@ -0,0 +1,162 @@ +import { TxEnvelopeEip1559, TxEnvelopeEip7702, TxEnvelopeLegacy } from "ox"; +import { UnsignedEVMTransaction } from "./types"; + +/** + * Convert a string/number field to bigint. + * Handles hex strings ("0x..."), decimal strings, and numbers. + */ +function toBigInt(value: string | number | undefined): bigint | undefined { + if (value == null) { + return undefined; + } + return BigInt(value); +} + +/** + * Signature format used by the existing codebase. + * Accepts either {r, s, v} (r, s as hex strings, v as number) + * or raw bytes (Uint8Array/Buffer of 65 bytes: r[32] + s[32] + v[1]). + */ +export type EVMSignatureLike = + | { + r: string; + s: string; + v: number; + } + | Uint8Array; + +function parseSignature( + sig: EVMSignatureLike +): { r: bigint; s: bigint; yParity: number } | undefined { + if (sig instanceof Uint8Array || Buffer.isBuffer(sig)) { + if (sig.length !== 65) { + throw new Error( + `Invalid signature length: expected 65 bytes, got ${sig.length}` + ); + } + const r = BigInt("0x" + Buffer.from(sig.slice(0, 32)).toString("hex")); + const s = BigInt("0x" + Buffer.from(sig.slice(32, 64)).toString("hex")); + const v = sig[64]; + // v can be 0/1 or 27/28 + const yParity = v >= 27 ? v - 27 : v; + return { r, s, yParity }; + } + + const rHex = sig.r.startsWith("0x") ? sig.r : `0x${sig.r}`; + const sHex = sig.s.startsWith("0x") ? sig.s : `0x${sig.s}`; + const v = sig.v; + // v can be 0/1 or 27/28 + const yParity = v >= 27 ? v - 27 : v; + return { r: BigInt(rHex), s: BigInt(sHex), yParity }; +} + +/** + * Serialize a normalized EVM transaction (and optionally sign it) using ox. + * + * This replaces `serialize()` from `@ethersproject/transactions`. + * The output is identical RLP encoding with "0x" prefix for supported + * transaction types. + * + * Legacy transactions may omit `chainId`, but typed transactions must provide + * an explicit `chainId` so we don't silently serialize for the wrong network. + */ +export function serializeEVMTransaction( + tx: UnsignedEVMTransaction, + signature?: EVMSignatureLike +): string { + const sig = signature ? parseSignature(signature) : undefined; + + const isTypedTransaction = + tx.type != null || + tx.accessList != null || + tx.maxFeePerGas != null || + tx.maxPriorityFeePerGas != null || + tx.authorizationList != null; + + // Legacy transactions may omit chainId, but typed transactions should + // always be bound to an explicit network. We intentionally avoid + // defaulting to mainnet (1) to prevent silent mis-serialization. + if (isTypedTransaction && tx.chainId == null) { + throw new Error("Typed EVM transactions require chainId"); + } + + const isEIP7702 = + tx.type === 4 || + (tx.authorizationList != null && tx.authorizationList.length > 0); + + if (isEIP7702) { + const envelope: Parameters[0] = { + chainId: tx.chainId as number, + nonce: toBigInt(tx.nonce), + gas: toBigInt(tx.gasLimit), + maxFeePerGas: toBigInt(tx.maxFeePerGas), + maxPriorityFeePerGas: toBigInt(tx.maxPriorityFeePerGas), + to: tx.to as `0x${string}`, + value: toBigInt(tx.value), + data: tx.data as `0x${string}` | undefined, + accessList: tx.accessList as + | readonly { + address: `0x${string}`; + storageKeys: readonly `0x${string}`[]; + }[] + | undefined, + authorizationList: (tx.authorizationList ?? []).map((a) => ({ + address: a.address as `0x${string}`, + chainId: typeof a.chainId === "string" ? Number(a.chainId) : a.chainId, + nonce: toBigInt(a.nonce) ?? BigInt(0), + r: toBigInt(a.r) ?? BigInt(0), + s: toBigInt(a.s) ?? BigInt(0), + yParity: + typeof a.yParity === "string" ? Number(a.yParity) : a.yParity ?? 0, + })), + }; + + return TxEnvelopeEip7702.serialize( + envelope, + sig ? { signature: sig } : undefined + ); + } + + const isEIP1559 = + tx.type === 2 || tx.maxFeePerGas != null || tx.maxPriorityFeePerGas != null; + + if (isEIP1559) { + const envelope: Parameters[0] = { + chainId: tx.chainId as number, + nonce: toBigInt(tx.nonce), + gas: toBigInt(tx.gasLimit), + maxFeePerGas: toBigInt(tx.maxFeePerGas), + maxPriorityFeePerGas: toBigInt(tx.maxPriorityFeePerGas), + to: tx.to as `0x${string}` | undefined, + value: toBigInt(tx.value), + data: tx.data as `0x${string}` | undefined, + accessList: tx.accessList as + | readonly { + address: `0x${string}`; + storageKeys: readonly `0x${string}`[]; + }[] + | undefined, + }; + + return TxEnvelopeEip1559.serialize( + envelope, + sig ? { signature: sig } : undefined + ); + } + + // Legacy transaction + const envelope: Parameters[0] = { + chainId: tx.chainId, + nonce: toBigInt(tx.nonce), + gas: toBigInt(tx.gasLimit), + gasPrice: toBigInt(tx.gasPrice), + to: tx.to as `0x${string}` | undefined, + value: toBigInt(tx.value), + data: tx.data as `0x${string}` | undefined, + }; + + return TxEnvelopeLegacy.serialize( + envelope, + sig ? { signature: sig } : undefined + ); +} diff --git a/packages/stores-eth/src/types.ts b/packages/stores-eth/src/types.ts index b5b0f2fdfc..240f5c5848 100644 --- a/packages/stores-eth/src/types.ts +++ b/packages/stores-eth/src/types.ts @@ -1,7 +1,27 @@ -import { UnsignedTransaction } from "@ethersproject/transactions"; import { EvmGasSimulationOutcome } from "@keplr-wallet/types"; -export type UnsignedEVMTransaction = UnsignedTransaction; +export type UnsignedEVMTransaction = { + to?: string; + from?: string; + nonce?: number; + gasLimit?: string | number; + gasPrice?: string | number; + data?: string; + value?: string | number; + chainId?: number; + type?: number | null; + accessList?: Array<{ address: string; storageKeys: Array }>; + maxPriorityFeePerGas?: string | number; + maxFeePerGas?: string | number; + authorizationList?: Array<{ + address: string; + chainId: number | string; + nonce: string | number; + r?: string; + s?: string; + yParity?: number | string; + }>; +}; export type UnsignedEVMTransactionWithErc20Approvals = UnsignedEVMTransaction & { diff --git a/packages/stores-starknet/package.json b/packages/stores-starknet/package.json index 6d2e254257..1032895d3a 100644 --- a/packages/stores-starknet/package.json +++ b/packages/stores-starknet/package.json @@ -21,11 +21,6 @@ "typecheck": "npx tsc -p tsconfig.check.json" }, "dependencies": { - "@ethersproject/abi": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/units": "^5.7.0", "@keplr-wallet/common": "0.13.19", "@keplr-wallet/simple-fetch": "0.13.19", "@keplr-wallet/stores": "0.13.19", diff --git a/packages/stores/src/account/store.ts b/packages/stores/src/account/store.ts index 361a46b658..0b8f1249e5 100644 --- a/packages/stores/src/account/store.ts +++ b/packages/stores/src/account/store.ts @@ -65,7 +65,7 @@ export class AccountStore< return mergeStores( accountSetBase, [this.chainGetter, chainId], - ...this.accountSetCreators + this.accountSetCreators ); }); diff --git a/packages/stores/src/common/merge.spec.ts b/packages/stores/src/common/merge.spec.ts index c2336f9146..380b837070 100644 --- a/packages/stores/src/common/merge.spec.ts +++ b/packages/stores/src/common/merge.spec.ts @@ -23,21 +23,23 @@ describe("Test merge stores function", () => { base: true, }, [3, "test"], - (base, n) => { - return { - test1: base.base ? n : 0, - }; - }, - (base) => { - return { - test2: base.test1 === 3 ? 4 : 0, - }; - }, - (_base, _n, str) => { - return { - test3: str, - }; - } + [ + (base, n) => { + return { + test1: base.base ? n : 0, + }; + }, + (base) => { + return { + test2: base.test1 === 3 ? 4 : 0, + }; + }, + (_base, _n, str) => { + return { + test3: str, + }; + }, + ] ); expect(result.test1).toBe(3); diff --git a/packages/stores/src/common/merge.ts b/packages/stores/src/common/merge.ts index 6752a14d2d..8ef9687cc0 100644 --- a/packages/stores/src/common/merge.ts +++ b/packages/stores/src/common/merge.ts @@ -71,7 +71,7 @@ export const mergeStores = < >( baseStore: Base, parameters: Params, - ...fns: ChainedFunctionifyTuple + fns: ChainedFunctionifyTuple ): Return => { for (let i = 0; i < fns.length; i++) { const fn = fns[i] as Functionify; diff --git a/packages/stores/src/query/queries.ts b/packages/stores/src/query/queries.ts index 1a2ce707cc..e581438a82 100644 --- a/packages/stores/src/query/queries.ts +++ b/packages/stores/src/query/queries.ts @@ -94,7 +94,7 @@ export class QueriesStore> { const merged = mergeStores( queriesSetBase, [this.sharedContext, chainId, this.chainGetter], - ...this.queriesCreators + this.queriesCreators ); this.queriesMap.set(chainId, merged); diff --git a/packages/types/src/ethereum.ts b/packages/types/src/ethereum.ts index c8cc3e8905..24711f40cd 100644 --- a/packages/types/src/ethereum.ts +++ b/packages/types/src/ethereum.ts @@ -2,6 +2,7 @@ export enum EthSignType { MESSAGE = "message", TRANSACTION = "transaction", EIP712 = "eip-712", + EIP5792 = "eip-5792", } export interface EthTxLog { @@ -52,6 +53,73 @@ export interface EthereumSignResponse { signature: Uint8Array; } +export type DelegationStatus = "supported" | "ready" | "unsupported"; + +export type GetCapabilitiesResult = Record>; + +// ── EIP-5792: wallet_sendCalls ────────────────────────────── + +// dApp → Background: raw request +export type WalletSendCallsRequest = { + atomicRequired: boolean; + calls: EIP5792Call[]; + chainId: string; // hex + version: string; // "2.0.0" + from?: string; + capabilities?: Record; +}; + +export type EIP5792Call = { + to?: string; + data?: string; + value?: string; +}; + +// Background → Frontend: interaction data +export type InternalSendCallsRequest = { + batchId: string; + calls: EIP5792Call[]; + apiVersion: string; + nonce: number; + chainCapabilities: { atomic: { status: DelegationStatus } }; +}; + +// Frontend → Background: signing data +export type BatchStrategy = "single" | "atomic" | "unavailable"; + +export interface BatchSigningData { + strategy: BatchStrategy; + batchId: string; + unsignedTxs: Record[]; +} + +// signEthereumBatch response +export interface EthereumBatchSignResponse { + strategy: BatchStrategy; + batchId: string; + signedTxs: string[]; +} + +// wallet_getCallsStatus response +export enum BatchCallStatusCode { + Pending = 100, + Confirmed = 200, + OffchainFailed = 400, + ChainRulesFailed = 500, + PartialFailed = 600, +} + +export type WalletGetCallStatusResponse = { + version: string; + chainId: string; + id: string; + status: BatchCallStatusCode; + atomic: boolean; + receipts: EthTxReceipt[]; +}; + +// ── EVM Gas Simulation ────────────────────────────────────── + export enum EvmGasSimulationOutcome { TX_SIMULATED = "tx-simulated", TX_BUNDLE_SIMULATED = "tx-bundle-simulated", diff --git a/packages/unit/.eslintrc.json b/packages/unit/.eslintrc.json index 2788a227ef..8f56043e04 100644 --- a/packages/unit/.eslintrc.json +++ b/packages/unit/.eslintrc.json @@ -6,5 +6,13 @@ "patterns": ["src/*", "@keplr-wallet/unit", "@keplr-wallet/unit/*"] } ] - } + }, + "overrides": [ + { + "files": ["**/*.spec.ts", "**/*.spec.js"], + "rules": { + "@typescript-eslint/no-loss-of-precision": "off" + } + } + ] } diff --git a/scripts/post-install.mjs b/scripts/post-install.mjs index 3a051e6d3c..39c512e2ca 100644 --- a/scripts/post-install.mjs +++ b/scripts/post-install.mjs @@ -31,10 +31,99 @@ import path from "path"; await fs.writeFile(p, "// @ts-nocheck\n" + data); } } + // miscreant 패키지의 .ts 소스에서 TS 5.7+ TypedArray 제네릭 변경으로 인한 타입 에러 수정 + await patchMiscreant(); } catch (e) { console.log(e); process.exit(1); } })(); +async function patchMiscreant() { + const findNodeModulesFile = (relativePath) => { + const maxDepth = 6; + let currentDir = __dirname; + for (let i = 0; i < maxDepth; i++) { + const filePath = path.join(currentDir, "node_modules", relativePath); + if (fs.existsSync(filePath)) { + return filePath; + } + currentDir = path.join(currentDir, ".."); + } + return null; + }; + + const replaceOrThrow = async ({ filePath, from, to, description }) => { + let data = await fs.readFile(filePath, "utf8"); + + if (data.includes(to)) { + return; + } + + if (!data.includes(from)) { + throw new Error( + `Failed to patch miscreant (${description}): expected source snippet was not found in ${filePath}` + ); + } + + data = data.replace(from, to); + await fs.writeFile(filePath, data); + }; + + // 1) polyfill/aes.ts: writeUint32BE의 out 파라미터에 명시적 Uint8Array 타입 추가 + const polyfillAes = findNodeModulesFile( + "miscreant/src/providers/polyfill/aes.ts" + ); + if (polyfillAes) { + const oldSig = + "function writeUint32BE(value: number, out = new Uint8Array(4), offset = 0): Uint8Array {"; + const newSig = + "function writeUint32BE(value: number, out: Uint8Array = new Uint8Array(4), offset = 0): Uint8Array {"; + await replaceOrThrow({ + filePath: polyfillAes, + from: oldSig, + to: newSig, + description: "polyfill/aes.ts writeUint32BE signature", + }); + } + + // 2) webcrypto/aes.ts: importKey와 encrypt 호출에서 Uint8Array를 BufferSource로 캐스트 + const webcryptoAes = findNodeModulesFile( + "miscreant/src/providers/webcrypto/aes.ts" + ); + if (webcryptoAes) { + await replaceOrThrow({ + filePath: webcryptoAes, + from: 'const key = await crypto.subtle.importKey("raw", keyData, "AES-CBC", false, ["encrypt"]);', + to: 'const key = await crypto.subtle.importKey("raw", keyData as unknown as BufferSource, "AES-CBC", false, ["encrypt"]);', + description: "webcrypto/aes.ts importKey BufferSource cast", + }); + await replaceOrThrow({ + filePath: webcryptoAes, + from: "const ctBlock = await this._crypto.subtle.encrypt(params, this._key, block.data);", + to: "const ctBlock = await this._crypto.subtle.encrypt(params, this._key, block.data as unknown as BufferSource);", + description: "webcrypto/aes.ts encrypt BufferSource cast", + }); + } + + // 3) webcrypto/aes_ctr.ts: importKey와 encrypt 호출에서 동일 수정 + const webcryptoAesCtr = findNodeModulesFile( + "miscreant/src/providers/webcrypto/aes_ctr.ts" + ); + if (webcryptoAesCtr) { + await replaceOrThrow({ + filePath: webcryptoAesCtr, + from: 'const key = await crypto.subtle.importKey("raw", keyData, "AES-CTR", false, ["encrypt"]);', + to: 'const key = await crypto.subtle.importKey("raw", keyData as unknown as BufferSource, "AES-CTR", false, ["encrypt"]);', + description: "webcrypto/aes_ctr.ts importKey BufferSource cast", + }); + await replaceOrThrow({ + filePath: webcryptoAesCtr, + from: 'const ciphertext = await this.crypto.subtle.encrypt(\n { name: "AES-CTR", counter: iv, length: 16 },\n this.key,\n plaintext,\n );', + to: 'const ciphertext = await this.crypto.subtle.encrypt(\n { name: "AES-CTR", counter: iv as unknown as BufferSource, length: 16 },\n this.key,\n plaintext as unknown as BufferSource,\n );', + description: "webcrypto/aes_ctr.ts encrypt BufferSource cast", + }); + } +} + /* eslint-enable import/no-extraneous-dependencies, @typescript-eslint/no-var-requires */ diff --git a/yarn.lock b/yarn.lock index 6ec5cd768e..dff689ae91 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,24 +5,6 @@ __metadata: version: 6 cacheKey: 8 -"@1stg/remark-preset@npm:^2.0.0": - version: 2.0.0 - resolution: "@1stg/remark-preset@npm:2.0.0" - dependencies: - remark-frontmatter: ^4.0.1 - remark-gfm: ^3.0.1 - remark-lint: ^9.1.1 - remark-lint-no-duplicate-headings: ^3.1.1 - remark-lint-no-duplicate-headings-in-section: ^3.1.1 - remark-preset-lint-consistent: ^5.1.1 - remark-preset-lint-markdown-style-guide: ^5.1.2 - remark-preset-lint-recommended: ^6.1.2 - remark-preset-prettier: ^2.0.1 - remark-validate-links: ^12.1.0 - checksum: 0de9d6dc5a197ab77ee7716506fe5227b57550be7ae4d9e173f783cd3424a48395a7eb6ec77465439ede2ea2a2b5f78cc0e6c51a5e3a068e2da958df2f574b80 - languageName: node - linkType: hard - "@adobe/css-tools@npm:^4.4.0": version: 4.4.4 resolution: "@adobe/css-tools@npm:4.4.4" @@ -30,6 +12,13 @@ __metadata: languageName: node linkType: hard +"@adraffy/ens-normalize@npm:^1.11.0": + version: 1.11.1 + resolution: "@adraffy/ens-normalize@npm:1.11.1" + checksum: e8b17fcc730ccc45a956e1fbb09edfe42be41c291079512082e9964f8ef4287e67913183cdd02fff71d2e215340d5b98a9bbbd9be32c5d36fad4ba2c1ec33ff2 + languageName: node + linkType: hard + "@amplitude/analytics-browser@npm:^1.10.3": version: 1.10.3 resolution: "@amplitude/analytics-browser@npm:1.10.3" @@ -175,7 +164,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.16.7, @babel/code-frame@npm:^7.18.6": +"@babel/code-frame@npm:^7.16.7, @babel/code-frame@npm:^7.18.6": version: 7.18.6 resolution: "@babel/code-frame@npm:7.18.6" dependencies: @@ -184,6 +173,17 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.21.4, @babel/code-frame@npm:^7.28.6, @babel/code-frame@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/code-frame@npm:7.29.0" + dependencies: + "@babel/helper-validator-identifier": ^7.28.5 + js-tokens: ^4.0.0 + picocolors: ^1.1.1 + checksum: 39f5b303757e4d63bbff8133e251094cd4f952b46e3fa9febc7368d907583911d6a1eded6090876dc1feeff5cf6e134fb19b706f8d58d26c5402cd50e5e1aeb2 + languageName: node + linkType: hard + "@babel/code-frame@npm:^7.22.5": version: 7.22.10 resolution: "@babel/code-frame@npm:7.22.10" @@ -214,17 +214,6 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.28.6, @babel/code-frame@npm:^7.29.0": - version: 7.29.0 - resolution: "@babel/code-frame@npm:7.29.0" - dependencies: - "@babel/helper-validator-identifier": ^7.28.5 - js-tokens: ^4.0.0 - picocolors: ^1.1.1 - checksum: 39f5b303757e4d63bbff8133e251094cd4f952b46e3fa9febc7368d907583911d6a1eded6090876dc1feeff5cf6e134fb19b706f8d58d26c5402cd50e5e1aeb2 - languageName: node - linkType: hard - "@babel/compat-data@npm:^7.13.11, @babel/compat-data@npm:^7.15.0": version: 7.15.0 resolution: "@babel/compat-data@npm:7.15.0" @@ -4785,20 +4774,45 @@ __metadata: languageName: node linkType: hard -"@eslint/eslintrc@npm:^1.4.1": - version: 1.4.1 - resolution: "@eslint/eslintrc@npm:1.4.1" +"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": + version: 4.9.1 + resolution: "@eslint-community/eslint-utils@npm:4.9.1" + dependencies: + eslint-visitor-keys: ^3.4.3 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: 0a27c2d676c4be6b329ebb5dd8f6c5ef5fae9a019ff575655306d72874bb26f3ab20e0b241a5f086464bb1f2511ca26a29ff6f80c1e2b0b02eca4686b4dfe1b5 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.6.1": + version: 4.12.2 + resolution: "@eslint-community/regexpp@npm:4.12.2" + checksum: 1770bc81f676a72f65c7200b5675ff7a349786521f30e66125faaf767fde1ba1c19c3790e16ba8508a62a3933afcfc806a893858b3b5906faf693d862b9e4120 + languageName: node + linkType: hard + +"@eslint/eslintrc@npm:^2.1.4": + version: 2.1.4 + resolution: "@eslint/eslintrc@npm:2.1.4" dependencies: ajv: ^6.12.4 debug: ^4.3.2 - espree: ^9.4.0 + espree: ^9.6.0 globals: ^13.19.0 ignore: ^5.2.0 import-fresh: ^3.2.1 js-yaml: ^4.1.0 minimatch: ^3.1.2 strip-json-comments: ^3.1.1 - checksum: cd3e5a8683db604739938b1c1c8b77927dc04fce3e28e0c88e7f2cd4900b89466baf83dfbad76b2b9e4d2746abdd00dd3f9da544d3e311633d8693f327d04cd7 + checksum: 10957c7592b20ca0089262d8c2a8accbad14b4f6507e35416c32ee6b4dbf9cad67dfb77096bbd405405e9ada2b107f3797fe94362e1c55e0b09d6e90dd149127 + languageName: node + linkType: hard + +"@eslint/js@npm:8.57.1": + version: 8.57.1 + resolution: "@eslint/js@npm:8.57.1" + checksum: 2afb77454c06e8316793d2e8e79a0154854d35e6782a1217da274ca60b5044d2c69d6091155234ed0551a1e408f86f09dd4ece02752c59568fa403e60611e880 languageName: node linkType: hard @@ -4842,23 +4856,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abi@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/abi@npm:5.6.0" - dependencies: - "@ethersproject/address": ^5.6.0 - "@ethersproject/bignumber": ^5.6.0 - "@ethersproject/bytes": ^5.6.0 - "@ethersproject/constants": ^5.6.0 - "@ethersproject/hash": ^5.6.0 - "@ethersproject/keccak256": ^5.6.0 - "@ethersproject/logger": ^5.6.0 - "@ethersproject/properties": ^5.6.0 - "@ethersproject/strings": ^5.6.0 - checksum: d0cf0450d21ff5beff5593ac4b1749eb64d67fdd7d0e2d489ab1996218ec7242b9dadcd7a9896687e84784c83bf3e39cba6e77b3e813165d6b400e584a96f2fc - languageName: node - linkType: hard - "@ethersproject/abi@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abi@npm:5.7.0" @@ -4876,21 +4873,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abstract-provider@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/abstract-provider@npm:5.6.0" - dependencies: - "@ethersproject/bignumber": ^5.6.0 - "@ethersproject/bytes": ^5.6.0 - "@ethersproject/logger": ^5.6.0 - "@ethersproject/networks": ^5.6.0 - "@ethersproject/properties": ^5.6.0 - "@ethersproject/transactions": ^5.6.0 - "@ethersproject/web": ^5.6.0 - checksum: 42ec4148217f7643f667f46235266100a1b31b8e87b6d540b6e8667703f56f633d25ec2e5d9b0f95556de0d0620189488e9d77dafc058c61e45872fef620ac5a - languageName: node - linkType: hard - "@ethersproject/abstract-provider@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abstract-provider@npm:5.7.0" @@ -4906,19 +4888,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abstract-signer@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/abstract-signer@npm:5.6.0" - dependencies: - "@ethersproject/abstract-provider": ^5.6.0 - "@ethersproject/bignumber": ^5.6.0 - "@ethersproject/bytes": ^5.6.0 - "@ethersproject/logger": ^5.6.0 - "@ethersproject/properties": ^5.6.0 - checksum: 91722f3ad449da1a26898132b53e0130deac19ab8dbef55c5fd3c6d2b9ddb0428f539021c9b7085f3fc5e8615bdf1fddcbe4f6c5365f6b6cfd5d3952816d27b7 - languageName: node - linkType: hard - "@ethersproject/abstract-signer@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abstract-signer@npm:5.7.0" @@ -4932,19 +4901,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/address@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/address@npm:5.6.0" - dependencies: - "@ethersproject/bignumber": ^5.6.0 - "@ethersproject/bytes": ^5.6.0 - "@ethersproject/keccak256": ^5.6.0 - "@ethersproject/logger": ^5.6.0 - "@ethersproject/rlp": ^5.6.0 - checksum: 504cddd422ec9890eda61da0421991ace7c5cd9f365cbc9761305013621915dc5ff5247f4b04699b7060fc272a7a8c9dc88f993bc6fa6e0f6e9e4fa30d6f3c0f - languageName: node - linkType: hard - "@ethersproject/address@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/address@npm:5.7.0" @@ -4958,15 +4914,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/base64@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/base64@npm:5.6.0" - dependencies: - "@ethersproject/bytes": ^5.6.0 - checksum: 5f316367acf18fdba82d50868171251f75218740a1c9bad8b11c6c3372c86ae323f91bc6727e78e527866357974d19fcced12f666fb067ffba2be638d54d36f7 - languageName: node - linkType: hard - "@ethersproject/base64@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/base64@npm:5.7.0" @@ -4976,27 +4923,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/basex@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/basex@npm:5.7.0" - dependencies: - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/properties": ^5.7.0 - checksum: 326087b7e1f3787b5fe6cd1cf2b4b5abfafbc355a45e88e22e5e9d6c845b613ffc5301d629b28d5c4d5e2bfe9ec424e6782c804956dff79be05f0098cb5817de - languageName: node - linkType: hard - -"@ethersproject/bignumber@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/bignumber@npm:5.6.0" - dependencies: - "@ethersproject/bytes": ^5.6.0 - "@ethersproject/logger": ^5.6.0 - bn.js: ^4.11.9 - checksum: cb1e0d712a1d991d7c74c66d34522413a2fd832e10bc15158b24e07f61e80a221689947936790334137c11c582f3f4d184d3ccf3036e09e4df1b2026923962b4 - languageName: node - linkType: hard - "@ethersproject/bignumber@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/bignumber@npm:5.7.0" @@ -5008,15 +4934,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/bytes@npm:^5.6.0": - version: 5.6.1 - resolution: "@ethersproject/bytes@npm:5.6.1" - dependencies: - "@ethersproject/logger": ^5.6.0 - checksum: d06ffe3bf12aa8a6588d99b82e40b46a2cbb8b057fc650aad836e3e8c95d4559773254eeeb8fed652066dcf8082e527e37cd2b9fff7ac8cabc4de7c49459a7eb - languageName: node - linkType: hard - "@ethersproject/bytes@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/bytes@npm:5.7.0" @@ -5026,15 +4943,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/constants@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/constants@npm:5.6.0" - dependencies: - "@ethersproject/bignumber": ^5.6.0 - checksum: da54458a0133b64c02052b86fefa6118ed88c449b02a61ba57745bf08029658214291935b0500461bde3f734ea98e6d8edc586eed9ce9fa7e6a16d9397716ff7 - languageName: node - linkType: hard - "@ethersproject/constants@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/constants@npm:5.7.0" @@ -5044,22 +4952,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/hash@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/hash@npm:5.6.0" - dependencies: - "@ethersproject/abstract-signer": ^5.6.0 - "@ethersproject/address": ^5.6.0 - "@ethersproject/bignumber": ^5.6.0 - "@ethersproject/bytes": ^5.6.0 - "@ethersproject/keccak256": ^5.6.0 - "@ethersproject/logger": ^5.6.0 - "@ethersproject/properties": ^5.6.0 - "@ethersproject/strings": ^5.6.0 - checksum: 7a3b9180963765fff1a307adeb2138219d1585fc979ee2d14888739102ae2b223759cf456a88da554b4043475ec459d3a8dd67a844e39a896f0584c5a9556a06 - languageName: node - linkType: hard - "@ethersproject/hash@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/hash@npm:5.7.0" @@ -5077,57 +4969,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/hdnode@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/hdnode@npm:5.7.0" - dependencies: - "@ethersproject/abstract-signer": ^5.7.0 - "@ethersproject/basex": ^5.7.0 - "@ethersproject/bignumber": ^5.7.0 - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/logger": ^5.7.0 - "@ethersproject/pbkdf2": ^5.7.0 - "@ethersproject/properties": ^5.7.0 - "@ethersproject/sha2": ^5.7.0 - "@ethersproject/signing-key": ^5.7.0 - "@ethersproject/strings": ^5.7.0 - "@ethersproject/transactions": ^5.7.0 - "@ethersproject/wordlists": ^5.7.0 - checksum: bfe5ca2d89a42de73655f853170ef4766b933c5f481cddad709b3aca18823275b096e572f92d1602a052f80b426edde44ad6b9d028799775a7dad4a5bbed2133 - languageName: node - linkType: hard - -"@ethersproject/json-wallets@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/json-wallets@npm:5.7.0" - dependencies: - "@ethersproject/abstract-signer": ^5.7.0 - "@ethersproject/address": ^5.7.0 - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/hdnode": ^5.7.0 - "@ethersproject/keccak256": ^5.7.0 - "@ethersproject/logger": ^5.7.0 - "@ethersproject/pbkdf2": ^5.7.0 - "@ethersproject/properties": ^5.7.0 - "@ethersproject/random": ^5.7.0 - "@ethersproject/strings": ^5.7.0 - "@ethersproject/transactions": ^5.7.0 - aes-js: 3.0.0 - scrypt-js: 3.0.1 - checksum: f583458d22db62efaaf94d38dd243482776a45bf90f9f3882fbad5aa0b8fd288b41eb7c1ff8ec0b99c9b751088e43d6173530db64dd33c59f9d8daa8d7ad5aa2 - languageName: node - linkType: hard - -"@ethersproject/keccak256@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/keccak256@npm:5.6.0" - dependencies: - "@ethersproject/bytes": ^5.6.0 - js-sha3: 0.8.0 - checksum: 8683ee5c665ae23c9e1a46be4efb9f208f256abc1885844ec653452ad6dd58d08e5df0d78fc01eef33dc10bca38e27a94390b71a86fae666ef7eddf49860e047 - languageName: node - linkType: hard - "@ethersproject/keccak256@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/keccak256@npm:5.7.0" @@ -5138,13 +4979,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/logger@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/logger@npm:5.6.0" - checksum: 6eee38a973c7a458552278971c109a3e5df3c257e433cb959da9a287ea04628d1f510d41b83bd5f9da5ddc05d97d307ed2162a9ba1b4fcc50664e4f60061636c - languageName: node - linkType: hard - "@ethersproject/logger@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/logger@npm:5.7.0" @@ -5152,15 +4986,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/networks@npm:^5.6.0": - version: 5.6.1 - resolution: "@ethersproject/networks@npm:5.6.1" - dependencies: - "@ethersproject/logger": ^5.6.0 - checksum: e894369e58b45563653155df6f6db9a919448fc077a74a8fcc3fa10423335250372243868bcc2cc08857f081af6320a3a62d322340d2e5364fb25c258c978b9e - languageName: node - linkType: hard - "@ethersproject/networks@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/networks@npm:5.7.0" @@ -5170,25 +4995,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/pbkdf2@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/pbkdf2@npm:5.7.0" - dependencies: - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/sha2": ^5.7.0 - checksum: b895adb9e35a8a127e794f7aadc31a2424ef355a70e51cde10d457e3e888bb8102373199a540cf61f2d6b9a32e47358f9c65b47d559f42bf8e596b5fd67901e9 - languageName: node - linkType: hard - -"@ethersproject/properties@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/properties@npm:5.6.0" - dependencies: - "@ethersproject/logger": ^5.6.0 - checksum: adcb6a843dcdf809262d77d6fbe52acdd48703327b298f78e698b76784e89564fb81791d27eaee72b1a6aaaf5688ea2ae7a95faabdef8b4aecc99989fec55901 - languageName: node - linkType: hard - "@ethersproject/properties@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/properties@npm:5.7.0" @@ -5198,54 +5004,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/providers@npm:^5.7.0": - version: 5.7.2 - resolution: "@ethersproject/providers@npm:5.7.2" - dependencies: - "@ethersproject/abstract-provider": ^5.7.0 - "@ethersproject/abstract-signer": ^5.7.0 - "@ethersproject/address": ^5.7.0 - "@ethersproject/base64": ^5.7.0 - "@ethersproject/basex": ^5.7.0 - "@ethersproject/bignumber": ^5.7.0 - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/constants": ^5.7.0 - "@ethersproject/hash": ^5.7.0 - "@ethersproject/logger": ^5.7.0 - "@ethersproject/networks": ^5.7.0 - "@ethersproject/properties": ^5.7.0 - "@ethersproject/random": ^5.7.0 - "@ethersproject/rlp": ^5.7.0 - "@ethersproject/sha2": ^5.7.0 - "@ethersproject/strings": ^5.7.0 - "@ethersproject/transactions": ^5.7.0 - "@ethersproject/web": ^5.7.0 - bech32: 1.1.4 - ws: 7.4.6 - checksum: 1754c731a5ca6782ae9677f4a9cd8b6246c4ef21a966c9a01b133750f3c578431ec43ec254e699969c4a0f87e84463ded50f96b415600aabd37d2056aee58c19 - languageName: node - linkType: hard - -"@ethersproject/random@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/random@npm:5.7.0" - dependencies: - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/logger": ^5.7.0 - checksum: 017829c91cff6c76470852855108115b0b52c611b6be817ed1948d56ba42d6677803ec2012aa5ae298a7660024156a64c11fcf544e235e239ab3f89f0fff7345 - languageName: node - linkType: hard - -"@ethersproject/rlp@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/rlp@npm:5.6.0" - dependencies: - "@ethersproject/bytes": ^5.6.0 - "@ethersproject/logger": ^5.6.0 - checksum: 3697871cec540e3bf3fd7a6a65ef3e5ca223f684ac928ecf028619eee251c6c5427b02493c152f057f5e9b07ea216d24f807ec84e5df80414511f8aff5505359 - languageName: node - linkType: hard - "@ethersproject/rlp@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/rlp@npm:5.7.0" @@ -5256,31 +5014,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/sha2@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/sha2@npm:5.7.0" - dependencies: - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/logger": ^5.7.0 - hash.js: 1.1.7 - checksum: 09321057c022effbff4cc2d9b9558228690b5dd916329d75c4b1ffe32ba3d24b480a367a7cc92d0f0c0b1c896814d03351ae4630e2f1f7160be2bcfbde435dbc - languageName: node - linkType: hard - -"@ethersproject/signing-key@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/signing-key@npm:5.6.0" - dependencies: - "@ethersproject/bytes": ^5.6.0 - "@ethersproject/logger": ^5.6.0 - "@ethersproject/properties": ^5.6.0 - bn.js: ^4.11.9 - elliptic: 6.5.4 - hash.js: 1.1.7 - checksum: c61118ff1ff89560da59cf77ca6553762e94b9d2757542be15dcf7eb4962327faede941d8461272afb8550cc2e28d38e7e89d199650ebae07a596df3c2059e08 - languageName: node - linkType: hard - "@ethersproject/signing-key@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/signing-key@npm:5.7.0" @@ -5295,17 +5028,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/strings@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/strings@npm:5.6.0" - dependencies: - "@ethersproject/bytes": ^5.6.0 - "@ethersproject/constants": ^5.6.0 - "@ethersproject/logger": ^5.6.0 - checksum: 0b69bdd2c2767049599e1b6bbf34782166a1b901fd00a09b2dab0f4a92a6a1e85bb28d498f40f138a68baf62714831b6398e170358c861b4b1e54bfac375b655 - languageName: node - linkType: hard - "@ethersproject/strings@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/strings@npm:5.7.0" @@ -5317,23 +5039,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/transactions@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/transactions@npm:5.6.0" - dependencies: - "@ethersproject/address": ^5.6.0 - "@ethersproject/bignumber": ^5.6.0 - "@ethersproject/bytes": ^5.6.0 - "@ethersproject/constants": ^5.6.0 - "@ethersproject/keccak256": ^5.6.0 - "@ethersproject/logger": ^5.6.0 - "@ethersproject/properties": ^5.6.0 - "@ethersproject/rlp": ^5.6.0 - "@ethersproject/signing-key": ^5.6.0 - checksum: b01a3a9ce1e2d945825adbecfc71b992293e0274b77caf2c0b3c45bb76919ce64aa888a5705e6745a84448c50fc4eb58ff5e0ad11c37b1aae33c7a7d3b8af883 - languageName: node - linkType: hard - "@ethersproject/transactions@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/transactions@npm:5.7.0" @@ -5351,53 +5056,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/units@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/units@npm:5.7.0" - dependencies: - "@ethersproject/bignumber": ^5.7.0 - "@ethersproject/constants": ^5.7.0 - "@ethersproject/logger": ^5.7.0 - checksum: 304714f848cd32e57df31bf545f7ad35c2a72adae957198b28cbc62166daa929322a07bff6e9c9ac4577ab6aa0de0546b065ed1b2d20b19e25748b7d475cb0fc - languageName: node - linkType: hard - -"@ethersproject/wallet@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/wallet@npm:5.7.0" - dependencies: - "@ethersproject/abstract-provider": ^5.7.0 - "@ethersproject/abstract-signer": ^5.7.0 - "@ethersproject/address": ^5.7.0 - "@ethersproject/bignumber": ^5.7.0 - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/hash": ^5.7.0 - "@ethersproject/hdnode": ^5.7.0 - "@ethersproject/json-wallets": ^5.7.0 - "@ethersproject/keccak256": ^5.7.0 - "@ethersproject/logger": ^5.7.0 - "@ethersproject/properties": ^5.7.0 - "@ethersproject/random": ^5.7.0 - "@ethersproject/signing-key": ^5.7.0 - "@ethersproject/transactions": ^5.7.0 - "@ethersproject/wordlists": ^5.7.0 - checksum: a4009bf7331eddab38e3015b5e9101ef92de7f705b00a6196b997db0e5635b6d83561674d46c90c6f77b87c0500fe4a6b0183ba13749efc22db59c99deb82fbd - languageName: node - linkType: hard - -"@ethersproject/web@npm:^5.6.0": - version: 5.6.0 - resolution: "@ethersproject/web@npm:5.6.0" - dependencies: - "@ethersproject/base64": ^5.6.0 - "@ethersproject/bytes": ^5.6.0 - "@ethersproject/logger": ^5.6.0 - "@ethersproject/properties": ^5.6.0 - "@ethersproject/strings": ^5.6.0 - checksum: 42b6e71658393e5abf8341c6bea0deb22cc744b4d22b3a979ed876bc772723b800c18e5180e223f77c47fb045828ef16ba5a01e8dd346474cf430533d1f053bc - languageName: node - linkType: hard - "@ethersproject/web@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/web@npm:5.7.0" @@ -5411,19 +5069,6 @@ __metadata: languageName: node linkType: hard -"@ethersproject/wordlists@npm:^5.7.0": - version: 5.7.0 - resolution: "@ethersproject/wordlists@npm:5.7.0" - dependencies: - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/hash": ^5.7.0 - "@ethersproject/logger": ^5.7.0 - "@ethersproject/properties": ^5.7.0 - "@ethersproject/strings": ^5.7.0 - checksum: 30eb6eb0731f9ef5faa44bf9c0c6e950bcaaef61e4d2d9ce0ae6d341f4e2d6d1f4ab4f8880bfce03b7aac4b862fb740e1421170cfbf8e2aafc359277d49e6e97 - languageName: node - linkType: hard - "@fal-works/esbuild-plugin-global-externals@npm:^2.1.2": version: 2.1.2 resolution: "@fal-works/esbuild-plugin-global-externals@npm:2.1.2" @@ -5625,14 +5270,14 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.11.8": - version: 0.11.8 - resolution: "@humanwhocodes/config-array@npm:0.11.8" +"@humanwhocodes/config-array@npm:^0.13.0": + version: 0.13.0 + resolution: "@humanwhocodes/config-array@npm:0.13.0" dependencies: - "@humanwhocodes/object-schema": ^1.2.1 - debug: ^4.1.1 + "@humanwhocodes/object-schema": ^2.0.3 + debug: ^4.3.1 minimatch: ^3.0.5 - checksum: 0fd6b3c54f1674ce0a224df09b9c2f9846d20b9e54fabae1281ecfc04f2e6ad69bf19e1d6af6a28f88e8aa3990168b6cb9e1ef755868c3256a630605ec2cb1d3 + checksum: eae69ff9134025dd2924f0b430eb324981494be26f0fddd267a33c28711c4db643242cf9fddf7dadb9d16c96b54b2d2c073e60a56477df86e0173149313bd5d6 languageName: node linkType: hard @@ -5643,10 +5288,10 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/object-schema@npm:^1.2.1": - version: 1.2.1 - resolution: "@humanwhocodes/object-schema@npm:1.2.1" - checksum: a824a1ec31591231e4bad5787641f59e9633827d0a2eaae131a288d33c9ef0290bd16fda8da6f7c0fcb014147865d12118df10db57f27f41e20da92369fcb3f1 +"@humanwhocodes/object-schema@npm:^2.0.3": + version: 2.0.3 + resolution: "@humanwhocodes/object-schema@npm:2.0.3" + checksum: d3b78f6c5831888c6ecc899df0d03bcc25d46f3ad26a11d7ea52944dc36a35ef543fad965322174238d677a43d5c694434f6607532cff7077062513ad7022631 languageName: node linkType: hard @@ -6512,10 +6157,6 @@ __metadata: dependencies: "@ethereumjs/common": ^2.6.5 "@ethereumjs/tx": ^3.5.2 - "@ethersproject/address": ^5.7.0 - "@ethersproject/hash": ^5.7.0 - "@ethersproject/transactions": ^5.7.0 - "@ethersproject/wallet": ^5.7.0 "@keplr-wallet/chain-validator": 0.13.19 "@keplr-wallet/common": 0.13.19 "@keplr-wallet/cosmos": 0.13.19 @@ -6525,6 +6166,7 @@ __metadata: "@keplr-wallet/proto-types": 0.13.19 "@keplr-wallet/router": 0.13.19 "@keplr-wallet/simple-fetch": 0.13.19 + "@keplr-wallet/stores-eth": 0.13.19 "@keplr-wallet/types": 0.13.19 "@keplr-wallet/unit": 0.13.19 "@ledgerhq/hw-app-eth": 6.42.8 @@ -6548,6 +6190,7 @@ __metadata: ledger-bitcoin: ^0.2.3 long: ^4.0.0 miscreant: 0.3.2 + ox: ^0.14.6 pbkdf2: ^3.1.2 utility-types: ^3.10.0 peerDependencies: @@ -6562,7 +6205,6 @@ __metadata: version: 0.0.0-use.local resolution: "@keplr-wallet/chain-validator@workspace:packages/chain-validator" dependencies: - "@ethersproject/abi": ^5.7.0 "@keplr-wallet/cosmos": 0.13.19 "@keplr-wallet/simple-fetch": 0.13.19 "@keplr-wallet/types": 0.13.19 @@ -6587,7 +6229,6 @@ __metadata: version: 0.0.0-use.local resolution: "@keplr-wallet/cosmos@workspace:packages/cosmos" dependencies: - "@ethersproject/address": ^5.6.0 "@keplr-wallet/common": 0.13.19 "@keplr-wallet/crypto": 0.13.19 "@keplr-wallet/proto-types": 0.13.19 @@ -6597,6 +6238,7 @@ __metadata: bech32: ^1.1.4 buffer: ^6.0.3 long: ^4.0.0 + ox: ^0.14.6 protobufjs: ^6.11.2 utility-types: ^3.10.0 languageName: unknown @@ -6647,8 +6289,6 @@ __metadata: "@babel/preset-env": ^7.24.5 "@babel/preset-react": ^7.24.1 "@babel/preset-typescript": ^7.24.1 - "@ethersproject/bignumber": ^5.7.0 - "@ethersproject/transactions": ^5.7.0 "@floating-ui/react": ^0.23.0 "@floating-ui/react-dom": ^1.3.0 "@keplr-wallet/analytics": 0.13.19 @@ -6726,7 +6366,7 @@ __metadata: css-loader: ^6.7.4 deepmerge: ^4.2.2 delay: ^4.4.0 - fork-ts-checker-webpack-plugin: ^7.2.13 + fork-ts-checker-webpack-plugin: ^9.1.0 html-webpack-plugin: ^5.5.0 https-browserify: ^1.0.0 identity-obj-proxy: ^3.0.0 @@ -6738,6 +6378,7 @@ __metadata: long: ^4.0.0 lottie-web: ^5.10.2 os-browserify: ^0.3.0 + ox: ^0.14.6 p-queue: ^6.6.2 process: ^0.11.10 qrcode.react: ^3.1.0 @@ -6764,7 +6405,7 @@ __metadata: styled-components: ^5.3.5 styled-normalize: ^8.0.7 swiper: ^8.4.4 - ts-loader: ^9.4.2 + ts-loader: ^9.5.4 utility-types: ^3.10.0 uuid: ^11.1.0 webextension-polyfill: ^0.12.0 @@ -6818,8 +6459,6 @@ __metadata: version: 0.0.0-use.local resolution: "@keplr-wallet/hooks-evm@workspace:packages/hooks-evm" dependencies: - "@ethersproject/address": ^5.7.0 - "@ethersproject/providers": ^5.7.0 "@keplr-wallet/common": 0.13.19 "@keplr-wallet/cosmos": 0.13.19 "@keplr-wallet/simple-fetch": 0.13.19 @@ -6828,6 +6467,7 @@ __metadata: "@keplr-wallet/types": 0.13.19 "@keplr-wallet/unit": 0.13.19 buffer: ^6.0.3 + ox: ^0.14.6 peerDependencies: mobx: ^6 mobx-utils: ^6 @@ -6857,8 +6497,6 @@ __metadata: version: 0.0.0-use.local resolution: "@keplr-wallet/hooks-starknet@workspace:packages/hooks-starknet" dependencies: - "@ethersproject/address": ^5.7.0 - "@ethersproject/providers": ^5.7.0 "@keplr-wallet/background": 0.13.19 "@keplr-wallet/common": 0.13.19 "@keplr-wallet/cosmos": 0.13.19 @@ -6886,8 +6524,6 @@ __metadata: version: 0.0.0-use.local resolution: "@keplr-wallet/hooks@workspace:packages/hooks" dependencies: - "@ethersproject/address": ^5.7.0 - "@ethersproject/providers": ^5.7.0 "@keplr-wallet/background": 0.13.19 "@keplr-wallet/common": 0.13.19 "@keplr-wallet/cosmos": 0.13.19 @@ -6901,6 +6537,7 @@ __metadata: "@keplr-wallet/unit": 0.13.19 buffer: ^6.0.3 long: ^4.0.0 + ox: ^0.14.6 utility-types: ^3.10.0 peerDependencies: mobx: ^6 @@ -7060,12 +6697,12 @@ __metadata: version: 0.0.0-use.local resolution: "@keplr-wallet/stores-etc@workspace:packages/stores-etc" dependencies: - "@ethersproject/abi": ^5.6.0 "@keplr-wallet/common": 0.13.19 "@keplr-wallet/simple-fetch": 0.13.19 "@keplr-wallet/stores": 0.13.19 "@keplr-wallet/types": 0.13.19 "@keplr-wallet/unit": 0.13.19 + ox: ^0.14.6 utility-types: ^3.10.0 peerDependencies: mobx: ^6 @@ -7077,12 +6714,6 @@ __metadata: version: 0.0.0-use.local resolution: "@keplr-wallet/stores-eth@workspace:packages/stores-eth" dependencies: - "@ethersproject/abi": ^5.7.0 - "@ethersproject/address": ^5.7.0 - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/strings": ^5.7.0 - "@ethersproject/transactions": ^5.7.0 - "@ethersproject/units": ^5.7.0 "@keplr-wallet/common": 0.13.19 "@keplr-wallet/simple-fetch": 0.13.19 "@keplr-wallet/stores": 0.13.19 @@ -7092,6 +6723,7 @@ __metadata: "@types/lodash.debounce": ^4 big-integer: ^1.6.48 lodash.debounce: ^4.0.8 + ox: ^0.14.6 utility-types: ^3.10.0 peerDependencies: mobx: ^6 @@ -7140,11 +6772,6 @@ __metadata: version: 0.0.0-use.local resolution: "@keplr-wallet/stores-starknet@workspace:packages/stores-starknet" dependencies: - "@ethersproject/abi": ^5.7.0 - "@ethersproject/address": ^5.7.0 - "@ethersproject/bytes": ^5.7.0 - "@ethersproject/transactions": ^5.7.0 - "@ethersproject/units": ^5.7.0 "@keplr-wallet/common": 0.13.19 "@keplr-wallet/simple-fetch": 0.13.19 "@keplr-wallet/stores": 0.13.19 @@ -7906,6 +7533,13 @@ __metadata: languageName: node linkType: hard +"@noble/ciphers@npm:^1.3.0": + version: 1.3.0 + resolution: "@noble/ciphers@npm:1.3.0" + checksum: 19722c35475df9bc78db60d261d0b5ef8a6d722561efc2135453f943eaa421b492195dc666e3e4df2b755bca3739e04f04b9c660198559f5dd05d3cfbf1b9e92 + languageName: node + linkType: hard + "@noble/curves@npm:1.0.0, @noble/curves@npm:~1.0.0": version: 1.0.0 resolution: "@noble/curves@npm:1.0.0" @@ -7924,6 +7558,15 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:1.9.1": + version: 1.9.1 + resolution: "@noble/curves@npm:1.9.1" + dependencies: + "@noble/hashes": 1.8.0 + checksum: 4f3483a1001538d2f55516cdcb19319d1eaef79550633f670e7d570b989cdbc0129952868b72bb67643329746b8ffefe8e4cd791c8cc35574e05a37f873eef42 + languageName: node + linkType: hard + "@noble/curves@npm:^1.7.0": version: 1.8.1 resolution: "@noble/curves@npm:1.8.1" @@ -7942,6 +7585,15 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:~1.9.0": + version: 1.9.7 + resolution: "@noble/curves@npm:1.9.7" + dependencies: + "@noble/hashes": 1.8.0 + checksum: 65acad44ac6944ab96471109087d6cfcbcaa251faad6295961be9a5ace220634f4b7c74a96d1ee2274ad3880ea953d8e8259893ed8c906c831ef29f5c04ec9cc + languageName: node + linkType: hard + "@noble/hashes@npm:1.0.0": version: 1.0.0 resolution: "@noble/hashes@npm:1.0.0" @@ -7977,6 +7629,13 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.8.0, @noble/hashes@npm:~1.8.0": + version: 1.8.0 + resolution: "@noble/hashes@npm:1.8.0" + checksum: c94e98b941963676feaba62475b1ccfa8341e3f572adbb3b684ee38b658df44100187fa0ef4220da580b13f8d27e87d5492623c8a02ecc61f23fb9960c7918f5 + languageName: node + linkType: hard + "@noble/hashes@npm:^1, @noble/hashes@npm:^1.0.0": version: 1.1.3 resolution: "@noble/hashes@npm:1.1.3" @@ -8135,18 +7794,19 @@ __metadata: languageName: node linkType: hard -"@npmcli/config@npm:^6.0.0": - version: 6.1.3 - resolution: "@npmcli/config@npm:6.1.3" +"@npmcli/config@npm:^8.0.0": + version: 8.3.4 + resolution: "@npmcli/config@npm:8.3.4" dependencies: "@npmcli/map-workspaces": ^3.0.2 - ini: ^3.0.0 - nopt: ^7.0.0 - proc-log: ^3.0.0 - read-package-json-fast: ^3.0.2 + "@npmcli/package-json": ^5.1.1 + ci-info: ^4.0.0 + ini: ^4.1.2 + nopt: ^7.2.1 + proc-log: ^4.2.0 semver: ^7.3.5 - walk-up-path: ^1.0.0 - checksum: 3ca1d1301354af50ecbfbfd1d5a34459b0b68f6364758a188cc65f04dd517e260d6c21f631fcc3840e8c25826ba5756e114166881ec4227d540919280e6cb0f4 + walk-up-path: ^3.0.1 + checksum: 9a8cc40fa577b37f85ef82f7cfe6a3b65be893cae0e00997f5f2a51ca89928ce56b3cf3cffc6cf8c74a615dd0102a230718ff937138caa3f4737dd34160f90b7 languageName: node linkType: hard @@ -8178,6 +7838,23 @@ __metadata: languageName: node linkType: hard +"@npmcli/git@npm:^5.0.0": + version: 5.0.8 + resolution: "@npmcli/git@npm:5.0.8" + dependencies: + "@npmcli/promise-spawn": ^7.0.0 + ini: ^4.1.3 + lru-cache: ^10.0.1 + npm-pick-manifest: ^9.0.0 + proc-log: ^4.0.0 + promise-inflight: ^1.0.1 + promise-retry: ^2.0.1 + semver: ^7.3.5 + which: ^4.0.0 + checksum: 8c1733b591e428719c60fceaca74b3355967f6ddbce851c0d163a3c2e8123aaa717361b8226f8f8e606685f14721ea97d8f99c4b5831bc9251007bb1a20663cd + languageName: node + linkType: hard + "@npmcli/git@npm:^6.0.0": version: 6.0.3 resolution: "@npmcli/git@npm:6.0.3" @@ -8331,6 +8008,21 @@ __metadata: languageName: node linkType: hard +"@npmcli/package-json@npm:^5.1.1": + version: 5.2.1 + resolution: "@npmcli/package-json@npm:5.2.1" + dependencies: + "@npmcli/git": ^5.0.0 + glob: ^10.2.2 + hosted-git-info: ^7.0.0 + json-parse-even-better-errors: ^3.0.0 + normalize-package-data: ^6.0.0 + proc-log: ^4.0.0 + semver: ^7.5.3 + checksum: f9f76428fb3b3350fe840f1fa49854d18ff1ecb82b426c9cf53a62a37389c357a89d64a07497f50b7fbf1c742f5a0cd349d8efdddef0bb6982497f8356c1f98a + languageName: node + linkType: hard + "@npmcli/package-json@npm:^7.0.0": version: 7.0.4 resolution: "@npmcli/package-json@npm:7.0.4" @@ -8346,6 +8038,15 @@ __metadata: languageName: node linkType: hard +"@npmcli/promise-spawn@npm:^7.0.0": + version: 7.0.2 + resolution: "@npmcli/promise-spawn@npm:7.0.2" + dependencies: + which: ^4.0.0 + checksum: 728256506ecbafb53064036e28c2815b9a9e9190ba7a48eec77b011a9f8a899515a6d96760dbde960bc1d3e5b828fd0b0b7fe3b512efaf049d299bacbd732fda + languageName: node + linkType: hard + "@npmcli/promise-spawn@npm:^8.0.0": version: 8.0.3 resolution: "@npmcli/promise-spawn@npm:8.0.3" @@ -8959,17 +8660,10 @@ __metadata: languageName: node linkType: hard -"@pkgr/utils@npm:^2.3.1": - version: 2.3.1 - resolution: "@pkgr/utils@npm:2.3.1" - dependencies: - cross-spawn: ^7.0.3 - is-glob: ^4.0.3 - open: ^8.4.0 - picocolors: ^1.0.0 - tiny-glob: ^0.2.9 - tslib: ^2.4.0 - checksum: 118a1971120253740121a1db0a6658c21195b7da962acf9c124b507a3df707cfc97b0b84a16edcbd4352853b182e8337da9fc6e8e3d06c60d75ae4fb42321c75 +"@pkgr/core@npm:^0.2.9": + version: 0.2.9 + resolution: "@pkgr/core@npm:0.2.9" + checksum: bb2fb86977d63f836f8f5b09015d74e6af6488f7a411dcd2bfdca79d76b5a681a9112f41c45bdf88a9069f049718efc6f3900d7f1de66a2ec966068308ae517f languageName: node linkType: hard @@ -9883,7 +9577,7 @@ __metadata: languageName: node linkType: hard -"@scure/base@npm:~1.2.1": +"@scure/base@npm:~1.2.1, @scure/base@npm:~1.2.5": version: 1.2.6 resolution: "@scure/base@npm:1.2.6" checksum: 1058cb26d5e4c1c46c9cc0ae0b67cc66d306733baf35d6ebdd8ddaba242b80c3807b726e3b48cb0411bb95ec10d37764969063ea62188f86ae9315df8ea6b325 @@ -9912,6 +9606,17 @@ __metadata: languageName: node linkType: hard +"@scure/bip32@npm:^1.7.0": + version: 1.7.0 + resolution: "@scure/bip32@npm:1.7.0" + dependencies: + "@noble/curves": ~1.9.0 + "@noble/hashes": ~1.8.0 + "@scure/base": ~1.2.5 + checksum: c83adca5a74ec5c4ded8ba93900d0065e4767c4759cf24c2674923aef01d45ba56f171574e3519f2341be99f53a333f01b674eb6cfeb6fa8379607c6d1bc90b5 + languageName: node + linkType: hard + "@scure/bip39@npm:1.2.0": version: 1.2.0 resolution: "@scure/bip39@npm:1.2.0" @@ -9932,6 +9637,16 @@ __metadata: languageName: node linkType: hard +"@scure/bip39@npm:^1.6.0": + version: 1.6.0 + resolution: "@scure/bip39@npm:1.6.0" + dependencies: + "@noble/hashes": ~1.8.0 + "@scure/base": ~1.2.5 + checksum: 96d46420780473d6c6c9700254a0eceec60302f61d7f9d7f29024e90c7acff3e8e40a5ee52dfaf104db539a10462e531996aaf9e69f082b8540b0a25870545fc + languageName: node + linkType: hard + "@scure/starknet@npm:1.1.0": version: 1.1.0 resolution: "@scure/starknet@npm:1.1.0" @@ -11854,15 +11569,6 @@ __metadata: languageName: node linkType: hard -"@types/acorn@npm:^4.0.0": - version: 4.0.6 - resolution: "@types/acorn@npm:4.0.6" - dependencies: - "@types/estree": "*" - checksum: 60e1fd28af18d6cb54a93a7231c7c18774a9a8739c9b179e9e8750dca631e10cbef2d82b02830ea3f557b1d121e6406441e9e1250bd492dc81d4b3456e76e4d4 - languageName: node - linkType: hard - "@types/aes-js@npm:^3.1.0": version: 3.1.1 resolution: "@types/aes-js@npm:3.1.1" @@ -12261,12 +11967,12 @@ __metadata: languageName: node linkType: hard -"@types/hast@npm:^2.0.0": - version: 2.3.4 - resolution: "@types/hast@npm:2.3.4" +"@types/hast@npm:^3.0.0": + version: 3.0.4 + resolution: "@types/hast@npm:3.0.4" dependencies: "@types/unist": "*" - checksum: fff47998f4c11e21a7454b58673f70478740ecdafd95aaf50b70a3daa7da9cdc57315545bf9c039613732c40b7b0e9e49d11d03fe9a4304721cdc3b29a88141e + checksum: 7a973e8d16fcdf3936090fa2280f408fb2b6a4f13b42edeb5fbd614efe042b82eac68e298e556d50f6b4ad585a3a93c353e9c826feccdc77af59de8dd400d044 languageName: node linkType: hard @@ -12405,12 +12111,12 @@ __metadata: languageName: node linkType: hard -"@types/mdast@npm:^3.0.0": - version: 3.0.10 - resolution: "@types/mdast@npm:3.0.10" +"@types/mdast@npm:^4.0.0": + version: 4.0.4 + resolution: "@types/mdast@npm:4.0.4" dependencies: "@types/unist": "*" - checksum: 3f587bfc0a9a2403ecadc220e61031b01734fedaf82e27eb4d5ba039c0eb54db8c85681ccc070ab4df3f7ec711b736a82b990e69caa14c74bf7ac0ccf2ac7313 + checksum: 20c4e9574cc409db662a35cba52b068b91eb696b3049e94321219d47d34c8ccc99a142be5c76c80a538b612457b03586bc2f6b727a3e9e7530f4c8568f6282ee languageName: node linkType: hard @@ -12504,13 +12210,22 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^18.0.0, @types/node@npm:^18.13.0": +"@types/node@npm:^18.0.0": version: 18.13.0 resolution: "@types/node@npm:18.13.0" checksum: 4ea10f8802848b01672bce938f678b6774ca2cee0c9774f12275ab064ae07818419c3e2e41d6257ce7ba846d1ea26c63214aa1dfa4166fa3746291752b8c6416 languageName: node linkType: hard +"@types/node@npm:^22.0.0": + version: 22.19.15 + resolution: "@types/node@npm:22.19.15" + dependencies: + undici-types: ~6.21.0 + checksum: 6e78cdb6cec95770432aceff75b349610b2a8c6e3b661fa6643afa199e49b2ada081546b74c79f3b1bd922fbf5e1b52f7714f6d9d8d275d2083578821328d33c + languageName: node + linkType: hard + "@types/normalize-package-data@npm:^2.4.0": version: 2.4.0 resolution: "@types/normalize-package-data@npm:2.4.0" @@ -12674,13 +12389,6 @@ __metadata: languageName: node linkType: hard -"@types/semver@npm:^7.3.12": - version: 7.3.13 - resolution: "@types/semver@npm:7.3.13" - checksum: 00c0724d54757c2f4bc60b5032fe91cda6410e48689633d5f35ece8a0a66445e3e57fa1d6e07eb780f792e82ac542948ec4d0b76eb3484297b79bd18b8cf1cb0 - languageName: node - linkType: hard - "@types/semver@npm:^7.3.4": version: 7.5.8 resolution: "@types/semver@npm:7.5.8" @@ -12743,13 +12451,20 @@ __metadata: languageName: node linkType: hard -"@types/unist@npm:*, @types/unist@npm:^2.0.0, @types/unist@npm:^2.0.2": +"@types/unist@npm:*, @types/unist@npm:^2.0.0": version: 2.0.6 resolution: "@types/unist@npm:2.0.6" checksum: 25cb860ff10dde48b54622d58b23e66214211a61c84c0f15f88d38b61aa1b53d4d46e42b557924a93178c501c166aa37e28d7f6d994aba13d24685326272d5db languageName: node linkType: hard +"@types/unist@npm:^3.0.0": + version: 3.0.3 + resolution: "@types/unist@npm:3.0.3" + checksum: 96e6453da9e075aaef1dc22482463898198acdc1eeb99b465e65e34303e2ec1e3b1ed4469a9118275ec284dc98019f63c3f5d49422f0e4ac707e5ab90fb3b71a + languageName: node + linkType: hard + "@types/uuid@npm:^9.0.1": version: 9.0.8 resolution: "@types/uuid@npm:9.0.8" @@ -12796,124 +12511,128 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/eslint-plugin@npm:5.52.0" +"@typescript-eslint/eslint-plugin@npm:^7.0.0": + version: 7.18.0 + resolution: "@typescript-eslint/eslint-plugin@npm:7.18.0" dependencies: - "@typescript-eslint/scope-manager": 5.52.0 - "@typescript-eslint/type-utils": 5.52.0 - "@typescript-eslint/utils": 5.52.0 - debug: ^4.3.4 - grapheme-splitter: ^1.0.4 - ignore: ^5.2.0 - natural-compare-lite: ^1.4.0 - regexpp: ^3.2.0 - semver: ^7.3.7 - tsutils: ^3.21.0 + "@eslint-community/regexpp": ^4.10.0 + "@typescript-eslint/scope-manager": 7.18.0 + "@typescript-eslint/type-utils": 7.18.0 + "@typescript-eslint/utils": 7.18.0 + "@typescript-eslint/visitor-keys": 7.18.0 + graphemer: ^1.4.0 + ignore: ^5.3.1 + natural-compare: ^1.4.0 + ts-api-utils: ^1.3.0 peerDependencies: - "@typescript-eslint/parser": ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + "@typescript-eslint/parser": ^7.0.0 + eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: cff07ee94d8ab2a1b6c33b5c5bf641eff2bf2bebc0f35a9d8b3f128fd610e27a4aaf620bc2ad23608ad161b1810b7e32e5a2e0f746cc5094c3f506f7a14daa34 + checksum: dfcf150628ca2d4ccdfc20b46b0eae075c2f16ef5e70d9d2f0d746acf4c69a09f962b93befee01a529f14bbeb3e817b5aba287d7dd0edc23396bc5ed1f448c3d languageName: node linkType: hard -"@typescript-eslint/parser@npm:^5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/parser@npm:5.52.0" +"@typescript-eslint/parser@npm:^7.0.0": + version: 7.18.0 + resolution: "@typescript-eslint/parser@npm:7.18.0" dependencies: - "@typescript-eslint/scope-manager": 5.52.0 - "@typescript-eslint/types": 5.52.0 - "@typescript-eslint/typescript-estree": 5.52.0 + "@typescript-eslint/scope-manager": 7.18.0 + "@typescript-eslint/types": 7.18.0 + "@typescript-eslint/typescript-estree": 7.18.0 + "@typescript-eslint/visitor-keys": 7.18.0 debug: ^4.3.4 peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 1d8ff6e932f9c9db8d24b16ce89fd963f0982c38559e500aa1f8dc5cd66abd02f1659dd1a1361ce550def05331803caa69a69a039b54c94fc0f22919a2305c12 + checksum: 132b56ac3b2d90b588d61d005a70f6af322860974225b60201cbf45abf7304d67b7d8a6f0ade1c188ac4e339884e78d6dcd450417f1481998f9ddd155bab0801 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/scope-manager@npm:5.52.0" +"@typescript-eslint/scope-manager@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/scope-manager@npm:7.18.0" dependencies: - "@typescript-eslint/types": 5.52.0 - "@typescript-eslint/visitor-keys": 5.52.0 - checksum: 9a03fe30f8e90a5106c482478f213eefdd09f2f74e24d9dc59b453885466a758fe6d1cd24d706aed6188fb03c84b16ca6491cf20da6b16b8fc53cad8b8c327f2 + "@typescript-eslint/types": 7.18.0 + "@typescript-eslint/visitor-keys": 7.18.0 + checksum: b982c6ac13d8c86bb3b949c6b4e465f3f60557c2ccf4cc229799827d462df56b9e4d3eaed7711d79b875422fc3d71ec1ebcb5195db72134d07c619e3c5506b57 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/type-utils@npm:5.52.0" +"@typescript-eslint/type-utils@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/type-utils@npm:7.18.0" dependencies: - "@typescript-eslint/typescript-estree": 5.52.0 - "@typescript-eslint/utils": 5.52.0 + "@typescript-eslint/typescript-estree": 7.18.0 + "@typescript-eslint/utils": 7.18.0 debug: ^4.3.4 - tsutils: ^3.21.0 + ts-api-utils: ^1.3.0 peerDependencies: - eslint: "*" + eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: ac5422040461febab8a2eeec76d969024ccff76203dec357f7220c9b5e0dde96e3e3a76fd4118d42b50bd5bfb3a194aaceeb63417a2ac4e1ebf5e687558a9a10 + checksum: 68fd5df5146c1a08cde20d59b4b919acab06a1b06194fe4f7ba1b928674880249890785fbbc97394142f2ef5cff5a7fba9b8a940449e7d5605306505348e38bc languageName: node linkType: hard -"@typescript-eslint/types@npm:5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/types@npm:5.52.0" - checksum: 018940d61aebf7cf3f7de1b9957446e2ea01f08fe950bef4788c716a3a88f7c42765fe7d80152b0d0428fcd4bd3ace2dfa8c459ba1c59d9a84e951642180f869 +"@typescript-eslint/types@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/types@npm:7.18.0" + checksum: 7df2750cd146a0acd2d843208d69f153b458e024bbe12aab9e441ad2c56f47de3ddfeb329c4d1ea0079e2577fea4b8c1c1ce15315a8d49044586b04fedfe7a4d languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/typescript-estree@npm:5.52.0" +"@typescript-eslint/typescript-estree@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/typescript-estree@npm:7.18.0" dependencies: - "@typescript-eslint/types": 5.52.0 - "@typescript-eslint/visitor-keys": 5.52.0 + "@typescript-eslint/types": 7.18.0 + "@typescript-eslint/visitor-keys": 7.18.0 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 - semver: ^7.3.7 - tsutils: ^3.21.0 + minimatch: ^9.0.4 + semver: ^7.6.0 + ts-api-utils: ^1.3.0 peerDependenciesMeta: typescript: optional: true - checksum: 67d396907fee3d6894e26411a5098a37f07e5d50343189e6361ff7db91c74a7ffe2abd630d11f14c2bda1f4af13edf52b80b11cbccb55b44079c7cec14c9e108 + checksum: c82d22ec9654973944f779eb4eb94c52f4a6eafaccce2f0231ff7757313f3a0d0256c3252f6dfe6d43f57171d09656478acb49a629a9d0c193fb959bc3f36116 languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/utils@npm:5.52.0" +"@typescript-eslint/utils@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/utils@npm:7.18.0" dependencies: - "@types/json-schema": ^7.0.9 - "@types/semver": ^7.3.12 - "@typescript-eslint/scope-manager": 5.52.0 - "@typescript-eslint/types": 5.52.0 - "@typescript-eslint/typescript-estree": 5.52.0 - eslint-scope: ^5.1.1 - eslint-utils: ^3.0.0 - semver: ^7.3.7 + "@eslint-community/eslint-utils": ^4.4.0 + "@typescript-eslint/scope-manager": 7.18.0 + "@typescript-eslint/types": 7.18.0 + "@typescript-eslint/typescript-estree": 7.18.0 peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 01906be5262ece36537e9d586e4d2d4791e05752a9354bcb42b1f5bf965f53daa13309c61c3dff5e201ea28c298e4e01cf0c93738afa0099fea0da3b1d8cb3a5 + eslint: ^8.56.0 + checksum: 751dbc816dab8454b7dc6b26a56671dbec08e3f4ef94c2661ce1c0fc48fa2d05a64e03efe24cba2c22d03ba943cd3c5c7a5e1b7b03bbb446728aec1c640bd767 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.52.0" +"@typescript-eslint/visitor-keys@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/visitor-keys@npm:7.18.0" dependencies: - "@typescript-eslint/types": 5.52.0 - eslint-visitor-keys: ^3.3.0 - checksum: 33b44f0cd35b7b47f34e89d52e47b8d8200f55af306b22db4de104d79f65907458ea022e548f50d966e32fea150432ac9c1ae65b3001b0ad2ac8a17c0211f370 + "@typescript-eslint/types": 7.18.0 + eslint-visitor-keys: ^3.4.3 + checksum: 6e806a7cdb424c5498ea187a5a11d0fef7e4602a631be413e7d521e5aec1ab46ba00c76cfb18020adaa0a8c9802354a163bfa0deb74baa7d555526c7517bb158 + languageName: node + linkType: hard + +"@ungap/structured-clone@npm:^1.2.0": + version: 1.3.0 + resolution: "@ungap/structured-clone@npm:1.3.0" + checksum: 64ed518f49c2b31f5b50f8570a1e37bde3b62f2460042c50f132430b2d869c4a6586f13aa33a58a4722715b8158c68cae2827389d6752ac54da2893c83e480fc languageName: node linkType: hard @@ -13643,6 +13362,21 @@ __metadata: languageName: node linkType: hard +"abitype@npm:^1.2.3": + version: 1.2.3 + resolution: "abitype@npm:1.2.3" + peerDependencies: + typescript: ">=5.0.4" + zod: ^3.22.0 || ^4.0.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + checksum: b5b5620f8e55a6dd7ae829630c0ded02b30f589f0f8f5ca931cdfcf6d7daa8154e30e3fe3593b3f6c4872a955ac55d447ccc2f801fd6a6aa698bdad966e3fe2e + languageName: node + linkType: hard + "accepts@npm:~1.3.5, accepts@npm:~1.3.8": version: 1.3.8 resolution: "accepts@npm:1.3.8" @@ -13720,7 +13454,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.0.0, acorn@npm:^8.8.0": +"acorn@npm:^8.0.0": version: 8.8.2 resolution: "acorn@npm:8.8.2" bin: @@ -13747,7 +13481,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.15.0": +"acorn@npm:^8.15.0, acorn@npm:^8.9.0": version: 8.16.0 resolution: "acorn@npm:8.16.0" bin: @@ -13779,13 +13513,6 @@ __metadata: languageName: node linkType: hard -"aes-js@npm:3.0.0": - version: 3.0.0 - resolution: "aes-js@npm:3.0.0" - checksum: 251e26d533cd1a915b44896b17d5ed68c24a02484cfdd2e74ec700a309267db96651ea4eb657bf20aac32a3baa61f6e34edf8e2fec2de440a655da9942d334b8 - languageName: node - linkType: hard - "aes-js@npm:^3.1.2": version: 3.1.2 resolution: "aes-js@npm:3.1.2" @@ -13871,7 +13598,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.10.0, ajv@npm:^6.12.3, ajv@npm:^6.12.4, ajv@npm:^6.12.5": +"ajv@npm:^6.12.3, ajv@npm:^6.12.4, ajv@npm:^6.12.5": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: @@ -14847,13 +14574,6 @@ __metadata: languageName: node linkType: hard -"bech32@npm:1.1.4, bech32@npm:^1.1.4": - version: 1.1.4 - resolution: "bech32@npm:1.1.4" - checksum: 0e98db619191548390d6f09ff68b0253ba7ae6a55db93dfdbb070ba234c1fd3308c0606fbcc95fad50437227b10011e2698b89f0181f6e7f845c499bd14d0f4b - languageName: node - linkType: hard - "bech32@npm:2.0.0, bech32@npm:^2.0.0": version: 2.0.0 resolution: "bech32@npm:2.0.0" @@ -14861,6 +14581,13 @@ __metadata: languageName: node linkType: hard +"bech32@npm:^1.1.4": + version: 1.1.4 + resolution: "bech32@npm:1.1.4" + checksum: 0e98db619191548390d6f09ff68b0253ba7ae6a55db93dfdbb070ba234c1fd3308c0606fbcc95fad50437227b10011e2698b89f0181f6e7f845c499bd14d0f4b + languageName: node + linkType: hard + "before-after-hook@npm:^2.2.0": version: 2.2.2 resolution: "before-after-hook@npm:2.2.2" @@ -15936,13 +15663,6 @@ __metadata: languageName: node linkType: hard -"character-entities-legacy@npm:^1.0.0": - version: 1.1.4 - resolution: "character-entities-legacy@npm:1.1.4" - checksum: fe03a82c154414da3a0c8ab3188e4237ec68006cbcd681cf23c7cfb9502a0e76cd30ab69a2e50857ca10d984d57de3b307680fff5328ccd427f400e559c3a811 - languageName: node - linkType: hard - "character-entities-legacy@npm:^3.0.0": version: 3.0.0 resolution: "character-entities-legacy@npm:3.0.0" @@ -15950,13 +15670,6 @@ __metadata: languageName: node linkType: hard -"character-entities@npm:^1.0.0": - version: 1.2.4 - resolution: "character-entities@npm:1.2.4" - checksum: e1545716571ead57beac008433c1ff69517cd8ca5b336889321c5b8ff4a99c29b65589a701e9c086cda8a5e346a67295e2684f6c7ea96819fe85cbf49bf8686d - languageName: node - linkType: hard - "character-entities@npm:^2.0.0": version: 2.0.2 resolution: "character-entities@npm:2.0.2" @@ -15964,13 +15677,6 @@ __metadata: languageName: node linkType: hard -"character-reference-invalid@npm:^1.0.0": - version: 1.1.4 - resolution: "character-reference-invalid@npm:1.1.4" - checksum: 20274574c70e05e2f81135f3b93285536bc8ff70f37f0809b0d17791a832838f1e49938382899ed4cb444e5bbd4314ca1415231344ba29f4222ce2ccf24fea0b - languageName: node - linkType: hard - "character-reference-invalid@npm:^2.0.0": version: 2.0.1 resolution: "character-reference-invalid@npm:2.0.1" @@ -16053,6 +15759,15 @@ __metadata: languageName: node linkType: hard +"chokidar@npm:^4.0.1": + version: 4.0.3 + resolution: "chokidar@npm:4.0.3" + dependencies: + readdirp: ^4.0.1 + checksum: a8765e452bbafd04f3f2fad79f04222dd65f43161488bb6014a41099e6ca18d166af613d59a90771908c1c823efa3f46ba36b86ac50b701c20c1b9908c5fe36e + languageName: node + linkType: hard + "chownr@npm:^1.1.1": version: 1.1.4 resolution: "chownr@npm:1.1.4" @@ -16979,6 +16694,23 @@ __metadata: languageName: node linkType: hard +"cosmiconfig@npm:^8.2.0": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" + dependencies: + import-fresh: ^3.3.0 + js-yaml: ^4.1.0 + parse-json: ^5.2.0 + path-type: ^4.0.0 + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: dc339ebea427898c9e03bf01b56ba7afbac07fc7d2a2d5a15d6e9c14de98275a9565da949375aee1809591c152c0a3877bb86dbeaf74d5bd5aaa79955ad9e7a0 + languageName: node + linkType: hard + "cosmjs-test@workspace:packages/cosmjs-test": version: 0.0.0-use.local resolution: "cosmjs-test@workspace:packages/cosmjs-test" @@ -17965,6 +17697,15 @@ __metadata: languageName: node linkType: hard +"devlop@npm:^1.0.0, devlop@npm:^1.1.0": + version: 1.1.0 + resolution: "devlop@npm:1.1.0" + dependencies: + dequal: ^2.0.0 + checksum: d2ff650bac0bb6ef08c48f3ba98640bb5fec5cce81e9957eb620408d1bab1204d382a45b785c6b3314dc867bb0684936b84c6867820da6db97cbb5d3c15dd185 + languageName: node + linkType: hard + "diff-sequences@npm:^29.4.3": version: 29.4.3 resolution: "diff-sequences@npm:29.4.3" @@ -18421,6 +18162,13 @@ __metadata: languageName: node linkType: hard +"emoji-regex@npm:^10.2.1": + version: 10.6.0 + resolution: "emoji-regex@npm:10.6.0" + checksum: 8785f6a7ec4559c931bd6640f748fe23791f5af4c743b131d458c5551b4aa7da2a9cd882518723cb3859e8b0b59b0cc08f2ce0f8e65c61a026eed71c2dc407d5 + languageName: node + linkType: hard + "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -19027,13 +18775,6 @@ __metadata: languageName: node linkType: hard -"escape-string-regexp@npm:^5.0.0": - version: 5.0.0 - resolution: "escape-string-regexp@npm:5.0.0" - checksum: 20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e - languageName: node - linkType: hard - "escodegen@npm:^1.11.0, escodegen@npm:^1.11.1": version: 1.14.3 resolution: "escodegen@npm:1.14.3" @@ -19112,27 +18853,29 @@ __metadata: languageName: node linkType: hard -"eslint-mdx@npm:^2.0.5": - version: 2.0.5 - resolution: "eslint-mdx@npm:2.0.5" +"eslint-mdx@npm:^3.7.0": + version: 3.7.0 + resolution: "eslint-mdx@npm:3.7.0" dependencies: - acorn: ^8.8.0 + acorn: ^8.15.0 acorn-jsx: ^5.3.2 - cosmiconfig: ^7.0.1 - espree: ^9.4.0 - estree-util-visit: ^1.2.0 - remark-mdx: ^2.1.3 - remark-parse: ^10.0.1 - remark-stringify: ^10.0.2 - synckit: ^0.8.4 - tslib: ^2.4.0 - unified: ^10.1.2 - unist-util-visit: ^4.1.1 - uvu: ^0.5.6 - vfile: ^5.3.4 + espree: ^9.6.1 || ^10.4.0 + estree-util-visit: ^2.0.0 + remark-mdx: ^3.1.0 + remark-parse: ^11.0.0 + remark-stringify: ^11.0.0 + synckit: ^0.11.8 + unified: ^11.0.5 + unified-engine: ^11.2.2 + unist-util-visit: ^5.0.0 + vfile: ^6.0.3 peerDependencies: eslint: ">=8.0.0" - checksum: f03009d2c19440e5687584d895ba9e0ababd501531ad539838a5b3d81b5aec2632321fa2cd748fe1041f1ce1d0955581b4fabe4cd7d0ff9a4b2582b7f5871de6 + remark-lint-file-extension: "*" + peerDependenciesMeta: + remark-lint-file-extension: + optional: true + checksum: 1ee345ca0cbc9ef3abeae01890565ea290aedc80757632bb2b378fd9888bc4eb7c800cadea792a42394152fba6dd548eb2b60126e3c6ff6f4d37f16459fb51c1 languageName: node linkType: hard @@ -19173,32 +18916,23 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-markdown@npm:^3.0.0": - version: 3.0.0 - resolution: "eslint-plugin-markdown@npm:3.0.0" - dependencies: - mdast-util-from-markdown: ^0.8.5 - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: ea9e8613cffcf7decbc2de0c900a83553ccdccfb6d90187e5d461a457a403d2634585a8c165cc4adf52c86f3b910161f33b1f24a46f296c4a577d2547780c997 - languageName: node - linkType: hard - -"eslint-plugin-mdx@npm:^2.0.5": - version: 2.0.5 - resolution: "eslint-plugin-mdx@npm:2.0.5" - dependencies: - eslint-mdx: ^2.0.5 - eslint-plugin-markdown: ^3.0.0 - remark-mdx: ^2.1.3 - remark-parse: ^10.0.1 - remark-stringify: ^10.0.2 - tslib: ^2.4.0 - unified: ^10.1.2 - vfile: ^5.3.4 +"eslint-plugin-mdx@npm:^3.7.0": + version: 3.7.0 + resolution: "eslint-plugin-mdx@npm:3.7.0" + dependencies: + eslint-mdx: ^3.7.0 + mdast-util-from-markdown: ^2.0.2 + mdast-util-mdx: ^3.0.0 + micromark-extension-mdxjs: ^3.0.0 + remark-mdx: ^3.1.0 + remark-parse: ^11.0.0 + remark-stringify: ^11.0.0 + synckit: ^0.11.8 + unified: ^11.0.5 + vfile: ^6.0.3 peerDependencies: eslint: ">=8.0.0" - checksum: dee06fbd3a3b1383b5cabdfeb006c9ce5ecc7c53ee8ef313757d1432db6a2e0599d80bde1125d83ec3c9e7d50b05be98ab620a43332b640149fd51230248971e + checksum: ea7127544a8b28482eda0bae917378e8690193153df50f0c2c538c0bd605d9e403e6b4f72caf5cbc70cece48f8a65884a25ef6951cb63d500011786b99d5e2d2 languageName: node linkType: hard @@ -19277,29 +19011,20 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-unused-imports@npm:^2.0.0": - version: 2.0.0 - resolution: "eslint-plugin-unused-imports@npm:2.0.0" - dependencies: - eslint-rule-composer: ^0.3.0 +"eslint-plugin-unused-imports@npm:^4.0.0": + version: 4.4.1 + resolution: "eslint-plugin-unused-imports@npm:4.4.1" peerDependencies: - "@typescript-eslint/eslint-plugin": ^5.0.0 - eslint: ^8.0.0 + "@typescript-eslint/eslint-plugin": ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0 + eslint: ^10.0.0 || ^9.0.0 || ^8.0.0 peerDependenciesMeta: "@typescript-eslint/eslint-plugin": optional: true - checksum: 8aa1e03e75da2a62a354065e0cb8fe370118c6f8d9720a32fe8c1da937de6adb81a4fed7d0d391d115ac9453b49029fb19f970d180a2cf3dba451fd4c20f0dc4 + checksum: b44557555462a0af1cd6b339fb3afdc30ad7e7ceb9a5b1f64737183b1b397acfd065e1f5838d0384dd239c8db84927feb0b289d0c4f453983065e215246fc6e6 languageName: node linkType: hard -"eslint-rule-composer@npm:^0.3.0": - version: 0.3.0 - resolution: "eslint-rule-composer@npm:0.3.0" - checksum: c2f57cded8d1c8f82483e0ce28861214347e24fd79fd4144667974cd334d718f4ba05080aaef2399e3bbe36f7d6632865110227e6b176ed6daa2d676df9281b1 - languageName: node - linkType: hard - -"eslint-scope@npm:5.1.1, eslint-scope@npm:^5.1.1": +"eslint-scope@npm:5.1.1": version: 5.1.1 resolution: "eslint-scope@npm:5.1.1" dependencies: @@ -19309,98 +19034,104 @@ __metadata: languageName: node linkType: hard -"eslint-scope@npm:^7.1.1": - version: 7.1.1 - resolution: "eslint-scope@npm:7.1.1" +"eslint-scope@npm:^7.2.2": + version: 7.2.2 + resolution: "eslint-scope@npm:7.2.2" dependencies: esrecurse: ^4.3.0 estraverse: ^5.2.0 - checksum: 9f6e974ab2db641ca8ab13508c405b7b859e72afe9f254e8131ff154d2f40c99ad4545ce326fd9fde3212ff29707102562a4834f1c48617b35d98c71a97fbf3e + checksum: ec97dbf5fb04b94e8f4c5a91a7f0a6dd3c55e46bfc7bbcd0e3138c3a76977570e02ed89a1810c778dcd72072ff0e9621ba1379b4babe53921d71e2e4486fda3e languageName: node linkType: hard -"eslint-utils@npm:^3.0.0": - version: 3.0.0 - resolution: "eslint-utils@npm:3.0.0" - dependencies: - eslint-visitor-keys: ^2.0.0 - peerDependencies: - eslint: ">=5" - checksum: 0668fe02f5adab2e5a367eee5089f4c39033af20499df88fe4e6aba2015c20720404d8c3d6349b6f716b08fdf91b9da4e5d5481f265049278099c4c836ccb619 +"eslint-visitor-keys@npm:^3.3.0": + version: 3.3.0 + resolution: "eslint-visitor-keys@npm:3.3.0" + checksum: d59e68a7c5a6d0146526b0eec16ce87fbf97fe46b8281e0d41384224375c4e52f5ffb9e16d48f4ea50785cde93f766b0c898e31ab89978d88b0e1720fbfb7808 languageName: node linkType: hard -"eslint-visitor-keys@npm:^2.0.0": - version: 2.0.0 - resolution: "eslint-visitor-keys@npm:2.0.0" - checksum: e07e9863fb8c9b1453f5ad1a26f3cc8dd6b349b26605cc06bc0c61215ac5b6f13a4d08c875218e6c0f8ac8fc06ca6e090df769e32c569f0fd2e6a848b8a76c75 +"eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": + version: 3.4.3 + resolution: "eslint-visitor-keys@npm:3.4.3" + checksum: 36e9ef87fca698b6fd7ca5ca35d7b2b6eeaaf106572e2f7fd31c12d3bfdaccdb587bba6d3621067e5aece31c8c3a348b93922ab8f7b2cbc6aaab5e1d89040c60 languageName: node linkType: hard -"eslint-visitor-keys@npm:^3.3.0": - version: 3.3.0 - resolution: "eslint-visitor-keys@npm:3.3.0" - checksum: d59e68a7c5a6d0146526b0eec16ce87fbf97fe46b8281e0d41384224375c4e52f5ffb9e16d48f4ea50785cde93f766b0c898e31ab89978d88b0e1720fbfb7808 +"eslint-visitor-keys@npm:^4.2.1": + version: 4.2.1 + resolution: "eslint-visitor-keys@npm:4.2.1" + checksum: 3a77e3f99a49109f6fb2c5b7784bc78f9743b834d238cdba4d66c602c6b52f19ed7bcd0a5c5dbbeae3a8689fd785e76c001799f53d2228b278282cf9f699fff5 languageName: node linkType: hard -"eslint@npm:^8.34.0": - version: 8.34.0 - resolution: "eslint@npm:8.34.0" +"eslint@npm:^8.56.0": + version: 8.57.1 + resolution: "eslint@npm:8.57.1" dependencies: - "@eslint/eslintrc": ^1.4.1 - "@humanwhocodes/config-array": ^0.11.8 + "@eslint-community/eslint-utils": ^4.2.0 + "@eslint-community/regexpp": ^4.6.1 + "@eslint/eslintrc": ^2.1.4 + "@eslint/js": 8.57.1 + "@humanwhocodes/config-array": ^0.13.0 "@humanwhocodes/module-importer": ^1.0.1 "@nodelib/fs.walk": ^1.2.8 - ajv: ^6.10.0 + "@ungap/structured-clone": ^1.2.0 + ajv: ^6.12.4 chalk: ^4.0.0 cross-spawn: ^7.0.2 debug: ^4.3.2 doctrine: ^3.0.0 escape-string-regexp: ^4.0.0 - eslint-scope: ^7.1.1 - eslint-utils: ^3.0.0 - eslint-visitor-keys: ^3.3.0 - espree: ^9.4.0 - esquery: ^1.4.0 + eslint-scope: ^7.2.2 + eslint-visitor-keys: ^3.4.3 + espree: ^9.6.1 + esquery: ^1.4.2 esutils: ^2.0.2 fast-deep-equal: ^3.1.3 file-entry-cache: ^6.0.1 find-up: ^5.0.0 glob-parent: ^6.0.2 globals: ^13.19.0 - grapheme-splitter: ^1.0.4 + graphemer: ^1.4.0 ignore: ^5.2.0 - import-fresh: ^3.0.0 imurmurhash: ^0.1.4 is-glob: ^4.0.0 is-path-inside: ^3.0.3 - js-sdsl: ^4.1.4 js-yaml: ^4.1.0 json-stable-stringify-without-jsonify: ^1.0.1 levn: ^0.4.1 lodash.merge: ^4.6.2 minimatch: ^3.1.2 natural-compare: ^1.4.0 - optionator: ^0.9.1 - regexpp: ^3.2.0 + optionator: ^0.9.3 strip-ansi: ^6.0.1 - strip-json-comments: ^3.1.0 text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: 4e13e9eb05ac2248efbb6acae0b2325091235d5c47ba91a4775c7d6760778cbcd358a773ebd42f4629d2ad89e27c02f5d66eb1f737d75d9f5fc411454f83b2e5 + checksum: e2489bb7f86dd2011967759a09164e65744ef7688c310bc990612fc26953f34cc391872807486b15c06833bdff737726a23e9b4cdba5de144c311377dc41d91b languageName: node linkType: hard -"espree@npm:^9.4.0": - version: 9.4.1 - resolution: "espree@npm:9.4.1" +"espree@npm:^9.6.0, espree@npm:^9.6.1": + version: 9.6.1 + resolution: "espree@npm:9.6.1" dependencies: - acorn: ^8.8.0 + acorn: ^8.9.0 acorn-jsx: ^5.3.2 - eslint-visitor-keys: ^3.3.0 - checksum: 4d266b0cf81c7dfe69e542c7df0f246e78d29f5b04dda36e514eb4c7af117ee6cfbd3280e560571ed82ff6c9c3f0003c05b82583fc7a94006db7497c4fe4270e + eslint-visitor-keys: ^3.4.1 + checksum: eb8c149c7a2a77b3f33a5af80c10875c3abd65450f60b8af6db1bfcfa8f101e21c1e56a561c6dc13b848e18148d43469e7cd208506238554fb5395a9ea5a1ab9 + languageName: node + linkType: hard + +"espree@npm:^9.6.1 || ^10.4.0": + version: 10.4.0 + resolution: "espree@npm:10.4.0" + dependencies: + acorn: ^8.15.0 + acorn-jsx: ^5.3.2 + eslint-visitor-keys: ^4.2.1 + checksum: 5f9d0d7c81c1bca4bfd29a55270067ff9d575adb8c729a5d7f779c2c7b910bfc68ccf8ec19b29844b707440fc159a83868f22c8e87bbf7cbcb225ed067df6c85 languageName: node linkType: hard @@ -19433,6 +19164,15 @@ __metadata: languageName: node linkType: hard +"esquery@npm:^1.4.2": + version: 1.7.0 + resolution: "esquery@npm:1.7.0" + dependencies: + estraverse: ^5.1.0 + checksum: 3239792b68cf39fe18966d0ca01549bb15556734f0144308fd213739b0f153671ae916013fce0bca032044a4dbcda98b43c1c667f20c20a54dec3597ac0d7c27 + languageName: node + linkType: hard + "esrecurse@npm:^4.3.0": version: 4.3.0 resolution: "esrecurse@npm:4.3.0" @@ -19463,20 +19203,20 @@ __metadata: languageName: node linkType: hard -"estree-util-is-identifier-name@npm:^2.0.0": - version: 2.1.0 - resolution: "estree-util-is-identifier-name@npm:2.1.0" - checksum: cab317a071fafb99cf83b57df7924bccd2e6ab4e252688739e49f00b16cefd168e279c171442b0557c80a1c80ffaa927d670dadea65bb3c9b151efb8e772e89d +"estree-util-is-identifier-name@npm:^3.0.0": + version: 3.0.0 + resolution: "estree-util-is-identifier-name@npm:3.0.0" + checksum: ea3909f0188ea164af0aadeca87c087e3e5da78d76da5ae9c7954ff1340ea3e4679c4653bbf4299ffb70caa9b322218cc1128db2541f3d2976eb9704f9857787 languageName: node linkType: hard -"estree-util-visit@npm:^1.0.0, estree-util-visit@npm:^1.2.0": - version: 1.2.1 - resolution: "estree-util-visit@npm:1.2.1" +"estree-util-visit@npm:^2.0.0": + version: 2.0.0 + resolution: "estree-util-visit@npm:2.0.0" dependencies: "@types/estree-jsx": ^1.0.0 - "@types/unist": ^2.0.0 - checksum: 6feea4fdc43b0ba0f79faf1d57cf32373007e146d4810c7c09c13f5a9c1b8600c1ac57a8d949967cedd2a9a91dddd246e19b59bacfc01e417168b4ebf220f691 + "@types/unist": ^3.0.0 + checksum: 6444b38f224322945a6d19ea81a8828a0eec64aefb2bf1ea791fe20df496f7b7c543408d637df899e6a8e318b638f66226f16378a33c4c2b192ba5c3f891121f languageName: node linkType: hard @@ -19576,6 +19316,13 @@ __metadata: languageName: node linkType: hard +"eventemitter3@npm:5.0.1": + version: 5.0.1 + resolution: "eventemitter3@npm:5.0.1" + checksum: 543d6c858ab699303c3c32e0f0f47fc64d360bf73c3daf0ac0b5079710e340d6fe9f15487f94e66c629f5f82cd1a8678d692f3dbb6f6fcd1190e1b97fcad36f8 + languageName: node + linkType: hard + "eventemitter3@npm:^4.0.4, eventemitter3@npm:^4.0.7": version: 4.0.7 resolution: "eventemitter3@npm:4.0.7" @@ -19957,15 +19704,6 @@ __metadata: languageName: node linkType: hard -"fault@npm:^2.0.0": - version: 2.0.1 - resolution: "fault@npm:2.0.1" - dependencies: - format: ^0.2.0 - checksum: c9b30f47d95769177130a9409976a899ed31eb598450fbad5b0d39f2f5f56d5f4a9ff9257e0bee8407cb0fc3ce37165657888c6aa6d78472e403893104329b72 - languageName: node - linkType: hard - "fb-watchman@npm:^2.0.0": version: 2.0.1 resolution: "fb-watchman@npm:2.0.1" @@ -20295,9 +20033,9 @@ __metadata: languageName: node linkType: hard -"fork-ts-checker-webpack-plugin@npm:^7.2.13": - version: 7.2.13 - resolution: "fork-ts-checker-webpack-plugin@npm:7.2.13" +"fork-ts-checker-webpack-plugin@npm:^8.0.0": + version: 8.0.0 + resolution: "fork-ts-checker-webpack-plugin@npm:8.0.0" dependencies: "@babel/code-frame": ^7.16.7 chalk: ^4.1.2 @@ -20313,23 +20051,19 @@ __metadata: tapable: ^2.2.1 peerDependencies: typescript: ">3.6.0" - vue-template-compiler: "*" webpack: ^5.11.0 - peerDependenciesMeta: - vue-template-compiler: - optional: true - checksum: 3d4694c6fee4b8b2f213d0d10a3f40da770ca0ed3aa2a3dc8d1e701ad1ecaed3a1507f77a1b0cea6ef80539b04d8e5f5f02560e688d310bcb9e8c81f684d2950 + checksum: aad4cbc5b802e6281a2700a379837697c93ad95288468f9595219d91d9c26674736d37852bb4c4341e9122f26181e9e05fc1a362e8d029fdd88e99de7816037b languageName: node linkType: hard -"fork-ts-checker-webpack-plugin@npm:^8.0.0": - version: 8.0.0 - resolution: "fork-ts-checker-webpack-plugin@npm:8.0.0" +"fork-ts-checker-webpack-plugin@npm:^9.1.0": + version: 9.1.0 + resolution: "fork-ts-checker-webpack-plugin@npm:9.1.0" dependencies: "@babel/code-frame": ^7.16.7 chalk: ^4.1.2 - chokidar: ^3.5.3 - cosmiconfig: ^7.0.1 + chokidar: ^4.0.1 + cosmiconfig: ^8.2.0 deepmerge: ^4.2.2 fs-extra: ^10.0.0 memfs: ^3.4.1 @@ -20341,7 +20075,7 @@ __metadata: peerDependencies: typescript: ">3.6.0" webpack: ^5.11.0 - checksum: aad4cbc5b802e6281a2700a379837697c93ad95288468f9595219d91d9c26674736d37852bb4c4341e9122f26181e9e05fc1a362e8d029fdd88e99de7816037b + checksum: 8c3e011cce7ad2b45adce8aea8226db7d79e6ea0900030e86d24ea689152127a7a420f16ac09b9634e461fcd317e32b922a1f3106fe5107b1e8b74b83ed8ae82 languageName: node linkType: hard @@ -20378,13 +20112,6 @@ __metadata: languageName: node linkType: hard -"format@npm:^0.2.0": - version: 0.2.2 - resolution: "format@npm:0.2.2" - checksum: 646a60e1336250d802509cf24fb801e43bd4a70a07510c816fa133aa42cdbc9c21e66e9cc0801bb183c5b031c9d68be62e7fbb6877756e52357850f92aa28799 - languageName: node - linkType: hard - "forwarded@npm:0.2.0": version: 0.2.0 resolution: "forwarded@npm:0.2.0" @@ -21014,7 +20741,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^8.0.0, glob@npm:^8.0.1": +"glob@npm:^8.0.1": version: 8.1.0 resolution: "glob@npm:8.1.0" dependencies: @@ -21064,13 +20791,6 @@ __metadata: languageName: node linkType: hard -"globalyzer@npm:0.1.0": - version: 0.1.0 - resolution: "globalyzer@npm:0.1.0" - checksum: 419a0f95ba542534fac0842964d31b3dc2936a479b2b1a8a62bad7e8b61054faa9b0a06ad9f2e12593396b9b2621cac93358d9b3071d33723fb1778608d358a1 - languageName: node - linkType: hard - "globby@npm:^11.0.1, globby@npm:^11.0.2, globby@npm:^11.1.0": version: 11.1.0 resolution: "globby@npm:11.1.0" @@ -21112,13 +20832,6 @@ __metadata: languageName: node linkType: hard -"globrex@npm:^0.1.2": - version: 0.1.2 - resolution: "globrex@npm:0.1.2" - checksum: adca162494a176ce9ecf4dd232f7b802956bb1966b37f60c15e49d2e7d961b66c60826366dc2649093cad5a0d69970cfa8875bd1695b5a1a2f33dcd2aa88da3c - languageName: node - linkType: hard - "google-protobuf@npm:^3.14.0": version: 3.21.2 resolution: "google-protobuf@npm:3.21.2" @@ -21173,10 +20886,10 @@ __metadata: languageName: node linkType: hard -"grapheme-splitter@npm:^1.0.4": - version: 1.0.4 - resolution: "grapheme-splitter@npm:1.0.4" - checksum: 0c22ec54dee1b05cd480f78cf14f732cb5b108edc073572c4ec205df4cd63f30f8db8025afc5debc8835a8ddeacf648a1c7992fe3dcd6ad38f9a476d84906620 +"graphemer@npm:^1.4.0": + version: 1.4.0 + resolution: "graphemer@npm:1.4.0" + checksum: bab8f0be9b568857c7bec9fda95a89f87b783546d02951c40c33f84d05bb7da3fd10f863a9beb901463669b6583173a8c8cc6d6b306ea2b9b9d5d3d943c3a673 languageName: node linkType: hard @@ -21546,12 +21259,12 @@ __metadata: languageName: node linkType: hard -"hosted-git-info@npm:^5.0.0": - version: 5.2.1 - resolution: "hosted-git-info@npm:5.2.1" +"hosted-git-info@npm:^7.0.0": + version: 7.0.2 + resolution: "hosted-git-info@npm:7.0.2" dependencies: - lru-cache: ^7.5.1 - checksum: fa35df185224adfd69141f3b2f8cc31f50e705a5ebb415ccfbfd055c5b94bd08d3e658edf1edad9e2ac7d81831ac7cf261f5d219b3adc8d744fb8cdacaaf2ead + lru-cache: ^10.0.1 + checksum: 467cf908a56556417b18e86ae3b8dee03c2360ef1d51e61c4028fe87f6f309b6ff038589c94b5666af207da9d972d5107698906aabeb78aca134641962a5c6f8 languageName: node linkType: hard @@ -21916,13 +21629,6 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.0.0": - version: 5.2.4 - resolution: "ignore@npm:5.2.4" - checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef - languageName: node - linkType: hard - "ignore@npm:^5.1.8": version: 5.1.9 resolution: "ignore@npm:5.1.9" @@ -21937,6 +21643,20 @@ __metadata: languageName: node linkType: hard +"ignore@npm:^5.3.1": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 2acfd32a573260ea522ea0bfeff880af426d68f6831f973129e2ba7363f422923cf53aab62f8369cbf4667c7b25b6f8a3761b34ecdb284ea18e87a5262a865be + languageName: node + linkType: hard + +"ignore@npm:^6.0.0": + version: 6.0.2 + resolution: "ignore@npm:6.0.2" + checksum: b5dfb811428a067d79c128144814d3d20f01ef21e19c2b2e5bc270895995ce352da9b0e1c46a33de7daaf214bf0cf59d3353c78cdf9e365aaea677db729c721e + languageName: node + linkType: hard + "ignore@npm:^7.0.5": version: 7.0.5 resolution: "ignore@npm:7.0.5" @@ -21954,7 +21674,7 @@ __metadata: languageName: node linkType: hard -"import-fresh@npm:^3.0.0, import-fresh@npm:^3.2.1": +"import-fresh@npm:^3.2.1": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" dependencies: @@ -21998,10 +21718,10 @@ __metadata: languageName: node linkType: hard -"import-meta-resolve@npm:^2.0.0": - version: 2.2.1 - resolution: "import-meta-resolve@npm:2.2.1" - checksum: 8dd5ff7f6e96dea13653cbf79457588b9850949fde0412dba3cc944f8a61a155a3713d65878d903af6b0db7da960600ef66dfe994311743cdd49fe33dc91b0c5 +"import-meta-resolve@npm:^4.0.0": + version: 4.2.0 + resolution: "import-meta-resolve@npm:4.2.0" + checksum: fe5ca3258f22dc3dd4e2f2e8f6b54324c1cf0261216c7d9aae801b2eadf664bbd61e26cfb907a1238761285a3e9c8c23403321d52ca0e579c341b8d90c97fa52 languageName: node linkType: hard @@ -22071,10 +21791,10 @@ __metadata: languageName: node linkType: hard -"ini@npm:^3.0.0": - version: 3.0.1 - resolution: "ini@npm:3.0.1" - checksum: 947b582a822f06df3c22c75c90aec217d604ea11f7a20249530ee5c1cf8f508288439abe17b0e1d9b421bda5f4fae5e7aae0b18cb3ded5ac9d68f607df82f10f +"ini@npm:^4.1.2, ini@npm:^4.1.3": + version: 4.1.3 + resolution: "ini@npm:4.1.3" + checksum: 004b2be42388877c58add606149f1a0c7985c90a0ba5dbf45a4738fdc70b0798d922caecaa54617029626505898ac451ff0537a08b949836b49d3267f66542c9 languageName: node linkType: hard @@ -22264,13 +21984,6 @@ __metadata: languageName: node linkType: hard -"is-alphabetical@npm:^1.0.0": - version: 1.0.4 - resolution: "is-alphabetical@npm:1.0.4" - checksum: 6508cce44fd348f06705d377b260974f4ce68c74000e7da4045f0d919e568226dc3ce9685c5a2af272195384df6930f748ce9213fc9f399b5d31b362c66312cb - languageName: node - linkType: hard - "is-alphabetical@npm:^2.0.0": version: 2.0.1 resolution: "is-alphabetical@npm:2.0.1" @@ -22278,16 +21991,6 @@ __metadata: languageName: node linkType: hard -"is-alphanumerical@npm:^1.0.0": - version: 1.0.4 - resolution: "is-alphanumerical@npm:1.0.4" - dependencies: - is-alphabetical: ^1.0.0 - is-decimal: ^1.0.0 - checksum: e2e491acc16fcf5b363f7c726f666a9538dba0a043665740feb45bba1652457a73441e7c5179c6768a638ed396db3437e9905f403644ec7c468fb41f4813d03f - languageName: node - linkType: hard - "is-alphanumerical@npm:^2.0.0": version: 2.0.1 resolution: "is-alphanumerical@npm:2.0.1" @@ -22396,13 +22099,6 @@ __metadata: languageName: node linkType: hard -"is-buffer@npm:^2.0.0": - version: 2.0.5 - resolution: "is-buffer@npm:2.0.5" - checksum: 764c9ad8b523a9f5a32af29bdf772b08eb48c04d2ad0a7240916ac2688c983bf5f8504bf25b35e66240edeb9d9085461f9b5dae1f3d2861c6b06a65fe983de42 - languageName: node - linkType: hard - "is-builtin-module@npm:^3.2.0": version: 3.2.1 resolution: "is-builtin-module@npm:3.2.1" @@ -22521,13 +22217,6 @@ __metadata: languageName: node linkType: hard -"is-decimal@npm:^1.0.0": - version: 1.0.4 - resolution: "is-decimal@npm:1.0.4" - checksum: ed483a387517856dc395c68403a10201fddcc1b63dc56513fbe2fe86ab38766120090ecdbfed89223d84ca8b1cd28b0641b93cb6597b6e8f4c097a7c24e3fb96 - languageName: node - linkType: hard - "is-decimal@npm:^2.0.0": version: 2.0.1 resolution: "is-decimal@npm:2.0.1" @@ -22683,13 +22372,6 @@ __metadata: languageName: node linkType: hard -"is-hexadecimal@npm:^1.0.0": - version: 1.0.4 - resolution: "is-hexadecimal@npm:1.0.4" - checksum: a452e047587b6069332d83130f54d30da4faf2f2ebaa2ce6d073c27b5703d030d58ed9e0b729c8e4e5b52c6f1dab26781bb77b7bc6c7805f14f320e328ff8cd5 - languageName: node - linkType: hard - "is-hexadecimal@npm:^2.0.0": version: 2.0.1 resolution: "is-hexadecimal@npm:2.0.1" @@ -23816,13 +23498,6 @@ __metadata: languageName: node linkType: hard -"js-sdsl@npm:^4.1.4": - version: 4.3.0 - resolution: "js-sdsl@npm:4.3.0" - checksum: ce908257cf6909e213af580af3a691a736f5ee8b16315454768f917a682a4ea0c11bde1b241bbfaecedc0eb67b72101b2c2df2ffaed32aed5d539fca816f054e - languageName: node - linkType: hard - "js-sha3@npm:0.8.0": version: 0.8.0 resolution: "js-sha3@npm:0.8.0" @@ -24199,12 +23874,12 @@ __metadata: "keplr-wallet-private@file:./noop-keplr-wallet-private::locator=%40keplr-wallet%2Fextension%40workspace%3Aapps%2Fextension": version: 0.0.1 - resolution: "keplr-wallet-private@file:./noop-keplr-wallet-private#./noop-keplr-wallet-private::hash=28117a&locator=%40keplr-wallet%2Fextension%40workspace%3Aapps%2Fextension" + resolution: "keplr-wallet-private@file:./noop-keplr-wallet-private#./noop-keplr-wallet-private::hash=ae7095&locator=%40keplr-wallet%2Fextension%40workspace%3Aapps%2Fextension" peerDependencies: "@keplr-wallet/simple-fetch": "*" react: ^16.8.0 || ^17 || ^18 styled-components: "*" - checksum: 12e86c8412aa82b1446e73c24d3ad4cd3fbd22b12e06b7821595dc80ebaec0ee0f18f9a2d2548677c7e665a862fc4321f20155ca4ba697ee62bc70b76612d196 + checksum: f5edef51d6629fe7a83c9112e2387cf37b633bd8fdd5b1d6ddb73db4e1aebe81738410dd7a618b1e72477496b0dda0bd76d0fbddc179d07ea6d8aa928ca7b336 languageName: node linkType: hard @@ -24212,27 +23887,26 @@ __metadata: version: 0.0.0-use.local resolution: "keplr@workspace:." dependencies: - "@1stg/remark-preset": ^2.0.0 "@octokit/core": ^3.5.1 "@types/filesystem": ^0.0.32 "@types/jest": ^29.4.0 - "@types/node": ^18.13.0 + "@types/node": ^22.0.0 "@types/react": ^18.2.19 "@types/react-dom": ^18.2.7 "@types/react-is": ^18.2.1 - "@typescript-eslint/eslint-plugin": ^5.52.0 - "@typescript-eslint/parser": ^5.52.0 + "@typescript-eslint/eslint-plugin": ^7.0.0 + "@typescript-eslint/parser": ^7.0.0 bitcoinjs-lib: ^6.1.7 cross-env: ^5.2.0 - eslint: ^8.34.0 + eslint: ^8.56.0 eslint-config-prettier: ^8.6.0 eslint-plugin-import: ^2.27.5 - eslint-plugin-mdx: ^2.0.5 + eslint-plugin-mdx: ^3.7.0 eslint-plugin-prettier: ^4.2.1 eslint-plugin-react: ^7.32.2 eslint-plugin-react-hooks: ^4.6.0 eslint-plugin-unicorn: ^45.0.2 - eslint-plugin-unused-imports: ^2.0.0 + eslint-plugin-unused-imports: ^4.0.0 folder-hash: ^4.0.2 husky: ^9.1.7 jest: ^29.4.3 @@ -24249,7 +23923,7 @@ __metadata: semver: ^7.6.0 starknet: ^8.9.1 ts-jest: ^29.0.5 - typescript: 5.0.4 + typescript: ^5.7.0 zx: ^4.2.0 languageName: unknown linkType: soft @@ -24300,13 +23974,6 @@ __metadata: languageName: node linkType: hard -"kleur@npm:^4.0.3": - version: 4.1.5 - resolution: "kleur@npm:4.1.5" - checksum: 1dc476e32741acf0b1b5b0627ffd0d722e342c1b0da14de3e8ae97821327ca08f9fb944542fb3c126d90ac5f27f9d804edbe7c585bf7d12ef495d115e0f22c12 - languageName: node - linkType: hard - "lazy-universal-dotenv@npm:^4.0.0": version: 4.0.0 resolution: "lazy-universal-dotenv@npm:4.0.0" @@ -24425,15 +24092,6 @@ __metadata: languageName: node linkType: hard -"levenshtein-edit-distance@npm:^1.0.0": - version: 1.0.0 - resolution: "levenshtein-edit-distance@npm:1.0.0" - bin: - levenshtein-edit-distance: cli.js - checksum: d628c4011a6724e4d6aea1af1c5d9ec8b3ba7f95eec0deb2e40ee77269e12b0433a7027f66e5375a17b803d36f86601c2692dfa4b2e6030aabc14969a2941de6 - languageName: node - linkType: hard - "levn@npm:^0.4.1": version: 0.4.1 resolution: "levn@npm:0.4.1" @@ -24607,7 +24265,7 @@ __metadata: languageName: node linkType: hard -"lines-and-columns@npm:2.0.3, lines-and-columns@npm:^2.0.2": +"lines-and-columns@npm:2.0.3": version: 2.0.3 resolution: "lines-and-columns@npm:2.0.3" checksum: 5955363dfd7d3d7c476d002eb47944dbe0310d57959e2112dce004c0dc76cecfd479cf8c098fd479ff344acdf04ee0e82b455462a26492231ac152f6c48d17a1 @@ -24621,6 +24279,13 @@ __metadata: languageName: node linkType: hard +"lines-and-columns@npm:^2.0.3": + version: 2.0.4 + resolution: "lines-and-columns@npm:2.0.4" + checksum: f5e3e207467d3e722280c962b786dc20ebceb191821dcd771d14ab3146b6744cae28cf305ee4638805bec524ac54800e15698c853fcc53243821f88df37e4975 + languageName: node + linkType: hard + "lint-staged@npm:^10.5.4": version: 10.5.4 resolution: "lint-staged@npm:10.5.4" @@ -24717,13 +24382,13 @@ __metadata: languageName: node linkType: hard -"load-plugin@npm:^5.0.0": - version: 5.1.0 - resolution: "load-plugin@npm:5.1.0" +"load-plugin@npm:^6.0.0": + version: 6.0.3 + resolution: "load-plugin@npm:6.0.3" dependencies: - "@npmcli/config": ^6.0.0 - import-meta-resolve: ^2.0.0 - checksum: d450c9a0838cec7f7581abcb8ff9170a5c6e1bc1ca816e4288e4a014bc0e819c4ca16163fd78b7e1fb6c1dffedf6ac881f9893d5a025b69f369a157d9a2aacf6 + "@npmcli/config": ^8.0.0 + import-meta-resolve: ^4.0.0 + checksum: 75e34816535fe3a1229452e4f9c98e661b282221be7d840f4f567d33955cf36e98443013e4d5c8a920800f2c32e76292e163e1b711ebe468b7c3a24b5f9d6dd6 languageName: node linkType: hard @@ -25061,13 +24726,6 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^7.5.1": - version: 7.16.0 - resolution: "lru-cache@npm:7.16.0" - checksum: 1a5511a0e695154c37f443c495ebcf3170ec8c291df62e140329cf0c48e2549db836e69371853a28286dc9de73a98f486a7566c64246249a6041c43d4a28bc60 - languageName: node - linkType: hard - "lru-cache@npm:^7.7.1": version: 7.15.0 resolution: "lru-cache@npm:7.15.0" @@ -25280,13 +24938,6 @@ __metadata: languageName: node linkType: hard -"markdown-table@npm:^3.0.0": - version: 3.0.3 - resolution: "markdown-table@npm:3.0.3" - checksum: 8fcd3d9018311120fbb97115987f8b1665a603f3134c93fbecc5d1463380c8036f789e2a62c19432058829e594fff8db9ff81c88f83690b2f8ed6c074f8d9e10 - languageName: node - linkType: hard - "markdown-to-jsx@npm:^7.1.8": version: 7.4.7 resolution: "markdown-to-jsx@npm:7.4.7" @@ -25307,16 +24958,6 @@ __metadata: languageName: node linkType: hard -"mdast-comment-marker@npm:^2.0.0": - version: 2.1.1 - resolution: "mdast-comment-marker@npm:2.1.1" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-mdx-expression: ^1.1.0 - checksum: aab4b99068d7530404dced0442102b56fc88bdd385ede999e865386b505d7c8e2bd4f2111455d0d3d1f628dcbfc149042a721a172665fb6924c20033a50d5de0 - languageName: node - linkType: hard - "mdast-util-definitions@npm:^4.0.0": version: 4.0.0 resolution: "mdast-util-definitions@npm:4.0.0" @@ -25326,223 +24967,111 @@ __metadata: languageName: node linkType: hard -"mdast-util-find-and-replace@npm:^2.0.0": - version: 2.2.2 - resolution: "mdast-util-find-and-replace@npm:2.2.2" - dependencies: - "@types/mdast": ^3.0.0 - escape-string-regexp: ^5.0.0 - unist-util-is: ^5.0.0 - unist-util-visit-parents: ^5.0.0 - checksum: b4ce463c43fe6e1c38a53a89703f755c84ab5437f49bff9a0ac751279733332ca11c85ed0262aa6c17481f77b555d26ca6d64e70d6814f5b8d12d34a3e53a60b - languageName: node - linkType: hard - -"mdast-util-from-markdown@npm:^0.8.5": - version: 0.8.5 - resolution: "mdast-util-from-markdown@npm:0.8.5" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-to-string: ^2.0.0 - micromark: ~2.11.0 - parse-entities: ^2.0.0 - unist-util-stringify-position: ^2.0.0 - checksum: 5a9d0d753a42db763761e874c22365d0c7c9934a5a18b5ff76a0643610108a208a041ffdb2f3d3dd1863d3d915225a4020a0aade282af0facfd0df110601eee6 - languageName: node - linkType: hard - -"mdast-util-from-markdown@npm:^1.0.0, mdast-util-from-markdown@npm:^1.1.0": - version: 1.3.0 - resolution: "mdast-util-from-markdown@npm:1.3.0" +"mdast-util-from-markdown@npm:^2.0.0, mdast-util-from-markdown@npm:^2.0.2": + version: 2.0.3 + resolution: "mdast-util-from-markdown@npm:2.0.3" dependencies: - "@types/mdast": ^3.0.0 - "@types/unist": ^2.0.0 + "@types/mdast": ^4.0.0 + "@types/unist": ^3.0.0 decode-named-character-reference: ^1.0.0 - mdast-util-to-string: ^3.1.0 - micromark: ^3.0.0 - micromark-util-decode-numeric-character-reference: ^1.0.0 - micromark-util-decode-string: ^1.0.0 - micromark-util-normalize-identifier: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - unist-util-stringify-position: ^3.0.0 - uvu: ^0.5.0 - checksum: cc971d1ad381150f6504fd753fbcffcc64c0abb527540ce343625c2bba76104505262122ef63d14ab66eb47203f323267017c6d09abfa8535ee6a8e14069595f + devlop: ^1.0.0 + mdast-util-to-string: ^4.0.0 + micromark: ^4.0.0 + micromark-util-decode-numeric-character-reference: ^2.0.0 + micromark-util-decode-string: ^2.0.0 + micromark-util-normalize-identifier: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + unist-util-stringify-position: ^4.0.0 + checksum: 2e6e9fbf521e0974c8c83082a4e5e5d17c32442e7584cbe248f92037d6b4ea13b822af3380363b99e81b181cddf7e61e62353aa3746a395de7e2fd0101007b8e languageName: node linkType: hard -"mdast-util-frontmatter@npm:^1.0.0": - version: 1.0.1 - resolution: "mdast-util-frontmatter@npm:1.0.1" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-to-markdown: ^1.3.0 - micromark-extension-frontmatter: ^1.0.0 - checksum: 0b0552047b753931da8265f2231a0b79aad1309ad7ad6599181c2d264e9b70b61acf742f29bdf2de8e901eb6eb37dd42b6f66007e735fd8138b2bf4d9acb0118 - languageName: node - linkType: hard - -"mdast-util-gfm-autolink-literal@npm:^1.0.0": - version: 1.0.3 - resolution: "mdast-util-gfm-autolink-literal@npm:1.0.3" - dependencies: - "@types/mdast": ^3.0.0 - ccount: ^2.0.0 - mdast-util-find-and-replace: ^2.0.0 - micromark-util-character: ^1.0.0 - checksum: 1748a8727cfc533bac0c287d6e72d571d165bfa77ae0418be4828177a3ec73c02c3f2ee534d87eb75cbaffa00c0866853bbcc60ae2255babb8210f7636ec2ce2 - languageName: node - linkType: hard - -"mdast-util-gfm-footnote@npm:^1.0.0": - version: 1.0.2 - resolution: "mdast-util-gfm-footnote@npm:1.0.2" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-to-markdown: ^1.3.0 - micromark-util-normalize-identifier: ^1.0.0 - checksum: 2d77505f9377ed7e14472ef5e6b8366c3fec2cf5f936bb36f9fbe5b97ccb7cce0464d9313c236fa86fb844206fd585db05707e4fcfb755e4fc1864194845f1f6 - languageName: node - linkType: hard - -"mdast-util-gfm-strikethrough@npm:^1.0.0": - version: 1.0.3 - resolution: "mdast-util-gfm-strikethrough@npm:1.0.3" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-to-markdown: ^1.3.0 - checksum: 17003340ff1bba643ec4a59fd4370fc6a32885cab2d9750a508afa7225ea71449fb05acaef60faa89c6378b8bcfbd86a9d94b05f3c6651ff27a60e3ddefc2549 - languageName: node - linkType: hard - -"mdast-util-gfm-table@npm:^1.0.0": - version: 1.0.7 - resolution: "mdast-util-gfm-table@npm:1.0.7" - dependencies: - "@types/mdast": ^3.0.0 - markdown-table: ^3.0.0 - mdast-util-from-markdown: ^1.0.0 - mdast-util-to-markdown: ^1.3.0 - checksum: 8b8c401bb4162e53f072a2dff8efbca880fd78d55af30601c791315ab6722cb2918176e8585792469a0c530cebb9df9b4e7fede75fdc4d83df2839e238836692 - languageName: node - linkType: hard - -"mdast-util-gfm-task-list-item@npm:^1.0.0": - version: 1.0.2 - resolution: "mdast-util-gfm-task-list-item@npm:1.0.2" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-to-markdown: ^1.3.0 - checksum: c9b86037d6953b84f11fb2fc3aa23d5b8e14ca0dfcb0eb2fb289200e172bb9d5647bfceb4f86606dc6d935e8d58f6a458c04d3e55e87ff8513c7d4ade976200b - languageName: node - linkType: hard - -"mdast-util-gfm@npm:^2.0.0": - version: 2.0.2 - resolution: "mdast-util-gfm@npm:2.0.2" - dependencies: - mdast-util-from-markdown: ^1.0.0 - mdast-util-gfm-autolink-literal: ^1.0.0 - mdast-util-gfm-footnote: ^1.0.0 - mdast-util-gfm-strikethrough: ^1.0.0 - mdast-util-gfm-table: ^1.0.0 - mdast-util-gfm-task-list-item: ^1.0.0 - mdast-util-to-markdown: ^1.0.0 - checksum: 7078cb985255208bcbce94a121906417d38353c6b1a9acbe56ee8888010d3500608b5d51c16b0999ac63ca58848fb13012d55f26930ff6c6f3450f053d56514e - languageName: node - linkType: hard - -"mdast-util-heading-style@npm:^2.0.0": +"mdast-util-mdx-expression@npm:^2.0.0": version: 2.0.1 - resolution: "mdast-util-heading-style@npm:2.0.1" - dependencies: - "@types/mdast": ^3.0.0 - checksum: 8ea1a36f526170f09e4ad597c3b75a580efe5b1736d6d21ccad222a002281ae4066414bf2e12911c72561762069a5045a817899a245999a66c01edefdba5a96b - languageName: node - linkType: hard - -"mdast-util-mdx-expression@npm:^1.0.0, mdast-util-mdx-expression@npm:^1.1.0": - version: 1.3.2 - resolution: "mdast-util-mdx-expression@npm:1.3.2" + resolution: "mdast-util-mdx-expression@npm:2.0.1" dependencies: "@types/estree-jsx": ^1.0.0 - "@types/hast": ^2.0.0 - "@types/mdast": ^3.0.0 - mdast-util-from-markdown: ^1.0.0 - mdast-util-to-markdown: ^1.0.0 - checksum: e4c90f26deaa5eb6217b0a9af559a80de41da02ab3bcd864c56bed3304b056ae703896e9876bc6ded500f4aff59f4de5cbf6a4b109a5ba408f2342805fe6dc05 + "@types/hast": ^3.0.0 + "@types/mdast": ^4.0.0 + devlop: ^1.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: 6af56b06bde3ab971129db9855dcf0d31806c70b3b052d7a90a5499a366b57ffd0c2efca67d281c448c557298ba7e3e61bd07133733b735440840dd339b28e19 languageName: node linkType: hard -"mdast-util-mdx-jsx@npm:^2.0.0": - version: 2.1.2 - resolution: "mdast-util-mdx-jsx@npm:2.1.2" +"mdast-util-mdx-jsx@npm:^3.0.0": + version: 3.2.0 + resolution: "mdast-util-mdx-jsx@npm:3.2.0" dependencies: "@types/estree-jsx": ^1.0.0 - "@types/hast": ^2.0.0 - "@types/mdast": ^3.0.0 - "@types/unist": ^2.0.0 + "@types/hast": ^3.0.0 + "@types/mdast": ^4.0.0 + "@types/unist": ^3.0.0 ccount: ^2.0.0 - mdast-util-from-markdown: ^1.1.0 - mdast-util-to-markdown: ^1.3.0 + devlop: ^1.1.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 parse-entities: ^4.0.0 stringify-entities: ^4.0.0 - unist-util-remove-position: ^4.0.0 - unist-util-stringify-position: ^3.0.0 - vfile-message: ^3.0.0 - checksum: 637e0bbd97c0c783f6b12bb05ccb1edaec076c5aa6d349147d77b8e6e10677f1be8e2870c05b1896f69095c9bc527f34be72b349b30737ab2e499bfc579b3a28 + unist-util-stringify-position: ^4.0.0 + vfile-message: ^4.0.0 + checksum: 224f5f6ad247f0f2622ee36c82ac7a4c6a60c31850de4056bf95f531bd2f7ec8943ef34dfe8a8375851f65c07e4913c4f33045d703df4ff4d11b2de5a088f7f9 languageName: node linkType: hard -"mdast-util-mdx@npm:^2.0.0": - version: 2.0.1 - resolution: "mdast-util-mdx@npm:2.0.1" +"mdast-util-mdx@npm:^3.0.0": + version: 3.0.0 + resolution: "mdast-util-mdx@npm:3.0.0" dependencies: - mdast-util-from-markdown: ^1.0.0 - mdast-util-mdx-expression: ^1.0.0 - mdast-util-mdx-jsx: ^2.0.0 - mdast-util-mdxjs-esm: ^1.0.0 - mdast-util-to-markdown: ^1.0.0 - checksum: 7303149230a26e524e319833b782bffca94e49cdab012996618701259bd056e014ca22a35d25ffa8880ba9064ee126a2a002f01e5c90a31ca726339ed775875e + mdast-util-from-markdown: ^2.0.0 + mdast-util-mdx-expression: ^2.0.0 + mdast-util-mdx-jsx: ^3.0.0 + mdast-util-mdxjs-esm: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: e2b007d826fcd49fd57ed03e190753c8b0f7d9eff6c7cb26ba609cde15cd3a472c0cd5e4a1ee3e39a40f14be22fdb57de243e093cea0c064d6f3366cff3e3af2 languageName: node linkType: hard -"mdast-util-mdxjs-esm@npm:^1.0.0": - version: 1.3.1 - resolution: "mdast-util-mdxjs-esm@npm:1.3.1" +"mdast-util-mdxjs-esm@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-mdxjs-esm@npm:2.0.1" dependencies: "@types/estree-jsx": ^1.0.0 - "@types/hast": ^2.0.0 - "@types/mdast": ^3.0.0 - mdast-util-from-markdown: ^1.0.0 - mdast-util-to-markdown: ^1.0.0 - checksum: ee78a4f58adfec38723cbc920f05481201ebb001eff3982f2d0e5f5ce5c75685e732e9d361ad4a1be8b936b4e5de0f2599cb96b92ad4bd92698ac0c4a09bbec3 + "@types/hast": ^3.0.0 + "@types/mdast": ^4.0.0 + devlop: ^1.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: 1f9dad04d31d59005332e9157ea9510dc1d03092aadbc607a10475c7eec1c158b475aa0601a3a4f74e13097ca735deb8c2d9d37928ddef25d3029fd7c9e14dc3 languageName: node linkType: hard -"mdast-util-phrasing@npm:^3.0.0": - version: 3.0.1 - resolution: "mdast-util-phrasing@npm:3.0.1" +"mdast-util-phrasing@npm:^4.0.0": + version: 4.1.0 + resolution: "mdast-util-phrasing@npm:4.1.0" dependencies: - "@types/mdast": ^3.0.0 - unist-util-is: ^5.0.0 - checksum: c5b616d9b1eb76a6b351d195d94318494722525a12a89d9c8a3b091af7db3dd1fc55d294f9d29266d8159a8267b0df4a7a133bda8a3909d5331c383e1e1ff328 + "@types/mdast": ^4.0.0 + unist-util-is: ^6.0.0 + checksum: 3a97533e8ad104a422f8bebb34b3dde4f17167b8ed3a721cf9263c7416bd3447d2364e6d012a594aada40cac9e949db28a060bb71a982231693609034ed5324e languageName: node linkType: hard -"mdast-util-to-markdown@npm:^1.0.0, mdast-util-to-markdown@npm:^1.3.0": - version: 1.5.0 - resolution: "mdast-util-to-markdown@npm:1.5.0" +"mdast-util-to-markdown@npm:^2.0.0": + version: 2.1.2 + resolution: "mdast-util-to-markdown@npm:2.1.2" dependencies: - "@types/mdast": ^3.0.0 - "@types/unist": ^2.0.0 + "@types/mdast": ^4.0.0 + "@types/unist": ^3.0.0 longest-streak: ^3.0.0 - mdast-util-phrasing: ^3.0.0 - mdast-util-to-string: ^3.0.0 - micromark-util-decode-string: ^1.0.0 - unist-util-visit: ^4.0.0 + mdast-util-phrasing: ^4.0.0 + mdast-util-to-string: ^4.0.0 + micromark-util-classify-character: ^2.0.0 + micromark-util-decode-string: ^2.0.0 + unist-util-visit: ^5.0.0 zwitch: ^2.0.0 - checksum: 64338eb33e49bb0aea417591fd986f72fdd39205052563bb7ce9eb9ecc160824509bfacd740086a05af355c6d5c36353aafe95cab9e6927d674478757cee6259 + checksum: 288d152bd50c00632e6e01c610bb904a220d1e226c8086c40627877959746f83ab0b872f4150cb7d910198953b1bf756e384ac3fee3e7b0ddb4517f9084c5803 languageName: node linkType: hard @@ -25553,19 +25082,12 @@ __metadata: languageName: node linkType: hard -"mdast-util-to-string@npm:^2.0.0": - version: 2.0.0 - resolution: "mdast-util-to-string@npm:2.0.0" - checksum: 0b2113ada10e002fbccb014170506dabe2f2ddacaacbe4bc1045c33f986652c5a162732a2c057c5335cdb58419e2ad23e368e5be226855d4d4e280b81c4e9ec2 - languageName: node - linkType: hard - -"mdast-util-to-string@npm:^3.0.0, mdast-util-to-string@npm:^3.1.0": - version: 3.1.1 - resolution: "mdast-util-to-string@npm:3.1.1" +"mdast-util-to-string@npm:^4.0.0": + version: 4.0.0 + resolution: "mdast-util-to-string@npm:4.0.0" dependencies: - "@types/mdast": ^3.0.0 - checksum: 5e9375e1757ebf2950e122ef3538e4257ed2b6f43ab1d3e9c45db5dd5d5b5d14fd041490afcde00934f1cdb4b99877597ae04eb810d313ec7b38c6009058dddd + "@types/mdast": ^4.0.0 + checksum: 35489fb5710d58cbc2d6c8b6547df161a3f81e0f28f320dfb3548a9393555daf07c310c0c497708e67ed4dfea4a06e5655799e7d631ca91420c288b4525d6c29 languageName: node linkType: hard @@ -25687,459 +25209,347 @@ __metadata: languageName: node linkType: hard -"micromark-core-commonmark@npm:^1.0.0, micromark-core-commonmark@npm:^1.0.1": - version: 1.0.6 - resolution: "micromark-core-commonmark@npm:1.0.6" +"micromark-core-commonmark@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-core-commonmark@npm:2.0.3" dependencies: decode-named-character-reference: ^1.0.0 - micromark-factory-destination: ^1.0.0 - micromark-factory-label: ^1.0.0 - micromark-factory-space: ^1.0.0 - micromark-factory-title: ^1.0.0 - micromark-factory-whitespace: ^1.0.0 - micromark-util-character: ^1.0.0 - micromark-util-chunked: ^1.0.0 - micromark-util-classify-character: ^1.0.0 - micromark-util-html-tag-name: ^1.0.0 - micromark-util-normalize-identifier: ^1.0.0 - micromark-util-resolve-all: ^1.0.0 - micromark-util-subtokenize: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.1 - uvu: ^0.5.0 - checksum: 4b483c46077f696ed310f6d709bb9547434c218ceb5c1220fde1707175f6f68b44da15ab8668f9c801e1a123210071e3af883a7d1215122c913fd626f122bfc2 - languageName: node - linkType: hard - -"micromark-extension-frontmatter@npm:^1.0.0": - version: 1.0.0 - resolution: "micromark-extension-frontmatter@npm:1.0.0" - dependencies: - fault: ^2.0.0 - micromark-util-character: ^1.0.0 - micromark-util-symbol: ^1.0.0 - checksum: d0bacd6aadd6e33e26245628b93f5bcaf9a1de47787cea6807f8569213ceeb1376c37fadcf059280f5eafe6a07682bd148989e65489e99c9a3f4d523eea5f5c0 - languageName: node - linkType: hard - -"micromark-extension-gfm-autolink-literal@npm:^1.0.0": - version: 1.0.3 - resolution: "micromark-extension-gfm-autolink-literal@npm:1.0.3" - dependencies: - micromark-util-character: ^1.0.0 - micromark-util-sanitize-uri: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - uvu: ^0.5.0 - checksum: bb181972ac346ca73ca1ab0b80b80c9d6509ed149799d2217d5442670f499c38a94edff73d32fa52b390d89640974cfbd7f29e4ad7d599581d5e1cabcae636a2 - languageName: node - linkType: hard - -"micromark-extension-gfm-footnote@npm:^1.0.0": - version: 1.0.4 - resolution: "micromark-extension-gfm-footnote@npm:1.0.4" - dependencies: - micromark-core-commonmark: ^1.0.0 - micromark-factory-space: ^1.0.0 - micromark-util-character: ^1.0.0 - micromark-util-normalize-identifier: ^1.0.0 - micromark-util-sanitize-uri: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - uvu: ^0.5.0 - checksum: 8daa203f5cf753338d5ecdbaae6b3ab6319d34b6013b90ea6860bed299418cecf86e69e48dabe42562e334760c738c77c5acdb47e75ae26f5f01f02f3bf0952d - languageName: node - linkType: hard - -"micromark-extension-gfm-strikethrough@npm:^1.0.0": - version: 1.0.4 - resolution: "micromark-extension-gfm-strikethrough@npm:1.0.4" - dependencies: - micromark-util-chunked: ^1.0.0 - micromark-util-classify-character: ^1.0.0 - micromark-util-resolve-all: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - uvu: ^0.5.0 - checksum: f43d316b85fe93df1711cdcdc99a5320b941239349234bd262fc708cb67ad47bdfb41d1a7ebe2a5829816b0e9d3107380a5c1e558cb536a75354cbe4857823ba - languageName: node - linkType: hard - -"micromark-extension-gfm-table@npm:^1.0.0": - version: 1.0.5 - resolution: "micromark-extension-gfm-table@npm:1.0.5" - dependencies: - micromark-factory-space: ^1.0.0 - micromark-util-character: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - uvu: ^0.5.0 - checksum: f0aab3b4333cc24b1534b08dc4cce986dd606df8b7ed913e5a1de9fe2d3ae67b2435663c0bc271b528874af4928e580e1ad540ea9117d7f2d74edb28859c97ef - languageName: node - linkType: hard - -"micromark-extension-gfm-tagfilter@npm:^1.0.0": - version: 1.0.1 - resolution: "micromark-extension-gfm-tagfilter@npm:1.0.1" - dependencies: - micromark-util-types: ^1.0.0 - checksum: 63e8d68f25871722900a67a8001d5da21f19ea707f3566fc7d0b2eb1f6d52476848bb6a41576cf22470565124af9497c5aae842355faa4c14ec19cb1847e71ec - languageName: node - linkType: hard - -"micromark-extension-gfm-task-list-item@npm:^1.0.0": - version: 1.0.3 - resolution: "micromark-extension-gfm-task-list-item@npm:1.0.3" - dependencies: - micromark-factory-space: ^1.0.0 - micromark-util-character: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - uvu: ^0.5.0 - checksum: d320b0c5301f87e211c06a2330d1ee0fee6da14f0d6d44d5211055b465dadff34390cd6b258a5e0ca376fcda3364fef9a12fe6e26a0c858231fa3b98ddbf7785 - languageName: node - linkType: hard - -"micromark-extension-gfm@npm:^2.0.0": - version: 2.0.1 - resolution: "micromark-extension-gfm@npm:2.0.1" - dependencies: - micromark-extension-gfm-autolink-literal: ^1.0.0 - micromark-extension-gfm-footnote: ^1.0.0 - micromark-extension-gfm-strikethrough: ^1.0.0 - micromark-extension-gfm-table: ^1.0.0 - micromark-extension-gfm-tagfilter: ^1.0.0 - micromark-extension-gfm-task-list-item: ^1.0.0 - micromark-util-combine-extensions: ^1.0.0 - micromark-util-types: ^1.0.0 - checksum: b181479c87be38d5ae8d28e6dc52fab73c894fd2706876746f27a91fb186644ce03532a9c35dca2186327a0e2285cd5242ad0361dc89adedd4a50376ffd94e22 - languageName: node - linkType: hard - -"micromark-extension-mdx-expression@npm:^1.0.0": - version: 1.0.4 - resolution: "micromark-extension-mdx-expression@npm:1.0.4" + devlop: ^1.0.0 + micromark-factory-destination: ^2.0.0 + micromark-factory-label: ^2.0.0 + micromark-factory-space: ^2.0.0 + micromark-factory-title: ^2.0.0 + micromark-factory-whitespace: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-chunked: ^2.0.0 + micromark-util-classify-character: ^2.0.0 + micromark-util-html-tag-name: ^2.0.0 + micromark-util-normalize-identifier: ^2.0.0 + micromark-util-resolve-all: ^2.0.0 + micromark-util-subtokenize: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: cfb0fd9c895f86a4e9344f7f0344fe6bd1018945798222835248146a42430b8c7bc0b2857af574cf4e1b4ce4e5c1a35a1479942421492e37baddde8de85814dc + languageName: node + linkType: hard + +"micromark-extension-mdx-expression@npm:^3.0.0": + version: 3.0.1 + resolution: "micromark-extension-mdx-expression@npm:3.0.1" dependencies: - micromark-factory-mdx-expression: ^1.0.0 - micromark-factory-space: ^1.0.0 - micromark-util-character: ^1.0.0 - micromark-util-events-to-acorn: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - uvu: ^0.5.0 - checksum: d19a31f9813dd5d4ad96b99e35b7c48067e69d75f92ec670dad5242857fb7688ba8b7c6a15616797b5df25dd89fd3b54916f93cb60ce2cfe97aca84739b45954 + "@types/estree": ^1.0.0 + devlop: ^1.0.0 + micromark-factory-mdx-expression: ^2.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-events-to-acorn: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 0e15bc3911b53704723acc300d99093e46e31a1f2210f6fadeaf065d04c964cd4588cf4aa1e9c324430bfd943dfa7f36e369a3bc92f4641015b107bbb2190034 languageName: node linkType: hard -"micromark-extension-mdx-jsx@npm:^1.0.0": - version: 1.0.3 - resolution: "micromark-extension-mdx-jsx@npm:1.0.3" +"micromark-extension-mdx-jsx@npm:^3.0.0": + version: 3.0.2 + resolution: "micromark-extension-mdx-jsx@npm:3.0.2" dependencies: - "@types/acorn": ^4.0.0 - estree-util-is-identifier-name: ^2.0.0 - micromark-factory-mdx-expression: ^1.0.0 - micromark-factory-space: ^1.0.0 - micromark-util-character: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - uvu: ^0.5.0 - vfile-message: ^3.0.0 - checksum: 1a5566890aabc52fe96b78e3a3a507dee03a2232e44b9360b00617734e156f934e85bc6a477fbb856c793fe33c9fb7d2207a4f50e680168c0d04ba9c9336d960 + "@types/estree": ^1.0.0 + devlop: ^1.0.0 + estree-util-is-identifier-name: ^3.0.0 + micromark-factory-mdx-expression: ^2.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-events-to-acorn: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + vfile-message: ^4.0.0 + checksum: abe07e592a95804445d2c667bc999696ac39ddd551374f5a39e2d910c8b25e75bf61b4933213696f7bc26f4a5a56d91b3ce31d9a063b6fd7bbd4633565b1d6ec languageName: node linkType: hard -"micromark-extension-mdx-md@npm:^1.0.0": - version: 1.0.0 - resolution: "micromark-extension-mdx-md@npm:1.0.0" +"micromark-extension-mdx-md@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-mdx-md@npm:2.0.0" dependencies: - micromark-util-types: ^1.0.0 - checksum: b4f205e1d5f0946b4755541ef44ffd0b3be8c7ecfc08d8b139b6a21fbd3ff62d8fdb6b7e6d17bd9a3b610450267f43a41703dc48b341da9addd743a28cdefa64 + micromark-util-types: ^2.0.0 + checksum: 7daf03372fd7faddf3f0ac87bdb0debb0bb770f33b586f72251e1072b222ceee75400ab6194c0e130dbf1e077369a5b627be6e9130d7a2e9e6b849f0d18ff246 languageName: node linkType: hard -"micromark-extension-mdxjs-esm@npm:^1.0.0": - version: 1.0.3 - resolution: "micromark-extension-mdxjs-esm@npm:1.0.3" +"micromark-extension-mdxjs-esm@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdxjs-esm@npm:3.0.0" dependencies: - micromark-core-commonmark: ^1.0.0 - micromark-util-character: ^1.0.0 - micromark-util-events-to-acorn: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - unist-util-position-from-estree: ^1.1.0 - uvu: ^0.5.0 - vfile-message: ^3.0.0 - checksum: 756074656391a5e5bb96bc8a0e9c1df7d9f7be5299847c9719e6a90552e1c76a11876aa89986ad5da89ab485f776a4a43a61ea3acddd4f865a5cee43ac523ffd + "@types/estree": ^1.0.0 + devlop: ^1.0.0 + micromark-core-commonmark: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-events-to-acorn: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + unist-util-position-from-estree: ^2.0.0 + vfile-message: ^4.0.0 + checksum: fb33d850200afce567b95c90f2f7d42259bd33eea16154349e4fa77c3ec934f46c8e5c111acea16321dce3d9f85aaa4c49afe8b810e31b34effc11617aeee8f6 languageName: node linkType: hard -"micromark-extension-mdxjs@npm:^1.0.0": - version: 1.0.0 - resolution: "micromark-extension-mdxjs@npm:1.0.0" +"micromark-extension-mdxjs@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdxjs@npm:3.0.0" dependencies: acorn: ^8.0.0 acorn-jsx: ^5.0.0 - micromark-extension-mdx-expression: ^1.0.0 - micromark-extension-mdx-jsx: ^1.0.0 - micromark-extension-mdx-md: ^1.0.0 - micromark-extension-mdxjs-esm: ^1.0.0 - micromark-util-combine-extensions: ^1.0.0 - micromark-util-types: ^1.0.0 - checksum: ba836c6d2dfc67597886e88f533ffa02f2029dbe216a0651f1066e70f8529a700bcc7fa2bc4201ee12fd3d1cd7da7093d5a442442daeb84b27df96aaffb7699c + micromark-extension-mdx-expression: ^3.0.0 + micromark-extension-mdx-jsx: ^3.0.0 + micromark-extension-mdx-md: ^2.0.0 + micromark-extension-mdxjs-esm: ^3.0.0 + micromark-util-combine-extensions: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 7da6f0fb0e1e0270a2f5ad257e7422cc16e68efa7b8214c63c9d55bc264cb872e9ca4ac9a71b9dfd13daf52e010f730bac316086f4340e4fcc6569ec699915bf languageName: node linkType: hard -"micromark-factory-destination@npm:^1.0.0": - version: 1.0.0 - resolution: "micromark-factory-destination@npm:1.0.0" +"micromark-factory-destination@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-destination@npm:2.0.1" dependencies: - micromark-util-character: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - checksum: 8e733ae9c1c2342f14ff290bf09946e20f6f540117d80342377a765cac48df2ea5e748f33c8b07501ad7a43414b1a6597c8510ede2052b6bf1251fab89748e20 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 9c4baa9ca2ed43c061bbf40ddd3d85154c2a0f1f485de9dea41d7dd2ad994ebb02034a003b2c1dbe228ba83a0576d591f0e90e0bf978713f84ee7d7f3aa98320 languageName: node linkType: hard -"micromark-factory-label@npm:^1.0.0": - version: 1.0.2 - resolution: "micromark-factory-label@npm:1.0.2" +"micromark-factory-label@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-label@npm:2.0.1" dependencies: - micromark-util-character: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - uvu: ^0.5.0 - checksum: 957e9366bdc8dbc1437c0706ff96972fa985ab4b1274abcae12f6094f527cbf5c69e7f2304c23c7f4b96e311ff7911d226563b8b43dcfcd4091e8c985fb97ce6 + devlop: ^1.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: bd03f5a75f27cdbf03b894ddc5c4480fc0763061fecf9eb927d6429233c930394f223969a99472df142d570c831236134de3dc23245d23d9f046f9d0b623b5c2 languageName: node linkType: hard -"micromark-factory-mdx-expression@npm:^1.0.0": - version: 1.0.7 - resolution: "micromark-factory-mdx-expression@npm:1.0.7" +"micromark-factory-mdx-expression@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-factory-mdx-expression@npm:2.0.3" dependencies: - micromark-factory-space: ^1.0.0 - micromark-util-character: ^1.0.0 - micromark-util-events-to-acorn: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - unist-util-position-from-estree: ^1.0.0 - uvu: ^0.5.0 - vfile-message: ^3.0.0 - checksum: e7893f21576bcb7755d341e45d3ff202ba466fa2278c6f31ae4db4002a28d6d13a4efad331ef46223372ec2010d9bc2ff27e2cd57a4580be6491e59ca21ba59d + "@types/estree": ^1.0.0 + devlop: ^1.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-events-to-acorn: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + unist-util-position-from-estree: ^2.0.0 + vfile-message: ^4.0.0 + checksum: f007987092a3bd00617f023d324caff10c63982e5125a3e3ff147baaf03f378e21c47306e2094b8c6480a726c57785c2175b4ffc3f3a6fde8be87e40fbdff068 languageName: node linkType: hard -"micromark-factory-space@npm:^1.0.0": - version: 1.0.0 - resolution: "micromark-factory-space@npm:1.0.0" +"micromark-factory-space@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-space@npm:2.0.1" dependencies: - micromark-util-character: ^1.0.0 - micromark-util-types: ^1.0.0 - checksum: 70d3aafde4e68ef4e509a3b644e9a29e4aada00801279e346577b008cbca06d78051bcd62aa7ea7425856ed73f09abd2b36607803055f726f52607ee7cb706b0 + micromark-util-character: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 1bd68a017c1a66f4787506660c1e1c5019169aac3b1cb075d49ac5e360e0b2065e984d4e1d6e9e52a9d44000f2fa1c98e66a743d7aae78b4b05616bf3242ed71 languageName: node linkType: hard -"micromark-factory-title@npm:^1.0.0": - version: 1.0.2 - resolution: "micromark-factory-title@npm:1.0.2" +"micromark-factory-title@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-title@npm:2.0.1" dependencies: - micromark-factory-space: ^1.0.0 - micromark-util-character: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - uvu: ^0.5.0 - checksum: 9a9cf66babde0bad1e25d6c1087082bfde6dfc319a36cab67c89651cc1a53d0e21cdec83262b5a4c33bff49f0e3c8dc2a7bd464e991d40dbea166a8f9b37e5b2 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: b4d2e4850a8ba0dff25ce54e55a3eb0d43dda88a16293f53953153288f9d84bcdfa8ca4606b2cfbb4f132ea79587bbb478a73092a349f893f5264fbcdbce2ee1 languageName: node linkType: hard -"micromark-factory-whitespace@npm:^1.0.0": - version: 1.0.0 - resolution: "micromark-factory-whitespace@npm:1.0.0" +"micromark-factory-whitespace@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-whitespace@npm:2.0.1" dependencies: - micromark-factory-space: ^1.0.0 - micromark-util-character: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - checksum: 0888386e6ea2dd665a5182c570d9b3d0a172d3f11694ca5a2a84e552149c9f1429f5b975ec26e1f0fa4388c55a656c9f359ce5e0603aff6175ba3e255076f20b + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 67b3944d012a42fee9e10e99178254a04d48af762b54c10a50fcab988688799993efb038daf9f5dbc04001a97b9c1b673fc6f00e6a56997877ab25449f0c8650 languageName: node linkType: hard -"micromark-util-character@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-util-character@npm:1.1.0" +"micromark-util-character@npm:^2.0.0": + version: 2.1.1 + resolution: "micromark-util-character@npm:2.1.1" dependencies: - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - checksum: 504a4e3321f69bddf3fec9f0c1058239fc23336bda5be31d532b150491eda47965a251b37f8a7a9db0c65933b3aaa49cf88044fb1028be3af7c5ee6212bf8d5f + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: e9e409efe4f2596acd44587e8591b722bfc041c1577e8fe0d9c007a4776fb800f9b3637a22862ad2ba9489f4bdf72bb547fce5767dbbfe0a5e6760e2a21c6495 languageName: node linkType: hard -"micromark-util-chunked@npm:^1.0.0": - version: 1.0.0 - resolution: "micromark-util-chunked@npm:1.0.0" +"micromark-util-chunked@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-chunked@npm:2.0.1" dependencies: - micromark-util-symbol: ^1.0.0 - checksum: c1efd56e8c4217bcf1c6f1a9fb9912b4a2a5503b00d031da902be922fb3fee60409ac53f11739991291357b2784fb0647ddfc74c94753a068646c0cb0fd71421 + micromark-util-symbol: ^2.0.0 + checksum: f8cb2a67bcefe4bd2846d838c97b777101f0043b9f1de4f69baf3e26bb1f9885948444e3c3aec66db7595cad8173bd4567a000eb933576c233d54631f6323fe4 languageName: node linkType: hard -"micromark-util-classify-character@npm:^1.0.0": - version: 1.0.0 - resolution: "micromark-util-classify-character@npm:1.0.0" +"micromark-util-classify-character@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-classify-character@npm:2.0.1" dependencies: - micromark-util-character: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - checksum: 180446e6a1dec653f625ded028f244784e1db8d10ad05c5d70f08af9de393b4a03dc6cf6fa5ed8ccc9c24bbece7837abf3bf66681c0b4adf159364b7d5236dfd + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 4d8bbe3a6dbf69ac0fc43516866b5bab019fe3f4568edc525d4feaaaf78423fa54e6b6732b5bccbeed924455279a3758ffc9556954aafb903982598a95a02704 languageName: node linkType: hard -"micromark-util-combine-extensions@npm:^1.0.0": - version: 1.0.0 - resolution: "micromark-util-combine-extensions@npm:1.0.0" +"micromark-util-combine-extensions@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-combine-extensions@npm:2.0.1" dependencies: - micromark-util-chunked: ^1.0.0 - micromark-util-types: ^1.0.0 - checksum: 5304a820ef75340e1be69d6ad167055b6ba9a3bafe8171e5945a935752f462415a9dd61eb3490220c055a8a11167209a45bfa73f278338b7d3d61fa1464d3f35 + micromark-util-chunked: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 5d22fb9ee37e8143adfe128a72b50fa09568c2cc553b3c76160486c96dbbb298c5802a177a10a215144a604b381796071b5d35be1f2c2b2ee17995eda92f0c8e languageName: node linkType: hard -"micromark-util-decode-numeric-character-reference@npm:^1.0.0": - version: 1.0.0 - resolution: "micromark-util-decode-numeric-character-reference@npm:1.0.0" +"micromark-util-decode-numeric-character-reference@npm:^2.0.0": + version: 2.0.2 + resolution: "micromark-util-decode-numeric-character-reference@npm:2.0.2" dependencies: - micromark-util-symbol: ^1.0.0 - checksum: f3ae2bb582a80f1e9d3face026f585c0c472335c064bd850bde152376f0394cb2831746749b6be6e0160f7d73626f67d10716026c04c87f402c0dd45a1a28633 + micromark-util-symbol: ^2.0.0 + checksum: ee11c8bde51e250e302050474c4a2adca094bca05c69f6cdd241af12df285c48c88d19ee6e022b9728281c280be16328904adca994605680c43af56019f4b0b6 languageName: node linkType: hard -"micromark-util-decode-string@npm:^1.0.0": - version: 1.0.2 - resolution: "micromark-util-decode-string@npm:1.0.2" +"micromark-util-decode-string@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-decode-string@npm:2.0.1" dependencies: decode-named-character-reference: ^1.0.0 - micromark-util-character: ^1.0.0 - micromark-util-decode-numeric-character-reference: ^1.0.0 - micromark-util-symbol: ^1.0.0 - checksum: 2dbb41c9691cc71505d39706405139fb7d6699429d577a524c7c248ac0cfd09d3dd212ad8e91c143a00b2896f26f81136edc67c5bda32d20446f0834d261b17a + micromark-util-character: ^2.0.0 + micromark-util-decode-numeric-character-reference: ^2.0.0 + micromark-util-symbol: ^2.0.0 + checksum: e9546ae53f9b5a4f9aa6aaf3e750087100d3429485ca80dbacec99ff2bb15a406fa7d93784a0fc2fe05ad7296b9295e75160ef71faec9e90110b7be2ae66241a languageName: node linkType: hard -"micromark-util-encode@npm:^1.0.0": - version: 1.0.1 - resolution: "micromark-util-encode@npm:1.0.1" - checksum: 9290583abfdc79ea3e7eb92c012c47a0e14327888f8aaa6f57ff79b3058d8e7743716b9d91abca3646f15ab3d78fdad9779fdb4ccf13349cd53309dfc845253a +"micromark-util-encode@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-encode@npm:2.0.1" + checksum: be890b98e78dd0cdd953a313f4148c4692cc2fb05533e56fef5f421287d3c08feee38ca679f318e740530791fc251bfe8c80efa926fcceb4419b269c9343d226 languageName: node linkType: hard -"micromark-util-events-to-acorn@npm:^1.0.0": - version: 1.2.1 - resolution: "micromark-util-events-to-acorn@npm:1.2.1" +"micromark-util-events-to-acorn@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-util-events-to-acorn@npm:2.0.3" dependencies: - "@types/acorn": ^4.0.0 "@types/estree": ^1.0.0 - estree-util-visit: ^1.0.0 - micromark-util-types: ^1.0.0 - uvu: ^0.5.0 - vfile-location: ^4.0.0 - vfile-message: ^3.0.0 - checksum: baf1cad66d860980cf20963f641c48c434e5be5802beabefdda21be136ae037845dd236b5e9ce5cf9409bf1b9ba8b4131a396d3a5bfa12098dae13e4a9724f2b + "@types/unist": ^3.0.0 + devlop: ^1.0.0 + estree-util-visit: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + vfile-message: ^4.0.0 + checksum: 8240f1aa072b3a2ec6df4fb55a0a19dd9f53923125a892da156e378b2af0333557f803f8da5228b03e5b1511c999701f0edbff9e483d00c5af5840f8466fb314 languageName: node linkType: hard -"micromark-util-html-tag-name@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-util-html-tag-name@npm:1.1.0" - checksum: a9b783cec89ec813648d59799464c1950fe281ae797b2a965f98ad0167d7fa1a247718eff023b4c015f47211a172f9446b8e6b98aad50e3cd44a3337317dad2c +"micromark-util-html-tag-name@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-html-tag-name@npm:2.0.1" + checksum: dea365f5ad28ad74ff29fcb581f7b74fc1f80271c5141b3b2bc91c454cbb6dfca753f28ae03730d657874fcbd89d0494d0e3965dfdca06d9855f467c576afa9d languageName: node linkType: hard -"micromark-util-normalize-identifier@npm:^1.0.0": - version: 1.0.0 - resolution: "micromark-util-normalize-identifier@npm:1.0.0" +"micromark-util-normalize-identifier@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-normalize-identifier@npm:2.0.1" dependencies: - micromark-util-symbol: ^1.0.0 - checksum: d7c09d5e8318fb72f194af72664bd84a48a2928e3550b2b21c8fbc0ec22524f2a72e0f6663d2b95dc189a6957d3d7759b60716e888909710767cd557be821f8b + micromark-util-symbol: ^2.0.0 + checksum: 1eb9a289d7da067323df9fdc78bfa90ca3207ad8fd893ca02f3133e973adcb3743b233393d23d95c84ccaf5d220ae7f5a28402a644f135dcd4b8cfa60a7b5f84 languageName: node linkType: hard -"micromark-util-resolve-all@npm:^1.0.0": - version: 1.0.0 - resolution: "micromark-util-resolve-all@npm:1.0.0" +"micromark-util-resolve-all@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-resolve-all@npm:2.0.1" dependencies: - micromark-util-types: ^1.0.0 - checksum: 409667f2bd126ef8acce009270d2aecaaa5584c5807672bc657b09e50aa91bd2e552cf41e5be1e6469244a83349cbb71daf6059b746b1c44e3f35446fef63e50 + micromark-util-types: ^2.0.0 + checksum: 9275f3ddb6c26f254dd2158e66215d050454b279707a7d9ce5a3cd0eba23201021cedcb78ae1a746c1b23227dcc418ee40dd074ade195359506797a5493550cc languageName: node linkType: hard -"micromark-util-sanitize-uri@npm:^1.0.0": - version: 1.1.0 - resolution: "micromark-util-sanitize-uri@npm:1.1.0" +"micromark-util-sanitize-uri@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-sanitize-uri@npm:2.0.1" dependencies: - micromark-util-character: ^1.0.0 - micromark-util-encode: ^1.0.0 - micromark-util-symbol: ^1.0.0 - checksum: fe6093faa0adeb8fad606184d927ce37f207dcc2ec7256438e7f273c8829686245dd6161b597913ef25a3c4fb61863d3612a40cb04cf15f83ba1b4087099996b + micromark-util-character: ^2.0.0 + micromark-util-encode: ^2.0.0 + micromark-util-symbol: ^2.0.0 + checksum: d01517840c17de67aaa0b0f03bfe05fac8a41d99723cd8ce16c62f6810e99cd3695364a34c335485018e5e2c00e69031744630a1b85c6868aa2f2ca1b36daa2f languageName: node linkType: hard -"micromark-util-subtokenize@npm:^1.0.0": - version: 1.0.2 - resolution: "micromark-util-subtokenize@npm:1.0.2" +"micromark-util-subtokenize@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-util-subtokenize@npm:2.1.0" dependencies: - micromark-util-chunked: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.0 - uvu: ^0.5.0 - checksum: c32ee58a7e1384ab1161a9ee02fbb04ad7b6e96d0b8c93dba9803c329a53d07f22ab394c7a96b2e30d6b8fbe3585b85817dba07277b1317111fc234e166bd2d1 + devlop: ^1.0.0 + micromark-util-chunked: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 2e194bc8a5279d256582020500e5072a95c1094571be49043704343032e1fffbe09c862ef9c131cf5c762e296ddb54ff8bc767b3786a798524a68d1db6942934 languageName: node linkType: hard -"micromark-util-symbol@npm:^1.0.0": - version: 1.0.1 - resolution: "micromark-util-symbol@npm:1.0.1" - checksum: c6a3023b3a7432c15864b5e33a1bcb5042ac7aa097f2f452e587bef45433d42d39e0a5cce12fbea91e0671098ba0c3f62a2b30ce1cde66ecbb5e8336acf4391d +"micromark-util-symbol@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-symbol@npm:2.0.1" + checksum: fb7346950550bc85a55793dda94a8b3cb3abc068dbd7570d1162db7aee803411d06c0a5de4ae59cd945f46143bdeadd4bba02a02248fa0d18cc577babaa00044 languageName: node linkType: hard -"micromark-util-types@npm:^1.0.0, micromark-util-types@npm:^1.0.1": - version: 1.0.2 - resolution: "micromark-util-types@npm:1.0.2" - checksum: 08dc901b7c06ee3dfeb54befca05cbdab9525c1cf1c1080967c3878c9e72cb9856c7e8ff6112816e18ead36ce6f99d55aaa91560768f2f6417b415dcba1244df +"micromark-util-types@npm:^2.0.0": + version: 2.0.2 + resolution: "micromark-util-types@npm:2.0.2" + checksum: 884f7974839e4bc6d2bd662e57c973a9164fd5c0d8fe16cddf07472b86a7e6726747c00674952c0321d17685d700cd3295e9f58a842a53acdf6c6d55ab051aab languageName: node linkType: hard -"micromark@npm:^3.0.0": - version: 3.1.0 - resolution: "micromark@npm:3.1.0" +"micromark@npm:^4.0.0": + version: 4.0.2 + resolution: "micromark@npm:4.0.2" dependencies: "@types/debug": ^4.0.0 debug: ^4.0.0 decode-named-character-reference: ^1.0.0 - micromark-core-commonmark: ^1.0.1 - micromark-factory-space: ^1.0.0 - micromark-util-character: ^1.0.0 - micromark-util-chunked: ^1.0.0 - micromark-util-combine-extensions: ^1.0.0 - micromark-util-decode-numeric-character-reference: ^1.0.0 - micromark-util-encode: ^1.0.0 - micromark-util-normalize-identifier: ^1.0.0 - micromark-util-resolve-all: ^1.0.0 - micromark-util-sanitize-uri: ^1.0.0 - micromark-util-subtokenize: ^1.0.0 - micromark-util-symbol: ^1.0.0 - micromark-util-types: ^1.0.1 - uvu: ^0.5.0 - checksum: 5fe5bc3bf92e2ddd37b5f0034080fc3a4d4b3c1130dd5e435bb96ec75e9453091272852e71a4d74906a8fcf992d6f79d794607657c534bda49941e9950a92e28 - languageName: node - linkType: hard - -"micromark@npm:~2.11.0": - version: 2.11.4 - resolution: "micromark@npm:2.11.4" - dependencies: - debug: ^4.0.0 - parse-entities: ^2.0.0 - checksum: f8a5477d394908a5d770227aea71657a76423d420227c67ea0699e659a5f62eb39d504c1f7d69ec525a6af5aaeb6a7bffcdba95614968c03d41d3851edecb0d6 + devlop: ^1.0.0 + micromark-core-commonmark: ^2.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-chunked: ^2.0.0 + micromark-util-combine-extensions: ^2.0.0 + micromark-util-decode-numeric-character-reference: ^2.0.0 + micromark-util-encode: ^2.0.0 + micromark-util-normalize-identifier: ^2.0.0 + micromark-util-resolve-all: ^2.0.0 + micromark-util-sanitize-uri: ^2.0.0 + micromark-util-subtokenize: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 5306c15dd12f543755bc627fc361d4255dfc430e7af6069a07ac0eacc338fbd761fe8e93f02a8bfab6097bab12ee903192fe31389222459d5029242a5aaba3b8 languageName: node linkType: hard @@ -26732,7 +26142,7 @@ __metadata: languageName: node linkType: hard -"mri@npm:^1.1.0, mri@npm:^1.2.0": +"mri@npm:^1.2.0": version: 1.2.0 resolution: "mri@npm:1.2.0" checksum: 83f515abbcff60150873e424894a2f65d68037e5a7fcde8a9e2b285ee9c13ac581b63cfc1e6826c4732de3aeb84902f7c1e16b7aff46cd3f897a0f757a894e85 @@ -26856,13 +26266,6 @@ __metadata: languageName: node linkType: hard -"natural-compare-lite@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare-lite@npm:1.4.0" - checksum: 5222ac3986a2b78dd6069ac62cbb52a7bf8ffc90d972ab76dfe7b01892485d229530ed20d0c62e79a6b363a663b273db3bde195a1358ce9e5f779d4453887225 - languageName: node - linkType: hard - "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" @@ -27218,14 +26621,14 @@ __metadata: languageName: node linkType: hard -"nopt@npm:^7.0.0": - version: 7.0.0 - resolution: "nopt@npm:7.0.0" +"nopt@npm:^7.2.1": + version: 7.2.1 + resolution: "nopt@npm:7.2.1" dependencies: abbrev: ^2.0.0 bin: nopt: bin/nopt.js - checksum: 71d296ea66a00e877ff8dd432d004ae6844f582d2ac203ce191c5e2873a878401093f13193f25352a749ae77d422fe2df1c168f55a720ee5285c85e7de3cb3a3 + checksum: 6fa729cc77ce4162cfad8abbc9ba31d4a0ff6850c3af61d59b505653bef4781ec059f8890ecfe93ee8aa0c511093369cca88bfc998101616a2904e715bbbb7c9 languageName: node linkType: hard @@ -27287,6 +26690,17 @@ __metadata: languageName: node linkType: hard +"normalize-package-data@npm:^6.0.0": + version: 6.0.2 + resolution: "normalize-package-data@npm:6.0.2" + dependencies: + hosted-git-info: ^7.0.0 + semver: ^7.3.5 + validate-npm-package-license: ^3.0.4 + checksum: ea35f8de68e03fc845f545c8197857c0cd256207fdb809ca63c2b39fe76ae77765ee939eb21811fb6c3b533296abf49ebe3cd617064f98a775adaccb24ff2e03 + languageName: node + linkType: hard + "normalize-path@npm:^2.1.1": version: 2.1.1 resolution: "normalize-path@npm:2.1.1" @@ -27328,6 +26742,15 @@ __metadata: languageName: node linkType: hard +"npm-install-checks@npm:^6.0.0": + version: 6.3.0 + resolution: "npm-install-checks@npm:6.3.0" + dependencies: + semver: ^7.1.1 + checksum: 6c20dadb878a0d2f1f777405217b6b63af1299d0b43e556af9363ee6eefaa98a17dfb7b612a473a473e96faf7e789c58b221e0d8ffdc1d34903c4f71618df3b4 + languageName: node + linkType: hard + "npm-install-checks@npm:^7.1.0": version: 7.1.2 resolution: "npm-install-checks@npm:7.1.2" @@ -27379,6 +26802,18 @@ __metadata: languageName: node linkType: hard +"npm-package-arg@npm:^11.0.0": + version: 11.0.3 + resolution: "npm-package-arg@npm:11.0.3" + dependencies: + hosted-git-info: ^7.0.0 + proc-log: ^4.0.0 + semver: ^7.3.5 + validate-npm-package-name: ^5.0.0 + checksum: cc6f22c39201aa14dcceeddb81bfbf7fa0484f94bcd2b3ad038e18afec5167c843cdde90c897f6034dc368faa0100c1eeee6e3f436a89e0af32ba932af4a8c28 + languageName: node + linkType: hard + "npm-package-arg@npm:^12.0.0": version: 12.0.2 resolution: "npm-package-arg@npm:12.0.2" @@ -27437,6 +26872,18 @@ __metadata: languageName: node linkType: hard +"npm-pick-manifest@npm:^9.0.0": + version: 9.1.0 + resolution: "npm-pick-manifest@npm:9.1.0" + dependencies: + npm-install-checks: ^6.0.0 + npm-normalize-package-bin: ^3.0.0 + npm-package-arg: ^11.0.0 + semver: ^7.3.5 + checksum: cbaad1e1420869efa851e8ba5d725263f679779e15bfca3713ec3ee1e897efab254e75c5445f442ffc96453cdfb15d362d25b0c0fcb03b156fe1653f9220cc40 + languageName: node + linkType: hard + "npm-registry-fetch@npm:19.1.0": version: 19.1.0 resolution: "npm-registry-fetch@npm:19.1.0" @@ -27962,17 +27409,17 @@ __metadata: languageName: node linkType: hard -"optionator@npm:^0.9.1": - version: 0.9.1 - resolution: "optionator@npm:0.9.1" +"optionator@npm:^0.9.3": + version: 0.9.4 + resolution: "optionator@npm:0.9.4" dependencies: deep-is: ^0.1.3 fast-levenshtein: ^2.0.6 levn: ^0.4.1 prelude-ls: ^1.2.1 type-check: ^0.4.0 - word-wrap: ^1.2.3 - checksum: dbc6fa065604b24ea57d734261914e697bd73b69eff7f18e967e8912aa2a40a19a9f599a507fa805be6c13c24c4eae8c71306c239d517d42d4c041c942f508a0 + word-wrap: ^1.2.5 + checksum: ecbd010e3dc73e05d239976422d9ef54a82a13f37c11ca5911dff41c98a6c7f0f163b27f922c37e7f8340af9d36febd3b6e9cef508f3339d4c393d7276d716bb languageName: node linkType: hard @@ -28030,6 +27477,27 @@ __metadata: languageName: node linkType: hard +"ox@npm:^0.14.6": + version: 0.14.10 + resolution: "ox@npm:0.14.10" + dependencies: + "@adraffy/ens-normalize": ^1.11.0 + "@noble/ciphers": ^1.3.0 + "@noble/curves": 1.9.1 + "@noble/hashes": ^1.8.0 + "@scure/bip32": ^1.7.0 + "@scure/bip39": ^1.6.0 + abitype: ^1.2.3 + eventemitter3: 5.0.1 + peerDependencies: + typescript: ">=5.4.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: faa5ed649458fa9f1daa2e4ee85e012676a5b4162f1aa37440246aaade8567410a7071e8459c194e30aa1cbaac7289a017a06c68e3555f4a1cc22b09325cd51a + languageName: node + linkType: hard + "p-finally@npm:^1.0.0": version: 1.0.0 resolution: "p-finally@npm:1.0.0" @@ -28398,20 +27866,6 @@ __metadata: languageName: node linkType: hard -"parse-entities@npm:^2.0.0": - version: 2.0.0 - resolution: "parse-entities@npm:2.0.0" - dependencies: - character-entities: ^1.0.0 - character-entities-legacy: ^1.0.0 - character-reference-invalid: ^1.0.0 - is-alphanumerical: ^1.0.0 - is-decimal: ^1.0.0 - is-hexadecimal: ^1.0.0 - checksum: 7addfd3e7d747521afac33c8121a5f23043c6973809756920d37e806639b4898385d386fcf4b3c8e2ecf1bc28aac5ae97df0b112d5042034efbe80f44081ebce - languageName: node - linkType: hard - "parse-entities@npm:^4.0.0": version: 4.0.1 resolution: "parse-entities@npm:4.0.1" @@ -28462,15 +27916,16 @@ __metadata: languageName: node linkType: hard -"parse-json@npm:^6.0.0": - version: 6.0.2 - resolution: "parse-json@npm:6.0.2" +"parse-json@npm:^7.0.0": + version: 7.1.1 + resolution: "parse-json@npm:7.1.1" dependencies: - "@babel/code-frame": ^7.16.0 + "@babel/code-frame": ^7.21.4 error-ex: ^1.3.2 - json-parse-even-better-errors: ^2.3.1 - lines-and-columns: ^2.0.2 - checksum: b33d93abf869f3102804896b9a1f8c04bf371e3c55d7afafaf18fca2813a20b2e14a1ae5c6823feea3b4fabc63f35984dc272fa057c4767531ffe1b46d52fa79 + json-parse-even-better-errors: ^3.0.0 + lines-and-columns: ^2.0.3 + type-fest: ^3.8.0 + checksum: 187275c7ac097dcfb3c7420bca2399caa4da33bcd5d5aac3604bda0e2b8eee4df61cc26aa0d79fab97f0d67bf42d41d332baa9f9f56ad27636ad785f1ae639e5 languageName: node linkType: hard @@ -29713,10 +29168,10 @@ __metadata: languageName: node linkType: hard -"proc-log@npm:^3.0.0": - version: 3.0.0 - resolution: "proc-log@npm:3.0.0" - checksum: 02b64e1b3919e63df06f836b98d3af002b5cd92655cab18b5746e37374bfb73e03b84fe305454614b34c25b485cc687a9eebdccf0242cda8fda2475dd2c97e02 +"proc-log@npm:^4.0.0, proc-log@npm:^4.2.0": + version: 4.2.0 + resolution: "proc-log@npm:4.2.0" + checksum: 98f6cd012d54b5334144c5255ecb941ee171744f45fca8b43b58ae5a0c1af07352475f481cadd9848e7f0250376ee584f6aa0951a856ff8f021bdfbff4eb33fc languageName: node linkType: hard @@ -29851,15 +29306,6 @@ __metadata: languageName: node linkType: hard -"propose@npm:0.0.5": - version: 0.0.5 - resolution: "propose@npm:0.0.5" - dependencies: - levenshtein-edit-distance: ^1.0.0 - checksum: ad472212772dd0ef60cafa859f140176243bd318c989f76577d0bb3a18cb425c1db2aab30986e325946fdc130cb11fe3d34274220d29b3535de61427b0dd922b - languageName: node - linkType: hard - "protobufjs@npm:6.11.3, protobufjs@npm:^6.11.2, protobufjs@npm:^6.11.3, protobufjs@npm:^6.8.8, protobufjs@npm:~6.11.2, protobufjs@npm:~6.11.3": version: 6.11.3 resolution: "protobufjs@npm:6.11.3" @@ -30422,7 +29868,7 @@ __metadata: languageName: node linkType: hard -"read-package-json-fast@npm:^3.0.0, read-package-json-fast@npm:^3.0.2": +"read-package-json-fast@npm:^3.0.0": version: 3.0.2 resolution: "read-package-json-fast@npm:3.0.2" dependencies: @@ -30533,6 +29979,13 @@ __metadata: languageName: node linkType: hard +"readdirp@npm:^4.0.1": + version: 4.1.2 + resolution: "readdirp@npm:4.1.2" + checksum: 3242ee125422cb7c0e12d51452e993f507e6ed3d8c490bc8bf3366c5cdd09167562224e429b13e9cb2b98d4b8b2b11dc100d3c73883aa92d657ade5a21ded004 + languageName: node + linkType: hard + "readdirp@npm:~3.6.0": version: 3.6.0 resolution: "readdirp@npm:3.6.0" @@ -30748,13 +30201,6 @@ __metadata: languageName: node linkType: hard -"regexpp@npm:^3.2.0": - version: 3.2.0 - resolution: "regexpp@npm:3.2.0" - checksum: a78dc5c7158ad9ddcfe01aa9144f46e192ddbfa7b263895a70a5c6c73edd9ce85faf7c0430e59ac38839e1734e275b9c3de5c57ee3ab6edc0e0b1bdebefccef8 - languageName: node - linkType: hard - "regexpu-core@npm:^4.7.1": version: 4.7.1 resolution: "regexpu-core@npm:4.7.1" @@ -30853,876 +30299,25 @@ __metadata: languageName: node linkType: hard -"remark-frontmatter@npm:^4.0.1": - version: 4.0.1 - resolution: "remark-frontmatter@npm:4.0.1" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-frontmatter: ^1.0.0 - micromark-extension-frontmatter: ^1.0.0 - unified: ^10.0.0 - checksum: c1c448923cd0239e9eeafb42d7129c05081c9a1bca4c8164b562cbb748e80d103bfd058597a48d54000ce3c776200ab8ccd64a9679d955423f07e4a4e77f10c3 - languageName: node - linkType: hard - -"remark-gfm@npm:^3.0.1": - version: 3.0.1 - resolution: "remark-gfm@npm:3.0.1" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-gfm: ^2.0.0 - micromark-extension-gfm: ^2.0.0 - unified: ^10.0.0 - checksum: 02254f74d67b3419c2c9cf62d799ec35f6c6cd74db25c001361751991552a7ce86049a972107bff8122d85d15ae4a8d1a0618f3bc01a7df837af021ae9b2a04e - languageName: node - linkType: hard - -"remark-lint-blockquote-indentation@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-blockquote-indentation@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - pluralize: ^8.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 605636c4bf43ab98948e08302dedaf60aa6f16a9f40696b5685e99e22ef647b56415a3e7d803f20003ff1c57e310f784d9fc14e2c2caf78d4e17664a84f51696 - languageName: node - linkType: hard - -"remark-lint-checkbox-character-style@npm:^4.0.0": - version: 4.1.1 - resolution: "remark-lint-checkbox-character-style@npm:4.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 7e35509f4bab21a697a0d4d8484b97c9c58cda775dda42a7f9133a1e60b8c966d32fc292e20c3c6b250b42103b0e1a8aa01db8210c34f2da87fcb4f988bcf767 - languageName: node - linkType: hard - -"remark-lint-code-block-style@npm:^3.0.0": - version: 3.1.0 - resolution: "remark-lint-code-block-style@npm:3.1.0" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 7fe60387a9f006928a7fc3265eaa4edda2b715d1ea5f3b6032fe75831e28631b3e7b563729b6093ddcae43e0356e19c22c0d373a748d4ed1d30d1d3b5eb5a339 - languageName: node - linkType: hard - -"remark-lint-definition-case@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-definition-case@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 00e19d692ae029b0e47afd1633c596108f948eff861c77134892aed05bd139aab3dfa858b1b55db3d865412369d0e2af1d9e1fed35cf4ed582dc94cf6977059f - languageName: node - linkType: hard - -"remark-lint-definition-spacing@npm:^3.0.0": +"remark-mdx@npm:^3.1.0": version: 3.1.1 - resolution: "remark-lint-definition-spacing@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 4d8ae38fd24225f0f89d2dddc3eab505ed6f2eea4683c10a8e398c89545b485d8fcb475204ccacf1a37c7305bdd2bca6a7383947e404de5b164b913cd12a42d2 - languageName: node - linkType: hard - -"remark-lint-emphasis-marker@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-emphasis-marker@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: db84e912a84ba2b5717d53bccb2393f8d132760c54b28d6a9b842439592e564d7eafeb4dd49ab859d9bf31b1693893728c1e047a451477da8d3b12450babf7d3 - languageName: node - linkType: hard - -"remark-lint-fenced-code-flag@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-fenced-code-flag@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 729b8fd83df0df4f61ac92e9f56a9ddddbe68ef88c54d24d982620bfd302d720789d887b2338d57a5318cffda4ddff2ae76b89a404c56eb17826c87cf419c3f7 - languageName: node - linkType: hard - -"remark-lint-fenced-code-marker@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-fenced-code-marker@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 7ce47fb1a3c457a52ef0044f619b9e6dbe8706a42c457eb56d063f75c6db8826253ac8dab5c4cb9cdcd89feb35a7997e30830a544fbca9e2b508923d743d2529 - languageName: node - linkType: hard - -"remark-lint-file-extension@npm:^2.0.0": - version: 2.1.1 - resolution: "remark-lint-file-extension@npm:2.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - checksum: 70bc12640e3d43bb81475f51d6156bbf0bb9829ce8a9ea26e893680d091f2f72ed9ac921364e1d654a628ec1f5666536a412a5e885f2c004e6d2857a04f7506e - languageName: node - linkType: hard - -"remark-lint-final-definition@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-final-definition@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 2bf203f268923e2e91a6bb5443ccfa400cc4c3d33f476bc676d549ff9a29263ba33ff4cd319a63786a649883c112de32f898ee082cb3ba098088f961f016b5fe - languageName: node - linkType: hard - -"remark-lint-final-newline@npm:^2.0.0": - version: 2.1.1 - resolution: "remark-lint-final-newline@npm:2.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - checksum: d68291b1794dfa67d6b5cca1dd73ce3032dafd845efaf9e0514cf3361c9a495245fef975aaf72a987be8859bea22cd3b0b5b744cff7320d42ab1b67dae0cfe8d - languageName: node - linkType: hard - -"remark-lint-hard-break-spaces@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-hard-break-spaces@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 8e84b0c66ef8aefedd0ff36f8ce7bf4db1434ab591f21184d8b922622d9ed2ed6cb8c8d612d4c409cfeed11701a704625f4787b51018ff3e6cb67f66e4f71d10 - languageName: node - linkType: hard - -"remark-lint-heading-increment@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-heading-increment@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-visit: ^4.0.0 - checksum: 2895b5849e6fbf9436451c637b39aea3db9083766d9bd0178300f18096be4c1c4022dc049ea044ed3f766c0314ef03937e38603c6fbe4fecedacd24b647be03b - languageName: node - linkType: hard - -"remark-lint-heading-style@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-heading-style@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-heading-style: ^2.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-visit: ^4.0.0 - checksum: fb5ee308a4b4d64e8039dfdfddf20406e5164002c245955b29d99facad2e21af911d8ef10b26640ab0d1e3efe3a657afc9affd42f9ae9aeefa79e781ffd4c571 - languageName: node - linkType: hard - -"remark-lint-link-title-style@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-link-title-style@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - vfile-location: ^4.0.0 - checksum: 29b38865fb9378390ab8818d4e121b77315ec525275e9c5c249c7b2c55e3bc359a2f17aa200c3343ad6d0926795a48ec78dddd10b061cf23b4126727af5435ed - languageName: node - linkType: hard - -"remark-lint-list-item-bullet-indent@npm:^4.0.0": - version: 4.1.1 - resolution: "remark-lint-list-item-bullet-indent@npm:4.1.1" - dependencies: - "@types/mdast": ^3.0.0 - pluralize: ^8.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-visit: ^4.0.0 - checksum: 8248285196970ad5f84ab94db3cf64a6083012a07a06649acfa5bb4a22a8786221d67d6752d22a49ce14bd1e61dd69a51ee24f8277d05690843e24b89d482d09 - languageName: node - linkType: hard - -"remark-lint-list-item-content-indent@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-list-item-content-indent@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - pluralize: ^8.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: ac1ea5f482af848050def5f550cbe0a42e610ce3cb200d54ab19d485fe923a80ee333e8cd005084ce0db5a834fce84b262547b43bb8f95f2c419ccee83ec7b0b - languageName: node - linkType: hard - -"remark-lint-list-item-indent@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-list-item-indent@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - pluralize: ^8.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 955c670d1617e3193a328624225cf52f1c59a75b65045dac8a644909ac834f65ab02b7647996d7e6f6a98456527f1cb4f3d4fa8a3be67e5ce51500bc4940d2ff - languageName: node - linkType: hard - -"remark-lint-list-item-spacing@npm:^4.0.0": - version: 4.1.1 - resolution: "remark-lint-list-item-spacing@npm:4.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 1c75e05572741e4e9b3ad65beaea85bd226196959c683017cef56ccb927d0f34ed4cdb4bad0074b1145e9b7b0c29c713c7dcec73a48c6625f8e38a112cdfde56 - languageName: node - linkType: hard - -"remark-lint-maximum-heading-length@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-maximum-heading-length@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-to-string: ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-visit: ^4.0.0 - checksum: d477a436c07a410cb82600965a5f94c597398007f84fbcb9880db6f8b17fdb01194b394923a3d61c812402b38b3f58ce161216ee14b5a6e9ac8a02fac1b8d4f2 - languageName: node - linkType: hard - -"remark-lint-maximum-line-length@npm:^3.0.0": - version: 3.1.2 - resolution: "remark-lint-maximum-line-length@npm:3.1.2" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 1370014b718b8cc34f6a740d30bb91f404fb67b9cc8952297933e9f608cd75bcd72fc183ad686ab45aeedf1d4a37ad523d2768226d42b604e32a31edf0f99ab2 - languageName: node - linkType: hard - -"remark-lint-no-blockquote-without-marker@npm:^5.0.0": - version: 5.1.1 - resolution: "remark-lint-no-blockquote-without-marker@npm:5.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - vfile-location: ^4.0.0 - checksum: 73d4583dbec06c206ed1ceeb754135117c478fa3c1e118c15446863910514ded3653f05f826b43f514728a6c0b3a6f26d463052fb8d2942c72df0c3b1a45be07 - languageName: node - linkType: hard - -"remark-lint-no-consecutive-blank-lines@npm:^4.0.0": - version: 4.1.2 - resolution: "remark-lint-no-consecutive-blank-lines@npm:4.1.2" - dependencies: - "@types/mdast": ^3.0.0 - "@types/unist": ^2.0.0 - pluralize: ^8.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 1c4d38ac356deb66a86c1f0d9a7b4c47630467b692ca82800d425177db9ed4c678fe553436228606b2d7804d37abae0370f1b75c5b5afc350d19e53375aa7cd2 - languageName: node - linkType: hard - -"remark-lint-no-duplicate-definitions@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-no-duplicate-definitions@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-stringify-position: ^3.0.0 - unist-util-visit: ^4.0.0 - checksum: a8de885eb64f521429ececfa72ea5d736c3a54c636c1d0c2c9aaf82c28cbb4c33a912d1caae5ae011635d36a40e550fb146be3d637e0968d573dbda465117a97 - languageName: node - linkType: hard - -"remark-lint-no-duplicate-headings-in-section@npm:^3.1.1": - version: 3.1.1 - resolution: "remark-lint-no-duplicate-headings-in-section@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-to-string: ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-stringify-position: ^3.0.0 - unist-util-visit: ^4.0.0 - checksum: cad91c4d75a36b370c511925c7aa34c9e528c07e11353d49a0cfec204422b4315b1b6ba8eef47e87e15e9e0e3cc039c57e22735d2156acf99d1e439312d837b8 - languageName: node - linkType: hard - -"remark-lint-no-duplicate-headings@npm:^3.0.0, remark-lint-no-duplicate-headings@npm:^3.1.1": - version: 3.1.1 - resolution: "remark-lint-no-duplicate-headings@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-to-string: ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-stringify-position: ^3.0.0 - unist-util-visit: ^4.0.0 - checksum: 81baa468d1e90664a0777041bde07483c3611e8d154989c9e411662be14eed6420b43b1f1308ef34907ddf9d5973639439487534cf34a42227cce430388eabef - languageName: node - linkType: hard - -"remark-lint-no-emphasis-as-heading@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-no-emphasis-as-heading@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-visit: ^4.0.0 - checksum: 751937ce6eb19ac57c0b654e5585a0e0bb67e36f3353030ec5720bde3357bdf9c6791aeca90c02ba336a5a84b18b51b708d9bc5ffa0f05f5696d83f21785ed28 - languageName: node - linkType: hard - -"remark-lint-no-file-name-articles@npm:^2.0.0": - version: 2.1.1 - resolution: "remark-lint-no-file-name-articles@npm:2.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - checksum: 9b23f833a4983900e4944521f4728eeb6a1ad26608fe91ec2e7b9d4c4571f9fb01961f08cf5c3e3f0e9ebe26d58afaca0301a28ce965d174d2c521d1bf50fe88 - languageName: node - linkType: hard - -"remark-lint-no-file-name-consecutive-dashes@npm:^2.0.0": - version: 2.1.1 - resolution: "remark-lint-no-file-name-consecutive-dashes@npm:2.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - checksum: 860d037031af9cbcad696776a0f62f60d8b38b853582980b414a3463c8753d88d24e02db48266e2ab63894266d6122ab8cd47ba09ec01f0382f3035f3ace66ec - languageName: node - linkType: hard - -"remark-lint-no-file-name-irregular-characters@npm:^2.0.0": - version: 2.1.1 - resolution: "remark-lint-no-file-name-irregular-characters@npm:2.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - checksum: 67a89de0022bcf6a4ed84b47f36eb5dc5c60f407dffe745a16c81c6f69687008665a7bad37ea6f21fffd777d7a7fd87d6607bec1a8982add7eeb7ef64ed144eb - languageName: node - linkType: hard - -"remark-lint-no-file-name-mixed-case@npm:^2.0.0": - version: 2.1.1 - resolution: "remark-lint-no-file-name-mixed-case@npm:2.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - checksum: 242641391e330c2f2229c606fbcaaf8cefc1aab4dc244d63cac328710af06c22eb5eda912cfff49b7b81f4fc0a617195fb16c4a958b187913dd1b9643012deb5 - languageName: node - linkType: hard - -"remark-lint-no-file-name-outer-dashes@npm:^2.0.0": - version: 2.1.1 - resolution: "remark-lint-no-file-name-outer-dashes@npm:2.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - checksum: 455ce51f8e90835a943f61797882103386623ecea102a9abf233009d068b35b68116b1c66487c7cd2acec28e200abdac0ff92c95ac271413a5e0d52ba8508959 - languageName: node - linkType: hard - -"remark-lint-no-heading-content-indent@npm:^4.0.0": - version: 4.1.1 - resolution: "remark-lint-no-heading-content-indent@npm:4.1.1" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-heading-style: ^2.0.0 - pluralize: ^8.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 086eaffdfae19116cda175b0a803c444350f86059e9486d7f1a6b30138d53ff6e0a06c6587942aeff5850b226974be768e244e4b8575fa7b0271b714049b2bfa - languageName: node - linkType: hard - -"remark-lint-no-heading-punctuation@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-no-heading-punctuation@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-to-string: ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-visit: ^4.0.0 - checksum: 9f15c8b0767c5b05538b0ad333e6b24c57680375ed15fe929ec7481fac709afd9af708fb369bef6c89d972cfb168fe0f7dcc2f128cbb96a7b9dfa17ccbec8bad - languageName: node - linkType: hard - -"remark-lint-no-inline-padding@npm:^4.0.0": - version: 4.1.1 - resolution: "remark-lint-no-inline-padding@npm:4.1.1" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-to-string: ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-visit: ^4.0.0 - checksum: fab21dc8fb4418b1bab16bb1b80742dea44a1ce560d83d6dc6019990a22af6a339c533d1c01d6e04f006ebd5f2875928971bcdb70732c149a5b8deb6e59d17b4 - languageName: node - linkType: hard - -"remark-lint-no-literal-urls@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-no-literal-urls@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-to-string: ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 305d0d24dbd14c0bd4bc843f2298eda92861fb1ce77f3079a1b89a52e620f35b52b12510f09006cc2e02bd356e0d80dec92d2615b09c5f6ef940c9116f70f499 - languageName: node - linkType: hard - -"remark-lint-no-multiple-toplevel-headings@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-no-multiple-toplevel-headings@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-stringify-position: ^3.0.0 - unist-util-visit: ^4.0.0 - checksum: dd462c590887bfa15c1551c832cfb7ce5db49645803751c695a14576d1d53c4ee2d83e18bc5549ec2b521e0eaf7804b313f15cf1ef2a614a8a2a26edbedd93d7 - languageName: node - linkType: hard - -"remark-lint-no-shell-dollars@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-no-shell-dollars@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-visit: ^4.0.0 - checksum: df675246299fb833151a3bf227902e85ca20c8990be5e80693ae4b2235cae5f913118940a2ceb11ee1233b4be7f4dac14ad25b445c2cf1d6f0b8246f9021fc65 - languageName: node - linkType: hard - -"remark-lint-no-shortcut-reference-image@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-no-shortcut-reference-image@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-visit: ^4.0.0 - checksum: 8ad48be913dac09b9c1f78c1a5b91b98684d1ae93e3d4a78aad19ec5ffaa17172114c2ccaf947b256a510e26e80d72255df859159f621b4e13bcac8003c2c59d - languageName: node - linkType: hard - -"remark-lint-no-shortcut-reference-link@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-no-shortcut-reference-link@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-visit: ^4.0.0 - checksum: c3b78bc0cbce6551dc47f4beda7e2e5c6a5f1f22e895d1d11865897c13f6105cd458a4b11a75576b503e2cff82b9d8de763326344323d6058a45b4b3114b018b - languageName: node - linkType: hard - -"remark-lint-no-table-indentation@npm:^4.0.0": - version: 4.1.1 - resolution: "remark-lint-no-table-indentation@npm:4.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - vfile-location: ^4.0.0 - checksum: d594b79ba404c244fa13b966008abe57e8db754ea253d963be3a5bd2ba0de207fb52e8ca9020aa0f898dcdeb67e576397d5f19ae3b67b7d35693ff9b1bbfb209 - languageName: node - linkType: hard - -"remark-lint-no-undefined-references@npm:^4.0.0": - version: 4.2.0 - resolution: "remark-lint-no-undefined-references@npm:4.2.0" + resolution: "remark-mdx@npm:3.1.1" dependencies: - "@types/mdast": ^3.0.0 - micromark-util-normalize-identifier: ^1.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - vfile-location: ^4.0.0 - checksum: effedeb3f06dab28f6d8e7dbb664d18215eff328b3ee2a29b6061d54f4a825b571003d976d6daa3d04df332c66755c31a78b62da61679c2cc164bb4cfcca2942 + mdast-util-mdx: ^3.0.0 + micromark-extension-mdxjs: ^3.0.0 + checksum: 9e6406ba83e545b5232ce98de71c29ad5746c2d920eed070a2c58687412453875bad52dfdfaf21bee6de59d3a45fa84cf785b3111c5eb4822f29b67cf1dfec96 languageName: node linkType: hard -"remark-lint-no-unused-definitions@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-no-unused-definitions@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-visit: ^4.0.0 - checksum: 959e5d4e508c9265a846a3a23256f15f47a7f5bbed22f5c9494e190cd117ef3a44dbe429d2e53bf801d3bd1116549386be0c68c6ff4ee641d62fbb944fe775a1 - languageName: node - linkType: hard - -"remark-lint-ordered-list-marker-style@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-ordered-list-marker-style@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: b7437f7176772aae80732402c4d2d7e13e84c0fe41dbaebf0db157b15b634057cd424f723d0fe6be2af31965a970359a5f0fe9116f948d555d25b51dc141bbc6 - languageName: node - linkType: hard - -"remark-lint-ordered-list-marker-value@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-ordered-list-marker-value@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 532c0733d07225e3fc312afe3662ea09f04b8b42eca872c5d962830cd6b8a54773222292f2224306de3cabf1a65f3023cd4bd45d77430314283b1a7332169177 - languageName: node - linkType: hard - -"remark-lint-rule-style@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-rule-style@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: e2899cfd21c530043e31eb52154eacc1a7f046945848fe227b5061a959ed896c48d108a567d85aefb2b0b8b9613c35aff2ce7cbd0e3c63774f3a924bcdd11e37 - languageName: node - linkType: hard - -"remark-lint-strong-marker@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-strong-marker@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: af837e372ead8d8090f5bfe45dcef5034704e2b8b9690c0b0fb10fed9a60809d21b402d00065a96bde9195172b87bb83f65228f4351b872b48e61c6d75d8cea9 - languageName: node - linkType: hard - -"remark-lint-table-cell-padding@npm:^4.0.0": - version: 4.1.2 - resolution: "remark-lint-table-cell-padding@npm:4.1.2" - dependencies: - "@types/mdast": ^3.0.0 - "@types/unist": ^2.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 432e5c774ee1125caa93c0306b70b4f8f91e41c0a06c18454b1cd80bb22af063822529a77233983a26d2a9d8865e9a1727efb3739510cc92102da39aa0472ed3 - languageName: node - linkType: hard - -"remark-lint-table-pipe-alignment@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-table-pipe-alignment@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 0dfe58de4ea5676f07e5a7c8ccea89ce3906539e801c51541b8f488c251ef8cd44ab2e24e09a6d20ca7bac0ca0ebbd529ff71bafe2874a21a890ab01c47335e2 - languageName: node - linkType: hard - -"remark-lint-table-pipes@npm:^4.0.0": - version: 4.1.1 - resolution: "remark-lint-table-pipes@npm:4.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 14c973a5ef4372d25c4807cf00236be832388dd93cdab655bc7f5db9e234955b7bde08775221eb1553525d1a08b57fcdc8714c7d43e0e37fd1cd560cdd4fd727 - languageName: node - linkType: hard - -"remark-lint-unordered-list-marker-style@npm:^3.0.0": - version: 3.1.1 - resolution: "remark-lint-unordered-list-marker-style@npm:3.1.1" - dependencies: - "@types/mdast": ^3.0.0 - unified: ^10.0.0 - unified-lint-rule: ^2.0.0 - unist-util-generated: ^2.0.0 - unist-util-position: ^4.0.0 - unist-util-visit: ^4.0.0 - checksum: 226f572a00dc2f29ca0e085a12e0490a7e1d9e6508aa02f42d8b6c35be4b880f9d915aca2e2a72b92e96ac3c165a83810ca6599f386df7ec5ec999c74dbf0e07 - languageName: node - linkType: hard - -"remark-lint@npm:^9.0.0, remark-lint@npm:^9.1.1": - version: 9.1.1 - resolution: "remark-lint@npm:9.1.1" - dependencies: - "@types/mdast": ^3.0.0 - remark-message-control: ^7.0.0 - unified: ^10.1.0 - checksum: c5a2ca78fd9fca028cfd178b07782c4be543b56572e60bdc66032485ef5f043f7090a6026d1e4c7f56001af3783fde4d4c93e2f0035ba2e2dc60ecb51d898b17 - languageName: node - linkType: hard - -"remark-mdx@npm:^2.1.3": - version: 2.3.0 - resolution: "remark-mdx@npm:2.3.0" - dependencies: - mdast-util-mdx: ^2.0.0 - micromark-extension-mdxjs: ^1.0.0 - checksum: 98486986c5b6f6a8321eb2f3b13c70fcd5644821428c77b7bfeb5ee5d4605b9761b322b2f6b531e83883cd2d5bc7bc4623427149aee00e1eba012f538b3d5627 - languageName: node - linkType: hard - -"remark-message-control@npm:^7.0.0": - version: 7.1.1 - resolution: "remark-message-control@npm:7.1.1" - dependencies: - "@types/mdast": ^3.0.0 - mdast-comment-marker: ^2.0.0 - unified: ^10.0.0 - unified-message-control: ^4.0.0 - vfile: ^5.0.0 - checksum: ac6058e93b07c9cb46a828e89b6f372063b76f4c41283358c2913c10e69076cba35401189c0a0eb2a60b7c31714dd30430e770346b2a0ac8ba6b81572345fdd9 - languageName: node - linkType: hard - -"remark-parse@npm:^10.0.1": - version: 10.0.1 - resolution: "remark-parse@npm:10.0.1" +"remark-parse@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-parse@npm:11.0.0" dependencies: - "@types/mdast": ^3.0.0 - mdast-util-from-markdown: ^1.0.0 - unified: ^10.0.0 - checksum: 505088e564ab53ff054433368adbb7b551f69240c7d9768975529837a86f1d0f085e72d6211929c5c42db315273df4afc94f3d3a8662ffdb69468534c6643d29 - languageName: node - linkType: hard - -"remark-preset-lint-consistent@npm:^5.1.1": - version: 5.1.1 - resolution: "remark-preset-lint-consistent@npm:5.1.1" - dependencies: - "@types/mdast": ^3.0.0 - remark-lint: ^9.0.0 - remark-lint-blockquote-indentation: ^3.0.0 - remark-lint-checkbox-character-style: ^4.0.0 - remark-lint-code-block-style: ^3.0.0 - remark-lint-emphasis-marker: ^3.0.0 - remark-lint-fenced-code-marker: ^3.0.0 - remark-lint-heading-style: ^3.0.0 - remark-lint-link-title-style: ^3.0.0 - remark-lint-list-item-content-indent: ^3.0.0 - remark-lint-ordered-list-marker-style: ^3.0.0 - remark-lint-rule-style: ^3.0.0 - remark-lint-strong-marker: ^3.0.0 - remark-lint-table-cell-padding: ^4.0.0 - unified: ^10.0.0 - checksum: ee4b70662e7b6686a18940df6f3886bac58a94e80a048df2b9e79d4e155460556a5be16a6f211c72fd241fb8d081f17a0c04ab6628f1058166a62eb89a4ed3b4 - languageName: node - linkType: hard - -"remark-preset-lint-markdown-style-guide@npm:^5.1.2": - version: 5.1.2 - resolution: "remark-preset-lint-markdown-style-guide@npm:5.1.2" - dependencies: - "@types/mdast": ^3.0.0 - remark-lint: ^9.0.0 - remark-lint-blockquote-indentation: ^3.0.0 - remark-lint-code-block-style: ^3.0.0 - remark-lint-definition-case: ^3.0.0 - remark-lint-definition-spacing: ^3.0.0 - remark-lint-emphasis-marker: ^3.0.0 - remark-lint-fenced-code-flag: ^3.0.0 - remark-lint-fenced-code-marker: ^3.0.0 - remark-lint-file-extension: ^2.0.0 - remark-lint-final-definition: ^3.0.0 - remark-lint-hard-break-spaces: ^3.0.0 - remark-lint-heading-increment: ^3.0.0 - remark-lint-heading-style: ^3.0.0 - remark-lint-link-title-style: ^3.0.0 - remark-lint-list-item-content-indent: ^3.0.0 - remark-lint-list-item-indent: ^3.0.0 - remark-lint-list-item-spacing: ^4.0.0 - remark-lint-maximum-heading-length: ^3.0.0 - remark-lint-maximum-line-length: ^3.0.0 - remark-lint-no-blockquote-without-marker: ^5.0.0 - remark-lint-no-consecutive-blank-lines: ^4.0.0 - remark-lint-no-duplicate-headings: ^3.0.0 - remark-lint-no-emphasis-as-heading: ^3.0.0 - remark-lint-no-file-name-articles: ^2.0.0 - remark-lint-no-file-name-consecutive-dashes: ^2.0.0 - remark-lint-no-file-name-irregular-characters: ^2.0.0 - remark-lint-no-file-name-mixed-case: ^2.0.0 - remark-lint-no-file-name-outer-dashes: ^2.0.0 - remark-lint-no-heading-punctuation: ^3.0.0 - remark-lint-no-inline-padding: ^4.0.0 - remark-lint-no-literal-urls: ^3.0.0 - remark-lint-no-multiple-toplevel-headings: ^3.0.0 - remark-lint-no-shell-dollars: ^3.0.0 - remark-lint-no-shortcut-reference-image: ^3.0.0 - remark-lint-no-shortcut-reference-link: ^3.0.0 - remark-lint-no-table-indentation: ^4.0.0 - remark-lint-ordered-list-marker-style: ^3.0.0 - remark-lint-ordered-list-marker-value: ^3.0.0 - remark-lint-rule-style: ^3.0.0 - remark-lint-strong-marker: ^3.0.0 - remark-lint-table-cell-padding: ^4.0.0 - remark-lint-table-pipe-alignment: ^3.0.0 - remark-lint-table-pipes: ^4.0.0 - remark-lint-unordered-list-marker-style: ^3.0.0 - unified: ^10.0.0 - checksum: 795f9d3a6e406f8d449afadaf14d584e3680e3e89d00706b02ba7985efddb1b2243aa73ea668ee8eb53d9987f00d92511039c91dc359bc49a3850329a9e11c5a - languageName: node - linkType: hard - -"remark-preset-lint-recommended@npm:^6.1.2": - version: 6.1.2 - resolution: "remark-preset-lint-recommended@npm:6.1.2" - dependencies: - "@types/mdast": ^3.0.0 - remark-lint: ^9.0.0 - remark-lint-final-newline: ^2.0.0 - remark-lint-hard-break-spaces: ^3.0.0 - remark-lint-list-item-bullet-indent: ^4.0.0 - remark-lint-list-item-indent: ^3.0.0 - remark-lint-no-blockquote-without-marker: ^5.0.0 - remark-lint-no-duplicate-definitions: ^3.0.0 - remark-lint-no-heading-content-indent: ^4.0.0 - remark-lint-no-inline-padding: ^4.0.0 - remark-lint-no-literal-urls: ^3.0.0 - remark-lint-no-shortcut-reference-image: ^3.0.0 - remark-lint-no-shortcut-reference-link: ^3.0.0 - remark-lint-no-undefined-references: ^4.0.0 - remark-lint-no-unused-definitions: ^3.0.0 - remark-lint-ordered-list-marker-style: ^3.0.0 - unified: ^10.0.0 - checksum: 8f92dab9648ed8030b6fa9b855b849d6e95536535b24c5622185f8134bba2131d69e4e496f8ca60ff7ff38e4bc1d2e755973cf6f11bb78eb78e975fb3f91e6c6 - languageName: node - linkType: hard - -"remark-preset-prettier@npm:^2.0.1": - version: 2.0.1 - resolution: "remark-preset-prettier@npm:2.0.1" - peerDependencies: - prettier: ">=1.0.0" - checksum: 4c2bfbd902a81e4f5e5b68c4e75b43af402b3fc9049fd65023a6818be036b7f48f9d6f1a1e4b2cf354cb639c6f1a0a11c597b3e33eb2e1f93ce9a3f24a8c95b7 + "@types/mdast": ^4.0.0 + mdast-util-from-markdown: ^2.0.0 + micromark-util-types: ^2.0.0 + unified: ^11.0.0 + checksum: d83d245290fa84bb04fb3e78111f09c74f7417e7c012a64dd8dc04fccc3699036d828fbd8eeec8944f774b6c30cc1d925c98f8c46495ebcee7c595496342ab7f languageName: node linkType: hard @@ -31737,33 +30332,14 @@ __metadata: languageName: node linkType: hard -"remark-stringify@npm:^10.0.2": - version: 10.0.2 - resolution: "remark-stringify@npm:10.0.2" - dependencies: - "@types/mdast": ^3.0.0 - mdast-util-to-markdown: ^1.0.0 - unified: ^10.0.0 - checksum: 25424201e698353f6c0afc9ec29a8cac1dac8c06750d92214e3216bd76ac37902a0ba3702ac2a11c1040938a667b3bc22d6949af1d35e8fc81a3572643cdc263 - languageName: node - linkType: hard - -"remark-validate-links@npm:^12.1.0": - version: 12.1.0 - resolution: "remark-validate-links@npm:12.1.0" +"remark-stringify@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-stringify@npm:11.0.0" dependencies: - "@types/mdast": ^3.0.0 - github-slugger: ^1.0.0 - hosted-git-info: ^5.0.0 - mdast-util-to-string: ^3.0.0 - propose: 0.0.5 - to-vfile: ^7.0.0 - trough: ^2.0.0 - unified: ^10.0.0 - unified-engine: ^10.0.1 - unist-util-visit: ^4.0.0 - vfile: ^5.0.0 - checksum: eb1743c0f4e9ca54a7da58f97d70e97393e10a5a7573e23559b6f4ac6ee8a98db6983cfd4bbf1bb9393966e002000943c20e2203d8364283f02b5f3dfdad48ad + "@types/mdast": ^4.0.0 + mdast-util-to-markdown: ^2.0.0 + unified: ^11.0.0 + checksum: 59e07460eb629d6c3b3c0f438b0b236e7e6858fd5ab770303078f5a556ec00354d9c7fb9ef6d5f745a4617ac7da1ab618b170fbb4dac120e183fecd9cc86bce6 languageName: node linkType: hard @@ -32286,15 +30862,6 @@ __metadata: languageName: node linkType: hard -"sade@npm:^1.7.3": - version: 1.8.1 - resolution: "sade@npm:1.8.1" - dependencies: - mri: ^1.1.0 - checksum: 0756e5b04c51ccdc8221ebffd1548d0ce5a783a44a0fa9017a026659b97d632913e78f7dca59f2496aa996a0be0b0c322afd87ca72ccd909406f49dbffa0f45d - languageName: node - linkType: hard - "safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": version: 5.1.2 resolution: "safe-buffer@npm:5.1.2" @@ -32433,7 +31000,7 @@ __metadata: languageName: node linkType: hard -"scrypt-js@npm:3.0.1, scrypt-js@npm:^3.0.0, scrypt-js@npm:^3.0.1": +"scrypt-js@npm:^3.0.0, scrypt-js@npm:^3.0.1": version: 3.0.1 resolution: "scrypt-js@npm:3.0.1" checksum: b7c7d1a68d6ca946f2fbb0778e0c4ec63c65501b54023b2af7d7e9f48fdb6c6580d6f7675cd53bda5944c5ebc057560d5a6365079752546865defb3b79dea454 @@ -33173,6 +31740,13 @@ __metadata: languageName: node linkType: hard +"source-map@npm:^0.7.4": + version: 0.7.6 + resolution: "source-map@npm:0.7.6" + checksum: 932f4a2390aa7100e91357d88cc272de984ad29139ac09eedfde8cc78d46da35f389065d0c5343c5d71d054a6ebd4939a8c0f2c98d5df64fe97bb8a730596c2d + languageName: node + linkType: hard + "space-separated-tokens@npm:^1.0.0": version: 1.1.5 resolution: "space-separated-tokens@npm:1.1.5" @@ -33623,7 +32197,7 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^5.0.0, string-width@npm:^5.0.1, string-width@npm:^5.1.2": +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": version: 5.1.2 resolution: "string-width@npm:5.1.2" dependencies: @@ -33634,6 +32208,17 @@ __metadata: languageName: node linkType: hard +"string-width@npm:^6.0.0": + version: 6.1.0 + resolution: "string-width@npm:6.1.0" + dependencies: + eastasianwidth: ^0.2.0 + emoji-regex: ^10.2.1 + strip-ansi: ^7.0.1 + checksum: 8aefb456a230c8d7fe254049b1b2d62603da1a3b6c7fc9f3332f6779583cc1c72653f9b6e4cd0c1c92befee1565d4a0a7542d09ba4ceb6d96af02fbd8425bb03 + languageName: node + linkType: hard + "string.prototype.matchall@npm:^4.0.8": version: 4.0.8 resolution: "string.prototype.matchall@npm:4.0.8" @@ -33844,7 +32429,7 @@ __metadata: languageName: node linkType: hard -"strip-json-comments@npm:^3.0.1, strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": +"strip-json-comments@npm:^3.0.1, strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 @@ -34065,13 +32650,12 @@ __metadata: languageName: node linkType: hard -"synckit@npm:^0.8.4": - version: 0.8.5 - resolution: "synckit@npm:0.8.5" +"synckit@npm:^0.11.8": + version: 0.11.12 + resolution: "synckit@npm:0.11.12" dependencies: - "@pkgr/utils": ^2.3.1 - tslib: ^2.5.0 - checksum: 8a9560e5d8f3d94dc3cf5f7b9c83490ffa30d320093560a37b88f59483040771fd1750e76b9939abfbb1b5a23fd6dfbae77f6b338abffe7cae7329cd9b9bb86b + "@pkgr/core": ^0.2.9 + checksum: a53fb563d01ba8912a111b883fc3c701e267896ff8273e7aba9001f5f74711e125888f4039e93060795cd416122cf492ae419eb10a6a3e3b00e830917669d2cf languageName: node linkType: hard @@ -34400,16 +32984,6 @@ __metadata: languageName: node linkType: hard -"tiny-glob@npm:^0.2.9": - version: 0.2.9 - resolution: "tiny-glob@npm:0.2.9" - dependencies: - globalyzer: 0.1.0 - globrex: ^0.1.2 - checksum: aea5801eb6663ddf77ebb74900b8f8bd9dfcfc9b6a1cc8018cb7421590c00bf446109ff45e4b64a98e6c95ddb1255a337a5d488fb6311930e2a95334151ec9c6 - languageName: node - linkType: hard - "tiny-inflate@npm:^1.0.0": version: 1.0.3 resolution: "tiny-inflate@npm:1.0.3" @@ -34557,16 +33131,6 @@ __metadata: languageName: node linkType: hard -"to-vfile@npm:^7.0.0": - version: 7.2.4 - resolution: "to-vfile@npm:7.2.4" - dependencies: - is-buffer: ^2.0.0 - vfile: ^5.1.0 - checksum: 5fa9bd6c3b0dae6abc65a882bef4d899940305237449740ee803c5ef87c1df56425290009abde7d215884f481c3254d78d19120f38109217c6c066676f2e7609 - languageName: node - linkType: hard - "tocbot@npm:^4.20.1": version: 4.27.16 resolution: "tocbot@npm:4.27.16" @@ -34644,6 +33208,15 @@ __metadata: languageName: node linkType: hard +"ts-api-utils@npm:^1.3.0": + version: 1.4.3 + resolution: "ts-api-utils@npm:1.4.3" + peerDependencies: + typescript: ">=4.2.0" + checksum: ea00dee382d19066b2a3d8929f1089888b05fec797e32e7a7004938eda1dccf2e77274ee2afcd4166f53fab9b8d7ee90ebb225a3183f9ba8817d636f688a148d + languageName: node + linkType: hard + "ts-custom-error@npm:^3.0.0": version: 3.3.0 resolution: "ts-custom-error@npm:3.3.0" @@ -34691,18 +33264,19 @@ __metadata: languageName: node linkType: hard -"ts-loader@npm:^9.4.2": - version: 9.4.2 - resolution: "ts-loader@npm:9.4.2" +"ts-loader@npm:^9.5.4": + version: 9.5.4 + resolution: "ts-loader@npm:9.5.4" dependencies: chalk: ^4.1.0 enhanced-resolve: ^5.0.0 micromatch: ^4.0.0 semver: ^7.3.4 + source-map: ^0.7.4 peerDependencies: typescript: "*" webpack: ^5.0.0 - checksum: 6f306ee4c615c2a159fb177561e3fb86ca2cbd6c641e710d408a64b4978e1ff3f2c9733df07bff27d3f82efbfa7c287523d4306049510c7485ac2669a9c37eb0 + checksum: ee8a6883d0f8c0db0ea254fe4e9247ab0f6747cbbbee987af80e69822b840bdc2b67cee267ed3a93af803aeed47790d64dbaf07c001322b9091671f51cbf12b2 languageName: node linkType: hard @@ -34772,7 +33346,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:1.14.1, tslib@npm:^1.13.0, tslib@npm:^1.8.1, tslib@npm:^1.9.0": +"tslib@npm:1.14.1, tslib@npm:^1.13.0, tslib@npm:^1.9.0": version: 1.14.1 resolution: "tslib@npm:1.14.1" checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd @@ -34807,7 +33381,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.4.0, tslib@npm:^2.5.0": +"tslib@npm:^2.4.0": version: 2.5.0 resolution: "tslib@npm:2.5.0" checksum: ae3ed5f9ce29932d049908ebfdf21b3a003a85653a9a140d614da6b767a93ef94f460e52c3d787f0e4f383546981713f165037dc2274df212ea9f8a4541004e1 @@ -34821,17 +33395,6 @@ __metadata: languageName: node linkType: hard -"tsutils@npm:^3.21.0": - version: 3.21.0 - resolution: "tsutils@npm:3.21.0" - dependencies: - tslib: ^1.8.1 - peerDependencies: - typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - checksum: 1843f4c1b2e0f975e08c4c21caa4af4f7f65a12ac1b81b3b8489366826259323feb3fc7a243123453d2d1a02314205a7634e048d4a8009921da19f99755cdc48 - languageName: node - linkType: hard - "tty-browserify@npm:0.0.0": version: 0.0.0 resolution: "tty-browserify@npm:0.0.0" @@ -34954,6 +33517,13 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^3.8.0": + version: 3.13.1 + resolution: "type-fest@npm:3.13.1" + checksum: c06b0901d54391dc46de3802375f5579868949d71f93b425ce564e19a428a0d411ae8d8cb0e300d330071d86152c3ea86e744c3f2860a42a79585b6ec2fdae8e + languageName: node + linkType: hard + "type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18" @@ -34989,17 +33559,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:5.0.4": - version: 5.0.4 - resolution: "typescript@npm:5.0.4" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 82b94da3f4604a8946da585f7d6c3025fff8410779e5bde2855ab130d05e4fd08938b9e593b6ebed165bda6ad9292b230984f10952cf82f0a0ca07bbeaa08172 - languageName: node - linkType: hard - -"typescript@npm:>=3 < 6": +"typescript@npm:>=3 < 6, typescript@npm:^5.7.0": version: 5.9.3 resolution: "typescript@npm:5.9.3" bin: @@ -35009,17 +33569,7 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@5.0.4#~builtin": - version: 5.0.4 - resolution: "typescript@patch:typescript@npm%3A5.0.4#~builtin::version=5.0.4&hash=1f5320" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 6a1fe9a77bb9c5176ead919cc4a1499ee63e46b4e05bf667079f11bf3a8f7887f135aa72460a4c3b016e6e6bb65a822cb8689a6d86cbfe92d22cc9f501f09213 - languageName: node - linkType: hard - -"typescript@patch:typescript@>=3 < 6#~builtin": +"typescript@patch:typescript@>=3 < 6#~builtin, typescript@patch:typescript@^5.7.0#~builtin": version: 5.9.3 resolution: "typescript@patch:typescript@npm%3A5.9.3#~builtin::version=5.9.3&hash=1f5320" bin: @@ -35099,6 +33649,13 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~6.21.0": + version: 6.21.0 + resolution: "undici-types@npm:6.21.0" + checksum: 46331c7d6016bf85b3e8f20c159d62f5ae471aba1eb3dc52fff35a0259d58dcc7d592d4cc4f00c5f9243fa738a11cfa48bd20203040d4a9e6bc25e807fab7ab3 + languageName: node + linkType: hard + "unenv@npm:^1.7.4": version: 1.8.0 resolution: "unenv@npm:1.8.0" @@ -35204,74 +33761,47 @@ __metadata: languageName: node linkType: hard -"unified-engine@npm:^10.0.1": - version: 10.1.0 - resolution: "unified-engine@npm:10.1.0" +"unified-engine@npm:^11.2.2": + version: 11.2.2 + resolution: "unified-engine@npm:11.2.2" dependencies: "@types/concat-stream": ^2.0.0 "@types/debug": ^4.0.0 "@types/is-empty": ^1.0.0 - "@types/node": ^18.0.0 - "@types/unist": ^2.0.0 + "@types/node": ^22.0.0 + "@types/unist": ^3.0.0 concat-stream: ^2.0.0 debug: ^4.0.0 - fault: ^2.0.0 - glob: ^8.0.0 - ignore: ^5.0.0 - is-buffer: ^2.0.0 + extend: ^3.0.0 + glob: ^10.0.0 + ignore: ^6.0.0 is-empty: ^1.0.0 is-plain-obj: ^4.0.0 - load-plugin: ^5.0.0 - parse-json: ^6.0.0 - to-vfile: ^7.0.0 + load-plugin: ^6.0.0 + parse-json: ^7.0.0 trough: ^2.0.0 - unist-util-inspect: ^7.0.0 - vfile-message: ^3.0.0 - vfile-reporter: ^7.0.0 - vfile-statistics: ^2.0.0 + unist-util-inspect: ^8.0.0 + vfile: ^6.0.0 + vfile-message: ^4.0.0 + vfile-reporter: ^8.0.0 + vfile-statistics: ^3.0.0 yaml: ^2.0.0 - checksum: 27f4e5cd05c70a0f8a0ffa011f20257d97d62dc1b7ced0fa3c70516f23a4e8e9b676496e94a04726c85da2783153412f526724e512ec1dddcf5af82ce39b2fd2 - languageName: node - linkType: hard - -"unified-lint-rule@npm:^2.0.0": - version: 2.1.1 - resolution: "unified-lint-rule@npm:2.1.1" - dependencies: - "@types/unist": ^2.0.0 - trough: ^2.0.0 - unified: ^10.0.0 - vfile: ^5.0.0 - checksum: 224cd0a89396d560674d7caac8cc9b52e89912954e83a4b940efadb3c41b34e5f6602c0d79f801a18666cf01427b1c6a09cf50abeb0f2b84f5c9d3b647885435 - languageName: node - linkType: hard - -"unified-message-control@npm:^4.0.0": - version: 4.0.0 - resolution: "unified-message-control@npm:4.0.0" - dependencies: - "@types/unist": ^2.0.0 - unist-util-is: ^5.0.0 - unist-util-visit: ^3.0.0 - vfile: ^5.0.0 - vfile-location: ^4.0.0 - vfile-message: ^3.0.0 - checksum: a90a9f8c371fce8679162dcf917f82ed4562518ad37e12778cabc9cb02500d504cd29d2500f37d822fd450ea6ddfa5f7be82cdba6c1f221c53288d1f0f25fd2c + checksum: 294d56b57293b315bf879458bc5897917033cb5bf586b3d412bae33dfe0a87d6406787b84f2b09c668badc9d264500279e55abf9ed14d2e9b2582f26963b3a45 languageName: node linkType: hard -"unified@npm:^10.0.0, unified@npm:^10.1.0, unified@npm:^10.1.2": - version: 10.1.2 - resolution: "unified@npm:10.1.2" +"unified@npm:^11.0.0, unified@npm:^11.0.5": + version: 11.0.5 + resolution: "unified@npm:11.0.5" dependencies: - "@types/unist": ^2.0.0 + "@types/unist": ^3.0.0 bail: ^2.0.0 + devlop: ^1.0.0 extend: ^3.0.0 - is-buffer: ^2.0.0 is-plain-obj: ^4.0.0 trough: ^2.0.0 - vfile: ^5.0.0 - checksum: 053e7c65ede644607f87bd625a299e4b709869d2f76ec8138569e6e886903b6988b21cd9699e471eda42bee189527be0a9dac05936f1d069a5e65d0125d5d756 + vfile: ^6.0.0 + checksum: b3bf7fd6f568cc261e074dae21188483b0f2a8ab858d62e6e85b75b96cc655f59532906ae3c64d56a9b257408722d71f1d4135292b3d7ee02907c8b592fb3cf0 languageName: node linkType: hard @@ -35364,19 +33894,12 @@ __metadata: languageName: node linkType: hard -"unist-util-generated@npm:^2.0.0": - version: 2.0.1 - resolution: "unist-util-generated@npm:2.0.1" - checksum: 6221ad0571dcc9c8964d6b054f39ef6571ed59cc0ce3e88ae97ea1c70afe76b46412a5ffaa91f96814644ac8477e23fb1b477d71f8d70e625728c5258f5c0d99 - languageName: node - linkType: hard - -"unist-util-inspect@npm:^7.0.0": - version: 7.0.2 - resolution: "unist-util-inspect@npm:7.0.2" +"unist-util-inspect@npm:^8.0.0": + version: 8.1.0 + resolution: "unist-util-inspect@npm:8.1.0" dependencies: - "@types/unist": ^2.0.0 - checksum: e8f2a3836516e5ac973d56914832fad83c2391686143008a40fa8c852eb452f04bd5a42c30ce716c52217b202328ca2f365c7f0f13e67f838603d659c39b9720 + "@types/unist": ^3.0.0 + checksum: 2c943aabebdcc3245be42fef4944b4511fb9b65d8ced1d77621da124ab18659abb37d5c33e85847baf3f2f30be8365499c064f86a014abaaf26aadd0e063baa8 languageName: node linkType: hard @@ -35387,56 +33910,30 @@ __metadata: languageName: node linkType: hard -"unist-util-is@npm:^5.0.0": - version: 5.2.0 - resolution: "unist-util-is@npm:5.2.0" - checksum: b80debe1ce5d40a8d685c510f597e5c8b8f7089540e9e268bda1b05bcce735c10bf36d5b0e4ecded50c63fa43b8a11b0e4b784beecf1559f153a2f2855e8526c - languageName: node - linkType: hard - -"unist-util-position-from-estree@npm:^1.0.0, unist-util-position-from-estree@npm:^1.1.0": - version: 1.1.2 - resolution: "unist-util-position-from-estree@npm:1.1.2" - dependencies: - "@types/unist": ^2.0.0 - checksum: e3f4060e2a9e894c6ed63489c5a7cb58ff282e5dae9497cbc2073033ca74d6e412af4d4d342c97aea08d997c908b8bce2fe43a2062aafc2bb3f266533016588b - languageName: node - linkType: hard - -"unist-util-position@npm:^4.0.0": - version: 4.0.4 - resolution: "unist-util-position@npm:4.0.4" - dependencies: - "@types/unist": ^2.0.0 - checksum: e7487b6cec9365299695e3379ded270a1717074fa11fd2407c9b934fb08db6fe1d9077ddeaf877ecf1813665f8ccded5171693d3d9a7a01a125ec5cdd5e88691 - languageName: node - linkType: hard - -"unist-util-remove-position@npm:^4.0.0": - version: 4.0.2 - resolution: "unist-util-remove-position@npm:4.0.2" +"unist-util-is@npm:^6.0.0": + version: 6.0.1 + resolution: "unist-util-is@npm:6.0.1" dependencies: - "@types/unist": ^2.0.0 - unist-util-visit: ^4.0.0 - checksum: 989831da913d09a82a99ed9b47b78471b6409bde95942cde47e09da54b7736516f17e3c7e026af468684c1efcec5fb52df363381b2f9dc7fd96ce791c5a2fa4a + "@types/unist": ^3.0.0 + checksum: e57733e1766b55c9a873a42d2f34daa211580788b1bba26af2fc22e48e147bdcff0f9a752ed2a19238864823735fbbe27a1804d6a5a22b182c23aa0191e41c12 languageName: node linkType: hard -"unist-util-stringify-position@npm:^2.0.0": - version: 2.0.3 - resolution: "unist-util-stringify-position@npm:2.0.3" +"unist-util-position-from-estree@npm:^2.0.0": + version: 2.0.0 + resolution: "unist-util-position-from-estree@npm:2.0.0" dependencies: - "@types/unist": ^2.0.2 - checksum: f755cadc959f9074fe999578a1a242761296705a7fe87f333a37c00044de74ab4b184b3812989a57d4cd12211f0b14ad397b327c3a594c7af84361b1c25a7f09 + "@types/unist": ^3.0.0 + checksum: d3b3048a5727c2367f64ef6dcc5b20c4717215ef8b1372ff9a7c426297c5d1e5776409938acd01531213e2cd2543218d16e73f9f862f318e9496e2c73bb18354 languageName: node linkType: hard -"unist-util-stringify-position@npm:^3.0.0": - version: 3.0.3 - resolution: "unist-util-stringify-position@npm:3.0.3" +"unist-util-stringify-position@npm:^4.0.0": + version: 4.0.0 + resolution: "unist-util-stringify-position@npm:4.0.0" dependencies: - "@types/unist": ^2.0.0 - checksum: dbd66c15183607ca942a2b1b7a9f6a5996f91c0d30cf8966fb88955a02349d9eefd3974e9010ee67e71175d784c5a9fea915b0aa0b0df99dcb921b95c4c9e124 + "@types/unist": ^3.0.0 + checksum: e2e7aee4b92ddb64d314b4ac89eef7a46e4c829cbd3ee4aee516d100772b490eb6b4974f653ba0717a0071ca6ea0770bf22b0a2ea62c65fcba1d071285e96324 languageName: node linkType: hard @@ -35450,23 +33947,13 @@ __metadata: languageName: node linkType: hard -"unist-util-visit-parents@npm:^4.0.0": - version: 4.1.1 - resolution: "unist-util-visit-parents@npm:4.1.1" - dependencies: - "@types/unist": ^2.0.0 - unist-util-is: ^5.0.0 - checksum: 49d78984a6dd858a989f849d2b4330c8a04d1ee99c0e9920a5e37668cf847dab95db77a3bf0c8aaeb3e66abeae12e2d454949ec401614efef377d8f82d215662 - languageName: node - linkType: hard - -"unist-util-visit-parents@npm:^5.0.0, unist-util-visit-parents@npm:^5.1.1": - version: 5.1.3 - resolution: "unist-util-visit-parents@npm:5.1.3" +"unist-util-visit-parents@npm:^6.0.0": + version: 6.0.2 + resolution: "unist-util-visit-parents@npm:6.0.2" dependencies: - "@types/unist": ^2.0.0 - unist-util-is: ^5.0.0 - checksum: 8ecada5978994f846b64658cf13b4092cd78dea39e1ba2f5090a5de842ba4852712c02351a8ae95250c64f864635e7b02aedf3b4a093552bb30cf1bd160efbaa + "@types/unist": ^3.0.0 + unist-util-is: ^6.0.0 + checksum: cf28578a6f0b81877965e261fe82460f83b8c3a9cab3b2080c046b215f3223c6195b01064256619ca3411a1930face93a1a2a72d34d8716e684d6cd59f53cd9a languageName: node linkType: hard @@ -35481,25 +33968,14 @@ __metadata: languageName: node linkType: hard -"unist-util-visit@npm:^3.0.0": - version: 3.1.0 - resolution: "unist-util-visit@npm:3.1.0" - dependencies: - "@types/unist": ^2.0.0 - unist-util-is: ^5.0.0 - unist-util-visit-parents: ^4.0.0 - checksum: c37dbc0c5509f85f3abdf46d927b3dd11e6c419159771b1f1a5ce446d36ac993d04b087e28bc6173a172e0fbe9d77e997f120029b2b449766ebe55b6f6e0cc2c - languageName: node - linkType: hard - -"unist-util-visit@npm:^4.0.0, unist-util-visit@npm:^4.1.1": - version: 4.1.2 - resolution: "unist-util-visit@npm:4.1.2" +"unist-util-visit@npm:^5.0.0": + version: 5.1.0 + resolution: "unist-util-visit@npm:5.1.0" dependencies: - "@types/unist": ^2.0.0 - unist-util-is: ^5.0.0 - unist-util-visit-parents: ^5.1.1 - checksum: 95a34e3f7b5b2d4b68fd722b6229972099eb97b6df18913eda44a5c11df8b1e27efe7206dd7b88c4ed244a48c474a5b2e2629ab79558ff9eb936840295549cee + "@types/unist": ^3.0.0 + unist-util-is: ^6.0.0 + unist-util-visit-parents: ^6.0.0 + checksum: c7b6cce10db3d912ca0d021f3fec1c7142878e0d3bf7df2b17c84ccb61b2b41342f8972874cb8fab50dc02121fc11858a857ccffa9c8305f0d957308c5b4e5fa languageName: node linkType: hard @@ -35939,20 +34415,6 @@ __metadata: languageName: node linkType: hard -"uvu@npm:^0.5.0, uvu@npm:^0.5.6": - version: 0.5.6 - resolution: "uvu@npm:0.5.6" - dependencies: - dequal: ^2.0.0 - diff: ^5.0.0 - kleur: ^4.0.3 - sade: ^1.7.3 - bin: - uvu: bin.js - checksum: 09460a37975627de9fcad396e5078fb844d01aaf64a6399ebfcfd9e55f1c2037539b47611e8631f89be07656962af0cf48c334993db82b9ae9c3d25ce3862168 - languageName: node - linkType: hard - "v8-compile-cache@npm:^2.0.0": version: 2.3.0 resolution: "v8-compile-cache@npm:2.3.0" @@ -35988,6 +34450,13 @@ __metadata: languageName: node linkType: hard +"validate-npm-package-name@npm:^5.0.0": + version: 5.0.1 + resolution: "validate-npm-package-name@npm:5.0.1" + checksum: 0d583a1af23aeffea7748742cf22b6802458736fb8b60323ba5949763824d46f796474b0e1b9206beb716f9d75269e19dbd7795d6b038b29d561be95dd827381 + languageName: node + linkType: hard + "validate-npm-package-name@npm:^7.0.0": version: 7.0.0 resolution: "validate-npm-package-name@npm:7.0.0" @@ -36029,71 +34498,59 @@ __metadata: languageName: node linkType: hard -"vfile-location@npm:^4.0.0": - version: 4.1.0 - resolution: "vfile-location@npm:4.1.0" - dependencies: - "@types/unist": ^2.0.0 - vfile: ^5.0.0 - checksum: c894e8e5224170d1f85288f4a1d1ebcee0780823ea2b49d881648ab360ebf01b37ecb09b1c4439a75f9a51f31a9f9742cd045e987763e367c352a1ef7c50d446 - languageName: node - linkType: hard - -"vfile-message@npm:^3.0.0": - version: 3.1.4 - resolution: "vfile-message@npm:3.1.4" +"vfile-message@npm:^4.0.0": + version: 4.0.3 + resolution: "vfile-message@npm:4.0.3" dependencies: - "@types/unist": ^2.0.0 - unist-util-stringify-position: ^3.0.0 - checksum: d0ee7da1973ad76513c274e7912adbed4d08d180eaa34e6bd40bc82459f4b7bc50fcaff41556135e3339995575eac5f6f709aba9332b80f775618ea4880a1367 + "@types/unist": ^3.0.0 + unist-util-stringify-position: ^4.0.0 + checksum: f5e8516f2aa0feb4c866d507543d4e90f9ab309e2c988577dbf4ebd268d495f72f2b48149849d14300164d5d60b5f74b5641cd285bb4408a3942b758683d9276 languageName: node linkType: hard -"vfile-reporter@npm:^7.0.0": - version: 7.0.5 - resolution: "vfile-reporter@npm:7.0.5" +"vfile-reporter@npm:^8.0.0": + version: 8.1.1 + resolution: "vfile-reporter@npm:8.1.1" dependencies: "@types/supports-color": ^8.0.0 - string-width: ^5.0.0 + string-width: ^6.0.0 supports-color: ^9.0.0 - unist-util-stringify-position: ^3.0.0 - vfile: ^5.0.0 - vfile-message: ^3.0.0 - vfile-sort: ^3.0.0 - vfile-statistics: ^2.0.0 - checksum: 0d66370c6c821fbc850c898bfc48c73f19fb320792c532a3af0456bd0f3d395590b365009e60ca4c08ab09a0dabdd43311297bb5c6fbd0abb90bb5abce98264e + unist-util-stringify-position: ^4.0.0 + vfile: ^6.0.0 + vfile-message: ^4.0.0 + vfile-sort: ^4.0.0 + vfile-statistics: ^3.0.0 + checksum: db0adf4c1127d303b695fe49d157fe1377378695d7d4da308f804e3d1b1a07ee48fc9d6c3950ed2067d5c03fbb5aba38290f366f62695cd6e6c9a8504e3cfed7 languageName: node linkType: hard -"vfile-sort@npm:^3.0.0": - version: 3.0.1 - resolution: "vfile-sort@npm:3.0.1" +"vfile-sort@npm:^4.0.0": + version: 4.0.0 + resolution: "vfile-sort@npm:4.0.0" dependencies: - vfile: ^5.0.0 - vfile-message: ^3.0.0 - checksum: 6a29e0513c03b3468c628cc27d1511e2f955c3095cd65eeddcb8f601b0972c0cb1f2dc008a7c760e217cf97a44e04e0331b00929b83adc6661b46043b03b5a24 + vfile: ^6.0.0 + vfile-message: ^4.0.0 + checksum: 86e169ff4aad63bd63ddca25516af3205033a00b17c5d311f98b2d04c97d1d540b1b60026e1142e4725e029ceeaa8939c6c0c504ec60e3ac913096de18e704d2 languageName: node linkType: hard -"vfile-statistics@npm:^2.0.0": - version: 2.0.1 - resolution: "vfile-statistics@npm:2.0.1" +"vfile-statistics@npm:^3.0.0": + version: 3.0.0 + resolution: "vfile-statistics@npm:3.0.0" dependencies: - vfile: ^5.0.0 - vfile-message: ^3.0.0 - checksum: e3f731bcf992c61c1231a0793785b1288e0a004be9e18ff147e3ead901ae2d21723358609bfe0565881ffe202af68cb171b49753fc8b4bd7a30337aaef256266 + vfile: ^6.0.0 + vfile-message: ^4.0.0 + checksum: 0dbbc8adeb73bb24b5f723e947122e1ae7b6bd0c5ff3fd1ae0ef4a3066f74be00425102c95aa4eaa0f529ba05237255fe8342af76661b0ba6aee3f4c16ca135f languageName: node linkType: hard -"vfile@npm:^5.0.0, vfile@npm:^5.1.0, vfile@npm:^5.3.4": - version: 5.3.7 - resolution: "vfile@npm:5.3.7" +"vfile@npm:^6.0.0, vfile@npm:^6.0.3": + version: 6.0.3 + resolution: "vfile@npm:6.0.3" dependencies: - "@types/unist": ^2.0.0 - is-buffer: ^2.0.0 - unist-util-stringify-position: ^3.0.0 - vfile-message: ^3.0.0 - checksum: 642cce703afc186dbe7cabf698dc954c70146e853491086f5da39e1ce850676fc96b169fcf7898aa3ff245e9313aeec40da93acd1e1fcc0c146dc4f6308b4ef9 + "@types/unist": ^3.0.0 + vfile-message: ^4.0.0 + checksum: 152b6729be1af70df723efb65c1a1170fd483d41086557da3651eea69a1dd1f0c22ea4344834d56d30734b9185bcab63e22edc81d3f0e9bed8aa4660d61080af languageName: node linkType: hard @@ -36188,10 +34645,10 @@ __metadata: languageName: node linkType: hard -"walk-up-path@npm:^1.0.0": - version: 1.0.0 - resolution: "walk-up-path@npm:1.0.0" - checksum: b8019ac4fb9ba1576839ec66d2217f62ab773c1cc4c704bfd1c79b1359fef5366f1382d3ab230a66a14c3adb1bf0fe102d1fdaa3437881e69154dfd1432abd32 +"walk-up-path@npm:^3.0.1": + version: 3.0.1 + resolution: "walk-up-path@npm:3.0.1" + checksum: 9ffca02fe30fb65f6db531260582988c5e766f4c739cf86a6109380a7f791236b5d0b92b1dce37a6f73e22dca6bc9d93bf3700413e16251b2bd6bbd1ca2be316 languageName: node linkType: hard @@ -36579,6 +35036,17 @@ __metadata: languageName: node linkType: hard +"which@npm:^4.0.0": + version: 4.0.0 + resolution: "which@npm:4.0.0" + dependencies: + isexe: ^3.1.1 + bin: + node-which: bin/which.js + checksum: f17e84c042592c21e23c8195108cff18c64050b9efb8459589116999ea9da6dd1509e6a1bac3aeebefd137be00fabbb61b5c2bc0aa0f8526f32b58ee2f545651 + languageName: node + linkType: hard + "which@npm:^5.0.0": version: 5.0.0 resolution: "which@npm:5.0.0" @@ -36626,7 +35094,14 @@ __metadata: languageName: node linkType: hard -"word-wrap@npm:^1.2.3, word-wrap@npm:~1.2.3": +"word-wrap@npm:^1.2.5": + version: 1.2.5 + resolution: "word-wrap@npm:1.2.5" + checksum: f93ba3586fc181f94afdaff3a6fef27920b4b6d9eaefed0f428f8e07adea2a7f54a5f2830ce59406c8416f033f86902b91eb824072354645eea687dff3691ccb + languageName: node + linkType: hard + +"word-wrap@npm:~1.2.3": version: 1.2.3 resolution: "word-wrap@npm:1.2.3" checksum: 30b48f91fcf12106ed3186ae4fa86a6a1842416df425be7b60485de14bec665a54a68e4b5156647dec3a70f25e84d270ca8bc8cd23182ed095f5c7206a938c1f @@ -36746,21 +35221,6 @@ __metadata: languageName: node linkType: hard -"ws@npm:7.4.6": - version: 7.4.6 - resolution: "ws@npm:7.4.6" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 3a990b32ed08c72070d5e8913e14dfcd831919205be52a3ff0b4cdd998c8d554f167c9df3841605cde8b11d607768cacab3e823c58c96a5c08c987e093eb767a - languageName: node - linkType: hard - "ws@npm:^5.1.1": version: 5.2.3 resolution: "ws@npm:5.2.3"