diff --git a/apps/evm/.env.example b/apps/evm/.env.example index 48b53e491..2cb8ff363 100644 --- a/apps/evm/.env.example +++ b/apps/evm/.env.example @@ -10,3 +10,9 @@ VITE_FEATURE_FLAG_BTC_ONRAMP=disabled VITE_INDEXER_BRIDGE_URL="" VITE_SENTRY_URL="" VITE_SENTRY_AUTH_TOKEN="" + + +/* MAINNET */ +VITE_ONRAMP_API_URL="https://onramp-api-mainnet.gobob.xyz" +VITE_BTC_API_URL="https://btc-mainnet.gobob.xyz" +VITE_L1_CHAIN_NAME="ethereum" diff --git a/apps/evm/package.json b/apps/evm/package.json index 7e3257762..42c728f2d 100644 --- a/apps/evm/package.json +++ b/apps/evm/package.json @@ -15,6 +15,7 @@ "dependencies": { "@eth-optimism/sdk": "^3.1.6", "@ethersproject/providers": "^5.7.2", + "@gobob/bob-sdk": "1.3.0", "@gobob/chains": "workspace:^", "@gobob/connect-ui": "workspace:^", "@gobob/currency": "workspace:^", diff --git a/apps/evm/src/lib/bob-sdk/gateway.ts b/apps/evm/src/lib/bob-sdk/gateway.ts new file mode 100644 index 000000000..f762d882b --- /dev/null +++ b/apps/evm/src/lib/bob-sdk/gateway.ts @@ -0,0 +1,5 @@ +import { GatewayApiClient } from '@gobob/bob-sdk'; + +const gatewayClient = new GatewayApiClient('/onramp-api'); + +export { gatewayClient }; diff --git a/apps/evm/src/lib/bob-sdk/index.ts b/apps/evm/src/lib/bob-sdk/index.ts new file mode 100644 index 000000000..fc6761695 --- /dev/null +++ b/apps/evm/src/lib/bob-sdk/index.ts @@ -0,0 +1 @@ +export * from './gateway'; diff --git a/apps/evm/src/lib/react-query/keys.ts b/apps/evm/src/lib/react-query/keys.ts index fdc85abc8..af33f5c27 100644 --- a/apps/evm/src/lib/react-query/keys.ts +++ b/apps/evm/src/lib/react-query/keys.ts @@ -43,8 +43,7 @@ export const bridgeKeys = { proveTransaction: (address: Address | undefined, hash: Address) => [address, hash, 'prove'], relayTransaction: (address: Address | undefined, hash: Address) => [address, hash, 'relay'], btc: (address: Address | undefined, btcAddress: string | undefined) => ['btc', address, btcAddress], - btcTotalLiquidity: () => ['btc-total-liquidity'], - btcQuote: (address: Address | undefined, btcAddress: string | undefined, atomicAmount: number | undefined) => [ + btcQuote: (address: Address | undefined, btcAddress: string | undefined, atomicAmount?: number | 'max') => [ ...bridgeKeys.btc(address, btcAddress), atomicAmount, 'quote' diff --git a/apps/evm/src/pages/Bridge/components/BridgeForm/BtcBridgeForm.tsx b/apps/evm/src/pages/Bridge/components/BridgeForm/BtcBridgeForm.tsx index b450a21ad..e031a3d0a 100644 --- a/apps/evm/src/pages/Bridge/components/BridgeForm/BtcBridgeForm.tsx +++ b/apps/evm/src/pages/Bridge/components/BridgeForm/BtcBridgeForm.tsx @@ -28,10 +28,10 @@ import { bridgeSchema } from '../../../../lib/form/bridge'; import { isFormDisabled } from '../../../../lib/form/utils'; -import { onRampApiClient } from '../../../../utils'; import { useGetTransactions } from '../../hooks'; import { OnRampData } from '../../types'; import { bridgeKeys } from '../../../../lib/react-query'; +import { gatewayClient } from '../../../../lib/bob-sdk'; type BtcBridgeFormProps = { type: 'deposit' | 'withdraw'; @@ -41,7 +41,7 @@ type BtcBridgeFormProps = { onFailOnRamp: () => void; }; -const MIN_DEPOSIT_AMOUNT = 40000; +const MIN_DEPOSIT_AMOUNT = 4000; const gasEstimatePlaceholder = CurrencyAmount.fromRawAmount(BITCOIN, 0n); @@ -87,18 +87,18 @@ const BtcBridgeForm = ({ toast.error(e.message); }, []); - const { data: availableLiquidity, isLoading: isLoadingLiquidity } = useQuery({ + const { data: availableLiquidity, isLoading: isLoadingMaxQuote } = useQuery({ enabled: Boolean(btcToken), - queryKey: bridgeKeys.btcTotalLiquidity(), + queryKey: bridgeKeys.btcQuote(evmAddress, btcAddress, 'max'), refetchInterval: INTERVAL.MINUTE, refetchOnMount: false, refetchOnWindowFocus: false, queryFn: async () => { if (!currencyAmount || !btcToken) return; - const total = await onRampApiClient.getTotalLiquidity(btcToken.raw.address); + const maxQuoteData = await gatewayClient.getQuote(btcToken.raw.address); - return CurrencyAmount.fromRawAmount(BITCOIN, total); + return CurrencyAmount.fromRawAmount(BITCOIN, maxQuoteData.satoshis); } }); @@ -133,7 +133,7 @@ const BtcBridgeForm = ({ const atomicAmount = currencyAmount.numerator.toString(); - const { fee, onramp_address, bitcoin_address, gratuity } = await onRampApiClient.getQuote( + const { fee, onramp_address, bitcoin_address, gratuity } = await gatewayClient.getQuote( btcToken.raw.address, atomicAmount ); @@ -185,12 +185,12 @@ const BtcBridgeForm = ({ const atomicAmount = Number(currencyAmount.numerator); - const orderId = await onRampApiClient.createOrder(onrampAddress, evmAddress, atomicAmount); + const orderId = await gatewayClient.createOrder(onrampAddress, evmAddress, atomicAmount); const tx = await connector.createTxWithOpReturn(bitcoinAddress, atomicAmount, evmAddress); // NOTE: relayer should broadcast the tx - await onRampApiClient.updateOrder(orderId, tx.toHex()); + await gatewayClient.updateOrder(orderId, tx.toHex()); return { ...data, txid: tx.getId() }; }, @@ -220,7 +220,7 @@ const BtcBridgeForm = ({ if (type === 'deposit') { return depositMutation.mutate({ - onrampAddress: quoteData.onrampAddress, + onrampAddress: quoteData.onrampAddress as Address, bitcoinAddress: quoteData.bitcoinAddress, evmAddress: (data[BRIDGE_RECIPIENT] as Address) || evmAddress, currencyAmount @@ -267,7 +267,10 @@ const BtcBridgeForm = ({ const params: BridgeFormValidationParams = { [BRIDGE_AMOUNT]: { - minAmount: currencyAmount && new Big(MIN_DEPOSIT_AMOUNT / 10 ** currencyAmount?.currency.decimals), + minAmount: + currencyAmount && MIN_DEPOSIT_AMOUNT + ? new Big(MIN_DEPOSIT_AMOUNT / 10 ** currencyAmount?.currency.decimals) + : undefined, maxAmount: new Big(balanceAmount.toExact()) }, [BRIDGE_RECIPIENT]: !!isSmartAccount @@ -289,7 +292,7 @@ const BtcBridgeForm = ({ const isTapRootAddress = btcAddressType === BtcAddressType.p2tr; const isDisabled = - isSubmitDisabled || !quoteData || isQuoteError || isTapRootAddress || isLoadingLiquidity || !hasLiquidity; + isSubmitDisabled || !quoteData || isQuoteError || isTapRootAddress || isLoadingMaxQuote || !hasLiquidity; const isLoading = !isSubmitDisabled && (depositMutation.isPending || isFetchingQuote); @@ -361,7 +364,7 @@ const BtcBridgeForm = ({

)} - {!hasLiquidity && !isLoadingLiquidity && ( + {!hasLiquidity && !isLoadingMaxQuote && (

There is currently no available liquidity to onramp BTC into {btcToken?.currency.symbol}.

diff --git a/apps/evm/src/pages/Bridge/hooks/useGetOnRampTransactions.ts b/apps/evm/src/pages/Bridge/hooks/useGetOnRampTransactions.ts index 782b4089b..cd59e06f7 100644 --- a/apps/evm/src/pages/Bridge/hooks/useGetOnRampTransactions.ts +++ b/apps/evm/src/pages/Bridge/hooks/useGetOnRampTransactions.ts @@ -6,9 +6,10 @@ import { Address, isAddressEqual } from 'viem'; import { L2_CHAIN } from '../../../constants'; import { FeatureFlags, TokenData, useFeatureFlag, useTokens } from '../../../hooks'; -import { electrsClient, onRampApiClient } from '../../../utils'; +import { electrsClient } from '../../../utils'; import { OnRampDepositSteps } from '../constants'; import { TransactionType } from '../types'; +import { gatewayClient } from '../../../lib/bob-sdk'; type OnRampTransaction = { status: OnRampDepositSteps; @@ -21,12 +22,12 @@ type OnRampTransaction = { }; const getOnRampTransactions = async (address: Address, l2Tokens: TokenData[]): Promise => { - const [orders, latestBlock] = await Promise.all([onRampApiClient.getOrders(address), electrsClient.getLatestBlock()]); + const [orders, latestBlock] = await Promise.all([gatewayClient.getOrders(address), electrsClient.getLatestBlock()]); return ( await Promise.all( orders.map(async (order): Promise => { - const token = l2Tokens.find((token) => isAddressEqual(token.raw.address, order.token_address)); + const token = l2Tokens.find((token) => isAddressEqual(token.raw.address, order.token_address as Address)); if (!token) return undefined; diff --git a/apps/evm/src/utils/index.ts b/apps/evm/src/utils/index.ts index db82e8c5a..478c570b4 100644 --- a/apps/evm/src/utils/index.ts +++ b/apps/evm/src/utils/index.ts @@ -1,4 +1,3 @@ export * from './api-client'; export * from './electrs-client'; -export * from './onramp-api-client'; export * from './math'; diff --git a/apps/evm/src/utils/onramp-api-client.ts b/apps/evm/src/utils/onramp-api-client.ts deleted file mode 100644 index 74112fa7b..000000000 --- a/apps/evm/src/utils/onramp-api-client.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { Address } from 'viem'; - -type OnRampQuote = { - onramp_address: Address; - dust_threshold: number; - satoshis: number; - fee: number; - gratuity: string; - bitcoin_address: string; - tx_proof_difficulty_factor: number; -}; - -type OnRampOrderResponse = { - onramp_address: Address; - token_address: Address; - txid: string; - status: boolean; - timestamp: number; - tokens: string; - satoshis: number; - fee: number; - tx_proof_difficulty_factor: number; -}; - -class OnRampApiClient { - private baseUrl: string; - - constructor(baseUrl: string) { - this.baseUrl = baseUrl; - } - - async getQuote(address: string, atomicAmount: number | string): Promise { - const response = await fetch(`${this.baseUrl}/quote/${address}/${atomicAmount}`, { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json' - } - }); - - return await response.json(); - } - - // TODO: add error handling - async createOrder(contractAddress: string, userAddress: Address, atomicAmount: number | string): Promise { - const response = await fetch(`${this.baseUrl}/order`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json' - }, - body: JSON.stringify({ onramp_address: contractAddress, user_address: userAddress, satoshis: atomicAmount }) - }); - - if (!response.ok) { - throw new Error('Failed to create order'); - } - - return await response.json(); - } - - async updateOrder(id: string, tx: string) { - const response = await fetch(`${this.baseUrl}/order/${id}`, { - method: 'PATCH', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json' - }, - body: JSON.stringify({ bitcoin_tx: tx }) - }); - - if (!response.ok) { - throw new Error('Failed to update order'); - } - } - - async getOrders(userAddress: Address): Promise { - const response = await fetch(`${this.baseUrl}/orders/${userAddress}`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json' - } - }); - - return response.json(); - } - - async getTotalLiquidity(assetAddress: Address): Promise { - const response = await fetch(`${this.baseUrl}/total/${assetAddress.toLowerCase()}`, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json' - } - }); - - return response.json(); - } -} - -export const onRampApiClient = new OnRampApiClient('/onramp-api'); diff --git a/packages/sats-wagmi/package.json b/packages/sats-wagmi/package.json index 0dbab4b6f..10e2588a7 100644 --- a/packages/sats-wagmi/package.json +++ b/packages/sats-wagmi/package.json @@ -45,7 +45,7 @@ }, "dependencies": { "@bitcoin-js/tiny-secp256k1-asmjs": "^2.2.3", - "@gobob/bob-sdk": "^1.2.0", + "@gobob/bob-sdk": "^1.3.0", "@gobob/react-query": "workspace:^", "@gobob/types": "workspace:^", "@gobob/utils": "workspace:^", diff --git a/packages/sats-wagmi/src/connectors/base.ts b/packages/sats-wagmi/src/connectors/base.ts index 9622806aa..a9f470310 100644 --- a/packages/sats-wagmi/src/connectors/base.ts +++ b/packages/sats-wagmi/src/connectors/base.ts @@ -1,4 +1,4 @@ -import { DefaultElectrsClient, RemoteSigner } from '@gobob/bob-sdk'; +import { DefaultEsploraClient, RemoteSigner } from '@gobob/bob-sdk'; import { Network as LibNetwork, Psbt, Transaction, networks } from 'bitcoinjs-lib'; import * as bitcoin from 'bitcoinjs-lib'; import retry from 'async-retry'; @@ -126,7 +126,7 @@ abstract class SatsConnector { // const network = await this.getNetwork(); - // const electrsClient = new DefaultElectrsClient(this.network as string); + // const electrsClient = new DefaultEsploraClient(this.network as string); // const utxos = await electrsClient.getAddressUtxos(this.ordinalsAddress); @@ -176,7 +176,7 @@ abstract class SatsConnector { } async getTransaction(txId: string): Promise { - const electrsClient = new DefaultElectrsClient(this.network as string); + const electrsClient = new DefaultEsploraClient(this.network as string); return retry( async (bail) => { @@ -205,7 +205,7 @@ abstract class SatsConnector { // throw new Error('Something went wrong while connecting'); // } - // const electrsClient = new DefaultElectrsClient(this.network as string); + // const electrsClient = new DefaultEsploraClient(this.network as string); // let inscription; diff --git a/packages/sats-wagmi/src/connectors/mm-snap.ts b/packages/sats-wagmi/src/connectors/mm-snap.ts index 962eb4526..674efa19e 100644 --- a/packages/sats-wagmi/src/connectors/mm-snap.ts +++ b/packages/sats-wagmi/src/connectors/mm-snap.ts @@ -174,7 +174,7 @@ class MMSnapConnector extends SatsConnector { // throw new Error('Public key missing'); // } - // const electrsClient = new DefaultElectrsClient(this.network as string); + // const electrsClient = new DefaultEsploraClient(this.network as string); // const libNetwork = await this.getNetwork(); // const network = this.network.toString(); @@ -271,7 +271,7 @@ class MMSnapConnector extends SatsConnector { // const libNetwork = await this.getNetwork(); // const senderAddress = bitcoin.payments.p2wpkh({ pubkey, network: libNetwork }).address!; - // const electrsClient = new DefaultElectrsClient(this.network as string); + // const electrsClient = new DefaultEsploraClient(this.network as string); // const utxos = await electrsClient.getAddressUtxos(senderAddress); // const inscriptionUtxo = await findUtxoForInscriptionId(electrsClient, utxos, inscriptionId); diff --git a/packages/sats-wagmi/src/hooks/useFeeRate.tsx b/packages/sats-wagmi/src/hooks/useFeeRate.tsx index db79aeddd..e3089d75d 100644 --- a/packages/sats-wagmi/src/hooks/useFeeRate.tsx +++ b/packages/sats-wagmi/src/hooks/useFeeRate.tsx @@ -1,4 +1,4 @@ -import { DefaultElectrsClient } from '@gobob/bob-sdk'; +import { DefaultEsploraClient } from '@gobob/bob-sdk'; import { CONFIRMATION_TARGET } from '@gobob/utils'; import { INTERVAL, UndefinedInitialDataOptions, useQuery } from '@gobob/react-query'; @@ -15,7 +15,7 @@ const useFeeRate = ({ query, confirmations = CONFIRMATION_TARGET }: UseFeeRatePr return useQuery({ queryKey: ['sats-fee-rate', network], queryFn: async () => { - const electrsClient = new DefaultElectrsClient(network); + const electrsClient = new DefaultEsploraClient(network); const feeRate = await electrsClient.getFeeEstimate(confirmations); diff --git a/packages/utils/package.json b/packages/utils/package.json index d9d200319..11616f224 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -36,7 +36,7 @@ "vitest": "^1.5.2" }, "dependencies": { - "@gobob/bob-sdk": "^1.2.0", + "@gobob/bob-sdk": "^1.3.0", "@scure/base": "^1.1.6", "@scure/btc-signer": "^1.3.1", "bitcoin-address-validation": "^2.2.3", diff --git a/packages/utils/src/inscription.ts b/packages/utils/src/inscription.ts index e7a87f4c0..59a141b4b 100644 --- a/packages/utils/src/inscription.ts +++ b/packages/utils/src/inscription.ts @@ -1,4 +1,4 @@ -import { ElectrsClient } from '@gobob/bob-sdk'; +import { EsploraClient } from '@gobob/bob-sdk'; import * as bitcoin from 'bitcoinjs-lib'; import { InscriptionId } from '@gobob/bob-sdk/dist/ordinal-api'; @@ -92,8 +92,8 @@ export function parseInscriptions(tx: bitcoin.Transaction) { return inscriptions; } -export async function getTxInscriptions(electrsClient: ElectrsClient, txid: string) { - const txHex = await electrsClient.getTransactionHex(txid); +export async function getTxInscriptions(esploraClient: EsploraClient, txid: string) { + const txHex = await esploraClient.getTransactionHex(txid); const tx = bitcoin.Transaction.fromHex(txHex); return parseInscriptions(tx); @@ -116,9 +116,9 @@ export function createImageInscription(image: Buffer) { return { contentType, content: image }; } -export async function getInscriptionFromId(electrsClient: ElectrsClient, inscriptionId: string) { +export async function getInscriptionFromId(esploraClient: EsploraClient, inscriptionId: string) { const { txid, index } = InscriptionId.fromString(inscriptionId); - const inscriptions = await getTxInscriptions(electrsClient, txid); + const inscriptions = await getTxInscriptions(esploraClient, txid); return inscriptions[index]; } diff --git a/packages/utils/src/utxo.ts b/packages/utils/src/utxo.ts index 047734279..1e1fadda8 100644 --- a/packages/utils/src/utxo.ts +++ b/packages/utils/src/utxo.ts @@ -1,4 +1,4 @@ -import { DefaultElectrsClient, ElectrsClient, UTXO } from '@gobob/bob-sdk'; +import { DefaultEsploraClient, EsploraClient, UTXO } from '@gobob/bob-sdk'; import { DefaultOrdinalsClient, TESTNET_ORD_BASE_PATH } from '@gobob/bob-sdk/dist/ordinal-api'; import { Transaction, Script, selectUTXO, TEST_NETWORK, NETWORK, p2wpkh, p2sh } from '@scure/btc-signer'; import { hex } from '@scure/base'; @@ -39,7 +39,7 @@ export interface Input { } export async function findUtxoForInscriptionId( - electrsClient: ElectrsClient, + esploraClient: EsploraClient, utxos: UTXO[], inscriptionId: string ): Promise { @@ -61,7 +61,7 @@ export async function findUtxoForInscriptionId( return utxo; } } else if (txid == utxo.txid) { - const inscriptions = await getTxInscriptions(electrsClient, utxo.txid); + const inscriptions = await getTxInscriptions(esploraClient, utxo.txid); if (typeof inscriptions[index] !== 'undefined') { return utxo; @@ -105,7 +105,7 @@ export async function createTransferWithOpReturn( addressType: string, publicKey?: string ): Promise { - const electrsClient = new DefaultElectrsClient(network); + const electrsClient = new DefaultEsploraClient(network); // eslint-disable-next-line no-console console.log('Payment address:', paymentAddress); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 679f9d8b7..ea61f8172 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -180,6 +180,9 @@ importers: '@ethersproject/providers': specifier: ^5.7.2 version: 5.7.2 + '@gobob/bob-sdk': + specifier: 1.3.0 + version: 1.3.0 '@gobob/chains': specifier: workspace:^ version: link:../../packages/chains @@ -441,8 +444,8 @@ importers: specifier: ^2.2.3 version: 2.2.3 '@gobob/bob-sdk': - specifier: ^1.2.0 - version: 1.2.0 + specifier: ^1.3.0 + version: 1.3.0 '@gobob/react-query': specifier: workspace:^ version: link:../react-query @@ -680,8 +683,8 @@ importers: packages/utils: dependencies: '@gobob/bob-sdk': - specifier: ^1.2.0 - version: 1.2.0 + specifier: ^1.3.0 + version: 1.3.0 '@scure/base': specifier: ^1.1.6 version: 1.1.6 @@ -3517,9 +3520,12 @@ packages: ts-interface-checker: 0.1.13 dev: true - /@gobob/bob-sdk@1.2.0: - resolution: {integrity: sha512-qugfTrYMqM5AAK10+E6qgCZgxEtp6xvY8+q9FPh/HL0e2JP5SBTeyG4jzherCvxYP+nuz08TwSqQW2yihw46+g==} + /@gobob/bob-sdk@1.3.0: + resolution: {integrity: sha512-NFrkl8cqgK7vFYnXdijkr3kTP2ZVWVMWeawUKRJHljZT6QB/P170kObI6jF88Z+oDM8u5dchbf1nmTne2lGLEA==} dependencies: + '@scure/base': 1.1.7 + '@scure/btc-signer': 1.3.2 + bitcoin-address-validation: 2.2.3 bitcoinjs-lib: 6.1.6 dev: false @@ -4159,7 +4165,7 @@ packages: '@ethereumjs/tx': 4.2.0 '@metamask/superstruct': 3.0.0 '@noble/hashes': 1.4.0 - '@scure/base': 1.1.6 + '@scure/base': 1.1.7 '@types/debug': 4.1.12 debug: 4.3.5(supports-color@8.1.1) pony-cause: 2.1.11 @@ -6437,6 +6443,10 @@ packages: /@scure/base@1.1.6: resolution: {integrity: sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==} + /@scure/base@1.1.7: + resolution: {integrity: sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g==} + dev: false + /@scure/bip32@1.3.2: resolution: {integrity: sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==} dependencies: @@ -6449,7 +6459,7 @@ packages: dependencies: '@noble/curves': 1.4.0 '@noble/hashes': 1.4.0 - '@scure/base': 1.1.6 + '@scure/base': 1.1.7 dev: false /@scure/bip39@1.2.1: @@ -6462,7 +6472,7 @@ packages: resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} dependencies: '@noble/hashes': 1.4.0 - '@scure/base': 1.1.6 + '@scure/base': 1.1.7 dev: false /@scure/btc-signer@1.3.2: @@ -16862,7 +16872,7 @@ packages: /micro-packed@0.6.3: resolution: {integrity: sha512-VmVkyc7lIzAq/XCPFuLc/CwQ7Ehs5XDK3IwqsZHiBIDttAI9Gs7go6Lv4lNRuAIKrGKcRTtthFKUNyHS0S4wJQ==} dependencies: - '@scure/base': 1.1.6 + '@scure/base': 1.1.7 dev: false /micromatch@4.0.5: