From 8b8feea4a2196bc9178bc1d1f3a088ea6a1d12e5 Mon Sep 17 00:00:00 2001 From: Ted Palmer Date: Thu, 10 Oct 2024 10:17:48 -0400 Subject: [PATCH 01/14] wip: unverified token support --- packages/ui/panda.config.ts | 1 + .../src/components/common/CopyToClipBoard.tsx | 69 ++++++ packages/ui/src/components/common/Modal.tsx | 12 +- .../common/TokenSelector/TokenSelector.tsx | 208 +++++++++++------- .../TokenSelector/steps/SetCurrencyStep.tsx | 74 ++++++- .../common/UnverifiedTokenModal.tsx | 138 ++++++++++++ .../ui/src/components/primitives/Button.tsx | 4 +- packages/ui/src/utils/localStorage.ts | 20 ++ 8 files changed, 437 insertions(+), 89 deletions(-) create mode 100644 packages/ui/src/components/common/CopyToClipBoard.tsx create mode 100644 packages/ui/src/components/common/UnverifiedTokenModal.tsx create mode 100644 packages/ui/src/utils/localStorage.ts diff --git a/packages/ui/panda.config.ts b/packages/ui/panda.config.ts index f815b853..0a4a3182 100644 --- a/packages/ui/panda.config.ts +++ b/packages/ui/panda.config.ts @@ -57,6 +57,7 @@ export const Colors = { // Amber amber2: { value: '{colors.amber.2}' }, amber3: { value: '{colors.amber.3}' }, + amber4: { value: '{colors.amber.4}' }, amber9: { value: '{colors.amber.9}' }, amber10: { value: '{colors.amber.10}' }, amber11: { value: '{colors.amber.11}' }, diff --git a/packages/ui/src/components/common/CopyToClipBoard.tsx b/packages/ui/src/components/common/CopyToClipBoard.tsx new file mode 100644 index 00000000..64010f43 --- /dev/null +++ b/packages/ui/src/components/common/CopyToClipBoard.tsx @@ -0,0 +1,69 @@ +import { type FC, useState } from 'react' +import { Button, Text } from '../primitives/index.js' +import Tooltip from '../primitives/Tooltip.js' +import { useCopyToClipboard } from 'usehooks-ts' +import { AnimatePresence, motion } from 'framer-motion' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faCheck, faCopy } from '@fortawesome/free-solid-svg-icons' + +type CopyToClipBoardProps = { + text: string +} + +export const CopyToClipBoard: FC = ({ text }) => { + const [value, copy] = useCopyToClipboard() + const [isCopied, setIsCopied] = useState(false) + const [open, setOpen] = useState(false) + + const handleCopy = () => { + copy(text) + setIsCopied(true) + setTimeout(() => setIsCopied(false), 1000) + } + + return ( + {isCopied ? 'Copied!' : 'Copy'}} + > + + + ) +} diff --git a/packages/ui/src/components/common/Modal.tsx b/packages/ui/src/components/common/Modal.tsx index da9e23f9..c005ca65 100644 --- a/packages/ui/src/components/common/Modal.tsx +++ b/packages/ui/src/components/common/Modal.tsx @@ -15,6 +15,7 @@ import { AnimatePresence } from 'framer-motion' type ModalProps = { trigger?: ReactNode css?: SystemStyleObject + overlayZIndex?: number showCloseButton?: boolean children: ReactNode } @@ -26,7 +27,14 @@ export const Modal: FC< ComponentPropsWithoutRef, 'onPointerDownOutside' > -> = ({ trigger, css, showCloseButton = true, children, ...props }) => { +> = ({ + trigger, + css, + overlayZIndex = 9999, + showCloseButton = true, + children, + ...props +}) => { return ( {trigger} @@ -41,9 +49,9 @@ export const Modal: FC< left: 0, right: 0, bottom: 0, - zIndex: 9999, backgroundColor: 'blackA10' }} + style={{ zIndex: overlayZIndex }} > >] @@ -70,6 +75,10 @@ const TokenSelector: FC = ({ setToken, onAnalyticEvent }) => { + const [unverifiedTokenModalOpen, setUnverifiedTokenModalOpen] = + useState(false) + const [unverifiedToken, setUnverifiedToken] = useState() + const [internalOpen, setInternalOpen] = useState(false) const [open, setOpen] = openState || [internalOpen, setInternalOpen] const isSmallDevice = useMediaQuery('(max-width: 600px)') @@ -96,7 +105,10 @@ const TokenSelector: FC = ({ const relayClient = useRelayClient() const configuredChains = useMemo(() => { let chains = - relayClient?.chains.sort((a, b) => a.name.localeCompare(b.name)) ?? [] + relayClient?.chains.sort((a, b) => + a.displayName.localeCompare(b.displayName) + ) ?? [] + if (!multiWalletSupportEnabled && context === 'from') { chains = chains.filter((chain) => chain.vmType !== 'svm') } @@ -383,6 +395,7 @@ const TokenSelector: FC = ({ logoURI: currency.metadata?.logoURI ?? '' }) setOpen(false) + // reset state resetState() } @@ -417,81 +430,126 @@ const TokenSelector: FC = ({ }, [open]) return ( - { - onAnalyticEvent?.( - openChange - ? EventNames.SWAP_START_TOKEN_SELECT - : EventNames.SWAP_EXIT_TOKEN_SELECT, - { - type, - direction: context === 'from' ? 'input' : 'output' - } - ) - setOpen(openChange) - }} - showCloseButton={true} - trigger={trigger} - css={{ - p: '4', - sm: { - minWidth: - size === 'desktop' - ? !chainIdsFilter || chainIdsFilter.length > 1 - ? 568 - : 378 - : 400, - maxWidth: - size === 'desktop' && (!chainIdsFilter || chainIdsFilter.length > 1) - ? 568 - : 378 - } - }} - > - - {tokenSelectorStep === TokenSelectorStep.SetCurrency ? ( - +
+ { + onAnalyticEvent?.( + openChange + ? EventNames.SWAP_START_TOKEN_SELECT + : EventNames.SWAP_EXIT_TOKEN_SELECT, + { + type, + direction: context === 'from' ? 'input' : 'output' + } + ) + setOpen(openChange) + }} + showCloseButton={true} + trigger={trigger} + css={{ + p: '4', + sm: { + minWidth: + size === 'desktop' + ? !chainIdsFilter || chainIdsFilter.length > 1 + ? 568 + : 378 + : 400, + maxWidth: + size === 'desktop' && + (!chainIdsFilter || chainIdsFilter.length > 1) + ? 568 + : 378 + } + }} + > + + {tokenSelectorStep === TokenSelectorStep.SetCurrency ? ( + + ) : null} + {tokenSelectorStep === TokenSelectorStep.SetChain ? ( + + ) : null} + + +
+ + {unverifiedTokenModalOpen && ( + { + if (token) { + const currentData = getRelayUiKitData() + const tokenIdentifier = `${token.chainId}:${token.address}` + + console.log('currentData: ', currentData) + console.log('tokenIdentifier: ', tokenIdentifier) + if ( + !currentData.acceptedUnverifiedTokens.includes(tokenIdentifier) + ) { + console.log('setting new token data') + setRelayUiKitData({ + acceptedUnverifiedTokens: [ + ...currentData.acceptedUnverifiedTokens, + tokenIdentifier + ] + }) + } + + selectToken(token, token.chainId) } - token={token} - selectToken={selectToken} - setCurrencyList={setCurrencyList} - onAnalyticEvent={onAnalyticEvent} - /> - ) : null} - {tokenSelectorStep === TokenSelectorStep.SetChain ? ( - - ) : null} -
-
+ resetState() + setOpen(false) + setUnverifiedTokenModalOpen(false) + }} + /> + )} + ) } diff --git a/packages/ui/src/components/common/TokenSelector/steps/SetCurrencyStep.tsx b/packages/ui/src/components/common/TokenSelector/steps/SetCurrencyStep.tsx index cb31f2d1..829eee6c 100644 --- a/packages/ui/src/components/common/TokenSelector/steps/SetCurrencyStep.tsx +++ b/packages/ui/src/components/common/TokenSelector/steps/SetCurrencyStep.tsx @@ -10,7 +10,10 @@ import { ChainTokenIcon } from '../../../primitives/index.js' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons' +import { + faExclamationTriangle, + faMagnifyingGlass +} from '@fortawesome/free-solid-svg-icons' import { formatBN } from '../../../../utils/numbers.js' import { truncateAddress } from '../../../../utils/truncate.js' import { LoadingSpinner } from '../../LoadingSpinner.js' @@ -22,6 +25,7 @@ import Fuse from 'fuse.js' import { useMediaQuery } from 'usehooks-ts' import type { Token } from '../../../../types/index.js' import { EventNames } from '../../../../constants/events.js' +import { getRelayUiKitData } from '../../../../utils/localStorage.js' type SetCurrencyProps = { size: 'mobile' | 'desktop' @@ -39,6 +43,8 @@ type SetCurrencyProps = { enhancedCurrencyList?: EnhancedCurrencyList[] token?: Token selectToken: (currency: Currency, chainId?: number) => void + setUnverifiedTokenModalOpen: React.Dispatch> + setUnverifiedToken: React.Dispatch> setCurrencyList: (currencyList: EnhancedCurrencyList) => void onAnalyticEvent?: (eventName: string, data?: any) => void } @@ -63,6 +69,8 @@ export const SetCurrencyStep: FC = ({ isLoadingDuneBalances, enhancedCurrencyList, selectToken, + setUnverifiedTokenModalOpen, + setUnverifiedToken, setCurrencyList, onAnalyticEvent }) => { @@ -288,6 +296,8 @@ export const SetCurrencyStep: FC = ({ setCurrencyList={setCurrencyList} selectToken={selectToken} isLoadingDuneBalances={isLoadingDuneBalances} + setUnverifiedToken={setUnverifiedToken} + setUnverifiedTokenModalOpen={setUnverifiedTokenModalOpen} key={idx} /> ) : null @@ -311,6 +321,8 @@ type CurrencyRowProps = { currencyList: EnhancedCurrencyList setCurrencyList: (currencyList: EnhancedCurrencyList) => void selectToken: (currency: Currency, chainId?: number) => void + setUnverifiedTokenModalOpen: React.Dispatch> + setUnverifiedToken: React.Dispatch> isLoadingDuneBalances: boolean } @@ -318,6 +330,8 @@ const CurrencyRow: FC = ({ currencyList, setCurrencyList, selectToken, + setUnverifiedTokenModalOpen, + setUnverifiedToken, isLoadingDuneBalances }) => { const balance = currencyList.totalBalance @@ -338,11 +352,35 @@ const CurrencyRow: FC = ({ if (!isSingleChainCurrency) { setCurrencyList(currencyList) } else { - selectToken( - currencyList?.chains?.[0], - currencyList?.chains?.[0].chainId - ) - setCurrencyList(currencyList) + const token = { + ...currencyList?.chains?.[0], + logoURI: currencyList?.chains?.[0].metadata?.logoURI + } + + // @TODO: check if not isVerified + if (true) { + const relayUiKitData = getRelayUiKitData() + const tokenKey = `${token.chainId}:${token.address}` + const isAlreadyAccepted = + relayUiKitData.acceptedUnverifiedTokens.includes(tokenKey) + + console.log('relayUiKitData: ', relayUiKitData) + console.log('isAlreadyAccepted: ', isAlreadyAccepted) + + if (isAlreadyAccepted) { + // If already accepted, proceed with selection + selectToken(token, token.chainId) + setCurrencyList(currencyList) + } else { + setUnverifiedToken(token as Token) + setUnverifiedTokenModalOpen(true) + } + } + // if(token?.isVerified) + else { + selectToken(token, token.chainId) + setCurrencyList(currencyList) + } } }} css={{ @@ -379,12 +417,28 @@ const CurrencyRow: FC = ({ /> )} - {currencyList?.chains?.[0]?.symbol} - {isSingleChainCurrency ? ( + {currencyList?.chains?.[0]?.name} + - {truncateAddress(currencyList?.chains?.[0].address)} + {currencyList?.chains?.[0]?.symbol} - ) : null} + {isSingleChainCurrency ? ( + + {truncateAddress(currencyList?.chains?.[0].address)} + + ) : null} + + {/* @TODO: update with isVerified variable */} + {Math.random() > 0.5 ? ( + + + + ) : null} + {!isSingleChainCurrency ? ( diff --git a/packages/ui/src/components/common/UnverifiedTokenModal.tsx b/packages/ui/src/components/common/UnverifiedTokenModal.tsx new file mode 100644 index 00000000..0317fe43 --- /dev/null +++ b/packages/ui/src/components/common/UnverifiedTokenModal.tsx @@ -0,0 +1,138 @@ +import type { FC } from 'react' +import { Modal } from './Modal.js' +import type { Token } from '../../types/index.js' +import { Anchor, Box, Button, Flex, Text } from '../primitives/index.js' +import { CopyToClipBoard } from './CopyToClipBoard.js' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { + faExclamationTriangle, + faExternalLink +} from '@fortawesome/free-solid-svg-icons' +import useRelayClient from '../../hooks/useRelayClient.js' + +type UnverifiedTokenModalProps = { + open: boolean + onOpenChange: (open: boolean) => void + token?: Token + onAcceptToken: (token?: Token) => void +} + +export const UnverifiedTokenModal: FC = ({ + open, + onOpenChange, + token, + onAcceptToken +}) => { + const client = useRelayClient() + const chain = client?.chains?.find((chain) => chain.id === token?.chainId) + + return ( + + + Unverified Token + + + {token?.name} + + + + + + + + This token isn’t traded on leading U.S. centralized exchanges or + frequently swapped on major DEXes. Always conduct your own research + before trading. + + + + {token?.address} + + + + + + + + + + + + + + + + + ) +} diff --git a/packages/ui/src/components/primitives/Button.tsx b/packages/ui/src/components/primitives/Button.tsx index c10a239b..613bf06d 100644 --- a/packages/ui/src/components/primitives/Button.tsx +++ b/packages/ui/src/components/primitives/Button.tsx @@ -86,10 +86,10 @@ const ButtonCss = cva({ } }, warning: { - backgroundColor: 'amber2', + backgroundColor: 'amber3', color: 'amber11', '&:hover': { - backgroundColor: 'amber3', + backgroundColor: 'amber4', color: 'amber11' } } diff --git a/packages/ui/src/utils/localStorage.ts b/packages/ui/src/utils/localStorage.ts new file mode 100644 index 00000000..eafc65dd --- /dev/null +++ b/packages/ui/src/utils/localStorage.ts @@ -0,0 +1,20 @@ +const RELAY_UI_KIT_KEY = 'relayUiKitData' + +interface RelayUiKitData { + acceptedUnverifiedTokens: string[] +} + +export function getRelayUiKitData(): RelayUiKitData { + if (typeof window === 'undefined') return { acceptedUnverifiedTokens: [] } + + const storedData = localStorage.getItem(RELAY_UI_KIT_KEY) + return storedData ? JSON.parse(storedData) : { acceptedUnverifiedTokens: [] } +} + +export function setRelayUiKitData(newData: Partial): void { + if (typeof window === 'undefined') return + + const currentData = getRelayUiKitData() + const updatedData = { ...currentData, ...newData } + localStorage.setItem(RELAY_UI_KIT_KEY, JSON.stringify(updatedData)) +} From 4a017748c67cba16724cee5c0d4fa751b261cbeb Mon Sep 17 00:00:00 2001 From: Ted Palmer Date: Wed, 16 Oct 2024 19:00:24 -0400 Subject: [PATCH 02/14] Add usdc total to token selector and update styling --- .../TokenSelector/steps/SetCurrencyStep.tsx | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/packages/ui/src/components/common/TokenSelector/steps/SetCurrencyStep.tsx b/packages/ui/src/components/common/TokenSelector/steps/SetCurrencyStep.tsx index 829eee6c..819e84a5 100644 --- a/packages/ui/src/components/common/TokenSelector/steps/SetCurrencyStep.tsx +++ b/packages/ui/src/components/common/TokenSelector/steps/SetCurrencyStep.tsx @@ -14,7 +14,7 @@ import { faExclamationTriangle, faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons' -import { formatBN } from '../../../../utils/numbers.js' +import { formatBN, formatDollar } from '../../../../utils/numbers.js' import { truncateAddress } from '../../../../utils/truncate.js' import { LoadingSpinner } from '../../LoadingSpinner.js' import type { EnhancedCurrencyList } from '../TokenSelector.js' @@ -113,7 +113,7 @@ export const SetCurrencyStep: FC = ({ > Select Token - + {isDesktop && (!chainIdsFilter || chainIdsFilter.length > 1) ? ( <> = ({ setUnverifiedToken, isLoadingDuneBalances }) => { + const totalValueUsd = currencyList.totalValueUsd const balance = currencyList.totalBalance const decimals = currencyList?.chains?.length > 0 @@ -386,7 +387,7 @@ const CurrencyRow: FC = ({ css={{ gap: '2', cursor: 'pointer', - px: '4', + px: '2', py: '2', transition: 'backdrop-filter 250ms linear', _hover: { @@ -416,8 +417,10 @@ const CurrencyRow: FC = ({ style={{ borderRadius: 9999 }} /> )} - - {currencyList?.chains?.[0]?.name} + + + {currencyList?.chains?.[0]?.name} + {currencyList?.chains?.[0]?.symbol} @@ -443,7 +446,7 @@ const CurrencyRow: FC = ({ {!isSingleChainCurrency ? ( - {currencyList?.chains?.slice(0, 6).map((currency, index) => ( + {currencyList?.chains?.slice(0, 3).map((currency, index) => ( = ({ }} /> ))} - {currencyList?.chains?.length > 6 ? ( + {currencyList?.chains?.length > 3 ? ( + more ) : null} ) : null} - {isLoadingDuneBalances && !balance ? ( - - ) : null} - {balance ? ( - - {formatBN(balance, 5, decimals, compactBalance)} - - ) : null} + + {isLoadingDuneBalances ? ( + <> + + + + ) : ( + <> + {balance ? ( + + {formatBN(balance, 4, decimals, compactBalance)} + + ) : null} + {totalValueUsd ? ( + + {formatDollar(totalValueUsd)} + + ) : null} + + )} + ) } From 312c4f6bcdb456a355fa7ec8de60b5a4e3f943f0 Mon Sep 17 00:00:00 2001 From: Ted Palmer Date: Fri, 18 Oct 2024 12:16:51 -0400 Subject: [PATCH 03/14] Sync api types --- packages/sdk/src/routes/index.ts | 9 +- packages/sdk/src/types/api.ts | 602 ++++++++++++++++++++++++++----- 2 files changed, 527 insertions(+), 84 deletions(-) diff --git a/packages/sdk/src/routes/index.ts b/packages/sdk/src/routes/index.ts index da9d9709..dbc2eb91 100644 --- a/packages/sdk/src/routes/index.ts +++ b/packages/sdk/src/routes/index.ts @@ -11,10 +11,13 @@ export const routes = [ "/execute/permits", "/quote", "/price", + "/execute/user-op/{chainId}", "/lives", "/intents/status", - "/intents/quote", "/intents/status/v2", + "/intents/quote", + "/intents/quote/v2", + "/requests/{requestId}/signature", "/requests", "/requests/v2", "/transactions/index", @@ -22,5 +25,7 @@ export const routes = [ "/conduit/install", "/prices/rates", "/currencies/v1", - "/currencies/token/price" + "/tokenlist", + "/currencies/token/price", + "/provision/chain" ]; \ No newline at end of file diff --git a/packages/sdk/src/types/api.ts b/packages/sdk/src/types/api.ts index eac36278..c8aab21f 100644 --- a/packages/sdk/src/types/api.ts +++ b/packages/sdk/src/types/api.ts @@ -85,7 +85,7 @@ export interface paths { * @description The type of VM the chain runs on * @enum {string} */ - vmType?: "evm" | "svm"; + vmType?: "bvm" | "evm" | "svm"; explorerQueryParams?: { [key: string]: unknown; } | null; @@ -144,7 +144,7 @@ export interface paths { /** @description User address, when supplied returns user balance and max bridge amount */ user?: string; /** @description Restricts the user balance and capacity to a particular currency when supplied with a currency id. Defaults to the native currency of the destination chain. */ - currency?: "degen" | "eth" | "usdc" | "xai" | "sipher" | "pop" | "tia" | "tg7" | "cgt" | "omi"; + currency?: "anime" | "btc" | "cgt" | "degen" | "eth" | "omi" | "pop" | "sipher" | "tg7" | "tia" | "topia" | "usdc" | "xai" | "weth" | "apeeth"; }; }; responses: { @@ -197,7 +197,7 @@ export interface paths { originChainId: number; destinationChainId: number; /** @enum {string} */ - currency: "degen" | "eth" | "usdc" | "xai" | "sipher" | "pop" | "tia" | "tg7" | "cgt" | "omi"; + currency: "anime" | "btc" | "cgt" | "degen" | "eth" | "omi" | "pop" | "sipher" | "tg7" | "tia" | "topia" | "usdc" | "xai" | "weth" | "apeeth"; /** @description Amount to bridge as the base amount (can be switched to exact input using the dedicated flag), denoted in wei */ amount: string; /** @description App fees to be charged for execution */ @@ -296,7 +296,7 @@ export interface paths { * @description Origin chain gas currency * @enum {string} */ - gasCurrency?: "avax" | "degen" | "bnb" | "matic" | "eth" | "usdc" | "xai" | "dai" | "sipher" | "sol" | "pop" | "tia" | "tg7" | "cgt" | "omi"; + gasCurrency?: "anime" | "btc" | "cgt" | "degen" | "eth" | "omi" | "pop" | "sipher" | "tg7" | "tia" | "topia" | "usdc" | "xai" | "weth" | "apeeth" | "ape" | "avax" | "bnb" | "dai" | "matic" | "sol"; /** @description Combination of the relayerGas and relayerService to give you the full relayer fee in wei */ relayer?: string; /** @description Destination chain gas fee in wei */ @@ -307,10 +307,10 @@ export interface paths { * @description The currency for all relayer fees (gas and service) * @enum {string} */ - relayerCurrency?: "degen" | "eth" | "usdc" | "xai" | "sipher" | "pop" | "tia" | "tg7" | "cgt" | "omi"; + relayerCurrency?: "anime" | "btc" | "cgt" | "degen" | "eth" | "omi" | "pop" | "sipher" | "tg7" | "tia" | "topia" | "usdc" | "xai" | "weth" | "apeeth"; app?: string; /** @enum {string} */ - appCurrency?: "degen" | "eth" | "usdc" | "xai" | "sipher" | "pop" | "tia" | "tg7" | "cgt" | "omi"; + appCurrency?: "anime" | "btc" | "cgt" | "degen" | "eth" | "omi" | "pop" | "sipher" | "tg7" | "tia" | "topia" | "usdc" | "xai" | "weth" | "apeeth"; }; breakdown?: { /** @description Amount that will be bridged in the estimated time */ @@ -372,7 +372,7 @@ export interface paths { originChainId: number; destinationChainId: number; /** @enum {string} */ - currency: "degen" | "eth" | "usdc" | "xai" | "sipher" | "pop" | "tia" | "tg7" | "cgt" | "omi"; + currency: "anime" | "btc" | "cgt" | "degen" | "eth" | "omi" | "pop" | "sipher" | "tg7" | "tia" | "topia" | "usdc" | "xai" | "weth" | "apeeth"; /** @description Amount to bridge as the base amount (can be switched to exact input using the dedicated flag), denoted in wei */ amount: string; /** @description App fees to be charged for execution */ @@ -472,7 +472,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ gas?: { @@ -491,6 +492,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Combination of the relayerGas and relayerService to give you the full relayer fee @@ -509,7 +511,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayer?: { @@ -528,6 +531,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Destination chain gas fee @@ -546,7 +550,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayerGas?: { @@ -565,6 +570,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Fees paid to the relay solver, note that this value can be negative (which represents network rewards for moving in a direction that optimizes liquidity distribution) @@ -583,7 +589,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayerService?: { @@ -602,6 +609,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Fees paid to the app. Currency will be the same as the relayer fee currency. This needs to be claimed later by the app owner and is not immediately distributed to the app @@ -620,7 +628,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ app?: { @@ -639,6 +648,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; }; breakdown?: { @@ -796,7 +806,7 @@ export interface paths { * @description Origin chain gas currency * @enum {string} */ - gasCurrency?: "avax" | "degen" | "bnb" | "matic" | "eth" | "usdc" | "xai" | "dai" | "sipher" | "sol" | "pop" | "tia" | "tg7" | "cgt" | "omi"; + gasCurrency?: "anime" | "btc" | "cgt" | "degen" | "eth" | "omi" | "pop" | "sipher" | "tg7" | "tia" | "topia" | "usdc" | "xai" | "weth" | "apeeth" | "ape" | "avax" | "bnb" | "dai" | "matic" | "sol"; /** @description Combination of the relayerGas and relayerService to give you the full relayer fee in wei */ relayer?: string; /** @description Destination chain gas fee in wei */ @@ -807,10 +817,10 @@ export interface paths { * @description The currency for all relayer fees (gas and service) * @enum {string} */ - relayerCurrency?: "degen" | "eth" | "usdc" | "xai" | "sipher" | "pop" | "tia" | "tg7" | "cgt" | "omi"; + relayerCurrency?: "anime" | "btc" | "cgt" | "degen" | "eth" | "omi" | "pop" | "sipher" | "tg7" | "tia" | "topia" | "usdc" | "xai" | "weth" | "apeeth"; app?: string; /** @enum {string} */ - appCurrency?: "degen" | "eth" | "usdc" | "xai" | "sipher" | "pop" | "tia" | "tg7" | "cgt" | "omi"; + appCurrency?: "anime" | "btc" | "cgt" | "degen" | "eth" | "omi" | "pop" | "sipher" | "tg7" | "tia" | "topia" | "usdc" | "xai" | "weth" | "apeeth"; }; /** * @example { @@ -981,7 +991,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ gas?: { @@ -1000,6 +1011,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Combination of the relayerGas and relayerService to give you the full relayer fee @@ -1018,7 +1030,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayer?: { @@ -1037,6 +1050,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Destination chain gas fee @@ -1055,7 +1069,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayerGas?: { @@ -1074,6 +1089,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Fees paid to the relay solver, note that this value can be negative (which represents network rewards for moving in a direction that optimizes liquidity distribution) @@ -1092,7 +1108,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayerService?: { @@ -1111,6 +1128,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Fees paid to the app. Currency will be the same as the relayer fee currency. This needs to be claimed later by the app owner and is not immediately distributed to the app @@ -1129,7 +1147,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ app?: { @@ -1148,6 +1167,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; }; /** @@ -1345,7 +1365,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ gas?: { @@ -1364,6 +1385,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Combination of the relayerGas and relayerService to give you the full relayer fee @@ -1382,7 +1404,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayer?: { @@ -1401,6 +1424,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Destination chain gas fee @@ -1419,7 +1443,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayerGas?: { @@ -1438,6 +1463,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Fees paid to the relay solver, note that this value can be negative (which represents network rewards for moving in a direction that optimizes liquidity distribution) @@ -1456,7 +1482,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayerService?: { @@ -1475,6 +1502,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Fees paid to the app. Currency will be the same as the relayer fee currency. This needs to be claimed later by the app owner and is not immediately distributed to the app @@ -1493,7 +1521,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ app?: { @@ -1512,6 +1541,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; }; breakdown?: { @@ -1554,7 +1584,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ currencyIn?: { @@ -1573,6 +1604,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @example { @@ -1590,7 +1622,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ currencyOut?: { @@ -1609,6 +1642,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** @description The difference between the input and output values, including fees */ totalImpact?: { @@ -1673,6 +1707,7 @@ export interface paths { content: { "application/json": { user: string; + recipient?: string; origins: { chainId: number; currency: string; @@ -1683,6 +1718,7 @@ export interface paths { partial?: boolean; /** @enum {string} */ tradeType: "EXACT_INPUT"; + useUserOperation?: boolean; }; }; }; @@ -1764,7 +1800,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ gas?: { @@ -1783,6 +1820,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Combination of the relayerGas and relayerService to give you the full relayer fee @@ -1801,7 +1839,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayer?: { @@ -1820,6 +1859,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Destination chain gas fee @@ -1838,7 +1878,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayerGas?: { @@ -1857,6 +1898,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Fees paid to the relay solver, note that this value can be negative (which represents network rewards for moving in a direction that optimizes liquidity distribution) @@ -1875,7 +1917,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayerService?: { @@ -1894,6 +1937,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Fees paid to the app. Currency will be the same as the relayer fee currency. This needs to be claimed later by the app owner and is not immediately distributed to the app @@ -1912,7 +1956,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ app?: { @@ -1931,6 +1976,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; }; breakdown?: { @@ -1973,7 +2019,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ currencyIn?: { @@ -1992,6 +2039,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @example { @@ -2009,7 +2057,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ currencyOut?: { @@ -2028,6 +2077,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** @description The difference between the input and output values, including fees */ totalImpact?: { @@ -2161,7 +2211,7 @@ export interface paths { * @description Whether to use the amount as the output or the input for the basis of the swap * @enum {string} */ - tradeType: "EXACT_INPUT" | "EXACT_OUTPUT"; + tradeType: "EXACT_INPUT" | "EXACT_OUTPUT" | "EXPECTED_OUTPUT"; txs?: { to?: string; value?: string; @@ -2272,7 +2322,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ gas?: { @@ -2291,6 +2342,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Combination of the relayerGas and relayerService to give you the full relayer fee @@ -2309,7 +2361,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayer?: { @@ -2328,6 +2381,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Destination chain gas fee @@ -2346,7 +2400,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayerGas?: { @@ -2365,6 +2420,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Fees paid to the relay solver, note that this value can be negative (which represents network rewards for moving in a direction that optimizes liquidity distribution) @@ -2383,7 +2439,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayerService?: { @@ -2402,6 +2459,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Fees paid to the app. Currency will be the same as the relayer fee currency. This needs to be claimed later by the app owner and is not immediately distributed to the app @@ -2420,7 +2478,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ app?: { @@ -2439,6 +2498,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; }; /** @description A summary of the swap and what the user should expect to happen given an input */ @@ -2465,7 +2525,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ currencyIn?: { @@ -2484,6 +2545,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @example { @@ -2501,7 +2563,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ currencyOut?: { @@ -2520,6 +2583,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** @description The difference between the input and output values, including fees */ totalImpact?: { @@ -2601,7 +2665,7 @@ export interface paths { * @description Whether to use the amount as the output or the input for the basis of the swap * @enum {string} */ - tradeType: "EXACT_INPUT" | "EXACT_OUTPUT"; + tradeType: "EXACT_INPUT" | "EXACT_OUTPUT" | "EXPECTED_OUTPUT"; txs?: { to?: string; value?: string; @@ -2657,7 +2721,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ gas?: { @@ -2676,6 +2741,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Combination of the relayerGas and relayerService to give you the full relayer fee @@ -2694,7 +2760,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayer?: { @@ -2713,6 +2780,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Destination chain gas fee @@ -2731,7 +2799,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayerGas?: { @@ -2750,6 +2819,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Fees paid to the relay solver, note that this value can be negative (which represents network rewards for moving in a direction that optimizes liquidity distribution) @@ -2768,7 +2838,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ relayerService?: { @@ -2787,6 +2858,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @description Fees paid to the app. Currency will be the same as the relayer fee currency. This needs to be claimed later by the app owner and is not immediately distributed to the app @@ -2805,7 +2877,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ app?: { @@ -2824,6 +2897,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; }; /** @description A summary of the swap and what the user should expect to happen given an input */ @@ -2850,7 +2924,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ currencyIn?: { @@ -2869,6 +2944,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @example { @@ -2886,7 +2962,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ currencyOut?: { @@ -2905,6 +2982,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** @description The difference between the input and output values, including fees */ totalImpact?: { @@ -2967,6 +3045,83 @@ export interface paths { }; }; }; + "/execute/user-op/{chainId}": { + post: { + parameters: { + path: { + chainId: string; + }; + }; + requestBody: { + content: { + "application/json": { + id: number; + jsonrpc: string; + method: string; + params: [{ + sender: string; + nonce: string; + factory?: string | null; + factoryData?: string | null; + callData: string; + callGasLimit: string; + verificationGasLimit: string; + preVerificationGas: string; + maxFeePerGas: string; + maxPriorityFeePerGas: string; + paymaster?: string | null; + paymasterVerificationGasLimit?: string | null; + paymasterPostOpGasLimit?: string | null; + paymasterData?: string | null; + signature: string; + }, string]; + }; + }; + }; + responses: { + /** @description Default Response */ + 200: { + content: { + "application/json": { + jsonrpc?: string; + id?: number; + result?: string; + }; + }; + }; + /** @description Default Response */ + 400: { + content: { + "application/json": { + jsonrpc?: string; + id?: number; + error?: unknown; + }; + }; + }; + /** @description Default Response */ + 401: { + content: { + "application/json": { + jsonrpc?: string; + id?: number; + error?: unknown; + }; + }; + }; + /** @description Default Response */ + 500: { + content: { + "application/json": { + jsonrpc?: string; + id?: number; + error?: unknown; + }; + }; + }; + }; + }; + }; "/lives": { get: { responses: { @@ -3014,6 +3169,39 @@ export interface paths { }; }; }; + "/intents/status/v2": { + get: { + parameters: { + query?: { + /** @description A unique id representing the execution in the Relay system. You can obtain this id from the requests api or the check object within the step items. */ + requestId?: string; + }; + }; + responses: { + /** @description Default Response */ + 200: { + content: { + "application/json": { + /** + * @description Note that fallback is returned in the case of a refund + * @enum {string} + */ + status?: "refund" | "delayed" | "waiting" | "failure" | "pending" | "success"; + details?: string; + /** @description Incoming transaction hashes */ + inTxHashes?: string[]; + /** @description Outgoing transaction hashes */ + txHashes?: string[]; + /** @description The last timestamp the data was updated */ + time?: number; + originChainId?: number; + destinationChainId?: number; + }; + }; + }; + }; + }; + }; "/intents/quote": { post: { requestBody: { @@ -3054,12 +3242,14 @@ export interface paths { }; }; }; - "/intents/status/v2": { - get: { - parameters: { - query?: { - /** @description A unique id representing the execution in the Relay system. You can obtain this id from the requests api or the check object within the step items. */ - requestId?: string; + "/intents/quote/v2": { + post: { + requestBody: { + content: { + "application/json": { + request: Record; + source?: string; + }; }; }; responses: { @@ -3067,20 +3257,140 @@ export interface paths { 200: { content: { "application/json": { + requestId?: string; + approvalTxData?: { + to?: string; + data?: string; + value?: string; + }; + depositTxData?: { + to?: string; + data?: string; + value?: string; + }; /** - * @description Note that fallback is returned in the case of a refund - * @enum {string} + * @example { + * "currency": { + * "chainId": 8453, + * "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + * "symbol": "USDC", + * "name": "USD Coin", + * "decimals": 6, + * "metadata": { + * "logoURI": "https://ethereum-optimism.github.io/data/USDC/logo.png", + * "verified": false, + * "isNative": false + * } + * }, + * "amount": "30754920", + * "amountFormatted": "30.75492", + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" + * } */ - status?: "refund" | "delayed" | "waiting" | "failure" | "pending" | "success"; - details?: string; - /** @description Incoming transaction hashes */ - inTxHashes?: string[]; - /** @description Outgoing transaction hashes */ - txHashes?: string[]; - /** @description The last timestamp the data was updated */ - time?: number; - originChainId?: number; - destinationChainId?: number; + currencyIn?: { + currency?: { + chainId?: number; + address?: string; + symbol?: string; + name?: string; + decimals?: number; + metadata?: { + logoURI?: string; + verified?: boolean; + isNative?: boolean; + }; + }; + amount?: string; + amountFormatted?: string; + amountUsd?: string; + minimumAmount?: string; + }; + /** + * @example { + * "currency": { + * "chainId": 8453, + * "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + * "symbol": "USDC", + * "name": "USD Coin", + * "decimals": 6, + * "metadata": { + * "logoURI": "https://ethereum-optimism.github.io/data/USDC/logo.png", + * "verified": false, + * "isNative": false + * } + * }, + * "amount": "30754920", + * "amountFormatted": "30.75492", + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" + * } + */ + currencyOut?: { + currency?: { + chainId?: number; + address?: string; + symbol?: string; + name?: string; + decimals?: number; + metadata?: { + logoURI?: string; + verified?: boolean; + isNative?: boolean; + }; + }; + amount?: string; + amountFormatted?: string; + amountUsd?: string; + minimumAmount?: string; + }; + relayerFee?: string; + depositGasFee?: string; + }; + }; + }; + /** @description Default Response */ + 400: { + content: { + "application/json": { + message?: string; + }; + }; + }; + }; + }; + }; + "/requests/{requestId}/signature": { + get: { + parameters: { + path: { + requestId: string; + }; + }; + responses: { + /** @description Default Response */ + 200: { + content: { + "application/json": { + requestData?: { + originChainId?: number; + originUser?: string; + originCurrency?: string; + originAmount?: string; + originTransferDestination?: string; + destinationChainId?: number; + destinationUser?: string; + }; + signature?: string; + }; + }; + }; + /** @description Default Response */ + 400: { + content: { + "application/json": { + message?: string; + code?: string; }; }; }; @@ -3222,7 +3532,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ currencyIn?: { @@ -3241,6 +3552,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @example { @@ -3258,7 +3570,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ currencyOut?: { @@ -3277,6 +3590,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; rate?: string; }; @@ -3319,6 +3633,9 @@ export interface paths { id?: string; startTimestamp?: number; endTimestamp?: number; + /** @description Get all requests for a single chain in either direction. Setting originChainId and/or destinationChainId will override this parameter. */ + chainId?: string; + sortBy?: "createdAt" | "updatedAt"; }; }; responses: { @@ -3459,7 +3776,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ refundCurrencyData?: { @@ -3478,6 +3796,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; appFees?: { recipient?: string; @@ -3502,7 +3821,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ currencyIn?: { @@ -3521,6 +3841,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; /** * @example { @@ -3538,7 +3859,8 @@ export interface paths { * }, * "amount": "30754920", * "amountFormatted": "30.75492", - * "amountUsd": "30.901612" + * "amountUsd": "30.901612", + * "minimumAmount": "30454920" * } */ currencyOut?: { @@ -3557,6 +3879,7 @@ export interface paths { amount?: string; amountFormatted?: string; amountUsd?: string; + minimumAmount?: string; }; rate?: string; }; @@ -3646,20 +3969,20 @@ export interface paths { content: { "application/json": { /** @enum {string} */ - event?: "INSTALLED" | "UNINSTALLED" | "NETWORK_UPDATED" | "NETWORK_DELETED"; + event: "INSTALLED" | "UNINSTALLED" | "NETWORK_UPDATED" | "NETWORK_DELETED"; id: string; - chain_id: number; - parent_chain_id: number; + chain_id?: number; + parent_chain_id?: number; /** @enum {string} */ - type: "OPTIMISM" | "ARBITRUM"; - name: string; - rpc: string; - ws: string; + type?: "OPTIMISM" | "ARBITRUM"; + name?: string; + rpc?: string; + ws?: string; explorer?: string; logo_url?: string; icon_url?: string; brand_color?: string; - native_currency: { + native_currency?: { name?: string; symbol?: string; decimals?: number; @@ -3730,6 +4053,8 @@ export interface paths { TIA?: number; POP?: number; OMI?: number; + TOPIA?: number; + ANIME?: number; }; }; }; @@ -3757,6 +4082,10 @@ export interface paths { verified?: boolean; /** @description Limit the number of results */ limit?: number; + /** @description Include all chains for a currency when filtering by chainId and address */ + includeAllChains?: boolean; + /** @description Uses 3rd party API's to search for a token, in case relay does not have it indexed */ + useExternalSearch?: boolean; }; }; }; @@ -3772,7 +4101,7 @@ export interface paths { name?: string; decimals?: number; /** @enum {string} */ - vmType?: "evm" | "svm"; + vmType?: "bvm" | "evm" | "svm"; metadata?: { logoURI?: string; verified?: boolean; @@ -3784,6 +4113,40 @@ export interface paths { }; }; }; + "/tokenlist": { + get: { + parameters: { + query?: { + chainId?: number; + }; + }; + responses: { + /** @description Default Response */ + 200: { + content: { + "application/json": { + name?: string; + logoURI?: string; + tokens?: { + name?: string; + decimals?: number; + symbol?: string; + address?: string; + chainId?: number; + logoURI?: string; + }[]; + timestamp?: string; + version?: { + major?: number; + minor?: number; + patch?: number; + }; + }; + }; + }; + }; + }; + }; "/currencies/token/price": { get: { parameters: { @@ -3816,6 +4179,81 @@ export interface paths { }; }; }; + "/provision/chain": { + post: { + parameters: { + header: { + "X-RELAY-INTEGRATION-SECRET": string; + }; + }; + requestBody: { + content: { + "application/json": { + chainId: number; + parentChainId: number; + /** @enum {string} */ + type: "OPTIMISM" | "ARBITRUM"; + name: string; + rpc: string; + ws: string; + explorer?: string; + logoUrl?: string; + iconurl?: string; + brandColor?: string; + nativeCurrency: { + name?: string; + symbol?: string; + decimals?: number; + contract?: string; + }; + contracts: Record; + }; + }; + }; + responses: { + /** @description Default Response */ + 200: { + content: { + "application/json": { + id?: string; + status?: string; + etaSeconds?: number; + }; + }; + }; + /** @description Default Response */ + 400: { + content: { + "application/json": { + message?: string; + code?: string; + status?: string; + }; + }; + }; + /** @description Default Response */ + 401: { + content: { + "application/json": { + message?: string; + code?: string; + status?: string; + }; + }; + }; + /** @description Default Response */ + 500: { + content: { + "application/json": { + message?: string; + code?: string; + status?: string; + }; + }; + }; + }; + }; + }; } export type webhooks = Record; From ff8766046d8a632d806f4067e9c29e66054d3558 Mon Sep 17 00:00:00 2001 From: Ted Palmer Date: Fri, 18 Oct 2024 14:02:26 -0400 Subject: [PATCH 04/14] wip: unverified token support --- packages/sdk/src/types/RelayChain.ts | 2 +- .../common/TokenSelector/TokenSelector.tsx | 65 +++++++++++++++++-- .../TokenSelector/steps/SetChainStep.tsx | 31 ++++++++- .../TokenSelector/steps/SetCurrencyStep.tsx | 14 ++-- packages/ui/src/constants/address.ts | 2 +- 5 files changed, 92 insertions(+), 22 deletions(-) diff --git a/packages/sdk/src/types/RelayChain.ts b/packages/sdk/src/types/RelayChain.ts index fd8c6942..840deefc 100644 --- a/packages/sdk/src/types/RelayChain.ts +++ b/packages/sdk/src/types/RelayChain.ts @@ -5,7 +5,7 @@ type Erc20Currencies = NonNullable< paths['/chains']['get']['responses']['200']['content']['application/json']['chains'] >['0']['erc20Currencies'] -export type ChainVM = 'evm' | 'svm' +export type ChainVM = 'evm' | 'svm' | 'bvm' export type RelayChain = { id: number diff --git a/packages/ui/src/components/common/TokenSelector/TokenSelector.tsx b/packages/ui/src/components/common/TokenSelector/TokenSelector.tsx index 54fc5df6..fae3cde9 100644 --- a/packages/ui/src/components/common/TokenSelector/TokenSelector.tsx +++ b/packages/ui/src/components/common/TokenSelector/TokenSelector.tsx @@ -157,6 +157,26 @@ const TokenSelector: FC = ({ } ) + const { data: externalTokenList } = useTokenList( + relayClient?.baseApiUrl, + { + chainIds: chainFilter.id ? [chainFilter.id] : configuredChainIds, + address: isAddress(debouncedTokenSearchValue) + ? debouncedTokenSearchValue + : undefined, + term: !isAddress(debouncedTokenSearchValue) + ? debouncedTokenSearchValue + : undefined, + defaultList: false, + limit: 20, + ...(tokenListQuery ? { tokens: tokenListQuery } : {}), + useExternalSearch: true + }, + { + enabled: !!debouncedTokenSearchValue + } + ) + const { data: duneTokens, balanceMap: tokenBalances, @@ -207,11 +227,43 @@ const TokenSelector: FC = ({ enabled: duneTokenBalances ? true : false } ) + + const combinedTokenList = useMemo(() => { + if (!tokenList) return externalTokenList + if (!externalTokenList) return tokenList + + const mergedList = [...tokenList] + + externalTokenList.forEach((currencyList) => { + const existingListIndex = mergedList.findIndex( + (list) => list[0]?.chainId === currencyList[0]?.chainId + ) + + if (existingListIndex !== -1) { + // Merge with existing list + mergedList[existingListIndex] = [ + ...mergedList[existingListIndex], + ...currencyList.filter( + (currency) => + !mergedList[existingListIndex].some( + (c) => c.address === currency.address + ) + ) + ] + } else { + // Add new list + mergedList.push(currencyList) + } + }) + + return mergedList + }, [tokenList, externalTokenList]) + // Filter out unconfigured chains and append Relay Chain to each currency const enhancedCurrencyList = useMemo(() => { const _tokenList = - tokenList && (tokenList as any).length - ? (tokenList as CurrencyList[]) + combinedTokenList && (combinedTokenList as any).length + ? (combinedTokenList as CurrencyList[]) : undefined let list = context === 'from' && @@ -220,7 +272,7 @@ const TokenSelector: FC = ({ suggestedTokens && suggestedTokens.length > 0 ? suggestedTokens - : tokenList + : combinedTokenList const ethTokens = _tokenList?.find( (list) => list[0] && list[0].groupID === 'ETH' @@ -290,7 +342,7 @@ const TokenSelector: FC = ({ .sort((a, b) => (b?.totalValueUsd ?? 0) - (a?.totalValueUsd ?? 0)) }, [ context, - tokenList, + combinedTokenList, suggestedTokens, useDefaultTokenList, configuredChains, @@ -507,6 +559,8 @@ const TokenSelector: FC = ({ chainSearchInput={chainSearchInput} setChainSearchInput={setChainSearchInput} selectToken={selectToken} + setUnverifiedToken={setUnverifiedToken} + setUnverifiedTokenModalOpen={setUnverifiedTokenModalOpen} selectedCurrencyList={selectedCurrencyList} type={type} size={size} @@ -527,12 +581,9 @@ const TokenSelector: FC = ({ const currentData = getRelayUiKitData() const tokenIdentifier = `${token.chainId}:${token.address}` - console.log('currentData: ', currentData) - console.log('tokenIdentifier: ', tokenIdentifier) if ( !currentData.acceptedUnverifiedTokens.includes(tokenIdentifier) ) { - console.log('setting new token data') setRelayUiKitData({ acceptedUnverifiedTokens: [ ...currentData.acceptedUnverifiedTokens, diff --git a/packages/ui/src/components/common/TokenSelector/steps/SetChainStep.tsx b/packages/ui/src/components/common/TokenSelector/steps/SetChainStep.tsx index 7891be6a..b187800f 100644 --- a/packages/ui/src/components/common/TokenSelector/steps/SetChainStep.tsx +++ b/packages/ui/src/components/common/TokenSelector/steps/SetChainStep.tsx @@ -10,6 +10,7 @@ import { import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faChevronLeft, + faExclamationTriangle, faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons' import { truncateAddress } from '../../../../utils/truncate.js' @@ -34,6 +35,8 @@ type SetChainStepProps = { multiWalletSupportEnabled?: boolean setTokenSelectorStep: React.Dispatch> setInputElement: React.Dispatch> + setUnverifiedToken: React.Dispatch> + setUnverifiedTokenModalOpen: React.Dispatch> chainSearchInput: string setChainSearchInput: React.Dispatch> selectToken: (currency: Currency, chainId?: number) => void @@ -73,6 +76,8 @@ export const SetChainStep: FC = ({ chainSearchInput, setChainSearchInput, selectToken, + setUnverifiedToken, + setUnverifiedTokenModalOpen, selectedCurrencyList }) => { const client = useRelayClient() @@ -189,11 +194,16 @@ export const SetChainStep: FC = ({ {filteredChains?.map((chain) => { const isSupported = chain.isSupported const token = isSupported - ? (chain.currency as Currency) + ? { + ...chain.currency, + logoURI: chain.currency?.metadata?.logoURI + } : { ...chain.relayChain.currency, + logoURI: `https://assets.relay.link/icons/currencies/${chain.relayChain.currency?.id}.png`, metadata: { - logoURI: `https://assets.relay.link/icons/currencies/${chain.relayChain.currency?.id}.png` + logoURI: `https://assets.relay.link/icons/currencies/${chain.relayChain.currency?.id}.png`, + verified: true } } @@ -203,13 +213,19 @@ export const SetChainStep: FC = ({ decimals && chain?.currency.balance.amount.toString().length - decimals > 4 ) + const isVerified = token?.metadata?.verified return ( - ) -} + + ) : null} + + {isLoadingDuneBalances ? ( + <> + + + + ) : ( + <> + {balance ? ( + + {formatBN(balance, 4, decimals, compactBalance)} + + ) : null} + {totalValueUsd ? ( + + {formatDollar(totalValueUsd)} + + ) : null} + + )} + + + ) + } +) diff --git a/packages/ui/src/constants/address.ts b/packages/ui/src/constants/address.ts index 39b52a18..d276116f 100644 --- a/packages/ui/src/constants/address.ts +++ b/packages/ui/src/constants/address.ts @@ -4,11 +4,7 @@ export const evmDeadAddress = '0x000000000000000000000000000000000000dead' as const export const solDeadAddress = '11111111111111111111111111111111' as const //need to check this -<<<<<<< HEAD -export const getDeadAddress = (vmType?: 'evm' | 'svm' | 'bvm') => { -======= export const getDeadAddress = (vmType?: ChainVM) => { ->>>>>>> fdc4cc371559b43c020a2f443299b16101d98fe3 if (vmType === 'svm') { return solDeadAddress } else { From 2eada587dd131a65d029f2011553e738c8f487b9 Mon Sep 17 00:00:00 2001 From: Ted Palmer Date: Tue, 22 Oct 2024 20:36:03 -0400 Subject: [PATCH 06/14] Add analytic event + support external search --- .../common/TokenSelector/TokenSelector.tsx | 55 +++++++++++-------- .../TokenSelector/steps/SetChainStep.tsx | 54 ++++++++---------- .../TokenSelector/steps/SetCurrencyStep.tsx | 49 ++++++++++------- .../triggers/SwapWidgetTokenTrigger.tsx | 39 +++++++++---- .../common/UnverifiedTokenModal.tsx | 16 +++--- .../components/primitives/ChainTokenIcon.tsx | 44 +++++++++++---- packages/ui/src/constants/events.ts | 1 + packages/ui/src/types/index.ts | 1 + 8 files changed, 156 insertions(+), 103 deletions(-) diff --git a/packages/ui/src/components/common/TokenSelector/TokenSelector.tsx b/packages/ui/src/components/common/TokenSelector/TokenSelector.tsx index 9d7724db..0d99f647 100644 --- a/packages/ui/src/components/common/TokenSelector/TokenSelector.tsx +++ b/packages/ui/src/components/common/TokenSelector/TokenSelector.tsx @@ -235,24 +235,20 @@ const TokenSelector: FC = ({ const mergedList = [...tokenList] externalTokenList.forEach((currencyList) => { - const existingListIndex = mergedList.findIndex( - (list) => list[0]?.chainId === currencyList[0]?.chainId - ) - - if (existingListIndex !== -1) { - // Merge with existing list - mergedList[existingListIndex] = [ - ...mergedList[existingListIndex], - ...currencyList.filter( - (currency) => - !mergedList[existingListIndex].some( - (c) => c.address === currency.address - ) + const externalCurrency = currencyList[0] + + if (externalCurrency) { + const alreadyExists = mergedList.some((list) => + list.some( + (existingCurrency) => + existingCurrency.chainId === externalCurrency.chainId && + existingCurrency?.address?.toLowerCase() === + externalCurrency?.address?.toLowerCase() ) - ] - } else { - // Add new list - mergedList.push(currencyList) + ) + if (!alreadyExists) { + mergedList.push(currencyList) + } } }) @@ -265,13 +261,20 @@ const TokenSelector: FC = ({ combinedTokenList && (combinedTokenList as any).length ? (combinedTokenList as CurrencyList[]) : undefined + + const filteredSuggestedTokens = chainFilter.id + ? suggestedTokens + ?.map((tokenList) => + tokenList.filter((token) => token.chainId === chainFilter.id) + ) + .filter((tokenList) => tokenList.length > 0) + : suggestedTokens + let list = - context === 'from' && useDefaultTokenList && - chainFilter.id === undefined && - suggestedTokens && - suggestedTokens.length > 0 - ? suggestedTokens + filteredSuggestedTokens && + filteredSuggestedTokens.length > 0 + ? filteredSuggestedTokens : combinedTokenList const ethTokens = _tokenList?.find( @@ -289,6 +292,7 @@ const TokenSelector: FC = ({ ) list = [ethTokens ?? [], usdcTokens ?? []].concat(list) } + const mappedList = list?.map((currencyList) => { const filteredList = currencyList .map((currency) => { @@ -347,7 +351,8 @@ const TokenSelector: FC = ({ useDefaultTokenList, configuredChains, tokenBalances, - multiWalletSupportEnabled + multiWalletSupportEnabled, + chainFilter ]) const isLoading = isLoadingSuggestedTokens || isLoadingTokenList @@ -444,7 +449,8 @@ const TokenSelector: FC = ({ symbol: currency.symbol, name: currency.name, decimals: currency.decimals, - logoURI: currency.metadata?.logoURI ?? '' + logoURI: currency.metadata?.logoURI ?? '', + verified: currency.metadata?.verified }) setOpen(false) @@ -594,6 +600,7 @@ const TokenSelector: FC = ({ } selectToken(token, token.chainId) + onAnalyticEvent?.(EventNames.UNVERIFIED_TOKEN_ACCEPTED, { token }) } resetState() setOpen(false) diff --git a/packages/ui/src/components/common/TokenSelector/steps/SetChainStep.tsx b/packages/ui/src/components/common/TokenSelector/steps/SetChainStep.tsx index 76f7f0b4..7172b64e 100644 --- a/packages/ui/src/components/common/TokenSelector/steps/SetChainStep.tsx +++ b/packages/ui/src/components/common/TokenSelector/steps/SetChainStep.tsx @@ -307,40 +307,32 @@ export const SetChainStep: FC = ({ } }} > - - - {chain.displayName} - {type === 'token' ? ( - - {truncateAddress(chain?.currency?.address)} - + + + + {chain.displayName} + {type === 'token' ? ( + + {truncateAddress(chain?.currency?.address)} + + ) : null} + + {!isVerified ? ( + + + ) : null} - {chain?.currency?.balance?.amount ? ( - - {formatBN( - BigInt(chain?.currency?.balance?.amount), - 5, - decimals, - compactBalance - )} - - ) : null} - {!isVerified ? ( - - - - ) : null} {chain?.currency?.balance?.amount ? ( {formatBN( diff --git a/packages/ui/src/components/common/TokenSelector/steps/SetCurrencyStep.tsx b/packages/ui/src/components/common/TokenSelector/steps/SetCurrencyStep.tsx index 52f33dcd..222d4538 100644 --- a/packages/ui/src/components/common/TokenSelector/steps/SetCurrencyStep.tsx +++ b/packages/ui/src/components/common/TokenSelector/steps/SetCurrencyStep.tsx @@ -315,7 +315,11 @@ export const SetCurrencyStep: FC = ({ onSelect={(value) => { if (value && value !== 'input') { const selectedCurrency = enhancedCurrencyList?.find((list) => - list?.chains.some((chain) => chain.address === value) + list.chains.some((chain) => + value.includes(':') + ? `${chain.chainId}:${chain.address}` === value + : chain.address === value + ) ) if (selectedCurrency) { handleCurrencySelection(selectedCurrency) @@ -401,26 +405,29 @@ export const SetCurrencyStep: FC = ({ {!isLoading && enhancedCurrencyList && enhancedCurrencyList?.length > 0 - ? enhancedCurrencyList?.map((list, idx) => - list && list.chains[0].address ? ( - - - - ) : null - ) + ? enhancedCurrencyList?.map((list, idx) => { + if (list && list.chains[0]?.address) { + const value = + list.chains.length === 1 + ? `${list.chains[0].chainId}:${list.chains[0].address}` + : list.chains[0].address + + return ( + + + + ) + } + }) : null} {/* Empty State */} {!isLoading && diff --git a/packages/ui/src/components/common/TokenSelector/triggers/SwapWidgetTokenTrigger.tsx b/packages/ui/src/components/common/TokenSelector/triggers/SwapWidgetTokenTrigger.tsx index 84cd0b62..3353ce99 100644 --- a/packages/ui/src/components/common/TokenSelector/triggers/SwapWidgetTokenTrigger.tsx +++ b/packages/ui/src/components/common/TokenSelector/triggers/SwapWidgetTokenTrigger.tsx @@ -7,7 +7,7 @@ import { Box } from '../../../../components/primitives/index.js' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faChevronDown } from '@fortawesome/free-solid-svg-icons' +import { faChevronDown, faCoins } from '@fortawesome/free-solid-svg-icons' type SwapWidgetTokenTriggerProps = { token?: Token @@ -18,6 +18,8 @@ export const SwapWidgetTokenTrigger: FC = ({ token, locked }) => { + const isValidTokenLogo = token?.logoURI && token.logoURI !== 'missing.png' + return token ? (