From dacf973da9576e157c24f21b132839685d8d8e02 Mon Sep 17 00:00:00 2001 From: plubber <51789398+ericHgorski@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:09:39 -0500 Subject: [PATCH] chore: release (#598) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Nur Fikri Co-authored-by: github-actions[bot] Co-authored-by: Not Jeremy Liu <31809888+NotJeremyLiu@users.noreply.github.com> Co-authored-by: Todd Kao Co-authored-by: thal0x <91888455+thal0x@users.noreply.github.com> --- .changeset/calm-deers-sniff.md | 5 + .changeset/curvy-windows-flash.md | 5 + .changeset/good-pans-unite.md | 5 + .changeset/lovely-dogs-beam.md | 5 + .changeset/nice-rivers-mix.md | 5 + .changeset/real-wasps-cheat.md | 5 + .changeset/serious-readers-beam.md | 5 + .changeset/small-mayflies-change.md | 5 + .changeset/strange-readers-relax.md | 5 + .changeset/stupid-bats-buy.md | 5 + ...altime-transaction-and-packet-tracking.mdx | 35 +- docs/widget/configuration.mdx | 88 ++- docs/widget/connected-wallet.mdx | 43 ++ examples/nextjs/src/app/injected/page.tsx | 181 +++++ examples/nextjs/src/app/layout.tsx | 3 +- examples/nextjs/src/app/page.tsx | 19 +- .../nextjs/src/hooks/useURLQueryParams.tsx | 4 +- examples/nextjs/window.d.ts | 7 + package.json | 4 +- packages/client/src/client-types.ts | 4 +- packages/client/src/types/converters.ts | 115 ++++ packages/client/src/types/lifecycle.ts | 39 +- packages/client/src/types/shared.ts | 40 ++ packages/client/src/types/unified.ts | 11 +- packages/widget/package.json | 9 +- .../src/components/RenderWalletList.tsx | 9 +- packages/widget/src/constants/wagmi.ts | 39 +- packages/widget/src/devMode/loadWidget.tsx | 15 - .../widget/src/hooks/useAutoSetAddress.ts | 29 +- .../src/hooks/useCreateCosmosWallets.tsx | 133 +++- .../widget/src/hooks/useCreateEvmWallets.tsx | 49 +- .../src/hooks/useCreateSolanaWallets.tsx | 46 +- .../widget/src/hooks/useFetchAllBalances.ts | 76 ++- packages/widget/src/hooks/useGetAccount.ts | 17 +- .../widget/src/hooks/useGetSourceBalance.ts | 4 +- .../src/hooks/useShowCosmosLedgerWarning.ts | 1 - .../AssetAndChainSelectorModalSearchInput.tsx | 7 +- .../useFilteredAssets.ts | 31 +- .../useFilteredChains.ts | 44 +- .../ConnectedWalletModal.tsx | 5 +- .../SetAddressModal/SetAddressModal.tsx | 8 +- .../SwapExecutionPageRouteDetailed.tsx | 2 + .../pages/SwapPage/ConnectedWalletContent.tsx | 2 +- .../widget/src/pages/SwapPage/SwapPage.tsx | 2 +- .../widget/src/providers/CosmosProvider.tsx | 5 +- packages/widget/src/state/balances.ts | 82 +-- packages/widget/src/state/callbacks.ts | 40 ++ packages/widget/src/state/skipClient.ts | 11 + .../widget/src/state/swapExecutionPage.ts | 24 +- packages/widget/src/state/wallets.ts | 6 +- packages/widget/src/utils/atomWithDebounce.ts | 2 +- packages/widget/src/utils/clientType.ts | 25 +- packages/widget/src/widget/Widget.tsx | 128 +--- packages/widget/src/widget/useInitWidget.ts | 157 +++++ yarn.lock | 631 ++++++++---------- 55 files changed, 1504 insertions(+), 778 deletions(-) create mode 100644 .changeset/calm-deers-sniff.md create mode 100644 .changeset/curvy-windows-flash.md create mode 100644 .changeset/good-pans-unite.md create mode 100644 .changeset/lovely-dogs-beam.md create mode 100644 .changeset/nice-rivers-mix.md create mode 100644 .changeset/real-wasps-cheat.md create mode 100644 .changeset/serious-readers-beam.md create mode 100644 .changeset/small-mayflies-change.md create mode 100644 .changeset/strange-readers-relax.md create mode 100644 .changeset/stupid-bats-buy.md create mode 100644 docs/widget/connected-wallet.mdx create mode 100644 examples/nextjs/src/app/injected/page.tsx create mode 100644 examples/nextjs/window.d.ts create mode 100644 packages/widget/src/state/callbacks.ts create mode 100644 packages/widget/src/widget/useInitWidget.ts diff --git a/.changeset/calm-deers-sniff.md b/.changeset/calm-deers-sniff.md new file mode 100644 index 000000000..b6bd04a9b --- /dev/null +++ b/.changeset/calm-deers-sniff.md @@ -0,0 +1,5 @@ +--- +'@skip-go/widget': patch +--- + +ability to pass signer and account diff --git a/.changeset/curvy-windows-flash.md b/.changeset/curvy-windows-flash.md new file mode 100644 index 000000000..fbffcb1ba --- /dev/null +++ b/.changeset/curvy-windows-flash.md @@ -0,0 +1,5 @@ +--- +'@skip-go/client': patch +--- + +update getCosmosSigner type diff --git a/.changeset/good-pans-unite.md b/.changeset/good-pans-unite.md new file mode 100644 index 000000000..362deb904 --- /dev/null +++ b/.changeset/good-pans-unite.md @@ -0,0 +1,5 @@ +--- +'@skip-go/widget': patch +--- + +fix balance loading display state diff --git a/.changeset/lovely-dogs-beam.md b/.changeset/lovely-dogs-beam.md new file mode 100644 index 000000000..25339ffe4 --- /dev/null +++ b/.changeset/lovely-dogs-beam.md @@ -0,0 +1,5 @@ +--- +'@skip-go/widget': patch +--- + +fix loading indicator diff --git a/.changeset/nice-rivers-mix.md b/.changeset/nice-rivers-mix.md new file mode 100644 index 000000000..e35bf858d --- /dev/null +++ b/.changeset/nice-rivers-mix.md @@ -0,0 +1,5 @@ +--- +'@skip-go/widget': patch +--- + +Add callback functions for wallet connect/disconnect and transaction broadcasted / completed / failed diff --git a/.changeset/real-wasps-cheat.md b/.changeset/real-wasps-cheat.md new file mode 100644 index 000000000..a030a9fca --- /dev/null +++ b/.changeset/real-wasps-cheat.md @@ -0,0 +1,5 @@ +--- +'@skip-go/client': minor +--- + +stargate transfer types diff --git a/.changeset/serious-readers-beam.md b/.changeset/serious-readers-beam.md new file mode 100644 index 000000000..6d3d3a06a --- /dev/null +++ b/.changeset/serious-readers-beam.md @@ -0,0 +1,5 @@ +--- +'@skip-go/widget': patch +--- + +exclude assets programatically diff --git a/.changeset/small-mayflies-change.md b/.changeset/small-mayflies-change.md new file mode 100644 index 000000000..680ccb89a --- /dev/null +++ b/.changeset/small-mayflies-change.md @@ -0,0 +1,5 @@ +--- +'@skip-go/widget': patch +--- + +add daodao iframe wallet diff --git a/.changeset/strange-readers-relax.md b/.changeset/strange-readers-relax.md new file mode 100644 index 000000000..1d90dbfa0 --- /dev/null +++ b/.changeset/strange-readers-relax.md @@ -0,0 +1,5 @@ +--- +'@skip-go/widget': minor +--- + +evm mobile wallet support diff --git a/.changeset/stupid-bats-buy.md b/.changeset/stupid-bats-buy.md new file mode 100644 index 000000000..1b61eaba3 --- /dev/null +++ b/.changeset/stupid-bats-buy.md @@ -0,0 +1,5 @@ +--- +'nextjs': patch +--- + +fix example default route and client asset search diff --git a/docs/general/multi-chain-realtime-transaction-and-packet-tracking.mdx b/docs/general/multi-chain-realtime-transaction-and-packet-tracking.mdx index 962910636..b3b0e14a3 100644 --- a/docs/general/multi-chain-realtime-transaction-and-packet-tracking.mdx +++ b/docs/general/multi-chain-realtime-transaction-and-packet-tracking.mdx @@ -59,6 +59,7 @@ The `transfer_sequence` array consists of `TransferEvent` objects, which give de * `AxelarTransferInfo` * `HyperlaneTransferInfo` * `GoFastTransferInfo` +* `StargateTransferInfo` Each one contains slightly different data and statuses corresponding to the details of their bridge, but they all contain some standard info: * `from_chain_id` @@ -174,8 +175,8 @@ When one of the transfers is a `GoFastTransfer`, the `transfer_sequence` array w Below are detailed explanations of the different fields and their purposes: -* `fromChainID`: The chain ID where the transfer originates (source chain). -* `toChainID`: The chain ID where the assets are being sent (destination chain). +* `from_chain_id`: The chain ID where the transfer originates (source chain). +* `to_chain_id`: The chain ID where the assets are being sent (destination chain). * `state`: Indicates the current status of the transfer. Possible values are: * `GO_FAST_TRANSFER_UNKNOWN`: An unknown error has occurred. * `GO_FAST_TRANSFER_SENT`: The user's intent has been successfully submitted on the source chain. @@ -184,14 +185,36 @@ Below are detailed explanations of the different fields and their purposes: * `GO_FAST_TRANSFER_FILLED`: The transfer was successfully fulfilled on the destination chain. * `GO_FAST_TRANSFER_REFUNDED`: The user's assets have been refunded on the source chain. * `txs`: Contains transaction details related to the GoFast transfer: - * `orderSubmittedTx`: The transaction where the user called initiateIntent on the source chain. - * `orderFilledTx`: The transaction where the solver called fulfill on the destination chain. - * `orderRefundedTx`: The transaction where the user received a refund on the source chain, if applicable. - * `orderTimeoutTx`: The transaction indicating a timeout occurred in the transfer process. + * `order_submitted_tx`: The transaction where the user called initiateIntent on the source chain. + * `order_filled_tx`: The transaction where the solver called fulfill on the destination chain. + * `order_refunded_tx`: The transaction where the user received a refund on the source chain, if applicable. + * `order_timeout_tx`: The transaction indicating a timeout occurred in the transfer process. When tracking a Go Fast transfer, you can use the `GoFastTransferInfo` to monitor the progress and status of your asset transfer between chains. For instance, if the state is `GO_FAST_TRANSFER_FILLED`, you know that the transfer was successful and your assets should be available on the destination chain. If the state is `GO_FAST_TRANSFER_TIMEOUT`, you can check the `orderTimeoutTx` for details on the timeout event. +### Stargate Transfer Data + +When one of the transfers is a `StargateTransfer`, the `transfer_sequence` array will include a `stargate_transfer` (`StargateTransferInfo`). This provides detailed information about a cross-chain asset transfer powered by Stargate, a popular cross-chain bridging protocol. + +Below are detailed explanations of the fields and their purposes: + +* `from_chain_id`: The chain ID where the transfer originates (source chain). +* `to_chain_id`: The chain ID where the assets are being sent (destination chain). + +* `state`: Indicates the current status of the Stargate transfer. Possible values are: + * `STARGATE_TRANSFER_UNKNOWN`: An unknown error has occurred or the state cannot be determined. + * `STARGATE_TRANSFER_SENT`: The transfer has been successfully initiated on the source chain (i.e., the assets have left the source chain and are in transit). + * `STARGATE_TRANSFER_RECEIVED`: The transfer has been successfully completed on the destination chain (i.e., the assets are now available at the recipient address on the destination chain). + * `STARGATE_TRANSFER_FAILED`: The transfer encountered an error during bridging and did not complete as intended. + +* `txs`: Contains transaction details related to the Stargate transfer. + * `send_tx`: The transaction on the source chain that initiated the Stargate transfer. + * `receive_tx`: The transaction on the destination chain where the assets were received. + * `error_tx`: A transaction (if any) related to the failure of the transfer. + +When monitoring a Stargate transfer, you can use `StargateTransferInfo` to confirm that your assets have safely bridged between chains or identify if and where a problem has occurred. + The Go Fast Protocol involves interactions with solvers who fulfill transfer intents. The additional transaction fields help provide transparency and traceability throughout the transfer process, ensuring users can track each step and identify any issues that may arise. diff --git a/docs/widget/configuration.mdx b/docs/widget/configuration.mdx index 3e39778b1..5a6dd2551 100644 --- a/docs/widget/configuration.mdx +++ b/docs/widget/configuration.mdx @@ -187,25 +187,33 @@ chainIdsToAffiliates: { } ``` -## Coming Soon - -The following props are in development and will be available soon. - ### `callbacks` Event handling functions. ```ts -onWalletConnected?: ({ walletName: string, chainId: string, address?: string }) => void; -onWalletDisconnected?: ({ chainType?: string }) => void; -onTransactionBroadcasted?: ({ txHash: string, chainId: string, explorerLink: string }) => void; -onTransactionComplete?: ({ txHash: string, chainId: string, explorerLink: string }) => void; -onTransactionFailed?: ({ error: string }) => void; -onValidateGasBalance?: (value: { - chainID?: string; - txIndex?: number; - status: "success" | "error" | "pending" | "completed" - }) => Promise; +onWalletConnected?: (params: { + walletName?: string; + chainIdToAddressMap: Record; + address?: string; +}) => void; + +onWalletDisconnected?: (params: { + walletName?: string; + chainType?: string; +}) => void; + +onTransactionBroadcasted?: (params: { + txHash: string; + chainId: string; + explorerLink?: string; +}) => void; +onTransactionComplete?: (params: { + txHash: string; + chainId: string; + explorerLink?: string; +}) => void; +onTransactionFailed?: (params: { error: Error }) => void; ``` - `onWalletConnected`: Called when a wallet is connected. @@ -213,27 +221,45 @@ onValidateGasBalance?: (value: { - `onTransactionBroadcasted`: Called when a transaction is broadcasted. This is called multiple times for multi-transaction routes. - `onTransactionComplete`: Triggered when a transaction is completed. - `onTransactionFailed`: Triggered when a transaction fails. -- `onValidateGasBalance`: Triggered when validating gas balance. -### `connectedWallet` +### `connectedAddresses` & `signers` + +If your application has already connected to a user's wallet (e.g., via MetaMask for EVM networks, Phantom for Solana, or Keplr for Cosmos), you **must provide both** the `connectedAddresses` and corresponding signer functions in order to enable the widget’s injected wallet functionality. +See an implementation example [here](https://github.com/skip-mev/skip-go/tree/staging/examples/nextjs/src/app/injected/page.tsx). -Inject your own wallet provider into the `Widget`. See an implementation example [here](https://github.com/skip-mev/skip-go/blob/3a7dcadde0eb0604c795b6a3bc857e6d2209b7a7/examples/nextjs/pages/inject-wallet.tsx#L73). `WalletClient` comes from the [`viem` package](https://viem.sh/docs/clients/wallet.html). `Adapter` comes from the [`@solana/wallet-adapter-base` package](https://solana.com/developers/cookbook/wallets/connect-wallet-react). And `OfflineSigner` comes from the [`@cosmjs` package](https://docs.keplr.app/api/cosmjs.html). -```ts -connectedWallet?: { - cosmos?: { - getAddress: (chainID: string) => Promise; - getSigner: (chainID: string) => Promise - }; - evm?: { - getAddress: (chainID: string) => Promise; - getSigner: (chainID: string) => Promise; - }; - svm?: { - getAddress: (chainID: string) => Promise; - getSigner: () => Promise; - }; +- **Type:** `Record` + +**Example:** +```typescript +const connectedAddresses: Record = { + "1": "0x123...abc", // Ethereum mainnet address + "cosmoshub-4": "cosmos1...", // Cosmos Hub address + "solana": "3n9...xyz", // Solana address + // ... add more chain IDs and addresses as needed }; ``` +### Signer Functions + +Each signer function below must be implemented to fully leverage the injected wallet capabilities: + +- **`getCosmosSigner(): Promise`** + Returns a Cosmos-compatible signer. + +- **`getEVMSigner(): Promise`** + Returns an EVM-compatible signer (e.g., from `viem`). + +- **`getSVMSigner(): Promise`** + Returns a Solana-compatible signer, such as a `PhantomWalletAdapter`. + +**Complete Example for injected wallet functionality:** +```jsx + +``` diff --git a/docs/widget/connected-wallet.mdx b/docs/widget/connected-wallet.mdx new file mode 100644 index 000000000..1e641b25b --- /dev/null +++ b/docs/widget/connected-wallet.mdx @@ -0,0 +1,43 @@ +--- +title: 'Connected Wallet' + +--- + +## Overview + +If your application has already connected to a user's wallet (e.g., via MetaMask for EVM networks, Phantom for Solana, or Keplr for Cosmos), you can provide this information directly to the Widget. By doing so, the Widget will: + +- Display and query balances for the user's already-connected wallet addresses for supported chains. +- Use the signer functions you provide to facilitate transactions, token swaps, or any operation that requires the user's signature. + +This eliminates the need for the user to perform a separate connection flow within the widget itself, improving their overall experience and reducing friction. + + +See a full code example [here](https://github.com/skip-mev/skip-go/tree/staging/examples/nextjs/src/app/injected/page.tsx). + + +## Key Props and Concepts + +### `connectedAddresses` + +The `connectedAddresses` prop is a map from chain IDs to addresses. This map tells the widget which addresses are currently connected and should be used for transactions. + +- **Type:** `Record` +- **Example:** + ```typescript + const accountMap: Record = { + "1": "0x123...abc", // Ethereum mainnet address + "solana": "3n9...xyz", // Solana address + "cosmoshub-4": "cosmos1...", // Cosmos Hub address + ... + }; + +### Signer Functions + +In addition to passing in `connectedAddresses`, you must also provide the widget with signer functions so it can sign and send transactions on behalf of the user. These functions vary by chain type and are provided as separate props: + +- `getCosmosSigner() => Promise` +- `getEVMSigner() => Promise` +- `getSVMSigner() => Promise` + +Each of these functions should return a signer (or signer-like interface) that the widget can use to create and broadcast transactions. diff --git a/examples/nextjs/src/app/injected/page.tsx b/examples/nextjs/src/app/injected/page.tsx new file mode 100644 index 000000000..101cd3d67 --- /dev/null +++ b/examples/nextjs/src/app/injected/page.tsx @@ -0,0 +1,181 @@ +'use client'; + +import React, { useState } from "react"; +import { Widget } from "@skip-go/widget"; +import { PhantomWalletAdapter } from "@solana/wallet-adapter-phantom"; +import { createWalletClient, custom, Account } from "viem"; +import { mainnet, optimism, polygon, base, arbitrum, avalanche } from 'viem/chains'; + +type ChainId = string; +type Address = string; + +export default function Home() { + // This state holds a mapping from chain IDs to connected addresses. + const [connectedAddresses, setConnectedAddresses] = useState>(); + + /** + * Helper to update the connectedAddresses with a given chainId and address. + */ + const updateAccount = (chainId: ChainId, address: Address) => { + setConnectedAddresses((prev) => ({ + ...prev, + [chainId]: address, + })); + }; + + /** + * Connect to an EVM-compatible wallet (e.g., MetaMask). + */ + const connectEthereum = async () => { + const ethereum = window.ethereum; + if (!ethereum) { + throw new Error("MetaMask not installed"); + } + + // Request accounts + const accounts = (await ethereum.request({ + method: "eth_requestAccounts", + })) as string[]; + + const evmAddress = accounts[0]; + if (!evmAddress) throw new Error("No EVM accounts found"); + + // Get currently selected chain ID from MetaMask + const chainIdHex = (await ethereum.request({ method: 'eth_chainId' })) as string; + const chainId = parseInt(chainIdHex, 16).toString(); + + updateAccount(chainId, evmAddress); + }; + + /** + * Connect to a Solana wallet using Phantom Wallet Adapter. + */ + const connectSolana = async () => { + const phantom = new PhantomWalletAdapter(); + await phantom.connect(); + const publicKey = phantom.publicKey?.toBase58(); + if (!publicKey) throw new Error("No public key found"); + updateAccount("solana", publicKey); + }; + + /** + * Connect to Cosmos-based chains using Keplr. + */ + const connectCosmos = async () => { + const chainIds = ["cosmoshub-4", "osmosis-1"]; + + // Request access to the specified Cosmos chains from Keplr + await window.keplr?.enable(chainIds); + + // Fetch and store addresses for each chain + await Promise.all( + chainIds.map(async (chainId) => { + const keyInfo = await window.keplr?.getKey(chainId); + if (keyInfo && keyInfo.bech32Address) { + updateAccount(chainId, keyInfo.bech32Address); + } + }) + ); + }; + + /** + * Get an offline signer for a given Cosmos chain using Keplr. + */ + const getCosmosSigner = async (chainId: string) => { + if (window.keplr?.getOfflineSigner === undefined) { + throw new Error("Keplr extension not installed"); + } + const offlineSigner = await window.keplr?.getOfflineSigner(chainId); + return offlineSigner; + } + + /** + * Get an EVM-compatible signer by creating a viem wallet client. + */ + const chainConfigMap: Record = { + "1": mainnet, + "10": optimism, + "137": polygon, + "8453": base, + "42161": arbitrum, + "43114": avalanche, + }; + + const getEVMSigner = async () => { + const ethereum = window.ethereum; + if (!ethereum) { + throw new Error("MetaMask not installed"); + } + + // Request accounts + const accounts = (await ethereum.request({ + method: "eth_requestAccounts", + })) as Account[]; + + const evmAddress = accounts?.[0]; + if (!evmAddress) { + throw new Error("No EVM accounts found"); + } + + // Get the currently selected chain ID + const chainIdHex = (await ethereum.request({ method: 'eth_chainId' })) as string; + const chainId = parseInt(chainIdHex, 16).toString(); + + const selectedChain = chainConfigMap[chainId] ?? mainnet; + + const client = createWalletClient({ + account: evmAddress, + chain: selectedChain, + transport: custom(ethereum), + }); + + return client; + }; + + /** + * Get an SVM-compatible signer using Phantom. + */ + const getSVMSigner = async () => { + const phantom = new PhantomWalletAdapter(); + await phantom.connect(); + return phantom; + }; + + return ( +
+

Connected addresses:

+
    + {Object.entries(connectedAddresses ?? {}).map(([chainId, address]) => ( +
  • + {chainId}: {address} +
  • + ))} +
+
+ + + +
+ +
+ ); +} diff --git a/examples/nextjs/src/app/layout.tsx b/examples/nextjs/src/app/layout.tsx index 4c35f5c92..86dcd06e1 100644 --- a/examples/nextjs/src/app/layout.tsx +++ b/examples/nextjs/src/app/layout.tsx @@ -2,8 +2,7 @@ import type { Metadata } from "next"; import "./globals.css"; export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Skip Go Example", }; export default function RootLayout({ diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx index b3270d857..563193122 100644 --- a/examples/nextjs/src/app/page.tsx +++ b/examples/nextjs/src/app/page.tsx @@ -50,15 +50,22 @@ export default function Home() { }} > {/* widget will cohere to the parent container's width */} -
+
console.log('onWalletConnected', { ...props })} + onWalletDisconnected={(props) => console.log('onWalletDisconnected', { ...props })} + onTransactionBroadcasted={(props) => console.log('onTransactionBroadcasted', { ...props })} + onTransactionFailed={(props) => console.log('onTransactionFailed', { ...props })} + onTransactionComplete={(props) => console.log('onTransactionComplete', { ...props })} />
diff --git a/examples/nextjs/src/hooks/useURLQueryParams.tsx b/examples/nextjs/src/hooks/useURLQueryParams.tsx index 06e9b04a3..fec84b2bf 100644 --- a/examples/nextjs/src/hooks/useURLQueryParams.tsx +++ b/examples/nextjs/src/hooks/useURLQueryParams.tsx @@ -2,7 +2,7 @@ import { useState, useEffect } from 'react'; import { WidgetProps } from '@skip-go/widget'; export const useQueryParams = () => { - const [params, setParams] = useState({}); + const [params, setParams] = useState(undefined); useEffect(() => { if (typeof window !== 'undefined') { @@ -35,6 +35,8 @@ export const useQueryParams = () => { } }); + if (!Object.keys(result).length) return; + setParams(result as WidgetProps['defaultRoute']); } }, []); diff --git a/examples/nextjs/window.d.ts b/examples/nextjs/window.d.ts new file mode 100644 index 000000000..479e6f31e --- /dev/null +++ b/examples/nextjs/window.d.ts @@ -0,0 +1,7 @@ +import { Window as KeplrWindow } from "@keplr-wallet/types"; + +declare global { + interface Window extends KeplrWindow { + ethereum: import("@metamask/providers").MetaMaskInpageProvider; + } +} diff --git a/package.json b/package.json index b42667ff3..cbd8216b0 100644 --- a/package.json +++ b/package.json @@ -86,9 +86,9 @@ "tsx": "^4.12.0", "typescript": "5.2.x", "typescript-plugin-styled-components": "3.0.0", - "viem": "2.21.4", + "viem": "^2.21.55", "vitest": "^1.2.2", - "wagmi": "2.12.9" + "wagmi": "^2.14.1" }, "packageManager": "yarn@3.2.0", "dependencies": { diff --git a/packages/client/src/client-types.ts b/packages/client/src/client-types.ts index 397a1ec4f..91ff9d0ff 100644 --- a/packages/client/src/client-types.ts +++ b/packages/client/src/client-types.ts @@ -1,4 +1,4 @@ -import { Coin, OfflineAminoSigner } from '@cosmjs/amino'; +import { OfflineAminoSigner } from '@cosmjs/amino'; import { GeneratedType, OfflineDirectSigner, @@ -37,7 +37,7 @@ export type Gas = { /** Signer Getters */ export interface SignerGetters { getEVMSigner?: (chainID: string) => Promise; - getCosmosSigner?: (chainID: string) => Promise; + getCosmosSigner?: (chainID: string) => Promise; getSVMSigner?: () => Promise; } diff --git a/packages/client/src/types/converters.ts b/packages/client/src/types/converters.ts index 05754ec9e..914ada5d4 100644 --- a/packages/client/src/types/converters.ts +++ b/packages/client/src/types/converters.ts @@ -49,6 +49,10 @@ import { GoFastTransferInfoJSON, GoFastTransferTransactions, GoFastTransferTransactionsJSON, + StargateTransferInfo, + StargateTransferInfoJSON, + StargateTransferTransactionsJSON, + StargateTransferTransactions, } from './lifecycle'; import { Chain, @@ -129,6 +133,8 @@ import { GoFastTransferJSON, GoFastFee, GoFastFeeJSON, + StargateTransferJSON, + StargateTransfer, } from './shared'; import { AssetBetweenChains, @@ -878,6 +884,43 @@ export function goFastTransferFromJSON(goFastJSON: GoFastTransferJSON): GoFastTr destinationDomain: goFastJSON.destination_domain, }; } + +export function stargateTransferFromJSON(stargateTransferJSON: StargateTransferJSON): StargateTransfer { + return { + fromChainID: stargateTransferJSON.from_chain_id, + toChainID: stargateTransferJSON.to_chain_id, + denomIn: stargateTransferJSON.denom_in, + denomOut: stargateTransferJSON.denom_out, + poolAddress: stargateTransferJSON.pool_address, + destinationEndpointID: stargateTransferJSON.destination_endpoint_id, + oftFeeAsset: assetFromJSON(stargateTransferJSON.oft_fee_asset), + oftFeeAmount: stargateTransferJSON.oft_fee_amount, + oftFeeAmountUSD: stargateTransferJSON.oft_fee_amount_usd, + sendFeeAsset: assetFromJSON(stargateTransferJSON.send_fee_asset), + sendFeeAmount: stargateTransferJSON.send_fee_amount, + sendFeeAmountUSD: stargateTransferJSON.send_fee_amount_usd, + bridgeID: stargateTransferJSON.bridge_id, + } +} + +export function stargateTransferToJSON(stargateTransfer: StargateTransfer): StargateTransferJSON { + return { + from_chain_id: stargateTransfer.fromChainID, + to_chain_id: stargateTransfer.toChainID, + denom_in: stargateTransfer.denomIn, + denom_out: stargateTransfer.denomOut, + pool_address: stargateTransfer.poolAddress, + destination_endpoint_id: stargateTransfer.destinationEndpointID, + oft_fee_asset: assetToJSON(stargateTransfer.oftFeeAsset), + oft_fee_amount: stargateTransfer.oftFeeAmount, + oft_fee_amount_usd: stargateTransfer.oftFeeAmountUSD, + send_fee_asset: assetToJSON(stargateTransfer.sendFeeAsset), + send_fee_amount: stargateTransfer.sendFeeAmount, + send_fee_amount_usd: stargateTransfer.sendFeeAmountUSD, + bridge_id: stargateTransfer.bridgeID, + } +} + export function operationFromJSON(operationJSON: OperationJSON): Operation { const commonProps = { txIndex: operationJSON.tx_index, @@ -934,6 +977,13 @@ export function operationFromJSON(operationJSON: OperationJSON): Operation { }; } + if ('stargate_transfer' in operationJSON) { + return { + ...commonProps, + stargateTransfer: stargateTransferFromJSON(operationJSON.stargate_transfer), + }; + } + if ('swap' in operationJSON) { return { ...commonProps, @@ -1007,6 +1057,13 @@ export function operationToJSON(operation: Operation): OperationJSON { }; } + if ('stargateTransfer' in operation) { + return { + ...commonProps, + stargate_transfer: stargateTransferToJSON(operation.stargateTransfer), + }; + } + if ('swap' in operation) { return { ...commonProps, @@ -1632,6 +1689,7 @@ export function hyperlaneTransferToJSON( }; } + export function opInitTransferFromJSON( value: OPInitTransferJSON ): OPInitTransfer { @@ -2018,6 +2076,12 @@ export function transferEventFromJSON(value: TransferEventJSON): TransferEvent { }; } + if ('stargate_transfer' in value) { + return { + stargateTransfer: stargateTransferInfoFromJSON(value.stargate_transfer), + }; + } + return { axelarTransfer: axelarTransferInfoFromJSON(value.axelar_transfer), }; @@ -2053,6 +2117,11 @@ export function transferEventToJSON(value: TransferEvent): TransferEventJSON { go_fast_transfer: goFastTransferInfoToJson(value.goFastTransfer), }; } + if ('stargateTransfer' in value) { + return { + stargate_transfer: stargateTransferInfoToJSON(value.stargateTransfer), + }; + } return { axelar_transfer: axelarTransferInfoToJSON(value.axelarTransfer), @@ -2405,6 +2474,30 @@ export function opInitTransferTransactionsToJSON( }; } +export function stargateTransferTransactionsFromJSON( + value: StargateTransferTransactionsJSON +): StargateTransferTransactions { + return { + sendTx: value.send_tx ? chainTransactionFromJSON(value.send_tx) : null, + receiveTx: value.receive_tx + ? chainTransactionFromJSON(value.receive_tx) + : null, + errorTx: value.error_tx ? chainTransactionFromJSON(value.error_tx) : null, + }; +} + +export function stargateTransferTransactionsToJSON( + value: StargateTransferTransactions +): StargateTransferTransactionsJSON { + return { + send_tx: value.sendTx ? chainTransactionToJSON(value.sendTx) : null, + receive_tx: value.receiveTx + ? chainTransactionToJSON(value.receiveTx) + : null, + error_tx: value.errorTx ? chainTransactionToJSON(value.errorTx) : null, + }; +} + export function opInitTransferInfoFromJSON( value: OPInitTransferInfoJSON ): OPInitTransferInfo { @@ -2426,6 +2519,28 @@ export function opInitTransferInfoToJSON( txs: value.txs && opInitTransferTransactionsToJSON(value.txs), }; } + +export function stargateTransferInfoFromJSON( + value: StargateTransferInfoJSON +): StargateTransferInfo { + return { + fromChainID: value.from_chain_id, + toChainID: value.to_chain_id, + state: value.state, + txs: value.txs && stargateTransferTransactionsFromJSON(value.txs), + }; +} + +export function stargateTransferInfoToJSON( + value: StargateTransferInfo +): StargateTransferInfoJSON { + return { + from_chain_id: value.fromChainID, + to_chain_id: value.toChainID, + state: value.state, + txs: value.txs && stargateTransferTransactionsToJSON(value.txs), + }; +} export function msgsDirectRequestFromJSON( msgDirectRequestJSON: MsgsDirectRequestJSON ): MsgsDirectRequest { diff --git a/packages/client/src/types/lifecycle.ts b/packages/client/src/types/lifecycle.ts index 2207c516a..25caea83b 100644 --- a/packages/client/src/types/lifecycle.ts +++ b/packages/client/src/types/lifecycle.ts @@ -435,6 +435,39 @@ export type GoFastTransferInfo = { txs: GoFastTransferTransactions; }; +export type StargateTransferState = + | "STARGATE_TRANSFER_UNKNOWN" + | "STARGATE_TRANSFER_SENT" + | "STARGATE_TRANSFER_RECEIVED" + | "STARGATE_TRANSFER_FAILED" + + +export type StargateTransferTransactionsJSON = { + send_tx: ChainTransactionJSON | null; + receive_tx: ChainTransactionJSON | null; + error_tx: ChainTransactionJSON | null; +}; + +export type StargateTransferTransactions = { + sendTx: ChainTransaction | null; + receiveTx: ChainTransaction | null; + errorTx: ChainTransaction | null; +}; + +export type StargateTransferInfoJSON = { + from_chain_id: string; + to_chain_id: string; + state: StargateTransferState; + txs: StargateTransferTransactionsJSON; +}; + +export type StargateTransferInfo = { + fromChainID: string; + toChainID: string; + state: StargateTransferState; + txs: StargateTransferTransactions; +}; + export type OPInitTransferState = | 'OPINIT_TRANSFER_UNKNOWN' | 'OPINIT_TRANSFER_SENT' @@ -475,7 +508,8 @@ export type TransferEventJSON = | { cctp_transfer: CCTPTransferInfoJSON } | { hyperlane_transfer: HyperlaneTransferInfoJSON } | { op_init_transfer: OPInitTransferInfoJSON } - | { go_fast_transfer: GoFastTransferInfoJSON }; + | { go_fast_transfer: GoFastTransferInfoJSON } + | { stargate_transfer: StargateTransferInfoJSON }; export type TransferEvent = | { @@ -485,7 +519,8 @@ export type TransferEvent = | { cctpTransfer: CCTPTransferInfo } | { hyperlaneTransfer: HyperlaneTransferInfo } | { opInitTransfer: OPInitTransferInfo } - | { goFastTransfer: GoFastTransferInfo }; + | { goFastTransfer: GoFastTransferInfo } + | { stargateTransfer: StargateTransferInfo }; type CallbackStatus = 'success' | 'error' | 'pending' | 'completed'; export interface TransactionCallbacks { diff --git a/packages/client/src/types/shared.ts b/packages/client/src/types/shared.ts index e8020c909..846384dba 100644 --- a/packages/client/src/types/shared.ts +++ b/packages/client/src/types/shared.ts @@ -198,6 +198,46 @@ export type GoFastTransferJSON = { destination_domain: string; } +export type StargateTransferJSON = { + from_chain_id: string; + to_chain_id: string; + denom_in: string; + denom_out: string; + + pool_address: string; + destination_endpoint_id: number; + + oft_fee_asset: AssetJSON; + oft_fee_amount: string; + oft_fee_amount_usd: string; + + send_fee_asset: AssetJSON; + send_fee_amount: string; + send_fee_amount_usd: string; + + bridge_id: BridgeType; +}; + +export type StargateTransfer = { + fromChainID: string; + toChainID: string; + denomIn: string; + denomOut: string; + + poolAddress: string; + destinationEndpointID: number; + + oftFeeAsset: Asset; + oftFeeAmount: string; + oftFeeAmountUSD: string; + + sendFeeAsset: Asset; + sendFeeAmount: string; + sendFeeAmountUSD: string; + + bridgeID: BridgeType; +}; + export type BankSendJSON = { chain_id: string; denom: string; diff --git a/packages/client/src/types/unified.ts b/packages/client/src/types/unified.ts index fb59dee79..66771f4c9 100644 --- a/packages/client/src/types/unified.ts +++ b/packages/client/src/types/unified.ts @@ -41,6 +41,8 @@ import { SmartSwapOptionsJSON, ChainAffiliatesJSON, ChainAffiliates, + StargateTransferJSON, + StargateTransfer, } from './shared'; export type AssetsRequestJSON = { @@ -290,7 +292,8 @@ export type OperationJSON = | (BaseOperationJSON & { hyperlane_transfer: HyperlaneTransferJSON }) | (BaseOperationJSON & { evm_swap: EvmSwapJSON }) | (BaseOperationJSON & { op_init_transfer: OPInitTransferJSON }) - | (BaseOperationJSON & { go_fast_transfer: GoFastTransferJSON }); + | (BaseOperationJSON & { go_fast_transfer: GoFastTransferJSON }) + | (BaseOperationJSON & { stargate_transfer: StargateTransferJSON }); interface BaseOperation { txIndex: number; @@ -307,7 +310,8 @@ export type Operation = | (BaseOperation & { hyperlaneTransfer: HyperlaneTransfer }) | (BaseOperation & { evmSwap: EvmSwap }) | (BaseOperation & { opInitTransfer: OPInitTransfer }) - | (BaseOperation & { goFastTransfer: GoFastTransfer }); + | (BaseOperation & { goFastTransfer: GoFastTransfer }) + | (BaseOperation & { stargateTransfer: StargateTransfer }); export type RouteResponseJSON = { source_asset_denom: string; @@ -527,13 +531,14 @@ export type MsgsResponse = { warning?: MsgsWarning; }; -export type BridgeType = 'IBC' | 'AXELAR' | 'CCTP' | 'HYPERLANE' | 'OPINIT' | 'GO_FAST'; +export type BridgeType = 'IBC' | 'AXELAR' | 'CCTP' | 'HYPERLANE' | 'OPINIT' | 'GO_FAST' | 'STARGATE'; export enum ChainType { Cosmos = 'cosmos', EVM = 'evm', SVM = 'svm', } + export type TxResult = { txHash: string chainID: string diff --git a/packages/widget/package.json b/packages/widget/package.json index 4954ed46d..8a99eb486 100644 --- a/packages/widget/package.json +++ b/packages/widget/package.json @@ -11,6 +11,7 @@ "dev": "vite --force --host", "dev:storybook": "storybook dev -p 6006", "build": "npm run generate-chains && NODE_OPTIONS=--max-old-space-size=16384 vite build", + "watch:build": "vite build --watch", "lint": "NODE_OPTIONS=--max-old-space-size=32384 eslint . --fix", "preview": "vite preview", "build:web-component": "NODE_OPTIONS=--max-old-space-size=32384 webpack --config webpack.config.js", @@ -49,7 +50,7 @@ "@types/eslint__js": "^8.42.3", "@types/pluralize": "^0.0.33", "@types/react": "^17.0.0", - "@types/react-dom": "^17.0.0", + "@types/react-dom": "^19.0.2", "@typescript-eslint/eslint-plugin": "^7.15.0", "@typescript-eslint/parser": "^7.15.0", "@vitejs/plugin-react": "^4.3.1", @@ -81,8 +82,8 @@ "graz": "^0.1.30", "react": ">=17.0.0", "react-dom": ">=17.0.0", - "viem": "2.21.4", - "wagmi": "2.12.9" + "viem": "^2.21.55", + "wagmi": "^2.14.1" }, "dependencies": { "@cosmjs/cosmwasm-stargate": "^0.32.4", @@ -108,6 +109,8 @@ "@solana/wallet-adapter-trust": "^0.1.13", "@solana/web3.js": "^1.95.8", "@tanstack/query-core": "^5.51.21", + "@walletconnect/modal": "2.7.0", + "@walletconnect/sign-client": "2.17.2", "jotai": "^2.10.1", "jotai-effect": "^1.0.2", "jotai-tanstack-query": "^0.8.6", diff --git a/packages/widget/src/components/RenderWalletList.tsx b/packages/widget/src/components/RenderWalletList.tsx index 5d95464f3..b37b88814 100644 --- a/packages/widget/src/components/RenderWalletList.tsx +++ b/packages/widget/src/components/RenderWalletList.tsx @@ -14,6 +14,7 @@ import { clearAssetInputAmountsAtom } from "@/state/swapPage"; import NiceModal from "@ebay/nice-modal-react"; import { Modals } from "@/modals/registerModals"; import { ChainType } from "@skip-go/client"; +import { WalletSource } from "@/modals/SetAddressModal/SetAddressModal"; export type RenderWalletListProps = { title: string; @@ -21,7 +22,7 @@ export type RenderWalletListProps = { onClickBackButton: () => void; isDestinationAddress?: boolean; chainId?: string; - chainType?: string; + chainType?: ChainType; isConnectEco?: boolean; chainAddressIndex?: number; }; @@ -74,9 +75,9 @@ export const RenderWalletList = ({ ...prev, [destinationIndex]: { chainID: chainId, - chainType: chainType as ChainType, - address: address, - source: "wallet", + chainType, + address, + source: WalletSource.Wallet, wallet: { walletName: wallet.walletName, walletPrettyName: wallet.walletPrettyName, diff --git a/packages/widget/src/constants/wagmi.ts b/packages/widget/src/constants/wagmi.ts index 5d6a4bfb2..4ed729ea1 100644 --- a/packages/widget/src/constants/wagmi.ts +++ b/packages/widget/src/constants/wagmi.ts @@ -29,37 +29,12 @@ import { polygonMumbai, sei, sepolia, + forma } from "wagmi/chains"; import { defineChain } from "viem"; -const isBrowser = typeof window !== "undefined"; +import { walletConnect } from "wagmi/connectors" -export const forma = defineChain({ - id: 984_122, - name: "Forma", - nativeCurrency: { - name: "TIA", - symbol: "TIA", - decimals: 18, - }, - rpcUrls: { - default: { - http: ["https://rpc.forma.art"], - }, - }, - blockExplorers: { - default: { - name: "Forma Explorer", - url: "https://explorer.forma.art", - }, - }, - contracts: { - multicall3: { - address: "0xd53C6FFB123F7349A32980F87faeD8FfDc9ef079", - blockCreated: 252_705, - }, - }, - testnet: false, -}); +const isBrowser = typeof window !== "undefined"; export const formaTestnet = defineChain({ id: 984_123, @@ -154,4 +129,12 @@ export const config: Config = createConfig({ storage: isBrowser ? localStorage : undefined, // Use a fallback for SSR key: "skip-go-widget-wagmi", }), + connectors: [ + walletConnect({ + projectId: "ff1b9e9bd6329cfb07642bd7f4d11a8c", + showQrModal: true + }) + ] }); + +export const walletConnectLogo = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAMAAABOo35HAAADAFBMVEVHcEwge/wfffwKcv4TeP0MdP4ngvwog/wcfP0Xe/0hgP0Vev0hgP0ff/wbfv8cffwbffwbfPwaff4QeP4Jc/4sg/oshfsng/wafPwggv8ihf8dffwYgf8hfPgffvsogfslgv0ffvwefvwafP0Ze/0Xe/4QeP4JdP4wiPskgfsliP8igPwhf/wgf/wff/wXe/0VfP8Wefw0ifsXev0Wev0Tfv8Hc/4nhv8kgfwjgPwVef0Tef8IdP4Hcv4vh/sTef0Gc/4Fcf4phf0rif8ng/0lgfsmgvsTeP0ngvsSeP0phf4og/sRd/0Pev8Pd/8Off8vjf8pg/sQd/0qhPsDcf4rhPsPdv4shfsyjf8thfsNdv4uhvs3i/sNdf4Ecf5Aj/k0i/0vh/wvhvoMdv8GdP40ivwyif0wh/oJev8zi/02j/8Ldf5Ik/kxh/oyiPoEcf5CkPgLdP4Kdf8ziPo5kf80ifoJdP41ifo3jP02ivoIdP8Ic/4IeP1Ik/g5jf03ivoHd/89lP84i/pCj/k5i/o5i/k6jPk7jfoGc/88jvw7jPkGcv4/kPw9kf88jflAkvtGkvpAk/89jfkBcP9Dlv8+jfk+jvkCdv9Dkfk/jvkEcv4DeP9Aj/kFcf9Bj/lJmP9Cj/lPlvhEkvxCkPkDcf9DkPlKk/dDkPhEkfhIlfxFkfhBj/hGkvhGkfhQnP9HkvgBc/9PlvdIk/gCcP9Jk/hOmf1Kk/hNlfdKlPhNlfhRl/dLlPggfvsdffspgvpVnPxgpP12sP2Ct/0ae/tanfqbxf2z0/7I3/7Z6f/k8P/x9//2+v/////U5/98s/wrhPqsz/7P4/78/f9Mlfi61/5bof6Uwf1OlfhtqvxQlveMvf1Ql/dOlfff7f9Wn/9OlvcthPlPlvcwhvlop/tQl/eiyf0AcP80iPlSmPdWmvZRl/cNdP3r9P82iflVm/nB2/5TmPdWmfdVmfdUmPdXmvdWmfdWmvhYmfZZm/Y+jfg8jPhZnPUDb/1bnPZbm/VcnfcUYgSRAAAA/3RSTlMACh8sRU5rhJSqw9XR7f//////7YASLOD4/////wQYObf//////7VfYf///////////53///+b///////AjKj/4Wvt///////////////////////V/////////7n/to33////+Nn////p//8o//+nSv///////////////4D//////7X///////////////ju///u/////9///////////2j/////W//////V//////+Z///////R//+o/////////////////////////////////////+b/t//v/////////////////9D/////////6f/////b9v///77///H5MkSAAAAo7klEQVR4AeTWBW4rMRSF4SbDWAgzM3PKzIz7X8o798HIr5Y1YnWSfwmfjq+88QMKhSVZUTXdMC3bcTfR1tY22olYlmnoUVWRpXBoY82LxWVVM+yEk0yl0+kUct3MJqPlum6WcpOOZRtRVY7H1pAply+oetF20lQKlUqlMpXJMFqoUqlWq7XaDqGhiFXXG4V8bn2k4k2t6LTS7XY61en2qH6fsMRag9/VarUhwIajSD3aiK/BouLNMfZETqkO6nah9YdLqFX1tCaTyXQ6HQ6Hs+wwYs0b0govLC/rptNuL9LLXapDdRE7Ln8ttLe3tz+czbKRg0M5v4pSYfUosVi000vKRwvxL5HVIq7j42OADU+M0/CKXSm1eNY+X1wsLy8vWx4WtNiXyN8tHou0PCxqf5idReqn0spsqlk8O4fUFbpErZb/tlgtJJoWur7e35/Bq7EC+wopRyR1g2CFWC2Gy1cLibSub2+H8JoroWA/P82+O1/c34OK1/J7ieKzxWGhh8fZoxUN7HPMyTSqu/vf/a8FLk+L25a/1hTxWg9Pz7OIIQfxOxFTzfOX81fkaSGhFvcSM9+vfFW8LcIirbc3zOvgNBa0o64lMKp35HFxT9HvbnFfeQ9LuC1wPT0/f0TDgTpVZy9/qARal4i9WxR3t/gPBK/FY4HrcRY5lIJCNQbVJ8VqUYIz//0llpDoK88/RF7r6+nxOTKXgkL1ixmz4I0jiGKwyigKCsrMzMzMeHwX3jAzc/Kv+6aBp63PmulKC/4Jn2w/z/z+/XNN7uZSWpeQluUk+mEJrV+/DK6axHeVQWWksETUWwALSj6QtUTGXQ+3JvoC1qaep9Pp34ALvcWTiOM0EK2M4HpSldjLeGb/ly/ZrMACXGAuksQLnBYPIoMl+vhx3+lE7q7DOUFlpLB+85pnSYSS59bCi4i08h8/Fg4nDtWhYilVV59d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" diff --git a/packages/widget/src/devMode/loadWidget.tsx b/packages/widget/src/devMode/loadWidget.tsx index dc47bc6e2..ca472cb53 100644 --- a/packages/widget/src/devMode/loadWidget.tsx +++ b/packages/widget/src/devMode/loadWidget.tsx @@ -46,21 +46,6 @@ const DevMode = () => { routeConfig={{ goFast: true, }} - // // @ts-expect-error - testing - // connectedAddress={{ - // "cosmoshub-4": "address", - // "1": "0xaddress", - // "solana": "address", - // }} - // getCosmosSigner={(chainId) => { - // return getSigner(chainId) - // }} - // getEVMSigner={(chainId) => { - // return getSigner(chainId) - // }} - // getSVMSigner={(chainId) => { - // return getSigner(chainId) - // }} /> diff --git a/packages/widget/src/hooks/useAutoSetAddress.ts b/packages/widget/src/hooks/useAutoSetAddress.ts index 9301f9bbd..11015c6bc 100644 --- a/packages/widget/src/hooks/useAutoSetAddress.ts +++ b/packages/widget/src/hooks/useAutoSetAddress.ts @@ -5,6 +5,7 @@ import { chainAddressesAtom, swapExecutionStateAtom, } from "@/state/swapExecutionPage"; +import { connectedAddressesAtom } from "@/state/wallets"; import { walletsAtom } from "@/state/wallets"; import { useQuery } from "@tanstack/react-query"; import { useAtom, useAtomValue } from "jotai"; @@ -16,6 +17,7 @@ import { getClientOperations } from "@/utils/clientType"; import NiceModal from "@ebay/nice-modal-react"; import { Modals } from "@/modals/registerModals"; import { ChainType } from "@skip-go/client"; +import { WalletSource } from "@/modals/SetAddressModal/SetAddressModal"; export const useAutoSetAddress = () => { const [chainAddresses, setChainAddresses] = useAtom(chainAddressesAtom); @@ -30,6 +32,8 @@ export const useAutoSetAddress = () => { const { createEvmWallets } = useCreateEvmWallets(); const { createSolanaWallets } = useCreateSolanaWallets(); + const connectedAddress = useAtomValue(connectedAddressesAtom); + const signRequiredChains = useMemo(() => { if (!route?.operations) return; const operations = getClientOperations(route.operations); @@ -63,6 +67,18 @@ export const useAutoSetAddress = () => { return; } const isSignRequired = signRequiredChains?.includes(chainID); + if (connectedAddress?.[chainID]) { + setChainAddresses((prev) => ({ + ...prev, + [index]: { + chainID, + address: connectedAddress[chainID], + chainType: chains?.find((c) => c.chainID === chainID)?.chainType, + source: WalletSource.Injected, + }, + })); + return; + } const chainType = chain.chainType; // If already set by manual entry do not auto set if (chainAddresses[index]?.address) return; @@ -94,7 +110,7 @@ export const useAutoSetAddress = () => { chainID, address, chainType: ChainType.Cosmos, - source: "wallet", + source: WalletSource.Wallet, wallet: { walletName: wallet?.walletName, walletPrettyName: wallet?.walletPrettyName, @@ -134,7 +150,7 @@ export const useAutoSetAddress = () => { chainID, address, chainType: ChainType.SVM, - source: "wallet", + source: WalletSource.Wallet, wallet: { walletName: wallet?.walletName, walletPrettyName: wallet?.walletPrettyName, @@ -175,7 +191,7 @@ export const useAutoSetAddress = () => { chainID, address, chainType: ChainType.EVM, - source: "wallet", + source: WalletSource.Wallet, wallet: { walletName: wallet?.walletName, walletPrettyName: wallet?.walletPrettyName, @@ -205,7 +221,8 @@ export const useAutoSetAddress = () => { sourceWallet.evm, sourceWallet.svm, signRequiredChains, - chainAddresses + chainAddresses, + connectedAddress, ] ); @@ -213,13 +230,13 @@ export const useAutoSetAddress = () => { queryKey: [ "auto-set-address", { - requiredChainAddresses, chains, sourceWallet, signRequiredChains, chainAddresses + requiredChainAddresses, chains, sourceWallet, signRequiredChains, chainAddresses, connectedAddress, }, ], enabled: !!requiredChainAddresses && !!chains && - (!!sourceWallet.cosmos || !!sourceWallet.evm || !!sourceWallet.svm), + (!!sourceWallet.cosmos || !!sourceWallet.evm || !!sourceWallet.svm || !!connectedAddress), queryFn: async () => { if (!requiredChainAddresses) return; await connectRequiredChains(); diff --git a/packages/widget/src/hooks/useCreateCosmosWallets.tsx b/packages/widget/src/hooks/useCreateCosmosWallets.tsx index 2a9fe5ca6..1775feeb7 100644 --- a/packages/widget/src/hooks/useCreateCosmosWallets.tsx +++ b/packages/widget/src/hooks/useCreateCosmosWallets.tsx @@ -7,6 +7,7 @@ import { WalletType, connect, isWalletConnect, + checkWallet, } from "graz"; import { useAtomValue, useSetAtom } from "jotai"; import { createPenumbraClient } from "@penumbra-zone/client"; @@ -21,20 +22,19 @@ import { walletConnectMainnetChainIdsInitialConnect, walletMainnetChainIdsInitialConnect, } from "@/constants/graz"; -import { - mainnetChains, - getChainInfo -} from "@/constants/chains"; +import { mainnetChains, getChainInfo } from "@/constants/chains"; import { useCallback } from "react"; import { skipAssetsAtom, skipChainsAtom } from "@/state/skipClient"; import { sourceAssetAtom } from "@/state/swapPage"; import { isMobile } from "@/utils/os"; +import { callbacksAtom } from "@/state/callbacks"; export const useCreateCosmosWallets = () => { const { data: chains } = useAtomValue(skipChainsAtom); const { data: assets } = useAtomValue(skipAssetsAtom); const setCosmosWallet = useSetAtom(cosmosWalletAtom); const setSourceAsset = useSetAtom(sourceAssetAtom); + const callbacks = useAtomValue(callbacksAtom); const { walletType: currentWallet } = useActiveWalletType(); const { data: accounts, isConnected } = useAccount({ @@ -46,17 +46,34 @@ export const useCreateCosmosWallets = () => { const createCosmosWallets = useCallback( (chainID?: string) => { const mobile = isMobile(); - const browserWallets = [WalletType.KEPLR, WalletType.LEAP, WalletType.COSMOSTATION, WalletType.XDEFI, WalletType.STATION, WalletType.VECTIS, WalletType.WALLETCONNECT]; + + const isIframeAvailable = checkWallet(WalletType.COSMIFRAME); + const browserWallets = [ + WalletType.KEPLR, + WalletType.LEAP, + WalletType.COSMOSTATION, + WalletType.XDEFI, + WalletType.STATION, + WalletType.VECTIS, + WalletType.WALLETCONNECT, + ]; + if (isIframeAvailable) { + browserWallets.push(WalletType.COSMIFRAME); + } const mobileCosmosWallets = [WalletType.WC_KEPLR_MOBILE]; - const availableMobileCosmosWallets = [...browserWallets, ...mobileCosmosWallets].filter((x) => { + const availableMobileCosmosWallets = [ + ...browserWallets, + ...mobileCosmosWallets, + ].filter((x) => { try { return Boolean(getWallet(x)); - } - catch (_error) { + } catch (_error) { return false; } }); - const cosmosWallets = mobile ? availableMobileCosmosWallets : browserWallets; + const cosmosWallets = mobile + ? availableMobileCosmosWallets + : browserWallets; const isPenumbra = chainID?.includes("penumbra"); if (isPenumbra && !mobile) { @@ -101,6 +118,10 @@ export const useCreateCosmosWallets = () => { }, disconnect: async () => { console.error("Prax wallet is not supported"); + callbacks?.onWalletDisconnected?.({ + walletName: "Prax Wallet", + chainType: ChainType.Cosmos, + }); }, isWalletConnected: false, }; @@ -110,21 +131,21 @@ export const useCreateCosmosWallets = () => { const wallets: MinimalWallet[] = []; for (const wallet of cosmosWallets) { - const isWC = isWalletConnect(wallet); const walletInfo = getCosmosWalletInfo(wallet); const initialChainIds = ( - isWC ? walletConnectMainnetChainIdsInitialConnect : wallet === WalletType.KEPLR - ? keplrMainnetChainIdsInitialConnect - : walletMainnetChainIdsInitialConnect + isWC + ? walletConnectMainnetChainIdsInitialConnect + : wallet === WalletType.KEPLR + ? keplrMainnetChainIdsInitialConnect + : walletMainnetChainIdsInitialConnect ).filter( (x) => chains ?.filter((z) => z.chainType === ChainType.Cosmos) .map((y) => y.chainID) - .includes(x) && - mainnetChains.map((c) => c.chainId).includes(x) + .includes(x) && mainnetChains.map((c) => c.chainId).includes(x) ); const connectEco = async () => { try { @@ -136,9 +157,13 @@ export const useCreateCosmosWallets = () => { } catch (e) { const error = e as Error; if (error?.message?.toLowerCase().includes("no chain info")) { - throw new Error(`There is no chain info for ${chainID}. Please add the ${chainID} chain to your wallet`); + throw new Error( + `There is no chain info for ${chainID}. Please add the ${chainID} chain to your wallet` + ); } - if (error?.message?.toLowerCase().includes("no ethereum public key")) { + if ( + error?.message?.toLowerCase().includes("no ethereum public key") + ) { await connect({ chainId: keplrMainnetWithoutEthermintChainIdsInitialConnect, walletType: wallet, @@ -161,7 +186,9 @@ export const useCreateCosmosWallets = () => { } catch (e) { const error = e as Error; if (error?.message?.toLowerCase().includes("no chain info")) { - throw new Error(`There is no chain info for ${chainID}. Please add ${chainID} chain in your wallet`); + throw new Error( + `There is no chain info for ${chainID}. Please add ${chainID} chain in your wallet` + ); } throw e; } @@ -190,13 +217,22 @@ export const useCreateCosmosWallets = () => { } else { await connectSingleChainId(); } - setCosmosWallet({ walletName: wallet, chainType: ChainType.Cosmos }); + setCosmosWallet({ + walletName: wallet, + chainType: ChainType.Cosmos, + }); } else if (currentAddress && isConnected && signRequired) { - setCosmosWallet({ walletName: wallet, chainType: ChainType.Cosmos }); + setCosmosWallet({ + walletName: wallet, + chainType: ChainType.Cosmos, + }); } if (!currentAddress) { if (!mobile && !isWC) { - if (!chainInfo) throw new Error(`getAddress: Chain info not found for chainID: ${chainID}`); + if (!chainInfo) + throw new Error( + `getAddress: Chain info not found for chainID: ${chainID}` + ); await getWallet(wallet).experimentalSuggestChain(chainInfo); } const isInitialConnect = initialChainIds.includes(chainID); @@ -205,7 +241,10 @@ export const useCreateCosmosWallets = () => { } else { await connectSingleChainId(); } - setCosmosWallet({ walletName: wallet, chainType: ChainType.Cosmos }); + setCosmosWallet({ + walletName: wallet, + chainType: ChainType.Cosmos, + }); } const address = (await getWallet(wallet).getKey(chainID)) .bech32Address; @@ -221,7 +260,10 @@ export const useCreateCosmosWallets = () => { }, connectEco: async () => { await connectEco(); - setCosmosWallet({ walletName: wallet, chainType: ChainType.Cosmos }); + setCosmosWallet({ + walletName: wallet, + chainType: ChainType.Cosmos, + }); const chain = chains?.find((x) => x.chainID === "cosmoshub-4"); const asset = assets?.find((x) => x.denom === "uatom"); setSourceAsset({ @@ -245,12 +287,35 @@ export const useCreateCosmosWallets = () => { const isInitialConnect = initialChainIds.includes(chainID); if (isInitialConnect) { await connectEco(); + + const chainIdToAddressMap = Object.fromEntries( + await Promise.all( + initialChainIds.map(async (chainId) => [ + chainId, + (await getWallet(wallet).getKey(chainId)).bech32Address, + ]) + ) + ); + + callbacks?.onWalletConnected?.({ + walletName: wallet, + chainIdToAddressMap, + }); } else { await connectSingleChainId(); + const address = (await getWallet(wallet).getKey(chainID)) + .bech32Address; + callbacks?.onWalletConnected?.({ + walletName: wallet, + chainId: chainID, + address, + }); } - setCosmosWallet({ walletName: wallet, chainType: ChainType.Cosmos }); + setCosmosWallet({ + walletName: wallet, + chainType: ChainType.Cosmos, + }); connectEco(); - // TODO: onWalletConnected } catch (error) { console.error(error); throw error; @@ -260,6 +325,10 @@ export const useCreateCosmosWallets = () => { disconnect: async () => { await disconnectAsync(); setCosmosWallet(undefined); + callbacks?.onWalletDisconnected?.({ + walletName: wallet, + chainType: ChainType.Cosmos, + }); }, isWalletConnected: currentWallet === wallet, isAvailable: (() => { @@ -270,13 +339,23 @@ export const useCreateCosmosWallets = () => { } catch (_error) { return false; } - })() + })(), }; wallets.push(minimalWallet); } return wallets; }, - [accounts, assets, chains, currentWallet, disconnectAsync, isConnected, setCosmosWallet, setSourceAsset] + [ + accounts, + callbacks, + assets, + chains, + currentWallet, + disconnectAsync, + isConnected, + setCosmosWallet, + setSourceAsset, + ] ); return { createCosmosWallets }; diff --git a/packages/widget/src/hooks/useCreateEvmWallets.tsx b/packages/widget/src/hooks/useCreateEvmWallets.tsx index 34347c716..a1c5a27af 100644 --- a/packages/widget/src/hooks/useCreateEvmWallets.tsx +++ b/packages/widget/src/hooks/useCreateEvmWallets.tsx @@ -8,12 +8,16 @@ import { createPublicClient, http } from "viem"; import { sei } from "viem/chains"; import { useAccount, useConnect, useConnectors } from "wagmi"; import { ChainType } from "@skip-go/client"; +import { walletConnectLogo } from "@/constants/wagmi"; +import { callbacksAtom } from "@/state/callbacks"; export const useCreateEvmWallets = () => { const { data: chains } = useAtomValue(skipChainsAtom); const { data: assets } = useAtomValue(skipAssetsAtom); const setSourceAsset = useSetAtom(sourceAssetAtom); const setEvmWallet = useSetAtom(evmWalletAtom); + const callbacks = useAtomValue(callbacksAtom); + const { connector: currentEvmConnector, address: evmAddress, @@ -59,10 +63,16 @@ export const useCreateEvmWallets = () => { connector, chainId: Number(chainID), }); - setEvmWallet({ walletName: connector.id, chainType: ChainType.EVM }); + setEvmWallet({ + walletName: connector.id, + chainType: ChainType.EVM, + }); return res.accounts[0]; } else if (evmAddress && isEvmConnected && signRequired) { - setEvmWallet({ walletName: connector.id, chainType: ChainType.EVM }); + setEvmWallet({ + walletName: connector.id, + chainType: ChainType.EVM, + }); } return evmAddress; }; @@ -72,7 +82,7 @@ export const useCreateEvmWallets = () => { walletPrettyName: connector.name, walletChainType: ChainType.EVM, walletInfo: { - logo: connector.icon, + logo: connector.id === "walletConnect" ? walletConnectLogo : connector.icon, }, connectEco: async () => { if ( @@ -90,7 +100,10 @@ export const useCreateEvmWallets = () => { } try { await connectAsync({ connector, chainId: Number(1) }); - setEvmWallet({ walletName: connector.id, chainType: ChainType.EVM }); + setEvmWallet({ + walletName: connector.id, + chainType: ChainType.EVM, + }); const chain = chains?.find((x) => x.chainID === "1"); const asset = assets?.find((x) => x.denom === "ethereum-native"); setSourceAsset({ @@ -98,7 +111,12 @@ export const useCreateEvmWallets = () => { chainName: chain?.chainName, ...asset, }); - // TODO: onWalletConnected + const account = await connector.getAccounts(); + callbacks?.onWalletConnected?.({ + walletName: connector.name, + chainId: chain?.chainID, + address: account[0], + }); } catch (error) { console.error(error); throw error; @@ -120,8 +138,16 @@ export const useCreateEvmWallets = () => { } try { await connectAsync({ connector, chainId: Number(chainID) }); - setEvmWallet({ walletName: connector.id, chainType: ChainType.EVM }); - // TODO: onWalletConnected + setEvmWallet({ + walletName: connector.id, + chainType: ChainType.EVM, + }); + const account = await connector.getAccounts(); + callbacks?.onWalletConnected?.({ + walletName: connector.name, + chainId: chainID, + address: account[0], + }); } catch (error) { console.error(error); throw error; @@ -139,7 +165,10 @@ export const useCreateEvmWallets = () => { disconnect: async () => { await currentConnector?.disconnect(); setEvmWallet(undefined); - // TODO: onWalletDisconnected + callbacks?.onWalletDisconnected?.({ + walletName: connector.name, + chainType: ChainType.EVM, + }); }, isWalletConnected: connector.id === currentEvmConnector?.id, }; @@ -149,7 +178,8 @@ export const useCreateEvmWallets = () => { connector.name.toLowerCase().includes("keplr") || connector.name.toLowerCase().includes("leap") || connector.name.toLowerCase().includes("cosmostation"); - minimalWallet.walletPrettyName = `${connector.name} ${isMultiChainWallet ? "(EVM)" : ""}`; + minimalWallet.walletPrettyName = `${connector.name} ${isMultiChainWallet ? "(EVM)" : "" + }`; minimalWallet.getAddress = async ({ signRequired, context }) => { const address = await evmGetAddress({ signRequired, context }); const publicClient = createPublicClient({ @@ -176,6 +206,7 @@ export const useCreateEvmWallets = () => { return wallets; }, [ + callbacks, assets, chainId, chains, diff --git a/packages/widget/src/hooks/useCreateSolanaWallets.tsx b/packages/widget/src/hooks/useCreateSolanaWallets.tsx index 75e1f8d43..87dcc0c3f 100644 --- a/packages/widget/src/hooks/useCreateSolanaWallets.tsx +++ b/packages/widget/src/hooks/useCreateSolanaWallets.tsx @@ -5,13 +5,15 @@ import { MinimalWallet, svmWalletAtom } from "@/state/wallets"; import { useAtomValue, useSetAtom } from "jotai"; import { useCallback } from "react"; import { ChainType } from "@skip-go/client"; - +import { callbacksAtom } from "@/state/callbacks"; export const useCreateSolanaWallets = () => { const { data: chains } = useAtomValue(skipChainsAtom); const { data: assets } = useAtomValue(skipAssetsAtom); const setSourceAsset = useSetAtom(sourceAssetAtom); const setSvmWallet = useSetAtom(svmWalletAtom); + const callbacks = useAtomValue(callbacksAtom); + const createSolanaWallets = useCallback(() => { const wallets: MinimalWallet[] = []; @@ -27,7 +29,14 @@ export const useCreateSolanaWallets = () => { try { await wallet.connect(); setSvmWallet({ walletName: wallet.name, chainType: ChainType.SVM }); - // TODO: onWalletConnected + const chain = chains?.find((x) => x.chainID === "solana"); + + const address = wallet.publicKey?.toBase58(); + callbacks?.onWalletConnected?.({ + walletName: wallet.name, + chainId: chain?.chainID, + address, + }); } catch (error) { console.error(error); throw error; @@ -38,14 +47,22 @@ export const useCreateSolanaWallets = () => { await wallet.connect(); setSvmWallet({ walletName: wallet.name, chainType: ChainType.SVM }); const chain = chains?.find((x) => x.chainID === "solana"); - const asset = assets?.find((x) => x.denom.toLowerCase() === - "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v".toLowerCase()); + const asset = assets?.find( + (x) => + x.denom.toLowerCase() === + "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v".toLowerCase() + ); setSourceAsset({ chainID: chain?.chainID, chainName: chain?.chainName, - ...asset + ...asset, + }); + const address = wallet.publicKey?.toBase58(); + callbacks?.onWalletConnected?.({ + walletName: wallet.name, + chainId: chain?.chainID, + address, }); - // TODO: onWalletConnected } catch (error) { console.error(error); throw error; @@ -56,12 +73,18 @@ export const useCreateSolanaWallets = () => { const isConnected = wallet.connected; if (!isConnected) { await wallet.connect(); - setSvmWallet({ walletName: wallet.name, chainType: ChainType.SVM }); + setSvmWallet({ + walletName: wallet.name, + chainType: ChainType.SVM, + }); } const address = wallet.publicKey; if (!address) throw new Error("No address found"); if (signRequired) { - setSvmWallet({ walletName: wallet.name, chainType: ChainType.SVM }); + setSvmWallet({ + walletName: wallet.name, + chainType: ChainType.SVM, + }); } return address.toBase58(); } catch (error) { @@ -71,7 +94,10 @@ export const useCreateSolanaWallets = () => { disconnect: async () => { await wallet.disconnect(); setSvmWallet(undefined); - // TODO: onWalletDisconnected + callbacks?.onWalletDisconnected?.({ + walletName: wallet.name, + chainType: ChainType.SVM, + }); }, isWalletConnected: wallet.connected, isAvailable: wallet.readyState === "Installed", @@ -79,6 +105,6 @@ export const useCreateSolanaWallets = () => { wallets.push(minimalWallet); } return wallets; - }, [assets, chains, setSourceAsset, setSvmWallet]); + }, [callbacks, assets, chains, setSourceAsset, setSvmWallet]); return { createSolanaWallets }; }; diff --git a/packages/widget/src/hooks/useFetchAllBalances.ts b/packages/widget/src/hooks/useFetchAllBalances.ts index 4ceaa6659..617002971 100644 --- a/packages/widget/src/hooks/useFetchAllBalances.ts +++ b/packages/widget/src/hooks/useFetchAllBalances.ts @@ -1,52 +1,58 @@ -import { useAtomValue, useSetAtom } from "jotai"; -import { useGetAccount } from "./useGetAccount"; -import { skipAllBalancesRequestAtom } from "@/state/balances"; -import { skipAssetsAtom, skipChainsAtom } from "@/state/skipClient"; -import { useAccount } from "wagmi"; -import { useQuery } from "@tanstack/react-query"; -import { useMemo } from "react"; +import { useAtomValue, useSetAtom } from 'jotai'; +import { useGetAccount } from './useGetAccount'; +import { skipAllBalancesRequestAtom } from '@/state/balances'; +import { skipAssetsAtom, skipChainsAtom } from '@/state/skipClient'; +import { useAccount } from 'wagmi'; +import { useQuery } from '@tanstack/react-query'; +import { useMemo } from 'react'; +import { connectedAddressesAtom } from '@/state/wallets'; +import { ChainType } from '@skip-go/client'; export const useFetchAllBalances = () => { const getAccount = useGetAccount(); - const { data: assets } = useAtomValue(skipAssetsAtom); - const setSkipAllBalancesRequest = useSetAtom(skipAllBalancesRequestAtom.debouncedValueAtom); + const { data: assets } = + useAtomValue(skipAssetsAtom); + const setSkipAllBalancesRequest = useSetAtom(skipAllBalancesRequestAtom); const { data: chains } = useAtomValue(skipChainsAtom); + const connectedAddresses = useAtomValue(connectedAddressesAtom); + const evmConnectedAddress = useMemo(() => { + if (!connectedAddresses) return; + const chainIds = Object.keys(connectedAddresses); + const _evmChainId = chainIds.find((chainId) => { + const chain = chains?.find((chain) => chain.chainID === chainId); + return chain?.chainType === ChainType.EVM; + }); + return _evmChainId && connectedAddresses?.[_evmChainId]; + }, [connectedAddresses, chains]); const { chainId: evmChainId } = useAccount(); const allBalancesRequest = useMemo(() => { - return assets?.reduce((acc, asset) => { - const address = getAccount(asset.chainID)?.address; - const chain = chains?.find((chain) => chain.chainID === asset.chainID); - const isEVM = chain?.chainType === "evm"; - const evmAddress = (isEVM && evmChainId) ? getAccount(String(evmChainId))?.address : undefined; - if (isEVM && evmAddress) { - if (!acc[asset.chainID]) { - acc[asset.chainID] = { - address: evmAddress, - }; - } - } else if (address) { - if (!acc[asset.chainID]) { - acc[asset.chainID] = { - address: address, - }; - } + if (!assets || !chains) return {}; + + return assets.reduce((acc, asset) => { + const chain = chains.find((chain) => chain.chainID === asset.chainID); + if (!chain) return acc; + + const evmAddress = evmConnectedAddress ?? getAccount(String(evmChainId))?.address; + const addressToUse = chain.chainType === ChainType.EVM ? evmAddress : getAccount(asset.chainID)?.address; + + if (addressToUse && !acc[asset.chainID]) { + acc[asset.chainID] = { address: addressToUse }; } + return acc; }, {} as Record); - }, [assets, getAccount, chains, evmChainId]); + }, [assets, getAccount, chains, evmConnectedAddress, evmChainId]); - // using useQuery to trigger the debouncedValueAtom useQuery({ - queryKey: ["all-balances-request", allBalancesRequest], + queryKey: ['all-balances-request', allBalancesRequest], queryFn: () => { - if (allBalancesRequest) { - setSkipAllBalancesRequest({ - chains: allBalancesRequest || {} - }); + if (!allBalancesRequest || Object.keys(allBalancesRequest).length === 0) { + throw new Error('No balance request provided'); } - return null; - } + setSkipAllBalancesRequest({ chains: allBalancesRequest }); + return { chains: allBalancesRequest }; + }, }); }; diff --git a/packages/widget/src/hooks/useGetAccount.ts b/packages/widget/src/hooks/useGetAccount.ts index 6d3b95dc6..e9c4e8123 100644 --- a/packages/widget/src/hooks/useGetAccount.ts +++ b/packages/widget/src/hooks/useGetAccount.ts @@ -6,18 +6,21 @@ import { evmWalletAtom, svmWalletAtom, walletsAtom, + connectedAddressesAtom } from "@/state/wallets"; import { useAccount as useCosmosAccount, WalletType } from "graz"; import { useAtom, useAtomValue } from "jotai"; import { useCallback, useEffect } from "react"; import { useAccount as useEvmAccount, useConnectors } from "wagmi"; import { ChainType } from "@skip-go/client"; +import { walletConnectLogo } from "@/constants/wagmi"; export const useGetAccount = () => { const wallet = useAtomValue(walletsAtom); const [evmWallet, setEvmWallet] = useAtom(evmWalletAtom); const [cosmosWallet, setCosmosWallet] = useAtom(cosmosWalletAtom); const [svmWallet, setSvmWallet] = useAtom(svmWalletAtom); + const connectedAddress = useAtomValue(connectedAddressesAtom); const { data: chains } = useAtomValue(skipChainsAtom); const { data: cosmosAccounts, walletType } = useCosmosAccount({ @@ -65,7 +68,18 @@ export const useGetAccount = () => { const getAccount = useCallback( // if checkChainType is true, it only check wallet connected no chainId is dependent (chainId?: string, checkChainType?: boolean) => { + if (!chainId) return const chainType = chains?.find((c) => c.chainID === chainId)?.chainType; + if (connectedAddress && connectedAddress[chainId]) { + return { + address: connectedAddress[chainId], + chainType: chainType, + wallet: { + name: "injected", + prettyName: "injected", + }, + } + } switch (chainType) { case ChainType.Cosmos: if (walletType && cosmosWallet === undefined) { @@ -132,7 +146,7 @@ export const useGetAccount = () => { wallet: { name: evmAccount.connector.id, prettyName: evmAccount.connector.name, - logo: connectors.find( + logo: evmAccount.connector.id === "walletConnect" ? walletConnectLogo : connectors.find( (item) => item.id === evmAccount.connector?.id )?.icon, }, @@ -172,6 +186,7 @@ export const useGetAccount = () => { wallet.cosmos, wallet.svm, connectors, + connectedAddress, ] ); diff --git a/packages/widget/src/hooks/useGetSourceBalance.ts b/packages/widget/src/hooks/useGetSourceBalance.ts index fe84d2bb1..309c3d72a 100644 --- a/packages/widget/src/hooks/useGetSourceBalance.ts +++ b/packages/widget/src/hooks/useGetSourceBalance.ts @@ -10,7 +10,7 @@ export const useGetSourceBalance = () => { const [sourceAsset] = useAtom(sourceAssetAtom); const getAccount = useGetAccount(); const sourceAccount = getAccount(sourceAsset?.chainID); - const { data: skipBalances, isLoading, refetch } = useAtomValue(skipAllBalancesAtom); + const { data: skipBalances, isFetched, isLoading, refetch } = useAtomValue(skipAllBalancesAtom); const cw20Balance = useCW20Balance({ asset: sourceAsset as ClientAsset, @@ -45,7 +45,7 @@ export const useGetSourceBalance = () => { return { data, - isLoading: isLoading || cw20Balance.isLoading, + isLoading: !isFetched || isLoading || cw20Balance.isLoading, refetch: () => { refetch(); cw20Balance.refetch(); diff --git a/packages/widget/src/hooks/useShowCosmosLedgerWarning.ts b/packages/widget/src/hooks/useShowCosmosLedgerWarning.ts index ef85cb25a..8ccf7be0a 100644 --- a/packages/widget/src/hooks/useShowCosmosLedgerWarning.ts +++ b/packages/widget/src/hooks/useShowCosmosLedgerWarning.ts @@ -23,6 +23,5 @@ export const useShowCosmosLedgerWarning = () => { sourceAsset?.chainID, chainType, getAccount, - knownEthermintLikeChains, ]) } diff --git a/packages/widget/src/modals/AssetAndChainSelectorModal/AssetAndChainSelectorModalSearchInput.tsx b/packages/widget/src/modals/AssetAndChainSelectorModal/AssetAndChainSelectorModalSearchInput.tsx index 322da0563..7993c70f4 100644 --- a/packages/widget/src/modals/AssetAndChainSelectorModal/AssetAndChainSelectorModalSearchInput.tsx +++ b/packages/widget/src/modals/AssetAndChainSelectorModal/AssetAndChainSelectorModalSearchInput.tsx @@ -10,6 +10,7 @@ import { Text } from "@/components/Typography"; import { Asset } from "@skip-go/client"; import { StyledAssetLabel } from "@/pages/SwapPage/SwapPageAssetChainInput"; import { useIsMobileScreenSize } from "@/hooks/useIsMobileScreenSize"; +import { isMobile } from "@/utils/os"; type AssetAndChainSelectorModalSearchInputProps = { onSearch: (term: string) => void; @@ -30,6 +31,7 @@ export const AssetAndChainSelectorModalSearchInput = ({ }: AssetAndChainSelectorModalSearchInputProps) => { const theme = useTheme(); const isMobileScreenSize = useIsMobileScreenSize(); + const mobile = isMobile(); const inputRef = useRef(null); const handleSearch = useCallback( @@ -42,10 +44,12 @@ export const AssetAndChainSelectorModalSearchInput = ({ ); useEffect(() => { + if (mobile) return; + if (isMobileScreenSize) return; setTimeout(() => { inputRef.current?.focus(); }, 0); - }, [asset]); + }, [asset, isMobileScreenSize, mobile]); return ( @@ -65,6 +69,7 @@ export const AssetAndChainSelectorModalSearchInput = ({ { - const filteredAssets = useMemo(() => { if (!groupedAssetsByRecommendedSymbol) return; - return matchSorter(groupedAssetsByRecommendedSymbol, searchQuery, { + + // Filter out excluded assets first + const sanitizedAssets = groupedAssetsByRecommendedSymbol + .map((group) => { + const allowedAssets = group.assets.filter((asset) => { + const isExcluded = EXCLUDED_TOKEN_COMBINATIONS.some( + (ex) => ex.id === group.id && ex.chainIDs.includes(asset.chainID) + ); + return !isExcluded; + }); + + if (allowedAssets.length === 0) return null; + return { ...group, assets: allowedAssets }; + }) + .filter(Boolean) as GroupedAsset[]; + + return matchSorter(sanitizedAssets, searchQuery, { keys: ["id", "name"], }).sort((assetA, assetB) => { const bothHaveZeroBalance = assetA.totalUsd === 0 && assetB.totalUsd === 0; - // If both assets have zero balance, sort by privileged status if (bothHaveZeroBalance) { const aPrivilegedIndex = PRIVILEGED_ASSETS.indexOf(assetA.id); const bPrivilegedIndex = PRIVILEGED_ASSETS.indexOf(assetB.id); const bothArePrivileged = aPrivilegedIndex !== -1 && bPrivilegedIndex !== -1; - if (bothArePrivileged) { - // Sort by privilege order return aPrivilegedIndex - bPrivilegedIndex; } - // If only one is privileged, it should come first if (bPrivilegedIndex !== -1) return 1; if (aPrivilegedIndex !== -1) return -1; } - // Sort by USD value (higher values first) return assetB.totalUsd - assetA.totalUsd; }); }, [groupedAssetsByRecommendedSymbol, searchQuery]); diff --git a/packages/widget/src/modals/AssetAndChainSelectorModal/useFilteredChains.ts b/packages/widget/src/modals/AssetAndChainSelectorModal/useFilteredChains.ts index 3a2a7cd40..0fcdf3711 100644 --- a/packages/widget/src/modals/AssetAndChainSelectorModal/useFilteredChains.ts +++ b/packages/widget/src/modals/AssetAndChainSelectorModal/useFilteredChains.ts @@ -5,6 +5,7 @@ import { skipChainsAtom } from "@/state/skipClient"; import { useAtomValue } from "jotai"; import { useGetBalance } from "@/hooks/useGetBalance"; import { chainFilterAtom } from "@/state/swapPage"; +import { EXCLUDED_TOKEN_COMBINATIONS } from "./useFilteredAssets"; export type useFilteredChainsProps = { selectedGroup: GroupedAsset | undefined; @@ -12,6 +13,7 @@ export type useFilteredChainsProps = { context: "source" | "destination"; }; + export const useFilteredChains = ({ selectedGroup, searchQuery = "", @@ -24,21 +26,29 @@ export const useFilteredChains = ({ const filteredChains = useMemo(() => { if (!selectedGroup || !chains) return; - const chainsWithAssets = selectedGroup.assets + // Filter out excluded assets before mapping to chains + const allowedAssets = selectedGroup.assets.filter((asset) => { + const isExcluded = EXCLUDED_TOKEN_COMBINATIONS.some( + (ex) => ex.id === selectedGroup.id && ex.chainIDs.includes(asset.chainID) + ); + return !isExcluded; + }); + + const chainsWithAssets = allowedAssets .map((asset) => { const chain = chains.find((c) => c.chainID === asset.chainID); - return chain ? { ...chain, asset } : null; + return chain ? ({ ...chain, asset } as ChainWithAsset) : null; }) .filter((chain) => { if (!chain) return false; - // Check if chain is allowed based on chainFilter - const isAllowedByFilter = !chainFilter?.[context] || + const isAllowedByFilter = + !chainFilter?.[context] || Object.keys(chainFilter[context]).includes(chain.chainID); // For source context, exclude Penumbra chains - const isPenumbraAllowed = context !== "source" || - !chain.chainID.includes("penumbra"); + const isPenumbraAllowed = + context !== "source" || !chain.chainID.startsWith("penumbra"); return isAllowedByFilter && isPenumbraAllowed; }) as ChainWithAsset[]; @@ -46,18 +56,22 @@ export const useFilteredChains = ({ return matchSorter(chainsWithAssets, searchQuery, { keys: ["prettyName", "chainName", "chainID"], }).sort((chainWithAssetA, chainWithAssetB) => { - const usdValueA = Number(getBalance(chainWithAssetA.chainID, chainWithAssetA.asset.denom)?.valueUSD ?? 0); - const usdValueB = Number(getBalance(chainWithAssetB.chainID, chainWithAssetB.asset.denom)?.valueUSD ?? 0); + const usdValueA = Number( + getBalance(chainWithAssetA.chainID, chainWithAssetA.asset.denom)?.valueUSD ?? 0 + ); + const usdValueB = Number( + getBalance(chainWithAssetB.chainID, chainWithAssetB.asset.denom)?.valueUSD ?? 0 + ); - // 1. Sort by USD value first - if (usdValueB !== usdValueA) { - return usdValueB - usdValueA; - } + // 1. Sort by USD value + if (usdValueB !== usdValueA) return usdValueB - usdValueA; - const chainAIsOrigin = chainWithAssetA.asset.originChainID === chainWithAssetA.chainID; - const chainBIsOrigin = chainWithAssetB.asset.originChainID === chainWithAssetB.chainID; + const chainAIsOrigin = + chainWithAssetA.asset.originChainID === chainWithAssetA.chainID; + const chainBIsOrigin = + chainWithAssetB.asset.originChainID === chainWithAssetB.chainID; - // 2. Sort by whether it's the origin chain + // 2. If USD values are equal, sort by origin chain if (chainBIsOrigin) return 1; if (chainAIsOrigin) return -1; diff --git a/packages/widget/src/modals/ConnectedWalletModal/ConnectedWalletModal.tsx b/packages/widget/src/modals/ConnectedWalletModal/ConnectedWalletModal.tsx index 6ecbb5e68..2fd0f39a1 100644 --- a/packages/widget/src/modals/ConnectedWalletModal/ConnectedWalletModal.tsx +++ b/packages/widget/src/modals/ConnectedWalletModal/ConnectedWalletModal.tsx @@ -130,7 +130,7 @@ const ConnectEco = ({ leftContent={ account ? ( - { + {account?.wallet.logo && ( {`${account?.wallet.prettyName} + ) } { const isMobileScreenSize = useIsMobileScreenSize(); const { theme, chainId, chainAddressIndex } = modalProps; @@ -97,7 +103,7 @@ export const SetAddressModal = createModal((modalProps: SetAddressModalProps) => chainID: chainId, chainType: chainType as ChainType, address: manualWalletAddress, - source: "input", + source: WalletSource.Input, }, }; }); diff --git a/packages/widget/src/pages/SwapExecutionPage/SwapExecutionPageRouteDetailed.tsx b/packages/widget/src/pages/SwapExecutionPage/SwapExecutionPageRouteDetailed.tsx index 68e1576df..c8c270d24 100644 --- a/packages/widget/src/pages/SwapExecutionPage/SwapExecutionPageRouteDetailed.tsx +++ b/packages/widget/src/pages/SwapExecutionPage/SwapExecutionPageRouteDetailed.tsx @@ -28,6 +28,7 @@ const operationTypeToIcon: operationTypeToIcon = { [OperationType.hyperlaneTransfer]: , [OperationType.opInitTransfer]: , [OperationType.goFastTransfer]: , + [OperationType.stargateTransfer]: , // send icon [OperationType.bankSend]: , }; @@ -42,6 +43,7 @@ const operationTypeToSimpleOperationType = { opInitTransfer: "Bridged", bankSend: "Sent", goFastTransfer: "Bridged", + stargateTransfer: "Bridged", }; type tooltipMap = Record; diff --git a/packages/widget/src/pages/SwapPage/ConnectedWalletContent.tsx b/packages/widget/src/pages/SwapPage/ConnectedWalletContent.tsx index ea06b1717..ab6830ba2 100644 --- a/packages/widget/src/pages/SwapPage/ConnectedWalletContent.tsx +++ b/packages/widget/src/pages/SwapPage/ConnectedWalletContent.tsx @@ -53,7 +53,7 @@ export const ConnectedWalletContent = () => { align="center" gap={8} > - {sourceAccount && ( + {sourceAccount?.wallet.logo && ( { (denom?: string, chainId?: string) => { if (!denom || !chainId) return; if (!assets) return; - return assets.find((a) => a.denom === denom && a.chainID === chainId); + return assets.find((a) => a.denom.toLowerCase() === denom.toLowerCase() && a.chainID === chainId); }, [assets] ); diff --git a/packages/widget/src/providers/CosmosProvider.tsx b/packages/widget/src/providers/CosmosProvider.tsx index 207eb35e7..d51e3ba0b 100644 --- a/packages/widget/src/providers/CosmosProvider.tsx +++ b/packages/widget/src/providers/CosmosProvider.tsx @@ -28,7 +28,10 @@ export const CosmosProvider: React.FC = ({ name: walletConnect.options?.name }, walletConnectModal: walletConnect?.walletConnectModal - } + }, + iframeOptions: { + allowedIframeParentOrigins: ["https://daodao.zone", "https://dao.daodao.zone"] + }, }}> {children} diff --git a/packages/widget/src/state/balances.ts b/packages/widget/src/state/balances.ts index b8ab9f1ce..a22426137 100644 --- a/packages/widget/src/state/balances.ts +++ b/packages/widget/src/state/balances.ts @@ -2,83 +2,18 @@ import { BalanceRequest, BalanceResponse } from "@skip-go/client"; import { atomWithQuery } from "jotai-tanstack-query"; import { skipClient } from "./skipClient"; import { isInvertingSwapAtom } from "./swapPage"; +import { atom } from "jotai"; -import { atom, SetStateAction } from "jotai"; - -// making this internal because useWithDebounce is conflicting with the original atomWithDebounce in utils -function atomWithDebounce( - initialValue: T, - delayMilliseconds = 500, - shouldDebounceOnReset = false, -) { - const prevTimeoutAtom = atom | undefined>( - undefined, - ); - - // DO NOT EXPORT currentValueAtom as using this atom to set state can cause - // inconsistent state between currentValueAtom and debouncedValueAtom - const _currentValueAtom = atom(initialValue); - const isDebouncingAtom = atom(false); - - const debouncedValueAtom = atom( - initialValue, - (get, set, update: SetStateAction) => { - clearTimeout(get(prevTimeoutAtom)); - - const prevValue = get(_currentValueAtom); - const nextValue = - typeof update === "function" - ? (update as (prev: T) => T)(prevValue) - : update; - - const onDebounceStart = () => { - set(_currentValueAtom, nextValue); - set(isDebouncingAtom, true); - }; - - const onDebounceEnd = () => { - set(debouncedValueAtom, nextValue); - set(isDebouncingAtom, false); - }; - - onDebounceStart(); - - if (!shouldDebounceOnReset && nextValue === initialValue) { - onDebounceEnd(); - return; - } - - const nextTimeoutId = setTimeout(() => { - onDebounceEnd(); - }, delayMilliseconds); - - // set previous timeout atom in case it needs to get cleared - set(prevTimeoutAtom, nextTimeoutId); - }, - ); - - // exported atom setter to clear timeout if needed - const clearTimeoutAtom = atom(null, (get, set, _arg) => { - clearTimeout(get(prevTimeoutAtom)); - set(isDebouncingAtom, false); - }); - - return { - currentValueAtom: atom((get) => get(_currentValueAtom)), - isDebouncingAtom, - clearTimeoutAtom, - debouncedValueAtom, - }; -} - -export const skipAllBalancesRequestAtom = atomWithDebounce(undefined); +export const skipAllBalancesRequestAtom = atom(undefined); export const skipAllBalancesAtom = atomWithQuery((get) => { const skip = get(skipClient); - const params = get(skipAllBalancesRequestAtom.debouncedValueAtom); + const params = get(skipAllBalancesRequestAtom); const isInvertingSwap = get(isInvertingSwapAtom); - const enabled = Object.values(params ?? {}).length > 0 && !isInvertingSwap; + const enabled = params && + Object.keys(params).length > 0 && + !isInvertingSwap; return { queryKey: ["skipBalances", params], @@ -86,13 +21,12 @@ export const skipAllBalancesAtom = atomWithQuery((get) => { if (!params) { throw new Error("No balance request provided"); } - return skip.balances(params); }, enabled, refetchInterval: 1000 * 60, retry: 1, gcTime: 0, - placeholderData: (previousData: BalanceResponse | undefined) => previousData + placeholderData: (prevData: BalanceResponse | undefined) => prevData }; -}); +}); \ No newline at end of file diff --git a/packages/widget/src/state/callbacks.ts b/packages/widget/src/state/callbacks.ts new file mode 100644 index 000000000..53b609658 --- /dev/null +++ b/packages/widget/src/state/callbacks.ts @@ -0,0 +1,40 @@ +import { ChainType } from "@skip-go/client"; +import { atom } from "jotai"; + +export type OnWalletConnectedProps = { + walletName: string; + chainIdToAddressMap?: Record; + chainId?: string; + address?: string; +}; + +export type OnWalletDisconnectedProps = { + walletName: string; + chainType?: ChainType; +}; + +export type OnTransactionBroadcastedProps = { + txHash: string; + chainId: string; + explorerLink: string; +}; + +export type OnTransactionCompleteProps = { + txHash: string; + chainId: string; + explorerLink: string; +}; + +export type OnTransactionFailedProps = { + error: string; +}; + +export type Callbacks = { + onWalletConnected?: (props: OnWalletConnectedProps) => void; + onWalletDisconnected?: (props: OnWalletDisconnectedProps) => void; + onTransactionBroadcasted?: (props: OnTransactionBroadcastedProps) => void; + onTransactionComplete?: (props: OnTransactionCompleteProps) => void; + onTransactionFailed?: (props: OnTransactionFailedProps) => void; +}; + +export const callbacksAtom = atom(); diff --git a/packages/widget/src/state/skipClient.ts b/packages/widget/src/state/skipClient.ts index f0f759e8e..6393cf11b 100644 --- a/packages/widget/src/state/skipClient.ts +++ b/packages/widget/src/state/skipClient.ts @@ -8,6 +8,7 @@ import { import { atomWithQuery } from "jotai-tanstack-query"; import { endpointOptions, prodApiUrl } from "@/constants/skipClientDefault"; import { walletsAtom } from "./wallets"; +import { getConnectedSignersAtom } from "@/state/wallets"; import { getWallet, WalletType } from "graz"; import { getWalletClient } from "@wagmi/core"; import { config } from "@/constants/wagmi"; @@ -32,10 +33,14 @@ export const themeAtom = atom(defaultTheme); export const skipClient = atom((get) => { const options = get(skipClientConfigAtom); const wallets = get(walletsAtom); + const getSigners = get(getConnectedSignersAtom); return new SkipClient({ ...options, getCosmosSigner: async (chainID) => { + if (getSigners?.getCosmosSigner) { + return getSigners.getCosmosSigner(chainID); + } if (!wallets.cosmos) { throw new Error("getCosmosSigner error: no cosmos wallet"); } @@ -50,6 +55,9 @@ export const skipClient = atom((get) => { : wallet.getOfflineSigner(chainID); }, getEVMSigner: async (chainID) => { + if (getSigners?.getEVMSigner) { + return getSigners.getEVMSigner(chainID); + } const evmWalletClient = (await getWalletClient(config, { chainId: parseInt(chainID), })) as WalletClient; @@ -57,6 +65,9 @@ export const skipClient = atom((get) => { return evmWalletClient; }, getSVMSigner: async () => { + if (getSigners?.getSVMSigner) { + return getSigners.getSVMSigner() + } const walletName = wallets.svm?.walletName; if (!walletName) throw new Error("getSVMSigner error: no svm wallet"); const solanaWallet = solanaWallets.find((w) => w.name === walletName); diff --git a/packages/widget/src/state/swapExecutionPage.ts b/packages/widget/src/state/swapExecutionPage.ts index f656e439e..238154d42 100644 --- a/packages/widget/src/state/swapExecutionPage.ts +++ b/packages/widget/src/state/swapExecutionPage.ts @@ -12,6 +12,7 @@ import { atomWithStorageNoCrossTabSync } from "@/utils/misc"; import { isUserRejectedRequestError } from "@/utils/error"; import { CosmosGasAmount, swapSettingsAtom } from "./swapPage"; import { createExplorerLink } from "@/utils/explorerLink"; +import { callbacksAtom } from "./callbacks"; type ValidatingGasBalanceData = { chainID?: string; @@ -34,7 +35,7 @@ export type ChainAddress = { chainType?: ChainType; address?: string; } & ( - | { source?: "input" | "parent" } + | { source?: "input" | "parent" | "injected" } | { source?: "wallet"; wallet: Pick< @@ -70,6 +71,7 @@ export const setSwapExecutionStateAtom = atom(null, (get, set) => { const { data: route } = get(skipRouteAtom); const { data: chains } = get(skipChainsAtom); const transactionHistory = get(transactionHistoryAtom); + const callbacks = get(callbacksAtom); const transactionHistoryIndex = transactionHistory.length; if (!route) return; @@ -97,11 +99,29 @@ export const setSwapExecutionStateAtom = atom(null, (get, set) => { const chain = chains?.find((chain) => chain.chainID === txInfo.chainID); const explorerLink = createExplorerLink({ chainID: txInfo.chainID, chainType: chain?.chainType, txHash: txInfo.txHash }); set(setTransactionDetailsAtom, { ...txInfo, explorerLink, status: undefined }, transactionHistoryIndex); + callbacks?.onTransactionBroadcasted?.({ + chainId: txInfo.chainID, + txHash: txInfo.txHash, + explorerLink: explorerLink ?? "", + }); + }, + onTransactionCompleted: async (chainId: string, txHash: string) => { + const chain = chains?.find((chain) => chain.chainID === chainId); + const explorerLink = createExplorerLink({ chainID: chainId, chainType: chain?.chainType, txHash }); + callbacks?.onTransactionComplete?.({ + chainId, + txHash, + explorerLink: explorerLink ?? "", + }); }, onTransactionSigned: async () => { set(setOverallStatusAtom, "pending"); }, onError: (error: unknown, transactionDetailsArray) => { + callbacks?.onTransactionFailed?.({ + error: (error as Error)?.message, + }); + const lastTransaction = transactionDetailsArray?.[transactionDetailsArray?.length - 1]; if (isUserRejectedRequestError(error)) { set(errorAtom, { @@ -221,7 +241,7 @@ export const fallbackGasAmountFnAtom = atom((get) => { const defaultGasAmount = Math.ceil(isSwapChain ? CosmosGasAmount.SWAP : CosmosGasAmount.DEFAULT); // Special case for carbon-1 - if (chainId === 'carbon-1') { + if (chainId === "carbon-1") { return CosmosGasAmount.CARBON; } diff --git a/packages/widget/src/state/wallets.ts b/packages/widget/src/state/wallets.ts index 2a3cd3609..80d135351 100644 --- a/packages/widget/src/state/wallets.ts +++ b/packages/widget/src/state/wallets.ts @@ -1,7 +1,7 @@ import { atom } from "jotai"; import { SignClientTypes } from "@walletconnect/types"; import { WalletConnectModalConfig } from "@walletconnect/modal"; -import { ChainType } from "@skip-go/client"; +import { ChainType, SignerGetters } from "@skip-go/client"; export type MinimalWallet = { walletName: string; @@ -65,3 +65,7 @@ export const knownEthermintLikeChains = [ 'haqq_11235-1', 'shido_9008-1', ]; + +export const getConnectedSignersAtom = atom() + +export const connectedAddressesAtom = atom>(); diff --git a/packages/widget/src/utils/atomWithDebounce.ts b/packages/widget/src/utils/atomWithDebounce.ts index 2f9c6539c..dfe66496e 100644 --- a/packages/widget/src/utils/atomWithDebounce.ts +++ b/packages/widget/src/utils/atomWithDebounce.ts @@ -1,7 +1,7 @@ import { atom } from "jotai"; import { SetStateAction } from "react"; -export function atomWithDebounce(delayMilliseconds = 500) { +export function atomWithDebounce(delayMilliseconds = 250) { const prevTimeoutAtom = atom( undefined ); diff --git a/packages/widget/src/utils/clientType.ts b/packages/widget/src/utils/clientType.ts index 88c38bf76..7cb73e11e 100644 --- a/packages/widget/src/utils/clientType.ts +++ b/packages/widget/src/utils/clientType.ts @@ -13,6 +13,9 @@ import { HyperlaneTransfer, HyperlaneTransferInfo, HyperlaneTransferState, + StargateTransferInfo, + StargateTransfer, + StargateTransferState, OPInitTransfer, OPInitTransferInfo, OPInitTransferState, @@ -39,6 +42,7 @@ export enum OperationType { opInitTransfer = "opInitTransfer", bankSend = "bankSend", goFastTransfer = "goFastTransfer", + stargateTransfer = "stargateTransfer", } type CombinedOperation = { @@ -54,6 +58,7 @@ type CombinedOperation = { evmSwap?: EvmSwap; opInitTransfer?: OPInitTransfer; goFastTransfer?: GoFastTransfer; + stargateTransfer?: StargateTransfer; }; type OperationDetails = CombineObjectTypes< @@ -64,6 +69,7 @@ type OperationDetails = CombineObjectTypes< CCTPTransfer & HyperlaneTransfer & EvmSwap & + StargateTransfer & OPInitTransfer & GoFastTransfer > & { @@ -220,6 +226,7 @@ function getClientTransferEvent(transferEvent: TransferEvent) { const opInitTransfer = combinedTransferEvent?.opInitTransfer as OPInitTransferInfo; const goFastTransfer = combinedTransferEvent?.goFastTransfer as GoFastTransferInfo; + const stargateTransfer = combinedTransferEvent?.stargateTransfer as StargateTransferInfo; let transferType = "" as TransferType; if (axelarTransfer) { @@ -234,6 +241,8 @@ function getClientTransferEvent(transferEvent: TransferEvent) { transferType = TransferType.opInitTransfer; } else if (goFastTransfer) { transferType = TransferType.goFastTransfer; + } else if (stargateTransfer) { + transferType = TransferType.stargateTransfer; } const getExplorerLink = (type: "send" | "receive") => { @@ -254,7 +263,9 @@ function getClientTransferEvent(transferEvent: TransferEvent) { type RemainingTransferTypes = | CCTPTransferInfo | HyperlaneTransferInfo - | OPInitTransferInfo; + | OPInitTransferInfo + | StargateTransferInfo; + if (type === "send") { return (combinedTransferEvent[transferType] as RemainingTransferTypes) ?.txs.sendTx?.explorerLink; @@ -268,8 +279,11 @@ function getClientTransferEvent(transferEvent: TransferEvent) { ...axelarTransfer, ...cctpTransfer, ...hyperlaneTransfer, + ...stargateTransfer, + ...hyperlaneTransfer, ...opInitTransfer, ...goFastTransfer, + ...stargateTransfer, fromExplorerLink: getExplorerLink("send"), toExplorerLink: getExplorerLink("receive"), } as ClientTransferEvent; @@ -314,6 +328,7 @@ export function getSimpleStatus( | HyperlaneTransferState | OPInitTransferState | GoFastTransferState + | StargateTransferState ): SimpleStatus { switch (state) { case "TRANSFER_PENDING": @@ -326,12 +341,14 @@ export function getSimpleStatus( case "HYPERLANE_TRANSFER_SENT": case "OPINIT_TRANSFER_SENT": case "GO_FAST_TRANSFER_SENT": + case "STARGATE_TRANSFER_SENT": return "pending"; case "TRANSFER_SUCCESS": case "AXELAR_TRANSFER_SUCCESS": case "CCTP_TRANSFER_RECEIVED": case "HYPERLANE_TRANSFER_RECEIVED": case "OPINIT_TRANSFER_RECEIVED": + case "STARGATE_TRANSFER_RECEIVED": case "GO_FAST_TRANSFER_FILLED": return "completed"; default: @@ -346,6 +363,8 @@ type CombinedTransferEvent = { [TransferType.hyperlaneTransfer]: HyperlaneTransferInfo; [TransferType.opInitTransfer]: OPInitTransferInfo; [TransferType.goFastTransfer]: GoFastTransferInfo; + [TransferType.stargateTransfer]: StargateTransferInfo; + }; export enum TransferType { @@ -355,6 +374,7 @@ export enum TransferType { hyperlaneTransfer = "hyperlaneTransfer", opInitTransfer = "opInitTransfer", goFastTransfer = "goFastTransfer", + stargateTransfer = "stargateTransfer", } export type SimpleStatus = @@ -376,7 +396,8 @@ export type ClientTransferEvent = { | CCTPTransferState | HyperlaneTransferState | OPInitTransferState - | GoFastTransferState; + | GoFastTransferState + | StargateTransferState; status?: SimpleStatus; fromExplorerLink?: string; toExplorerLink?: string; diff --git a/packages/widget/src/widget/Widget.tsx b/packages/widget/src/widget/Widget.tsx index 5e05e1ea3..6f3d8884c 100644 --- a/packages/widget/src/widget/Widget.tsx +++ b/packages/widget/src/widget/Widget.tsx @@ -7,31 +7,21 @@ import { ReactElement, ReactNode, useEffect, - useMemo, } from "react"; -import { defaultTheme, lightTheme, PartialTheme, Theme } from "./theme"; +import { PartialTheme } from "./theme"; import { Router } from "./Router"; -import { useSetAtom } from "jotai"; -import { - skipClientConfigAtom, - themeAtom, - defaultSkipClientConfig, - onlyTestnetsAtom, -} from "@/state/skipClient"; import { ChainAffiliates, SkipClientOptions } from "@skip-go/client"; -import { DefaultRouteConfig, useInitDefaultRoute } from "./useInitDefaultRoute"; +import { DefaultRouteConfig } from "./useInitDefaultRoute"; import { ChainFilter, - chainFilterAtom, - defaultSwapSettings, - swapSettingsAtom, } from "@/state/swapPage"; -import { routeConfigAtom } from "@/state/route"; import { RouteConfig } from "@skip-go/client"; import { registerModals } from "@/modals/registerModals"; import { WalletProviders } from "@/providers/WalletProviders"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { WalletConnect, walletConnectAtom } from "@/state/wallets"; +import { useInitWidget } from "./useInitWidget"; +import { WalletConnect } from "@/state/wallets"; +import { Callbacks } from "@/state/callbacks"; export type WidgetRouteConfig = Omit< RouteConfig, @@ -56,10 +46,22 @@ export type WidgetProps = { routeConfig?: WidgetRouteConfig; filter?: ChainFilter; walletConnect?: WalletConnect; + /** + * Map of connected wallet addresses, allowing your app to pass pre-connected addresses to the widget. + * This feature enables the widget to display a specific address as connected for a given chain. + * + * If a chain ID is mapped to an address, the widget will automatically use it as the connected address for that chain. + * + * @example + * ```tsx + * + * ``` + */ + connectedAddresses?: Record; } & Pick< NewSkipClientOptions, - "apiUrl" | "chainIdsToAffiliates" | "endpointOptions" ->; + "apiUrl" | "chainIdsToAffiliates" | "endpointOptions" | "getCosmosSigner" | "getEVMSigner" | "getSVMSigner" +> & Callbacks; type NewSwapVenueRequest = { name: string; @@ -140,98 +142,6 @@ const WidgetWrapper = ({ children }: { children: ReactNode }) => { ); }; -const useInitWidget = (props: WidgetProps) => { - useInitDefaultRoute(props.defaultRoute); - const setSkipClientConfig = useSetAtom(skipClientConfigAtom); - const setTheme = useSetAtom(themeAtom); - const setSwapSettings = useSetAtom(swapSettingsAtom); - const setRouteConfig = useSetAtom(routeConfigAtom); - const setChainFilter = useSetAtom(chainFilterAtom); - const setOnlyTestnets = useSetAtom(onlyTestnetsAtom); - const setWalletConnect = useSetAtom(walletConnectAtom); - - const mergedSkipClientConfig: SkipClientOptions = useMemo(() => { - const { apiUrl, chainIdsToAffiliates, endpointOptions } = props; - const fromWidgetProps = { - apiUrl, - chainIdsToAffiliates, - endpointOptions, - }; - - // merge if not undefined - - return { - apiURL: fromWidgetProps.apiUrl ?? defaultSkipClientConfig.apiUrl, - endpointOptions: - fromWidgetProps.endpointOptions ?? - defaultSkipClientConfig.endpointOptions, - chainIDsToAffiliates: fromWidgetProps.chainIdsToAffiliates ?? {}, - }; - }, [props]); - - const mergedTheme = useMemo(() => { - let theme: Theme; - if (typeof props.theme === "string") { - theme = props.theme === "light" ? lightTheme : defaultTheme; - } else { - theme = { ...defaultTheme, ...props.theme }; - } - if (props.brandColor) { - theme.brandColor = props.brandColor; - } - return theme; - }, [props.brandColor, props.theme]); - - useEffect(() => { - setSkipClientConfig({ - apiURL: mergedSkipClientConfig.apiURL, - endpointOptions: mergedSkipClientConfig.endpointOptions, - chainIDsToAffiliates: mergedSkipClientConfig.chainIDsToAffiliates, - }); - setTheme(mergedTheme); - }, [setSkipClientConfig, mergedSkipClientConfig, setTheme, mergedTheme]); - - useEffect(() => { - if (props.settings) { - setSwapSettings({ - ...defaultSwapSettings, - ...props.settings, - }); - } - if (props.routeConfig) { - setRouteConfig((prev) => { - return { - ...prev, - ...props.routeConfig, - }; - }); - } - if (props.filter) { - setChainFilter(props.filter); - } - if (props.onlyTestnet) { - setOnlyTestnets(props.onlyTestnet); - } - if (props.walletConnect) { - setWalletConnect(props.walletConnect); - } - }, [ - props.filter, - props.onlyTestnet, - props.routeConfig, - props.settings, - props.settings?.slippage, - props.walletConnect, - setChainFilter, - setOnlyTestnets, - setRouteConfig, - setSwapSettings, - setWalletConnect, - ]); - - return { theme: mergedTheme }; -}; - const WidgetContainer = styled.div` width: 100%; position: relative; diff --git a/packages/widget/src/widget/useInitWidget.ts b/packages/widget/src/widget/useInitWidget.ts new file mode 100644 index 000000000..3ea1b3782 --- /dev/null +++ b/packages/widget/src/widget/useInitWidget.ts @@ -0,0 +1,157 @@ +import { + useEffect, + useMemo, +} from "react"; +import { defaultTheme, lightTheme, Theme } from "./theme"; +import { useSetAtom } from "jotai"; +import { + skipClientConfigAtom, + themeAtom, + defaultSkipClientConfig, + onlyTestnetsAtom, +} from "@/state/skipClient"; +import { SkipClientOptions } from "@skip-go/client"; +import { useInitDefaultRoute } from "./useInitDefaultRoute"; +import { + chainFilterAtom, + defaultSwapSettings, + swapSettingsAtom, +} from "@/state/swapPage"; +import { routeConfigAtom } from "@/state/route"; +import { walletConnectAtom, getConnectedSignersAtom, connectedAddressesAtom } from "@/state/wallets"; +import { WidgetProps } from "./Widget"; +import { callbacksAtom } from "@/state/callbacks"; + +export const useInitWidget = (props: WidgetProps) => { + useInitDefaultRoute(props.defaultRoute); + useInitGetSigners(props); + + const setSkipClientConfig = useSetAtom(skipClientConfigAtom); + const setTheme = useSetAtom(themeAtom); + const setSwapSettings = useSetAtom(swapSettingsAtom); + const setRouteConfig = useSetAtom(routeConfigAtom); + const setChainFilter = useSetAtom(chainFilterAtom); + const setOnlyTestnets = useSetAtom(onlyTestnetsAtom); + const setWalletConnect = useSetAtom(walletConnectAtom); + const setCallbacks = useSetAtom(callbacksAtom); + + const mergedSkipClientConfig: SkipClientOptions = useMemo(() => { + const { apiUrl, chainIdsToAffiliates, endpointOptions } = props; + const fromWidgetProps = { + apiUrl, + chainIdsToAffiliates, + endpointOptions, + }; + + // merge if not undefined + return { + apiURL: fromWidgetProps.apiUrl ?? defaultSkipClientConfig.apiUrl, + endpointOptions: + fromWidgetProps.endpointOptions ?? + defaultSkipClientConfig.endpointOptions, + chainIDsToAffiliates: fromWidgetProps.chainIdsToAffiliates ?? {}, + }; + }, [props]); + + const mergedTheme = useMemo(() => { + let theme: Theme; + if (typeof props.theme === "string") { + theme = props.theme === "light" ? lightTheme : defaultTheme; + } else { + theme = { ...defaultTheme, ...props.theme }; + } + if (props.brandColor) { + theme.brandColor = props.brandColor; + } + return theme; + }, [props.brandColor, props.theme]); + + useEffect(() => { + setSkipClientConfig({ + apiURL: mergedSkipClientConfig.apiURL, + endpointOptions: mergedSkipClientConfig.endpointOptions, + chainIDsToAffiliates: mergedSkipClientConfig.chainIDsToAffiliates, + }); + setTheme(mergedTheme); + }, [setSkipClientConfig, mergedSkipClientConfig, setTheme, mergedTheme]); + + + useEffect(() => { + if (props.settings) { + setSwapSettings({ + ...defaultSwapSettings, + ...props.settings, + }); + } + if (props.routeConfig) { + setRouteConfig((prev) => { + return { + ...prev, + ...props.routeConfig, + }; + }); + } + if (props.filter) { + setChainFilter(props.filter); + } + if (props.onlyTestnet) { + setOnlyTestnets(props.onlyTestnet); + } + if (props.walletConnect) { + setWalletConnect(props.walletConnect); + } + + const callbacks = { + onWalletConnected: props.onWalletConnected, + onWalletDisconnected: props.onWalletDisconnected, + onTransactionBroadcasted: props.onTransactionBroadcasted, + onTransactionComplete: props.onTransactionComplete, + onTransactionFailed: props.onTransactionFailed, + }; + + if (Object.values(callbacks).some((callback) => callback !== undefined)) { + setCallbacks(callbacks); + } + + }, [ + props.onTransactionFailed, + props.onTransactionComplete, + props.onTransactionBroadcasted, + props.onWalletDisconnected, + props.onWalletConnected, + props.filter, + props.onlyTestnet, + props.routeConfig, + props.settings, + props.settings?.slippage, + props.walletConnect, + setChainFilter, + setOnlyTestnets, + setRouteConfig, + setSwapSettings, + setWalletConnect, + setCallbacks + ]); + + return { theme: mergedTheme }; +}; + +const useInitGetSigners = (props: Partial) => { + const setGetSigners = useSetAtom(getConnectedSignersAtom); + const setInjectedAddresses = useSetAtom(connectedAddressesAtom); + + // Update injected addresses whenever `connectedAddresses` changes + useEffect(() => { + setInjectedAddresses(props.connectedAddresses); + }, [props.connectedAddresses, setInjectedAddresses]); + + // Update all signers together whenever any of them changes + useEffect(() => { + setGetSigners((prev) => ({ + ...prev, + ...(props.getCosmosSigner && { getCosmosSigner: props.getCosmosSigner }), + ...(props.getEVMSigner && { getEVMSigner: props.getEVMSigner }), + ...(props.getSVMSigner && { getSVMSigner: props.getSVMSigner }), + })); + }, [props.getCosmosSigner, props.getEVMSigner, props.getSVMSigner, setGetSigners]); +}; diff --git a/yarn.lock b/yarn.lock index c056b712c..08cd4e4c0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,13 +12,6 @@ __metadata: languageName: node linkType: hard -"@adraffy/ens-normalize@npm:1.10.0": - version: 1.10.0 - resolution: "@adraffy/ens-normalize@npm:1.10.0" - checksum: af0540f963a2632da2bbc37e36ea6593dcfc607b937857133791781e246d47f870d5e3d21fa70d5cfe94e772c284588c81ea3f5b7f4ea8fbb824369444e4dbcb - languageName: node - linkType: hard - "@adraffy/ens-normalize@npm:^1.10.1": version: 1.11.0 resolution: "@adraffy/ens-normalize@npm:1.11.0" @@ -1908,7 +1901,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.9, @babel/runtime@npm:^7.19.4, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.8, @babel/runtime@npm:^7.24.7, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4": +"@babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.9, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.8, @babel/runtime@npm:^7.24.7, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4": version: 7.24.7 resolution: "@babel/runtime@npm:7.24.7" dependencies: @@ -1917,7 +1910,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.23.2": +"@babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.26.0": version: 7.26.0 resolution: "@babel/runtime@npm:7.26.0" dependencies: @@ -2459,17 +2452,15 @@ __metadata: languageName: node linkType: hard -"@coinbase/wallet-sdk@npm:4.0.4": - version: 4.0.4 - resolution: "@coinbase/wallet-sdk@npm:4.0.4" +"@coinbase/wallet-sdk@npm:4.2.3": + version: 4.2.3 + resolution: "@coinbase/wallet-sdk@npm:4.2.3" dependencies: - buffer: ^6.0.3 + "@noble/hashes": ^1.4.0 clsx: ^1.2.1 eventemitter3: ^5.0.1 - keccak: ^3.0.3 - preact: ^10.16.0 - sha.js: ^2.4.11 - checksum: 002d03d791683a15b465a285d7293a7994684f6f91d67c01b52ee9a07ba62f555a12d5c9471c964ccae0df048190f9c2e82929aeba9247e6d97ad1a9e9dd4132 + preact: ^10.24.2 + checksum: f1cb3c5975bf7eed46aa56077943becea16e92ac7dda46e78fb2939b3f3864815a7f218842410abb40b2b3182d09c9636ea699714c3d564009438c3611f45abc languageName: node linkType: hard @@ -2992,6 +2983,15 @@ __metadata: languageName: node linkType: hard +"@ecies/ciphers@npm:^0.2.1": + version: 0.2.2 + resolution: "@ecies/ciphers@npm:0.2.2" + peerDependencies: + "@noble/ciphers": ^1.0.0 + checksum: 10a623261aa212184850fcd41788ae1f616365b5084df03ac0d7108223519e24a5f7d92caac1ee9e0f2e3b6cfae3037a42e466b25de20cf85e91098f60ba1187 + languageName: node + linkType: hard + "@emnapi/runtime@npm:^1.2.0": version: 1.3.1 resolution: "@emnapi/runtime@npm:1.3.1" @@ -5674,9 +5674,9 @@ __metadata: languageName: node linkType: hard -"@metamask/sdk-communication-layer@npm:0.28.2": - version: 0.28.2 - resolution: "@metamask/sdk-communication-layer@npm:0.28.2" +"@metamask/sdk-communication-layer@npm:0.31.0": + version: 0.31.0 + resolution: "@metamask/sdk-communication-layer@npm:0.31.0" dependencies: bufferutil: ^4.0.8 date-fns: ^2.29.3 @@ -5685,71 +5685,47 @@ __metadata: uuid: ^8.3.2 peerDependencies: cross-fetch: ^4.0.0 - eciesjs: ^0.3.16 - eventemitter2: ^6.4.7 + eciesjs: "*" + eventemitter2: ^6.4.9 readable-stream: ^3.6.2 socket.io-client: ^4.5.1 - checksum: 349103ca72018fc4077ddf3d84d3976572525cf27b17b65308c6a00710c66f06d2d3880bb611a4a6462d1fb54bc59edd6855826f78796f49d8c7cd9904742577 + checksum: 3f9283d828d736f331154bfa0e1368b7c7c18e00eff66ccd20e97fb86618433cef3c60ed4168e2565bda825303562eb00bb9ca101d1abdcdc3f3848f807e614e languageName: node linkType: hard -"@metamask/sdk-install-modal-web@npm:0.28.1": - version: 0.28.1 - resolution: "@metamask/sdk-install-modal-web@npm:0.28.1" +"@metamask/sdk-install-modal-web@npm:0.31.2": + version: 0.31.2 + resolution: "@metamask/sdk-install-modal-web@npm:0.31.2" dependencies: - qr-code-styling: ^1.6.0-rc.1 - peerDependencies: - i18next: 23.11.5 - react: ^18.2.0 - react-dom: ^18.2.0 - react-native: "*" - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - react-native: - optional: true - checksum: 8ee147c63927323105bdf7d76667c06618119b30b355543a74f3a08e7559448d217bdf9a4fee0900efa0fc3f5a13f6376a76b2679e0b8322f6811789868dce42 + "@paulmillr/qr": ^0.2.1 + checksum: 02b5dac25b572d5ede5cf436dae3905193d38010da51bcfc89551902a4aa2867c51e03d95c11d8e13839b7478d368fb3e38fd19d3bde9882d1adbec51ad8a240 languageName: node linkType: hard -"@metamask/sdk@npm:0.28.2": - version: 0.28.2 - resolution: "@metamask/sdk@npm:0.28.2" +"@metamask/sdk@npm:0.31.2": + version: 0.31.2 + resolution: "@metamask/sdk@npm:0.31.2" dependencies: + "@babel/runtime": ^7.26.0 "@metamask/onboarding": ^1.0.1 "@metamask/providers": 16.1.0 - "@metamask/sdk-communication-layer": 0.28.2 - "@metamask/sdk-install-modal-web": 0.28.1 - "@types/dom-screen-wake-lock": ^1.0.0 - "@types/uuid": ^10.0.0 + "@metamask/sdk-communication-layer": 0.31.0 + "@metamask/sdk-install-modal-web": 0.31.2 + "@paulmillr/qr": ^0.2.1 bowser: ^2.9.0 cross-fetch: ^4.0.0 debug: ^4.3.4 - eciesjs: ^0.3.15 + eciesjs: ^0.4.11 eth-rpc-errors: ^4.0.3 - eventemitter2: ^6.4.7 - i18next: 23.11.5 - i18next-browser-languagedetector: 7.1.0 + eventemitter2: ^6.4.9 obj-multiplex: ^1.0.0 pump: ^3.0.0 - qrcode-terminal-nooctal: ^0.12.1 - react-native-webview: ^11.26.0 readable-stream: ^3.6.2 - rollup-plugin-visualizer: ^5.9.2 socket.io-client: ^4.5.1 + tslib: ^2.6.0 util: ^0.12.4 uuid: ^8.3.2 - peerDependencies: - react: ^18.2.0 - react-dom: ^18.2.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: f51eb506b8614b8eae2015668eccb9c5924c31bbdfc050bfa788bd03349107d9281a52107021f6daf3888bd0bd15796605ce883b270b2c4a304f830bac15aaf7 + checksum: a48f12bc0cfcab952608aa2c69c1174aca61bfb35b980a886e3e86c2ced9c789adbded24aca21e3c7357411e6667fcb9c691d1cd26a0c38753051f52b539d0bf languageName: node linkType: hard @@ -6060,6 +6036,13 @@ __metadata: languageName: node linkType: hard +"@noble/ciphers@npm:^1.0.0": + version: 1.1.3 + resolution: "@noble/ciphers@npm:1.1.3" + checksum: d6a740dbabbbc08637ef83332ca0ad2f38f3ec16d254afc7e3ec845533cd7fa4c76fb904b0c9ab217c76b7d7cc138a347e1fbaf7d0a2939983fe1270a21aee7e + languageName: node + linkType: hard + "@noble/curves@npm:1.4.0, @noble/curves@npm:^1.1.0, @noble/curves@npm:^1.4.0, @noble/curves@npm:~1.4.0": version: 1.4.0 resolution: "@noble/curves@npm:1.4.0" @@ -6078,6 +6061,15 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:1.7.0, @noble/curves@npm:~1.7.0": + version: 1.7.0 + resolution: "@noble/curves@npm:1.7.0" + dependencies: + "@noble/hashes": 1.6.0 + checksum: e220b704f1e516f326fff985e794e840a267f5542e1388737142b08177672ebc41b460b5a5bf636d7622c68e8ae719bc042ccd8aed16dc14311450a94b5f2a05 + languageName: node + linkType: hard + "@noble/curves@npm:~1.3.0": version: 1.3.0 resolution: "@noble/curves@npm:1.3.0" @@ -6108,6 +6100,20 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.6.0": + version: 1.6.0 + resolution: "@noble/hashes@npm:1.6.0" + checksum: 07729b80108d2a9b862eb4e070d4f78ca7ee86b9a9c13a4f7c338ba47a15d4386dd283235da71f21ad515fa9f0b9429fc3da39d2f2b4a50e2442212d14cfd4a9 + languageName: node + linkType: hard + +"@noble/hashes@npm:1.6.1, @noble/hashes@npm:~1.6.0": + version: 1.6.1 + resolution: "@noble/hashes@npm:1.6.1" + checksum: 57c62f65ee217c0293b4321b547792aa6d79812bfe70a7d62dc83e0f936cc677b14ed981b4e88cf8fdad37cd6d3a0cbd3bd0908b0728adc9daf066e678be8901 + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -6517,6 +6523,13 @@ __metadata: languageName: node linkType: hard +"@paulmillr/qr@npm:^0.2.1": + version: 0.2.1 + resolution: "@paulmillr/qr@npm:0.2.1" + checksum: 8a7b882f74f472759b0e5911c9c902a29c5232609373af4c5775625d9aad4ebda635d84c25be27e694144ba73d8e4204e72c3b9b59e9a375ec1d19f034a2d2ad + languageName: node + linkType: hard + "@penumbra-zone/bech32m@npm:^7.0.0": version: 7.0.0 resolution: "@penumbra-zone/bech32m@npm:7.0.0" @@ -7464,13 +7477,13 @@ __metadata: languageName: node linkType: hard -"@safe-global/safe-apps-provider@npm:0.18.3": - version: 0.18.3 - resolution: "@safe-global/safe-apps-provider@npm:0.18.3" +"@safe-global/safe-apps-provider@npm:0.18.4": + version: 0.18.4 + resolution: "@safe-global/safe-apps-provider@npm:0.18.4" dependencies: "@safe-global/safe-apps-sdk": ^9.1.0 events: ^3.3.0 - checksum: e208df42fe49474d54847d8edd44efb601b5aafaf9e25537500db7fefb1172201a62f577c749f424b34932439dd7ebe461d33b23075cf6b80fb35ef841017a30 + checksum: 8e4254c2d5d6852133d70f2fe63417796b349e2af875f45464a2d99e2423657af4465575779419d6f7c9db2155bbec42e0f617727666790fdd1c9f170b5b1794 languageName: node linkType: hard @@ -7505,6 +7518,13 @@ __metadata: languageName: node linkType: hard +"@scure/base@npm:~1.2.1": + version: 1.2.1 + resolution: "@scure/base@npm:1.2.1" + checksum: 061e04e4f6ed7bada6cdad4c799e6a82f30dda3f4008895bdb2e556f333f9b41f44dc067d25c064357ed6c012ea9c8be1e7927caf8a083af865b8de27b52370c + languageName: node + linkType: hard + "@scure/bip32@npm:1.4.0": version: 1.4.0 resolution: "@scure/bip32@npm:1.4.0" @@ -7527,6 +7547,17 @@ __metadata: languageName: node linkType: hard +"@scure/bip32@npm:1.6.0": + version: 1.6.0 + resolution: "@scure/bip32@npm:1.6.0" + dependencies: + "@noble/curves": ~1.7.0 + "@noble/hashes": ~1.6.0 + "@scure/base": ~1.2.1 + checksum: 1347477e28678a9bc4e2ec5e8e0f679263f2e3cb19c0e65849f76810c4c608461d4b283521c897249fa7dacc8c76e1b50e2a866b22467c8e93662a9c545cd42b + languageName: node + linkType: hard + "@scure/bip39@npm:1.3.0": version: 1.3.0 resolution: "@scure/bip39@npm:1.3.0" @@ -7547,6 +7578,16 @@ __metadata: languageName: node linkType: hard +"@scure/bip39@npm:1.5.0": + version: 1.5.0 + resolution: "@scure/bip39@npm:1.5.0" + dependencies: + "@noble/hashes": ~1.6.0 + "@scure/base": ~1.2.1 + checksum: 03d1888f5d0d514eebc5c3adc1e071d225963d434fcf789abea5ef2c8b4b99f3ad9ebee8a597c0c13d5415e6b2b380f55f61560c1643cd871961ab91cbcf5122 + languageName: node + linkType: hard + "@scure/starknet@npm:~1.0.0": version: 1.0.0 resolution: "@scure/starknet@npm:1.0.0" @@ -7674,10 +7715,12 @@ __metadata: "@types/eslint__js": ^8.42.3 "@types/pluralize": ^0.0.33 "@types/react": ^17.0.0 - "@types/react-dom": ^17.0.0 + "@types/react-dom": ^19.0.2 "@typescript-eslint/eslint-plugin": ^7.15.0 "@typescript-eslint/parser": ^7.15.0 "@vitejs/plugin-react": ^4.3.1 + "@walletconnect/modal": 2.7.0 + "@walletconnect/sign-client": 2.17.2 buffer: ^6.0.3 chain-registry: ^1.69.65 eslint: ^9.9.0 @@ -7716,8 +7759,8 @@ __metadata: graz: ^0.1.30 react: ">=17.0.0" react-dom: ">=17.0.0" - viem: 2.21.4 - wagmi: 2.12.9 + viem: ^2.21.55 + wagmi: ^2.14.1 languageName: unknown linkType: soft @@ -9105,13 +9148,6 @@ __metadata: languageName: node linkType: hard -"@types/dom-screen-wake-lock@npm:^1.0.0": - version: 1.0.3 - resolution: "@types/dom-screen-wake-lock@npm:1.0.3" - checksum: 66bece3508b4f4147db97a530c758f8f5d3132ef00c06cab1db4bf2b4af6a3a614ae0a0ba6b53ddc4177a6545adf9d312547087256efc8eff7314b13221380b8 - languageName: node - linkType: hard - "@types/elliptic@npm:^6.4.9": version: 6.4.18 resolution: "@types/elliptic@npm:6.4.18" @@ -9416,15 +9452,6 @@ __metadata: languageName: node linkType: hard -"@types/react-dom@npm:^17.0.0": - version: 17.0.25 - resolution: "@types/react-dom@npm:17.0.25" - dependencies: - "@types/react": ^17 - checksum: d1e582682478e0848c8d54ea3e89d02047bac6d916266b85ce63731b06987575919653ea7159d98fda47ade3362b8c4d5796831549564b83088e7aa9ce8b60ed - languageName: node - linkType: hard - "@types/react-dom@npm:^18": version: 18.3.1 resolution: "@types/react-dom@npm:18.3.1" @@ -9434,6 +9461,15 @@ __metadata: languageName: node linkType: hard +"@types/react-dom@npm:^19.0.2": + version: 19.0.2 + resolution: "@types/react-dom@npm:19.0.2" + peerDependencies: + "@types/react": ^19.0.0 + checksum: d2ae81ec0b8eee7a4bf31918796fdaa34e8db68f69682163bc212d759de76783e6ffcc02c02722dcf508429067148841e6da81414cc730ca2a28c9c2b350c880 + languageName: node + linkType: hard + "@types/react@npm:*, @types/react@npm:^18": version: 18.3.12 resolution: "@types/react@npm:18.3.12" @@ -9444,7 +9480,7 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:^17, @types/react@npm:^17.0.0": +"@types/react@npm:^17.0.0": version: 17.0.83 resolution: "@types/react@npm:17.0.83" dependencies: @@ -9485,7 +9521,7 @@ __metadata: languageName: node linkType: hard -"@types/secp256k1@npm:^4.0.1, @types/secp256k1@npm:^4.0.6": +"@types/secp256k1@npm:^4.0.1": version: 4.0.6 resolution: "@types/secp256k1@npm:4.0.6" dependencies: @@ -9538,13 +9574,6 @@ __metadata: languageName: node linkType: hard -"@types/uuid@npm:^10.0.0": - version: 10.0.0 - resolution: "@types/uuid@npm:10.0.0" - checksum: e3958f8b0fe551c86c14431f5940c3470127293280830684154b91dc7eb3514aeb79fe3216968833cf79d4d1c67f580f054b5be2cd562bebf4f728913e73e944 - languageName: node - linkType: hard - "@types/uuid@npm:^8.3.4": version: 8.3.4 resolution: "@types/uuid@npm:8.3.4" @@ -10562,35 +10591,34 @@ __metadata: languageName: node linkType: hard -"@wagmi/connectors@npm:5.1.9": - version: 5.1.9 - resolution: "@wagmi/connectors@npm:5.1.9" +"@wagmi/connectors@npm:5.6.1": + version: 5.6.1 + resolution: "@wagmi/connectors@npm:5.6.1" dependencies: - "@coinbase/wallet-sdk": 4.0.4 - "@metamask/sdk": 0.28.2 - "@safe-global/safe-apps-provider": 0.18.3 + "@coinbase/wallet-sdk": 4.2.3 + "@metamask/sdk": 0.31.2 + "@safe-global/safe-apps-provider": 0.18.4 "@safe-global/safe-apps-sdk": 9.1.0 - "@walletconnect/ethereum-provider": 2.15.3 - "@walletconnect/modal": 2.6.2 + "@walletconnect/ethereum-provider": 2.17.0 cbw-sdk: "npm:@coinbase/wallet-sdk@3.9.3" peerDependencies: - "@wagmi/core": 2.13.4 + "@wagmi/core": 2.16.0 typescript: ">=5.0.4" viem: 2.x peerDependenciesMeta: typescript: optional: true - checksum: 6ed6ef067142b65f5f417c330aaf5a010a47c3b19b307b43e00de9a5e11c976f4ab7bbef19dde52e89a6ae9d1a2e627a5265db9772cfadb7b25ce466f84916d7 + checksum: 6e9e4ebcfa7dcac7a6141f19332480b64a6a649a033a80d93dd50b3e8076d34247a3bbaf74209746db6673ed1fc61ef10db8e722ac9c88fd3faf10a6784e5265 languageName: node linkType: hard -"@wagmi/core@npm:2.13.4": - version: 2.13.4 - resolution: "@wagmi/core@npm:2.13.4" +"@wagmi/core@npm:2.16.0": + version: 2.16.0 + resolution: "@wagmi/core@npm:2.16.0" dependencies: eventemitter3: 5.0.1 mipd: 0.0.7 - zustand: 4.4.1 + zustand: 5.0.0 peerDependencies: "@tanstack/query-core": ">=5.0.0" typescript: ">=5.0.4" @@ -10600,7 +10628,7 @@ __metadata: optional: true typescript: optional: true - checksum: aa53de9dba8fa6d6b846a6584cb05fc03f2fb7ae023f8666ab030d5583966fc4b5aa81ca29b5ff8b6c04d26f1e6508126b62afad0ca2fa7fc5136e3a04e5cb33 + checksum: 344570354e94ab5e670b674d99fa2823120b0998227e601a6d81e3bf07b00b18b91be77fb66314dba57c749ea227cfdd812f4e1da1db07d49841d543615a24b8 languageName: node linkType: hard @@ -10650,9 +10678,9 @@ __metadata: languageName: node linkType: hard -"@walletconnect/core@npm:2.15.3": - version: 2.15.3 - resolution: "@walletconnect/core@npm:2.15.3" +"@walletconnect/core@npm:2.17.0": + version: 2.17.0 + resolution: "@walletconnect/core@npm:2.17.0" dependencies: "@walletconnect/heartbeat": 1.2.2 "@walletconnect/jsonrpc-provider": 1.0.14 @@ -10665,12 +10693,12 @@ __metadata: "@walletconnect/relay-auth": 1.0.4 "@walletconnect/safe-json": 1.0.2 "@walletconnect/time": 1.0.2 - "@walletconnect/types": 2.15.3 - "@walletconnect/utils": 2.15.3 + "@walletconnect/types": 2.17.0 + "@walletconnect/utils": 2.17.0 events: 3.3.0 lodash.isequal: 4.5.0 uint8arrays: 3.1.0 - checksum: 1a535024d37551fda0fe663612b6d5224899b6fddcc8fc5e6f09d306e81ed3c7aae0435f85a13835d22dd59b3f0b9a05e68ea73be481eacb18034bd63de7f8a8 + checksum: 97cd155fe79fe6dfc7128da6c38b6644209cf1840bc4c43fc76d691c3c0ba2fe544e5c61e5a8198886c3b037cc5551ed211523938793220db7f1effce705f4e2 languageName: node linkType: hard @@ -10708,21 +10736,21 @@ __metadata: languageName: node linkType: hard -"@walletconnect/ethereum-provider@npm:2.15.3": - version: 2.15.3 - resolution: "@walletconnect/ethereum-provider@npm:2.15.3" +"@walletconnect/ethereum-provider@npm:2.17.0": + version: 2.17.0 + resolution: "@walletconnect/ethereum-provider@npm:2.17.0" dependencies: "@walletconnect/jsonrpc-http-connection": 1.0.8 "@walletconnect/jsonrpc-provider": 1.0.14 "@walletconnect/jsonrpc-types": 1.0.4 "@walletconnect/jsonrpc-utils": 1.0.8 - "@walletconnect/modal": 2.6.2 - "@walletconnect/sign-client": 2.15.3 - "@walletconnect/types": 2.15.3 - "@walletconnect/universal-provider": 2.15.3 - "@walletconnect/utils": 2.15.3 + "@walletconnect/modal": 2.7.0 + "@walletconnect/sign-client": 2.17.0 + "@walletconnect/types": 2.17.0 + "@walletconnect/universal-provider": 2.17.0 + "@walletconnect/utils": 2.17.0 events: 3.3.0 - checksum: 08964c56345da848a0987eed6baec1f4ce487811034a6de84456352bb82cad361a7248d006fe0ccecdee7c1694e842459e99c50d74084544254c7bd1d361ac75 + checksum: e851ed258f9a1ef45db00cf46b225a9dc2efb09e4503f4a711a48e14abf4fa3746fad60960791e14c87cebde855e8487fe29146f1b025644472bacb5bb1d3a0f languageName: node linkType: hard @@ -10829,15 +10857,6 @@ __metadata: languageName: node linkType: hard -"@walletconnect/modal-core@npm:2.6.2": - version: 2.6.2 - resolution: "@walletconnect/modal-core@npm:2.6.2" - dependencies: - valtio: 1.11.2 - checksum: 94daceba50c323b06ecbeac2968d9f0972f327359c6118887c6526cd64006249b12f64322d71bc6c4a2b928436ecc89cf3d3af706511fcdc264c1f4b34a2dd5d - languageName: node - linkType: hard - "@walletconnect/modal-core@npm:2.7.0": version: 2.7.0 resolution: "@walletconnect/modal-core@npm:2.7.0" @@ -10847,18 +10866,6 @@ __metadata: languageName: node linkType: hard -"@walletconnect/modal-ui@npm:2.6.2": - version: 2.6.2 - resolution: "@walletconnect/modal-ui@npm:2.6.2" - dependencies: - "@walletconnect/modal-core": 2.6.2 - lit: 2.8.0 - motion: 10.16.2 - qrcode: 1.5.3 - checksum: cd1ec0205eb491e529670599d3dd26f6782d7c5a99d5594bf6949a8c760c1c5f4eb6ed72b8662450774fe4e2dd47678f2c05145c8f2494bd7153446ddf4bd7ed - languageName: node - linkType: hard - "@walletconnect/modal-ui@npm:2.7.0": version: 2.7.0 resolution: "@walletconnect/modal-ui@npm:2.7.0" @@ -10871,16 +10878,6 @@ __metadata: languageName: node linkType: hard -"@walletconnect/modal@npm:2.6.2": - version: 2.6.2 - resolution: "@walletconnect/modal@npm:2.6.2" - dependencies: - "@walletconnect/modal-core": 2.6.2 - "@walletconnect/modal-ui": 2.6.2 - checksum: 68b354d49960b96d22de0e47a3801df27c01a3e96ec5fbde3ca6df1344ca2b20668b0c4d58fe1803f5670ac7b7b4c6f5b7b405e354f5f9eaff5cca147c13de9c - languageName: node - linkType: hard - "@walletconnect/modal@npm:2.7.0": version: 2.7.0 resolution: "@walletconnect/modal@npm:2.7.0" @@ -10923,20 +10920,20 @@ __metadata: languageName: node linkType: hard -"@walletconnect/sign-client@npm:2.15.3": - version: 2.15.3 - resolution: "@walletconnect/sign-client@npm:2.15.3" +"@walletconnect/sign-client@npm:2.17.0": + version: 2.17.0 + resolution: "@walletconnect/sign-client@npm:2.17.0" dependencies: - "@walletconnect/core": 2.15.3 + "@walletconnect/core": 2.17.0 "@walletconnect/events": 1.0.1 "@walletconnect/heartbeat": 1.2.2 "@walletconnect/jsonrpc-utils": 1.0.8 "@walletconnect/logger": 2.1.2 "@walletconnect/time": 1.0.2 - "@walletconnect/types": 2.15.3 - "@walletconnect/utils": 2.15.3 + "@walletconnect/types": 2.17.0 + "@walletconnect/utils": 2.17.0 events: 3.3.0 - checksum: 16d66bb1b035b7ff3366cebcccb67f532700d9c0d56d98c4400af55fe55c3a29dca92c1755401c29085080fb820325aef6e1df6b274a0a223b33b064e0fce285 + checksum: 980c747a815c7016191086597f295268a4f285a5a830d6d80b2896bc6f6ca4a2528bae3c16bde83d2524b94553feb6fe74fd041de8d95d54dc6fd7f0613e87e2 languageName: node linkType: hard @@ -10966,9 +10963,9 @@ __metadata: languageName: node linkType: hard -"@walletconnect/types@npm:2.15.3": - version: 2.15.3 - resolution: "@walletconnect/types@npm:2.15.3" +"@walletconnect/types@npm:2.17.0": + version: 2.17.0 + resolution: "@walletconnect/types@npm:2.17.0" dependencies: "@walletconnect/events": 1.0.1 "@walletconnect/heartbeat": 1.2.2 @@ -10976,7 +10973,7 @@ __metadata: "@walletconnect/keyvaluestorage": 1.1.1 "@walletconnect/logger": 2.1.2 events: 3.3.0 - checksum: df59fa1b19e56f586d142de34f7839a0f936f0ad2eb871175257f8b152744842d154fc4ec992945d13b4418a6398dddb77585616580d826363e0d99a464e50bc + checksum: 0dd1eecd69a90a920f7cd33baeb1613f11ca24466783482752435b80a9362fd8f55b0d21c03073d97c20224f932d3fafc72fe8f6defeb0d1a139e8f10cc58aa3 languageName: node linkType: hard @@ -10994,26 +10991,26 @@ __metadata: languageName: node linkType: hard -"@walletconnect/universal-provider@npm:2.15.3": - version: 2.15.3 - resolution: "@walletconnect/universal-provider@npm:2.15.3" +"@walletconnect/universal-provider@npm:2.17.0": + version: 2.17.0 + resolution: "@walletconnect/universal-provider@npm:2.17.0" dependencies: "@walletconnect/jsonrpc-http-connection": 1.0.8 "@walletconnect/jsonrpc-provider": 1.0.14 "@walletconnect/jsonrpc-types": 1.0.4 "@walletconnect/jsonrpc-utils": 1.0.8 "@walletconnect/logger": 2.1.2 - "@walletconnect/sign-client": 2.15.3 - "@walletconnect/types": 2.15.3 - "@walletconnect/utils": 2.15.3 + "@walletconnect/sign-client": 2.17.0 + "@walletconnect/types": 2.17.0 + "@walletconnect/utils": 2.17.0 events: 3.3.0 - checksum: 02f8fe842f3ea2aa1ee9dac06647305bd34adf600b415d7339cf28b9f2470c141014d3bf9c8a3815092c4859f9e8ccd7d56e23f32f0e69b460d871544e0cdf08 + checksum: c7bb25a571ad5e354bd5e2aceabab3468def3b47a7ea83e0e93278b3c33c5a68a751e95bc526cd3b27c071cfabf37cda72736315c1416fcf226100b75c74c363 languageName: node linkType: hard -"@walletconnect/utils@npm:2.15.3": - version: 2.15.3 - resolution: "@walletconnect/utils@npm:2.15.3" +"@walletconnect/utils@npm:2.17.0": + version: 2.17.0 + resolution: "@walletconnect/utils@npm:2.17.0" dependencies: "@stablelib/chacha20poly1305": 1.0.1 "@stablelib/hkdf": 1.0.1 @@ -11024,14 +11021,14 @@ __metadata: "@walletconnect/relay-auth": 1.0.4 "@walletconnect/safe-json": 1.0.2 "@walletconnect/time": 1.0.2 - "@walletconnect/types": 2.15.3 + "@walletconnect/types": 2.17.0 "@walletconnect/window-getters": 1.0.1 "@walletconnect/window-metadata": 1.0.1 detect-browser: 5.3.0 elliptic: ^6.5.7 query-string: 7.1.3 uint8arrays: 3.1.0 - checksum: 1ff57939b99e0fbcd0398007373a321516d78d2d61561c062a427d890f88ac7ebe3645ade021f91f1f1f6574cdd7760239a3dd004f5a9060ad165dd634fc228e + checksum: 093e508718f1c770b1ff05442376add40ecbaffa8cb5c8cfdf76786d6422e33afdb39d4b7b374a3b65330a4da2cbb71a2c552b041831295a12006dc29cb32340 languageName: node linkType: hard @@ -11386,9 +11383,9 @@ __metadata: languageName: node linkType: hard -"abitype@npm:1.0.5": - version: 1.0.5 - resolution: "abitype@npm:1.0.5" +"abitype@npm:1.0.6, abitype@npm:^1.0.6": + version: 1.0.6 + resolution: "abitype@npm:1.0.6" peerDependencies: typescript: ">=5.0.4" zod: ^3 >=3.22.0 @@ -11397,13 +11394,13 @@ __metadata: optional: true zod: optional: true - checksum: 4a4865926e5e8e33e4fab0081a106ce4f627db30b4052fbc449e4707aea6d34d805d46c8d6d0a72234bdd9a2b4900993591515fc299bc57d393181c70dc0c19e + checksum: 0bf6ed5ec785f372746c3ec5d6c87bf4d8cf0b6db30867b8d24e86fbc66d9f6599ae3d463ccd49817e67eedec6deba7cdae317bcf4da85b02bc48009379b9f84 languageName: node linkType: hard -"abitype@npm:1.0.6, abitype@npm:^1.0.6": - version: 1.0.6 - resolution: "abitype@npm:1.0.6" +"abitype@npm:1.0.7": + version: 1.0.7 + resolution: "abitype@npm:1.0.7" peerDependencies: typescript: ">=5.0.4" zod: ^3 >=3.22.0 @@ -11412,7 +11409,7 @@ __metadata: optional: true zod: optional: true - checksum: 0bf6ed5ec785f372746c3ec5d6c87bf4d8cf0b6db30867b8d24e86fbc66d9f6599ae3d463ccd49817e67eedec6deba7cdae317bcf4da85b02bc48009379b9f84 + checksum: c3b3ee19becbbce1d5c55a40a13dee6c09c0d710eee9c601433eb496c5ee2cd39e97dd0d043fa1ff7e68b1239ef83fe56951b2009d467e989fe941785cd7f8b8 languageName: node linkType: hard @@ -14789,14 +14786,15 @@ __metadata: languageName: node linkType: hard -"eciesjs@npm:^0.3.15": - version: 0.3.19 - resolution: "eciesjs@npm:0.3.19" +"eciesjs@npm:^0.4.11": + version: 0.4.12 + resolution: "eciesjs@npm:0.4.12" dependencies: - "@types/secp256k1": ^4.0.6 - futoin-hkdf: ^1.5.3 - secp256k1: ^5.0.0 - checksum: 29d2cafcac452ae7086048cebeedf7b4307caf4a8e916120d0314e6da2076f2d1763b7f6a1916c6526fb78f0eb5e394d7dd0654c9a8bfe59252d242adb4830b2 + "@ecies/ciphers": ^0.2.1 + "@noble/ciphers": ^1.0.0 + "@noble/curves": ^1.6.0 + "@noble/hashes": ^1.5.0 + checksum: ef98528b8af23b013dd432b43cc1a378d58621f887a7db234ebc997006e16ab9ffa0ea973bf2195aa63dbfa996afa9e3a8f8410b6e3d5c3808365a3d02b1141a languageName: node linkType: hard @@ -15504,13 +15502,6 @@ __metadata: languageName: node linkType: hard -"escape-string-regexp@npm:2.0.0, escape-string-regexp@npm:^2.0.0": - version: 2.0.0 - resolution: "escape-string-regexp@npm:2.0.0" - checksum: 9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 - languageName: node - linkType: hard - "escape-string-regexp@npm:^1.0.2, escape-string-regexp@npm:^1.0.5": version: 1.0.5 resolution: "escape-string-regexp@npm:1.0.5" @@ -15518,6 +15509,13 @@ __metadata: languageName: node linkType: hard +"escape-string-regexp@npm:^2.0.0": + version: 2.0.0 + resolution: "escape-string-regexp@npm:2.0.0" + checksum: 9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 + languageName: node + linkType: hard + "escape-string-regexp@npm:^4.0.0": version: 4.0.0 resolution: "escape-string-regexp@npm:4.0.0" @@ -16098,7 +16096,7 @@ __metadata: languageName: node linkType: hard -"eventemitter2@npm:^6.4.7": +"eventemitter2@npm:^6.4.9": version: 6.4.9 resolution: "eventemitter2@npm:6.4.9" checksum: be59577c1e1c35509c7ba0e2624335c35bbcfd9485b8a977384c6cc6759341ea1a98d3cb9dbaa5cea4fff9b687e504504e3f9c2cc1674cf3bd8a43a7c74ea3eb @@ -16728,13 +16726,6 @@ __metadata: languageName: node linkType: hard -"futoin-hkdf@npm:^1.5.3": - version: 1.5.3 - resolution: "futoin-hkdf@npm:1.5.3" - checksum: 790da5675b31df4b9a34c19a5181f673171b5ad81fa92b91981bcfd2250692f895d6aada5ae4203212babba3c7d7a1916432e0b42c7aa88d3f70408439ec315e - languageName: node - linkType: hard - "fuzzy@npm:0.1.3": version: 0.1.3 resolution: "fuzzy@npm:0.1.3" @@ -17555,24 +17546,6 @@ __metadata: languageName: node linkType: hard -"i18next-browser-languagedetector@npm:7.1.0": - version: 7.1.0 - resolution: "i18next-browser-languagedetector@npm:7.1.0" - dependencies: - "@babel/runtime": ^7.19.4 - checksum: 36981b9a9995ed66387f3735cceffe107ed3cdb6ca278d45fa243fabc65669c0eca095ed4a55a93dac046ca1eb23fd986ec0079723be7ebb8505e6ba25f379bb - languageName: node - linkType: hard - -"i18next@npm:23.11.5": - version: 23.11.5 - resolution: "i18next@npm:23.11.5" - dependencies: - "@babel/runtime": ^7.23.2 - checksum: e9ec83703af59205af81f10929fd420314c0c976d1f4c42a191dc4d13f1284d13517105325286772571292953839c7183baa92e9bb43f41efe87dbc50c9aed1c - languageName: node - linkType: hard - "iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.17, iconv-lite@npm:^0.4.24": version: 0.4.24 resolution: "iconv-lite@npm:0.4.24" @@ -17867,7 +17840,7 @@ __metadata: languageName: node linkType: hard -"invariant@npm:2.2.4, invariant@npm:^2.2.4": +"invariant@npm:^2.2.4": version: 2.2.4 resolution: "invariant@npm:2.2.4" dependencies: @@ -18331,15 +18304,6 @@ __metadata: languageName: node linkType: hard -"isows@npm:1.0.4": - version: 1.0.4 - resolution: "isows@npm:1.0.4" - peerDependencies: - ws: "*" - checksum: a3ee62e3d6216abb3adeeb2a551fe2e7835eac87b05a6ecc3e7739259bf5f8e83290501f49e26137390c8093f207fc3378d4a7653aab76ad7bbab4b2dba9c5b9 - languageName: node - linkType: hard - "isows@npm:1.0.6": version: 1.0.6 resolution: "isows@npm:1.0.6" @@ -20827,15 +20791,6 @@ __metadata: languageName: node linkType: hard -"node-addon-api@npm:^5.0.0": - version: 5.1.0 - resolution: "node-addon-api@npm:5.1.0" - dependencies: - node-gyp: latest - checksum: 2508bd2d2981945406243a7bd31362fc7af8b70b8b4d65f869c61731800058fb818cc2fd36c8eac714ddd0e568cc85becf5e165cebbdf7b5024d5151bbc75ea1 - languageName: node - linkType: hard - "node-addon-api@npm:^7.0.0": version: 7.1.0 resolution: "node-addon-api@npm:7.1.0" @@ -22885,6 +22840,13 @@ __metadata: languageName: node linkType: hard +"preact@npm:^10.24.2": + version: 10.25.2 + resolution: "preact@npm:10.25.2" + checksum: f0927e3938a5a62df4a9fd639eecb01d184fb0526953ed03d75de4552ab511f507843bf050d6e1cea5b83f6592f1dc1641fea591061dc0e1838c2f3236684c6c + languageName: node + linkType: hard + "preferred-pm@npm:^3.0.0": version: 3.1.3 resolution: "preferred-pm@npm:3.1.3" @@ -23148,31 +23110,6 @@ __metadata: languageName: node linkType: hard -"qr-code-styling@npm:^1.6.0-rc.1": - version: 1.6.0-rc.1 - resolution: "qr-code-styling@npm:1.6.0-rc.1" - dependencies: - qrcode-generator: ^1.4.3 - checksum: 778754790fe0b586ecd38fb02de777c7dd9cf844cf6e3c88f9a23ad85b122200a8567c946e3c41dba84ddd2f0016aa31ddfd1507150e1dbfea8a58323b62d944 - languageName: node - linkType: hard - -"qrcode-generator@npm:^1.4.3": - version: 1.4.4 - resolution: "qrcode-generator@npm:1.4.4" - checksum: 860cfdd2a7a608d34e92cab99774cc08182e1911432f30ed36d16f8a5cdabd7fdf40239caed91fa2691cfe66c8d95c1340a2fc9cc439eed07a9f2eb328c6f527 - languageName: node - linkType: hard - -"qrcode-terminal-nooctal@npm:^0.12.1": - version: 0.12.1 - resolution: "qrcode-terminal-nooctal@npm:0.12.1" - bin: - qrcode-terminal: bin/qrcode-terminal.js - checksum: 1071c4be2bfa07b3956ad0a63c87452ced0b5180a9dc19f224fc3dd69bb24ad687a7af365acdde0f876ddf89dc1a4beadba88d89c7c5c5cbf2ef3efaef64736e - languageName: node - linkType: hard - "qrcode@npm:1.5.3": version: 1.5.3 resolution: "qrcode@npm:1.5.3" @@ -23455,19 +23392,6 @@ __metadata: languageName: node linkType: hard -"react-native-webview@npm:^11.26.0": - version: 11.26.1 - resolution: "react-native-webview@npm:11.26.1" - dependencies: - escape-string-regexp: 2.0.0 - invariant: 2.2.4 - peerDependencies: - react: "*" - react-native: "*" - checksum: d2f95a89e944a2f1e8cf402e4e274f3568edae42e7ef190915e9fba8004a01d699c962459bdc9688c159060538e90aea3017cab24e6f4112021cbbc10ef57104 - languageName: node - linkType: hard - "react-refresh@npm:^0.14.2": version: 0.14.2 resolution: "react-refresh@npm:0.14.2" @@ -24050,7 +23974,7 @@ __metadata: languageName: node linkType: hard -"rollup-plugin-visualizer@npm:^5.12.0, rollup-plugin-visualizer@npm:^5.5.4, rollup-plugin-visualizer@npm:^5.9.2": +"rollup-plugin-visualizer@npm:^5.12.0, rollup-plugin-visualizer@npm:^5.5.4": version: 5.12.0 resolution: "rollup-plugin-visualizer@npm:5.12.0" dependencies: @@ -24387,18 +24311,6 @@ __metadata: languageName: node linkType: hard -"secp256k1@npm:^5.0.0": - version: 5.0.0 - resolution: "secp256k1@npm:5.0.0" - dependencies: - elliptic: ^6.5.4 - node-addon-api: ^5.0.0 - node-gyp: latest - node-gyp-build: ^4.2.0 - checksum: a0719dff4687c38d385b5e0b7e811c51a4ea24893128be9d097aee99f879eb0ea52582590deb15a49da627a3db23c6b028ad5c9c6ac1fca92ce760153b8cf21c - languageName: node - linkType: hard - "secure-json-parse@npm:^2.4.0": version: 2.7.0 resolution: "secure-json-parse@npm:2.7.0" @@ -24869,9 +24781,9 @@ __metadata: tsx: ^4.12.0 typescript: 5.2.x typescript-plugin-styled-components: 3.0.0 - viem: 2.21.4 + viem: ^2.21.55 vitest: ^1.2.2 - wagmi: 2.12.9 + wagmi: ^2.14.1 languageName: unknown linkType: soft @@ -26236,7 +26148,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.1": +"tslib@npm:^2.0.1, tslib@npm:^2.6.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: e4aba30e632b8c8902b47587fd13345e2827fa639e7c3121074d5ee0880723282411a8838f830b55100cbe4517672f84a2472667d355b81e8af165a55dc6203a @@ -27257,37 +27169,37 @@ __metadata: languageName: node linkType: hard -"viem@npm:2.21.4": - version: 2.21.4 - resolution: "viem@npm:2.21.4" +"viem@npm:^2.1.1": + version: 2.21.45 + resolution: "viem@npm:2.21.45" dependencies: - "@adraffy/ens-normalize": 1.10.0 - "@noble/curves": 1.4.0 - "@noble/hashes": 1.4.0 - "@scure/bip32": 1.4.0 + "@noble/curves": 1.6.0 + "@noble/hashes": 1.5.0 + "@scure/bip32": 1.5.0 "@scure/bip39": 1.4.0 - abitype: 1.0.5 - isows: 1.0.4 - webauthn-p256: 0.0.5 - ws: 8.17.1 + abitype: 1.0.6 + isows: 1.0.6 + ox: 0.1.2 + webauthn-p256: 0.0.10 + ws: 8.18.0 peerDependencies: typescript: ">=5.0.4" peerDependenciesMeta: typescript: optional: true - checksum: b322e0e476d672852b28270bf00f15ed1572ab3d8ce5e7087e5708fbf0bb293a8da38ffd401c48b82df24cbe8a601ba142f087c803dce147763ed16fb992eafd + checksum: 1873d32a4a1b86830344ce348501783e35351c7d0fb2e16c1219df3dbd206a916ac174a23d7ef6aca9878e2d9afa42dceafc8ad8c6f69527a0065814be9a2a9d languageName: node linkType: hard -"viem@npm:^2.1.1": - version: 2.21.45 - resolution: "viem@npm:2.21.45" +"viem@npm:^2.21.55": + version: 2.21.55 + resolution: "viem@npm:2.21.55" dependencies: - "@noble/curves": 1.6.0 - "@noble/hashes": 1.5.0 - "@scure/bip32": 1.5.0 - "@scure/bip39": 1.4.0 - abitype: 1.0.6 + "@noble/curves": 1.7.0 + "@noble/hashes": 1.6.1 + "@scure/bip32": 1.6.0 + "@scure/bip39": 1.5.0 + abitype: 1.0.7 isows: 1.0.6 ox: 0.1.2 webauthn-p256: 0.0.10 @@ -27297,7 +27209,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 1873d32a4a1b86830344ce348501783e35351c7d0fb2e16c1219df3dbd206a916ac174a23d7ef6aca9878e2d9afa42dceafc8ad8c6f69527a0065814be9a2a9d + checksum: db937a33071f744951edf98f31f9c25e71ebce07bb620389980cd4c921f310b808ec87d132c23e022b5576b943c359dde65cbba5b9ab8d63c27ad8a6cba877dd languageName: node linkType: hard @@ -27764,12 +27676,12 @@ __metadata: languageName: node linkType: hard -"wagmi@npm:2.12.9": - version: 2.12.9 - resolution: "wagmi@npm:2.12.9" +"wagmi@npm:^2.14.1": + version: 2.14.1 + resolution: "wagmi@npm:2.14.1" dependencies: - "@wagmi/connectors": 5.1.9 - "@wagmi/core": 2.13.4 + "@wagmi/connectors": 5.6.1 + "@wagmi/core": 2.16.0 use-sync-external-store: 1.2.0 peerDependencies: "@tanstack/react-query": ">=5.0.0" @@ -27779,7 +27691,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 978a280a079640169abb161f6f3285d3a402bcff512e3b04ad68a321e0e8fb7e8c5bbee601205be71277e64730b40bed2eca5caeb887d14a8d3ceb44982dda69 + checksum: 00d2e4c315f7cf631dc7b7fddeddfdc0e43fd091063d91fb1e527dcd92de94de49b1ffd7021fa69f75744a3e8bc754158b9f663511fa398f586fda195b6c67a2 languageName: node linkType: hard @@ -27875,16 +27787,6 @@ __metadata: languageName: node linkType: hard -"webauthn-p256@npm:0.0.5": - version: 0.0.5 - resolution: "webauthn-p256@npm:0.0.5" - dependencies: - "@noble/curves": ^1.4.0 - "@noble/hashes": ^1.4.0 - checksum: 2837188d1e6d947c87c5728374fb6aec96387cb766f78e7a04d5903774264feb278d68a639748f09997f591e5278796c662bb5c4e8b8286b0f22254694023584 - languageName: node - linkType: hard - "webextension-polyfill@npm:>=0.10.0 <1.0": version: 0.12.0 resolution: "webextension-polyfill@npm:0.12.0" @@ -28250,9 +28152,9 @@ __metadata: languageName: node linkType: hard -"ws@npm:8.17.1, ws@npm:^8.11.0, ws@npm:^8.5.0, ws@npm:~8.17.1": - version: 8.17.1 - resolution: "ws@npm:8.17.1" +"ws@npm:8.18.0, ws@npm:^8.18.0, ws@npm:^8.2.3": + version: 8.18.0 + resolution: "ws@npm:8.18.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -28261,37 +28163,37 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 442badcce1f1178ec87a0b5372ae2e9771e07c4929a3180321901f226127f252441e8689d765aa5cfba5f50ac60dd830954afc5aeae81609aefa11d3ddf5cecf + checksum: 91d4d35bc99ff6df483bdf029b9ea4bfd7af1f16fc91231a96777a63d263e1eabf486e13a2353970efc534f9faa43bdbf9ee76525af22f4752cbc5ebda333975 languageName: node linkType: hard -"ws@npm:8.18.0, ws@npm:^8.18.0, ws@npm:^8.2.3": - version: 8.18.0 - resolution: "ws@npm:8.18.0" +"ws@npm:^7, ws@npm:^7.4.5, ws@npm:^7.5.1, ws@npm:^7.5.10": + version: 7.5.10 + resolution: "ws@npm:7.5.10" peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" + utf-8-validate: ^5.0.2 peerDependenciesMeta: bufferutil: optional: true utf-8-validate: optional: true - checksum: 91d4d35bc99ff6df483bdf029b9ea4bfd7af1f16fc91231a96777a63d263e1eabf486e13a2353970efc534f9faa43bdbf9ee76525af22f4752cbc5ebda333975 + checksum: f9bb062abf54cc8f02d94ca86dcd349c3945d63851f5d07a3a61c2fcb755b15a88e943a63cf580cbdb5b74436d67ef6b67f745b8f7c0814e411379138e1863cb languageName: node linkType: hard -"ws@npm:^7, ws@npm:^7.4.5, ws@npm:^7.5.1, ws@npm:^7.5.10": - version: 7.5.10 - resolution: "ws@npm:7.5.10" +"ws@npm:^8.11.0, ws@npm:^8.5.0, ws@npm:~8.17.1": + version: 8.17.1 + resolution: "ws@npm:8.17.1" peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 + utf-8-validate: ">=5.0.2" peerDependenciesMeta: bufferutil: optional: true utf-8-validate: optional: true - checksum: f9bb062abf54cc8f02d94ca86dcd349c3945d63851f5d07a3a61c2fcb755b15a88e943a63cf580cbdb5b74436d67ef6b67f745b8f7c0814e411379138e1863cb + checksum: 442badcce1f1178ec87a0b5372ae2e9771e07c4929a3180321901f226127f252441e8689d765aa5cfba5f50ac60dd830954afc5aeae81609aefa11d3ddf5cecf languageName: node linkType: hard @@ -28564,14 +28466,14 @@ __metadata: languageName: node linkType: hard -"zustand@npm:4.4.1": - version: 4.4.1 - resolution: "zustand@npm:4.4.1" +"zustand@npm:4.5.2": + version: 4.5.2 + resolution: "zustand@npm:4.5.2" dependencies: use-sync-external-store: 1.2.0 peerDependencies: "@types/react": ">=16.8" - immer: ">=9.0" + immer: ">=9.0.6" react: ">=16.8" peerDependenciesMeta: "@types/react": @@ -28580,19 +28482,18 @@ __metadata: optional: true react: optional: true - checksum: 80acd0fbf633782996642802c8692bbb80ae5c80a8dff4c501b88250acd5ccd468fbc6398bdce198475a25e3839c91385b81da921274f33ffb5c2d08c3eab400 + checksum: 160052a7faaefbaad1071e890a06e5d7a04f6ff6985def30a7b4471f4ddbdd1d30bb05b3688a2777cd0b717d1f0d98dad24883a5caa3deeb3afb4d83b6dabc55 languageName: node linkType: hard -"zustand@npm:4.5.2": - version: 4.5.2 - resolution: "zustand@npm:4.5.2" - dependencies: - use-sync-external-store: 1.2.0 +"zustand@npm:5.0.0": + version: 5.0.0 + resolution: "zustand@npm:5.0.0" peerDependencies: - "@types/react": ">=16.8" + "@types/react": ">=18.0.0" immer: ">=9.0.6" - react: ">=16.8" + react: ">=18.0.0" + use-sync-external-store: ">=1.2.0" peerDependenciesMeta: "@types/react": optional: true @@ -28600,6 +28501,8 @@ __metadata: optional: true react: optional: true - checksum: 160052a7faaefbaad1071e890a06e5d7a04f6ff6985def30a7b4471f4ddbdd1d30bb05b3688a2777cd0b717d1f0d98dad24883a5caa3deeb3afb4d83b6dabc55 + use-sync-external-store: + optional: true + checksum: dc7414de234f9d2c0afad472d6971e9ac32281292faa8ee0910521cad063f84eeeb6f792efab068d6750dab5854fb1a33ac6e9294b796925eb680a59fc1b42f9 languageName: node linkType: hard