diff --git a/apps/cowswap-frontend/package.json b/apps/cowswap-frontend/package.json index f77c11aaae5..e7ae30a48f7 100644 --- a/apps/cowswap-frontend/package.json +++ b/apps/cowswap-frontend/package.json @@ -40,7 +40,7 @@ "@cowprotocol/common-utils": "workspace:*", "@cowprotocol/core": "workspace:*", "@cowprotocol/cow-runner-game": "https://registry.npmjs.org/@cowprotocol/cow-runner-game/-/cow-runner-game-0.2.9.tgz", - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@cowprotocol/cowswap-abis": "workspace:*", "@cowprotocol/currency": "workspace:*", "@cowprotocol/ens": "workspace:*", @@ -49,12 +49,12 @@ "@cowprotocol/iframe-transport": "workspace:*", "@cowprotocol/multicall": "workspace:*", "@cowprotocol/permit-utils": "workspace:*", - "@cowprotocol/sdk-bridging": "4.4.1", - "@cowprotocol/sdk-contracts-ts": "3.3.2", - "@cowprotocol/sdk-cow-shed": "0.4.4", - "@cowprotocol/sdk-order-book": "4.0.1", - "@cowprotocol/sdk-trading": "2.2.5", - "@cowprotocol/sdk-viem-adapter": "0.3.25", + "@cowprotocol/sdk-bridging": "4.4.2", + "@cowprotocol/sdk-contracts-ts": "3.3.3", + "@cowprotocol/sdk-cow-shed": "0.4.5", + "@cowprotocol/sdk-order-book": "4.0.2", + "@cowprotocol/sdk-trading": "2.2.6", + "@cowprotocol/sdk-viem-adapter": "0.3.26", "@cowprotocol/snackbars": "workspace:*", "@cowprotocol/tokens": "workspace:*", "@cowprotocol/types": "workspace:*", diff --git a/apps/cowswap-frontend/src/legacy/components/Tokens/SplDelegationCell.tsx b/apps/cowswap-frontend/src/legacy/components/Tokens/SplDelegationCell.tsx new file mode 100644 index 00000000000..2415b908f27 --- /dev/null +++ b/apps/cowswap-frontend/src/legacy/components/Tokens/SplDelegationCell.tsx @@ -0,0 +1,46 @@ +import { ReactNode } from 'react' + +import { isFractionFalsy } from '@cowprotocol/common-utils' +import { CurrencyAmount, Token } from '@cowprotocol/currency' +import { TokenAmount } from '@cowprotocol/ui' + +import { Trans } from '@lingui/react/macro' + +import { ApproveLabel, NotDelegatedLabel } from './styled' + +type SplDelegationCellProps = { + balance: CurrencyAmount | undefined + allowance: CurrencyAmount | undefined +} + +/** + * Read-only "Actions" cell for Solana rows. Solana has no manual approve flow: the SPL delegation to the + * CoW settlement authority is fetched read-only (persisted as an allowance), so this mirrors the EVM row's + * labels without any action button. + */ +export function SplDelegationCell({ balance, allowance }: SplDelegationCellProps): ReactNode { + // No delegation to the CoW settlement authority — neutral placeholder, not a green "approved" state. + if (isFractionFalsy(allowance)) { + return + } + + // Delegation covers the whole balance → surface it as fully approved, like the EVM row does. + const fullyDelegated = !!balance && !!allowance && !balance.greaterThan(allowance) + + if (fullyDelegated) { + return ( + + Approved ✓ + + ) + } + + return ( + + Approved:{' '} + + + + + ) +} diff --git a/apps/cowswap-frontend/src/legacy/components/Tokens/TokensTableRow.tsx b/apps/cowswap-frontend/src/legacy/components/Tokens/TokensTableRow.tsx index 4468dd23c0a..d94412aba12 100644 --- a/apps/cowswap-frontend/src/legacy/components/Tokens/TokensTableRow.tsx +++ b/apps/cowswap-frontend/src/legacy/components/Tokens/TokensTableRow.tsx @@ -9,7 +9,7 @@ import { isFractionFalsy, COW_PROTOCOL_VAULT_RELAYER_ADDRESS, } from '@cowprotocol/common-utils' -import { MAX_UINT256, getAddressKey } from '@cowprotocol/cow-sdk' +import { MAX_UINT256, getAddressKey, isSolanaChain } from '@cowprotocol/cow-sdk' import { CurrencyAmount, Token } from '@cowprotocol/currency' import { useAreThereTokensWithSameSymbol } from '@cowprotocol/tokens' import { Command } from '@cowprotocol/types' @@ -34,6 +34,7 @@ import { CardsSpinner, ExtLink } from 'pages/Account/styled' import BalanceCell from './BalanceCell' import FavoriteTokenButton from './FavoriteTokenButton' import { FiatBalanceCell } from './FiatBalanceCell' +import { SplDelegationCell } from './SplDelegationCell' import { ApproveLabel, BalanceValue, @@ -67,6 +68,7 @@ export const TokensTableRow = ({ toggleWalletModal, }: DataRowParams): ReactNode => { const { account, chainId } = useWalletInfo() + const isSolana = isSolanaChain(chainId) const areThereTokensWithSameSymbol = useAreThereTokensWithSameSymbol() const theme = useTheme() @@ -199,6 +201,14 @@ export const TokensTableRow = ({ return }, [account, isNativeToken, allowance, handleApprove, approvalState, balanceLessThanAllowance]) + const explorerLink = ( + + + + + + ) + return ( <> @@ -229,16 +239,22 @@ export const TokensTableRow = ({ {fiatValue} - {displayApproveContent && ( - <> - - - - - - {displayApproveContent} - - )} + {/* This EVM/Solana split is temporary. Once a Solana approve (delegation) flow exists, + unify both branches into a single allowance cell instead of branching on chain here. */} + {isSolana + ? !isNativeToken && ( + <> + {explorerLink} + {/* Delegation status is only meaningful for a connected wallet; hide it otherwise. */} + {account && } + + ) + : displayApproveContent && ( + <> + {explorerLink} + {displayApproveContent} + + )} ) diff --git a/apps/cowswap-frontend/src/legacy/components/Tokens/styled.ts b/apps/cowswap-frontend/src/legacy/components/Tokens/styled.ts index 9ec751d2b9a..4b9efcc12b0 100644 --- a/apps/cowswap-frontend/src/legacy/components/Tokens/styled.ts +++ b/apps/cowswap-frontend/src/legacy/components/Tokens/styled.ts @@ -371,6 +371,14 @@ export const ApproveLabel = styled.span` font-weight: 500; ` +// Neutral (muted) label for the Solana "not delegated" placeholder — deliberately not the green +// `ApproveLabel`, since a dash is an empty state rather than an approval. +export const NotDelegatedLabel = styled.span` + color: inherit; + opacity: 0.5; + font-weight: 500; +` + export const CustomLimit = styled.div` > span:last-child { cursor: default; diff --git a/apps/cowswap-frontend/src/locales/en-US.po b/apps/cowswap-frontend/src/locales/en-US.po index 0df5c979dd0..d234bc32e0b 100644 --- a/apps/cowswap-frontend/src/locales/en-US.po +++ b/apps/cowswap-frontend/src/locales/en-US.po @@ -1291,6 +1291,8 @@ msgid "is on {chainName} network" msgstr "is on {chainName} network" #: apps/cowswap-frontend/src/common/pure/PermitModal/index.tsx +#: apps/cowswap-frontend/src/legacy/components/Tokens/SplDelegationCell.tsx +#: apps/cowswap-frontend/src/legacy/components/Tokens/SplDelegationCell.tsx #: apps/cowswap-frontend/src/legacy/components/Tokens/TokensTableRow.tsx #: apps/cowswap-frontend/src/legacy/components/Tokens/TokensTableRow.tsx msgid "Approved" diff --git a/apps/explorer/package.json b/apps/explorer/package.json index 68e5f8dc141..d49fc7f9c45 100644 --- a/apps/explorer/package.json +++ b/apps/explorer/package.json @@ -28,12 +28,12 @@ "@cowprotocol/common-hooks": "workspace:*", "@cowprotocol/common-utils": "workspace:*", "@cowprotocol/core": "workspace:*", - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@cowprotocol/hook-dapp-lib": "workspace:*", - "@cowprotocol/sdk-bridging": "4.4.1", - "@cowprotocol/sdk-contracts-ts": "3.3.2", - "@cowprotocol/sdk-subgraph": "1.2.0", - "@cowprotocol/sdk-viem-adapter": "0.3.25", + "@cowprotocol/sdk-bridging": "4.4.2", + "@cowprotocol/sdk-contracts-ts": "3.3.3", + "@cowprotocol/sdk-subgraph": "1.2.1", + "@cowprotocol/sdk-viem-adapter": "0.3.26", "@cowprotocol/types": "workspace:*", "@cowprotocol/ui": "workspace:*", "@fortawesome/fontawesome-svg-core": "6.7.2", diff --git a/apps/sdk-tools/package.json b/apps/sdk-tools/package.json index be52eef0ed4..eaf61a8da6e 100644 --- a/apps/sdk-tools/package.json +++ b/apps/sdk-tools/package.json @@ -24,9 +24,9 @@ }, "dependencies": { "@cowprotocol/common-const": "workspace:*", - "@cowprotocol/cow-sdk": "9.2.5", - "@cowprotocol/sdk-composable": "1.2.2", - "@cowprotocol/sdk-viem-adapter": "0.3.25", + "@cowprotocol/cow-sdk": "9.2.6", + "@cowprotocol/sdk-composable": "1.2.3", + "@cowprotocol/sdk-viem-adapter": "0.3.26", "@cowprotocol/wallet": "workspace:*", "viem": "2.48.8", "wagmi": "3.6.9", diff --git a/apps/widget-configurator/package.json b/apps/widget-configurator/package.json index f2708d9bfee..b10db76d64d 100644 --- a/apps/widget-configurator/package.json +++ b/apps/widget-configurator/package.json @@ -29,7 +29,7 @@ "@cowprotocol/common-const": "workspace:*", "@cowprotocol/common-hooks": "workspace:*", "@cowprotocol/common-utils": "workspace:*", - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@cowprotocol/events": "workspace:*", "@cowprotocol/types": "workspace:*", "@cowprotocol/ui": "workspace:*", diff --git a/bundle-size.jsonc b/bundle-size.jsonc index 4ab6beacf58..bc15ac00b85 100644 --- a/bundle-size.jsonc +++ b/bundle-size.jsonc @@ -5,10 +5,10 @@ { "schemaVersion": 1, "apps": { - "@cowprotocol/cow-fi": 6130633, // 5.85 MiB - "@cowprotocol/cowswap": 12985211, // 12.38 MiB + "@cowprotocol/cow-fi": 6130637, // 5.85 MiB + "@cowprotocol/cowswap": 12986441, // 12.38 MiB "@cowprotocol/explorer": 12754162, // 12.16 MiB - "@cowprotocol/sdk-tools": 12411573, // 11.84 MiB + "@cowprotocol/sdk-tools": 12411597, // 11.84 MiB "@cowprotocol/storybook": 4953374, // 4.72 MiB "@cowprotocol/widget-configurator": 12887230, // 12.29 MiB }, diff --git a/libs/analytics/package.json b/libs/analytics/package.json index c4df6958179..a52342783e3 100644 --- a/libs/analytics/package.json +++ b/libs/analytics/package.json @@ -24,7 +24,7 @@ } }, "dependencies": { - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@cowprotocol/common-const": "workspace:*", "@cowprotocol/common-hooks": "workspace:*", "@cowprotocol/common-utils": "workspace:*", diff --git a/libs/balances-and-allowances/package.json b/libs/balances-and-allowances/package.json index 75cbcb6c05a..c851b232e6c 100644 --- a/libs/balances-and-allowances/package.json +++ b/libs/balances-and-allowances/package.json @@ -24,7 +24,7 @@ } }, "dependencies": { - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@cowprotocol/common-const": "workspace:*", "@cowprotocol/common-hooks": "workspace:*", "@cowprotocol/common-utils": "workspace:*", diff --git a/libs/balances-and-allowances/src/const/solanaSettlement.ts b/libs/balances-and-allowances/src/const/solanaSettlement.ts new file mode 100644 index 00000000000..42500e93f35 --- /dev/null +++ b/libs/balances-and-allowances/src/const/solanaSettlement.ts @@ -0,0 +1,24 @@ +import { isBarnBackendEnv } from '@cowprotocol/common-utils' +import { SOLANA_SETTLEMENT_PROGRAM_ID_STAGING, SOLANA_SETTLEMENT_PROGRAM_ID } from '@cowprotocol/cow-sdk' + +import { PublicKey } from '@solana/web3.js' + +// CoW Protocol settlement program on Solana — https://github.com/cowprotocol/solana-programs +// Prod vs staging is picked by environment, mirroring how EVM contract addresses are handled +// (see `COW_PROTOCOL_VAULT_RELAYER_ADDRESS`). Also mirrors the order-flow constant in +// cowswap-frontend's solanaOrderFlow; consolidate to one source once both land. + +export const solSettlementAddress = isBarnBackendEnv + ? SOLANA_SETTLEMENT_PROGRAM_ID_STAGING + : SOLANA_SETTLEMENT_PROGRAM_ID + +const SETTLEMENT_SEED = new TextEncoder().encode('settlement') + +/** + * Settlement state PDA — the SPL delegate a sell-token account is approved to. A token's delegation + * counts as a CoW approval only when its on-account `delegate` equals this PDA (the program pulls the + * sell funds through it at execution time). This is the Solana analogue of the EVM vault relayer spender. + */ +export function findSolanaSettlementStatePda(): PublicKey { + return PublicKey.findProgramAddressSync([SETTLEMENT_SEED], new PublicKey(solSettlementAddress))[0] +} diff --git a/libs/balances-and-allowances/src/hooks/usePersistBalancesViaWebCalls.test.tsx b/libs/balances-and-allowances/src/hooks/usePersistBalancesViaWebCalls.test.tsx index 4328ee03d8d..6e506873043 100644 --- a/libs/balances-and-allowances/src/hooks/usePersistBalancesViaWebCalls.test.tsx +++ b/libs/balances-and-allowances/src/hooks/usePersistBalancesViaWebCalls.test.tsx @@ -19,8 +19,8 @@ jest.mock('wagmi', () => ({ // The Solana path has its own dedicated test; stub it here so this suite stays focused on // EVM wagmi gating and avoids pulling in the reown/web3/react-query runtime. -jest.mock('./usePersistSolanaBalancesViaWebCalls', () => ({ - usePersistSolanaBalancesViaWebCalls: jest.fn(), +jest.mock('./usePersistSplViaMulticall', () => ({ + usePersistSplViaMulticall: jest.fn(), })) const mockBalancesUpdate: PersistentStateByChain> = mapSupportedNetworks({}) diff --git a/libs/balances-and-allowances/src/hooks/usePersistBalancesViaWebCalls.ts b/libs/balances-and-allowances/src/hooks/usePersistBalancesViaWebCalls.ts index 1e594cbf87e..37ff7528d63 100644 --- a/libs/balances-and-allowances/src/hooks/usePersistBalancesViaWebCalls.ts +++ b/libs/balances-and-allowances/src/hooks/usePersistBalancesViaWebCalls.ts @@ -9,7 +9,7 @@ import { getIsNativeToken } from '@cowprotocol/common-utils' import { isEvmChain, SupportedChainId } from '@cowprotocol/cow-sdk' import { useIsBlockNumberRelevant } from './useIsBlockNumberRelevant' -import { usePersistSolanaBalancesViaWebCalls } from './usePersistSolanaBalancesViaWebCalls' +import { usePersistSplViaMulticall } from './usePersistSplViaMulticall' import { balancesAtom, BalancesState, balancesUpdateAtom } from '../state/balancesAtom' import { REPORT_THROTTLE_MS, reportBalancesError } from '../utils/reportBalancesError' @@ -52,8 +52,8 @@ export function usePersistBalancesViaWebCalls(params: PersistBalancesAndAllowanc // wagmi + viem only support evm chains const isEvm = isEvmChain(chainId) - // Non-EVM chains (e.g. Solana) load balances via their own web calls - usePersistSolanaBalancesViaWebCalls(params) + // Non-EVM chains (e.g. Solana) load balances and delegations via their own web calls + usePersistSplViaMulticall(params) const { data: balances, diff --git a/libs/balances-and-allowances/src/hooks/usePersistSolanaBalancesViaWebCalls.test.tsx b/libs/balances-and-allowances/src/hooks/usePersistSplViaMulticall.test.tsx similarity index 94% rename from libs/balances-and-allowances/src/hooks/usePersistSolanaBalancesViaWebCalls.test.tsx rename to libs/balances-and-allowances/src/hooks/usePersistSplViaMulticall.test.tsx index 89f88d76114..73a18453b89 100644 --- a/libs/balances-and-allowances/src/hooks/usePersistSolanaBalancesViaWebCalls.test.tsx +++ b/libs/balances-and-allowances/src/hooks/usePersistSplViaMulticall.test.tsx @@ -12,7 +12,7 @@ import { PublicKey } from '@solana/web3.js' import { renderHook, waitFor } from '@testing-library/react' import { PersistBalancesAndAllowancesParams } from './usePersistBalancesViaWebCalls' -import { usePersistSolanaBalancesViaWebCalls } from './usePersistSolanaBalancesViaWebCalls' +import { usePersistSplViaMulticall } from './usePersistSplViaMulticall' import { balancesAtom, BalancesState, balancesUpdateAtom } from '../state/balancesAtom' @@ -58,6 +58,12 @@ jest.mock('@solana/spl-token', () => ({ unpackAccount: (ata: { toBase58(): string }) => ({ amount: mockAmountByAta[ata.toBase58()] }), })) +// The settlement PDA derivation relies on ed25519 curve math that this env can't run; the delegate +// matching itself is covered in fetchSolanaTokenAccounts.test — here we only assert balances. +jest.mock('../const/solanaSettlement', () => ({ + findSolanaSettlementStatePda: () => ({ equals: () => false }), +})) + interface MockConnection { rpcEndpoint: string getMultipleAccountsInfo: jest.Mock @@ -92,7 +98,7 @@ function makeParams(overrides: Partial = {}) function renderWithBalances(params: PersistBalancesAndAllowancesParams): { result: { current: BalancesState } } { return renderHook( () => { - usePersistSolanaBalancesViaWebCalls(params) + usePersistSplViaMulticall(params) return useAtomValue(balancesAtom) }, { wrapper }, @@ -129,7 +135,7 @@ function wrapper({ children }: { children: ReactNode }): ReactNode { ) } -describe('usePersistSolanaBalancesViaWebCalls', () => { +describe('usePersistSplViaMulticall', () => { beforeEach(() => { mockTokensByAddress = {} mockAmountByAta = { [ataKey(MINT_A)]: 100n, [ataKey(MINT_B)]: 250n } @@ -203,7 +209,7 @@ describe('usePersistSolanaBalancesViaWebCalls', () => { it('keys the update timestamp by the case-sensitive Solana account, not a lowercased alias', async () => { const { result } = renderHook( () => { - usePersistSolanaBalancesViaWebCalls(makeParams()) + usePersistSplViaMulticall(makeParams()) return useAtomValue(balancesUpdateAtom) }, { wrapper }, diff --git a/libs/balances-and-allowances/src/hooks/usePersistSolanaBalancesViaWebCalls.ts b/libs/balances-and-allowances/src/hooks/usePersistSplViaMulticall.ts similarity index 57% rename from libs/balances-and-allowances/src/hooks/usePersistSolanaBalancesViaWebCalls.ts rename to libs/balances-and-allowances/src/hooks/usePersistSplViaMulticall.ts index d3e01fd1b82..01c9280570b 100644 --- a/libs/balances-and-allowances/src/hooks/usePersistSolanaBalancesViaWebCalls.ts +++ b/libs/balances-and-allowances/src/hooks/usePersistSplViaMulticall.ts @@ -5,33 +5,46 @@ import { skipToken, useQuery } from '@tanstack/react-query' import { getIsToken2022 } from '@cowprotocol/common-const' import { getIsNativeToken } from '@cowprotocol/common-utils' -import { getAddressKey, isSolanaChain } from '@cowprotocol/cow-sdk' +import { getAddressKey, isSolanaChain, SupportedChainId } from '@cowprotocol/cow-sdk' import { useTokensByAddressMapForChain } from '@cowprotocol/tokens' +import { PersistentStateByChain } from '@cowprotocol/types' import { useAppKitConnection } from '@reown/appkit-adapter-solana/react' -import { Connection } from '@solana/web3.js' +import { Connection, PublicKey } from '@solana/web3.js' import { useIsBlockNumberRelevant } from './useIsBlockNumberRelevant' import { PersistBalancesAndAllowancesParams } from './usePersistBalancesViaWebCalls' -import { fetchSolanaTokenBalances, SolanaTokenMint } from '../services/fetchSolanaTokenBalances' +import { findSolanaSettlementStatePda } from '../const/solanaSettlement' +import { fetchSolanaTokenAccounts, SolanaTokenAccountData, SolanaTokenMint } from '../services/fetchSolanaTokenAccounts' +import { allowancesAtom } from '../state/allowancesAtom' import { balancesAtom, BalancesState, balancesUpdateAtom } from '../state/balancesAtom' +type AllowancesByChain = PersistentStateByChain> + interface SolanaQueryConfig { enabled: boolean refetchInterval: number | false | undefined } +// The delegate authority is a deterministic PDA. Derived lazily on first fetch (not at module load) and +// cached: deriving eagerly would run Solana crypto the moment the balances barrel imports this module, +// which breaks environments that can't run it (e.g. unit tests). +let solanaDelegateAuthority: PublicKey | undefined + /** - * Solana counterpart to {@link usePersistBalancesViaWebCalls}. Loads SPL-token balances for - * `tokenAddresses` via the reown Solana adapter's `Connection` and persists them into `balancesAtom` - * in the same shape the EVM path uses, so downstream consumers stay chain-agnostic. + * Solana counterpart to {@link usePersistBalancesViaWebCalls}. A single batched multi-account read (the + * Solana analogue of an EVM multicall) loads both the SPL balance and the SPL delegation (the analogue of + * an EVM allowance) for `tokenAddresses` via the reown Solana adapter's `Connection` — the delegate rides + * along with the balance for free. Balances are persisted into `balancesAtom` and delegations into + * `allowancesAtom` in the same shapes the EVM path uses, so downstream consumers stay chain-agnostic. */ -export function usePersistSolanaBalancesViaWebCalls(params: PersistBalancesAndAllowancesParams): void { +export function usePersistSplViaMulticall(params: PersistBalancesAndAllowancesParams): void { const { account, chainId, tokenAddresses, setLoadingState, onBalancesLoaded, refreshTrigger } = params const setBalances = useSetAtom(balancesAtom) const setBalancesUpdate = useSetAtom(balancesUpdateAtom) + const setAllowances = useSetAtom(allowancesAtom) const { connection } = useAppKitConnection() @@ -47,20 +60,27 @@ export function usePersistSolanaBalancesViaWebCalls(params: PersistBalancesAndAl const { enabled, refetchInterval } = getSolanaQueryConfig(params, isSolana, connection, tokenMints.length) const queryKey = useMemo( - // `rpcEndpoint` keys the cache to the active network so a chain switch does not surface stale balances. + // `rpcEndpoint` keys the cache to the active network so a chain switch does not surface stale data. // `refreshTrigger` forces an immediate refetch (e.g. after an order is filled), mirroring the EVM `scopeKey`. - () => ['solanaTokenBalances', chainId, account, connection?.rpcEndpoint, refreshTrigger, tokenMints] as const, + () => ['solanaTokenAccounts', chainId, account, connection?.rpcEndpoint, refreshTrigger, tokenMints] as const, [chainId, account, connection?.rpcEndpoint, refreshTrigger, tokenMints], ) const { - data: balances, + data: accounts, isLoading: isBalancesLoading, error, dataUpdatedAt, } = useQuery({ queryKey, - queryFn: connection && account ? () => fetchSolanaTokenBalances(connection, account, tokenMints) : skipToken, + queryFn: + connection && account + ? () => { + solanaDelegateAuthority ??= findSolanaSettlementStatePda() + + return fetchSolanaTokenAccounts(connection, account, tokenMints, solanaDelegateAuthority) + } + : skipToken, enabled, refetchInterval: refetchInterval || undefined, refetchOnWindowFocus: false, @@ -89,51 +109,69 @@ export function usePersistSolanaBalancesViaWebCalls(params: PersistBalancesAndAl setBalances((state) => ({ ...state, error: message, isLoading: false })) }, [setBalances, error, setLoadingState, isSolana]) - // Set balances to the store + // Persist balances and delegations to their stores useEffect(() => { - if (!isSolana || !account || !balances || !isNewData) return - - const balancesState = balances.reduce((acc, { mint, balance }) => { - acc[getAddressKey(mint)] = balance - return acc - }, {}) + if (!isSolana || !account || !accounts || !isNewData) return onBalancesLoaded?.(true) - - setBalances((state) => { - return { - ...state, - chainId, - fromCache: false, - hasFirstLoad: true, - error: null, - values: { ...state.values, ...balancesState }, - ...(setLoadingState ? { isLoading: false } : {}), - } - }) + applySolanaBalances(setBalances, chainId, accounts, setLoadingState) + applySolanaAllowances(setAllowances, chainId, accounts) if (setLoadingState) { setBalancesUpdate((state) => ({ ...state, - [chainId]: { - ...state[chainId], - [getAddressKey(account)]: Date.now(), - }, + [chainId]: { ...state[chainId], [getAddressKey(account)]: Date.now() }, })) } }, [ isSolana, chainId, account, - balances, + accounts, isNewData, setBalances, + setAllowances, setLoadingState, onBalancesLoaded, setBalancesUpdate, ]) } +function applySolanaAllowances( + setAllowances: (update: (prev: AllowancesByChain) => AllowancesByChain) => void, + chainId: SupportedChainId, + accounts: SolanaTokenAccountData[], +): void { + const chainAllowances = accounts.reduce>((acc, { mint, delegatedAmount }) => { + acc[getAddressKey(mint)] = delegatedAmount + return acc + }, {}) + + setAllowances((state) => ({ ...state, [chainId]: { ...state[chainId], ...chainAllowances } })) +} + +function applySolanaBalances( + setBalances: (update: (prev: BalancesState) => BalancesState) => void, + chainId: SupportedChainId, + accounts: SolanaTokenAccountData[], + setLoadingState?: boolean, +): void { + const values = accounts.reduce((acc, { mint, balance }) => { + acc[getAddressKey(mint)] = balance + return acc + }, {}) + + setBalances((state) => ({ + ...state, + chainId, + fromCache: false, + hasFirstLoad: true, + error: null, + values: { ...state.values, ...values }, + ...(setLoadingState ? { isLoading: false } : {}), + })) +} + // Native SOL is handled elsewhere and has no ATA, so deriving one would throw — keep only SPL mints. // The list's `isToken2022` flag picks the token program; mints absent from the list default to classic // SPL, so a wrong ATA simply reads as a zero balance rather than erroring. diff --git a/libs/balances-and-allowances/src/hooks/useTokenAllowances.ts b/libs/balances-and-allowances/src/hooks/useTokenAllowances.ts index 0af0136c406..69de3617a9d 100644 --- a/libs/balances-and-allowances/src/hooks/useTokenAllowances.ts +++ b/libs/balances-and-allowances/src/hooks/useTokenAllowances.ts @@ -1,15 +1,18 @@ +import { useAtomValue } from 'jotai' import { useMemo } from 'react' import { erc20Abi } from 'viem' import { useReadContracts } from 'wagmi' -import { getAddressKey } from '@cowprotocol/cow-sdk' +import { getAddressKey, isSolanaChain } from '@cowprotocol/cow-sdk' import { useWalletInfo } from '@cowprotocol/wallet' import ms from 'ms.macro' import { useTradeSpenderAddress } from './useTradeSpenderAddress' +import { allowancesAtom } from '../state/allowancesAtom' + export type AllowancesState = Record export function useTokenAllowances(tokenAddresses: string[]): { @@ -26,9 +29,12 @@ export function useTokenAllowances(tokenAddresses: string[]): { */ const { chainId, account } = useWalletInfo() + const isSolana = isSolanaChain(chainId) const spender = useTradeSpenderAddress() + const persistedAllowancesByChain = useAtomValue(allowancesAtom) + const { data: allowances, isLoading } = useReadContracts({ contracts: tokenAddresses.map((address) => ({ abi: erc20Abi, @@ -38,7 +44,7 @@ export function useTokenAllowances(tokenAddresses: string[]): { args: [account as `0x${string}`, spender as `0x${string}`], })), query: { - enabled: !!account && !!spender && tokenAddresses.length > 0, + enabled: !isSolana && !!account && !!spender && tokenAddresses.length > 0, refetchInterval: ms`32s`, refetchOnWindowFocus: false, refetchOnReconnect: false, @@ -46,6 +52,8 @@ export function useTokenAllowances(tokenAddresses: string[]): { }) const state = useMemo(() => { + if (isSolana) return persistedAllowancesByChain[chainId] + if (!allowances?.length) return return tokenAddresses.reduce((acc, address, index) => { @@ -55,7 +63,8 @@ export function useTokenAllowances(tokenAddresses: string[]): { return acc }, {}) - }, [tokenAddresses, allowances]) + }, [isSolana, persistedAllowancesByChain, chainId, tokenAddresses, allowances]) - return useMemo(() => ({ state, isLoading }), [state, isLoading]) + // EVM loading comes from wagmi. Solana has no allowance-loading signal for now; it will be added later. + return useMemo(() => ({ state, isLoading: isSolana ? false : isLoading }), [state, isSolana, isLoading]) } diff --git a/libs/balances-and-allowances/src/services/fetchSolanaTokenAccounts.test.ts b/libs/balances-and-allowances/src/services/fetchSolanaTokenAccounts.test.ts new file mode 100644 index 00000000000..ee8504b6bca --- /dev/null +++ b/libs/balances-and-allowances/src/services/fetchSolanaTokenAccounts.test.ts @@ -0,0 +1,169 @@ +/** + * @jest-environment node + */ +import { + ACCOUNT_SIZE, + AccountLayout, + AccountState, + ASSOCIATED_TOKEN_PROGRAM_ID, + getAssociatedTokenAddressSync, + TOKEN_2022_PROGRAM_ID, + TOKEN_PROGRAM_ID, +} from '@solana/spl-token' +import { AccountInfo, Connection, Keypair, PublicKey } from '@solana/web3.js' + +import { fetchSolanaTokenAccounts } from './fetchSolanaTokenAccounts' + +const OWNER = Keypair.generate().publicKey +const CLASSIC_MINT = Keypair.generate().publicKey +const TOKEN_2022_MINT = Keypair.generate().publicKey +const AUTHORITY = Keypair.generate().publicKey +const OTHER_DELEGATE = Keypair.generate().publicKey + +function ataFor(mint: PublicKey, programId: PublicKey): PublicKey { + return getAssociatedTokenAddressSync(mint, OWNER, false, programId, ASSOCIATED_TOKEN_PROGRAM_ID) +} + +function createConnection(accounts: Map | null>): Connection { + return { + rpcEndpoint: 'mock', + getMultipleAccountsInfo: jest.fn(async (pubkeys: PublicKey[]) => + pubkeys.map((pubkey) => accounts.get(pubkey.toBase58()) ?? null), + ), + } as unknown as Connection +} + +/** + * Builds a real, decodable SPL-token account so the production `unpackAccount` runs for real — + * mocking it would hide an incorrect program being passed to it. + */ +function encodeTokenAccount( + mint: PublicKey, + amount: bigint, + programId: PublicKey, + delegate: PublicKey | null = null, + delegatedAmount = 0n, +): AccountInfo { + const data = Buffer.alloc(ACCOUNT_SIZE) + AccountLayout.encode( + { + mint, + owner: OWNER, + amount, + delegateOption: delegate ? 1 : 0, + delegate: delegate ?? PublicKey.default, + state: AccountState.Initialized, + isNativeOption: 0, + isNative: 0n, + delegatedAmount: delegate ? delegatedAmount : 0n, + closeAuthorityOption: 0, + closeAuthority: PublicKey.default, + }, + data, + ) + + return { data, owner: programId, lamports: 1, executable: false, rentEpoch: 0 } +} + +describe('fetchSolanaTokenAccounts — balances', () => { + it('reads classic and Token-2022 balances in the same request, aligned to input order', async () => { + const classicAta = ataFor(CLASSIC_MINT, TOKEN_PROGRAM_ID) + const token2022Ata = ataFor(TOKEN_2022_MINT, TOKEN_2022_PROGRAM_ID) + const connection = createConnection( + new Map | null>([ + [classicAta.toBase58(), encodeTokenAccount(CLASSIC_MINT, 500n, TOKEN_PROGRAM_ID)], + [token2022Ata.toBase58(), encodeTokenAccount(TOKEN_2022_MINT, 1234n, TOKEN_2022_PROGRAM_ID)], + ]), + ) + + const result = await fetchSolanaTokenAccounts( + connection, + OWNER.toBase58(), + [ + { mint: CLASSIC_MINT.toBase58(), isToken2022: false }, + { mint: TOKEN_2022_MINT.toBase58(), isToken2022: true }, + ], + AUTHORITY, + ) + + expect(result).toEqual([ + { mint: CLASSIC_MINT.toBase58(), balance: 500n, delegatedAmount: undefined }, + { mint: TOKEN_2022_MINT.toBase58(), balance: 1234n, delegatedAmount: undefined }, + ]) + }) + + it('returns a zero balance when the ATA does not exist', async () => { + const connection = createConnection(new Map | null>()) + + const result = await fetchSolanaTokenAccounts( + connection, + OWNER.toBase58(), + [{ mint: CLASSIC_MINT.toBase58(), isToken2022: false }], + AUTHORITY, + ) + + expect(result).toEqual([{ mint: CLASSIC_MINT.toBase58(), balance: 0n, delegatedAmount: undefined }]) + }) + + it('isolates a malformed mint so valid entries still load', async () => { + // Passes the base58 length/charset check but decodes to 33 bytes, so `new PublicKey` throws. + const BAD_MINT = 'z'.repeat(44) + const classicAta = ataFor(CLASSIC_MINT, TOKEN_PROGRAM_ID) + const connection = createConnection( + new Map | null>([ + [classicAta.toBase58(), encodeTokenAccount(CLASSIC_MINT, 500n, TOKEN_PROGRAM_ID)], + ]), + ) + + const result = await fetchSolanaTokenAccounts( + connection, + OWNER.toBase58(), + [ + { mint: BAD_MINT, isToken2022: false }, + { mint: CLASSIC_MINT.toBase58(), isToken2022: false }, + ], + AUTHORITY, + ) + + expect(result).toEqual([ + { mint: BAD_MINT, balance: 0n, delegatedAmount: undefined }, + { mint: CLASSIC_MINT.toBase58(), balance: 500n, delegatedAmount: undefined }, + ]) + }) +}) + +describe('fetchSolanaTokenAccounts — delegation', () => { + const TOKENS = [{ mint: CLASSIC_MINT.toBase58(), isToken2022: false }] + + function connectionWith(delegate: PublicKey | null, delegatedAmount: bigint): Connection { + const ata = ataFor(CLASSIC_MINT, TOKEN_PROGRAM_ID) + return createConnection( + new Map | null>([ + [ata.toBase58(), encodeTokenAccount(CLASSIC_MINT, 1000n, TOKEN_PROGRAM_ID, delegate, delegatedAmount)], + ]), + ) + } + + it('reports delegatedAmount when the delegate is the settlement authority', async () => { + const result = await fetchSolanaTokenAccounts(connectionWith(AUTHORITY, 777n), OWNER.toBase58(), TOKENS, AUTHORITY) + + expect(result).toEqual([{ mint: CLASSIC_MINT.toBase58(), balance: 1000n, delegatedAmount: 777n }]) + }) + + it('reports no delegation when the delegate is someone else', async () => { + const result = await fetchSolanaTokenAccounts( + connectionWith(OTHER_DELEGATE, 777n), + OWNER.toBase58(), + TOKENS, + AUTHORITY, + ) + + expect(result[0].delegatedAmount).toBeUndefined() + }) + + it('reports no delegation when there is no delegate', async () => { + const result = await fetchSolanaTokenAccounts(connectionWith(null, 0n), OWNER.toBase58(), TOKENS, AUTHORITY) + + expect(result[0].delegatedAmount).toBeUndefined() + }) +}) diff --git a/libs/balances-and-allowances/src/services/fetchSolanaTokenAccounts.ts b/libs/balances-and-allowances/src/services/fetchSolanaTokenAccounts.ts new file mode 100644 index 00000000000..b05f8f4554a --- /dev/null +++ b/libs/balances-and-allowances/src/services/fetchSolanaTokenAccounts.ts @@ -0,0 +1,42 @@ +import { Connection, PublicKey } from '@solana/web3.js' + +import { readSolanaTokenAccounts, SolanaTokenMint } from './readSolanaTokenAccounts' + +export type { SolanaTokenMint } from './readSolanaTokenAccounts' + +export interface SolanaTokenAccountData { + mint: string + balance: bigint + // SPL-approved amount when the account's delegate is the CoW settlement authority, else `undefined` + // (no CoW approval) — the Solana analogue of an EVM allowance. + delegatedAmount: bigint | undefined +} + +/** + * Reads the SPL balance AND delegation for `tokens` owned by `ownerAddress` in a single batched request. + * Both live on the same token account, so there is no separate delegate query — the delegation rides + * along with the balance for free. + * + * `delegatedAmount` is set only when the account's `delegate` equals `delegateAuthority` (the settlement + * state PDA). A missing account means the owner never held that token: zero balance, no delegation. + * Results stay aligned to `tokens` order. + */ +export async function fetchSolanaTokenAccounts( + connection: Connection, + ownerAddress: string, + tokens: SolanaTokenMint[], + delegateAuthority: PublicKey, +): Promise { + const accounts = await readSolanaTokenAccounts(connection, ownerAddress, tokens) + + return tokens.map(({ mint }, index) => { + const account = accounts[index] + const isCowDelegate = account?.delegate?.equals(delegateAuthority) ?? false + + return { + mint, + balance: account?.amount ?? 0n, + delegatedAmount: isCowDelegate ? account?.delegatedAmount : undefined, + } + }) +} diff --git a/libs/balances-and-allowances/src/services/fetchSolanaTokenBalances.test.ts b/libs/balances-and-allowances/src/services/fetchSolanaTokenBalances.test.ts deleted file mode 100644 index 1f928c3a543..00000000000 --- a/libs/balances-and-allowances/src/services/fetchSolanaTokenBalances.test.ts +++ /dev/null @@ -1,168 +0,0 @@ -/** - * @jest-environment node - */ -import { - ACCOUNT_SIZE, - AccountLayout, - AccountState, - ASSOCIATED_TOKEN_PROGRAM_ID, - getAssociatedTokenAddressSync, - TOKEN_2022_PROGRAM_ID, - TOKEN_PROGRAM_ID, -} from '@solana/spl-token' -import { AccountInfo, Connection, Keypair, PublicKey } from '@solana/web3.js' - -import { fetchSolanaTokenBalances } from './fetchSolanaTokenBalances' - -const OWNER = Keypair.generate().publicKey -const CLASSIC_MINT = Keypair.generate().publicKey -const TOKEN_2022_MINT = Keypair.generate().publicKey - -function ataFor(mint: PublicKey, programId: PublicKey): PublicKey { - return getAssociatedTokenAddressSync(mint, OWNER, false, programId, ASSOCIATED_TOKEN_PROGRAM_ID) -} - -function createConnection(accounts: Map | null>): Connection { - return { - rpcEndpoint: 'mock', - getMultipleAccountsInfo: jest.fn(async (pubkeys: PublicKey[]) => - pubkeys.map((pubkey) => accounts.get(pubkey.toBase58()) ?? null), - ), - } as unknown as Connection -} - -/** - * Builds a real, decodable SPL-token account so the production `unpackAccount` runs for real — - * mocking `unpackAccount` would hide an incorrect program being passed to it. - */ -function encodeTokenAccount( - mint: PublicKey, - owner: PublicKey, - amount: bigint, - programId: PublicKey, -): AccountInfo { - const data = Buffer.alloc(ACCOUNT_SIZE) - AccountLayout.encode( - { - mint, - owner, - amount, - delegateOption: 0, - delegate: PublicKey.default, - state: AccountState.Initialized, - isNativeOption: 0, - isNative: 0n, - delegatedAmount: 0n, - closeAuthorityOption: 0, - closeAuthority: PublicKey.default, - }, - data, - ) - - return { data, owner: programId, lamports: 1, executable: false, rentEpoch: 0 } -} - -describe('fetchSolanaTokenBalances', () => { - it('derives a Token-2022 ATA for mints flagged isToken2022', async () => { - const ata = ataFor(TOKEN_2022_MINT, TOKEN_2022_PROGRAM_ID) - const connection = createConnection( - new Map | null>([ - [ata.toBase58(), encodeTokenAccount(TOKEN_2022_MINT, OWNER, 1234n, TOKEN_2022_PROGRAM_ID)], - ]), - ) - - const result = await fetchSolanaTokenBalances(connection, OWNER.toBase58(), [ - { mint: TOKEN_2022_MINT.toBase58(), isToken2022: true }, - ]) - - expect(result).toEqual([{ mint: TOKEN_2022_MINT.toBase58(), balance: 1234n }]) - }) - - it('derives a classic ATA for mints not flagged isToken2022', async () => { - const ata = ataFor(CLASSIC_MINT, TOKEN_PROGRAM_ID) - const connection = createConnection( - new Map | null>([ - [ata.toBase58(), encodeTokenAccount(CLASSIC_MINT, OWNER, 500n, TOKEN_PROGRAM_ID)], - ]), - ) - - const result = await fetchSolanaTokenBalances(connection, OWNER.toBase58(), [ - { mint: CLASSIC_MINT.toBase58(), isToken2022: false }, - ]) - - expect(result).toEqual([{ mint: CLASSIC_MINT.toBase58(), balance: 500n }]) - }) - - it('resolves classic and Token-2022 mints in the same request', async () => { - const classicAta = ataFor(CLASSIC_MINT, TOKEN_PROGRAM_ID) - const token2022Ata = ataFor(TOKEN_2022_MINT, TOKEN_2022_PROGRAM_ID) - const connection = createConnection( - new Map | null>([ - [classicAta.toBase58(), encodeTokenAccount(CLASSIC_MINT, OWNER, 500n, TOKEN_PROGRAM_ID)], - [token2022Ata.toBase58(), encodeTokenAccount(TOKEN_2022_MINT, OWNER, 1234n, TOKEN_2022_PROGRAM_ID)], - ]), - ) - - const result = await fetchSolanaTokenBalances(connection, OWNER.toBase58(), [ - { mint: CLASSIC_MINT.toBase58(), isToken2022: false }, - { mint: TOKEN_2022_MINT.toBase58(), isToken2022: true }, - ]) - - expect(result).toEqual([ - { mint: CLASSIC_MINT.toBase58(), balance: 500n }, - { mint: TOKEN_2022_MINT.toBase58(), balance: 1234n }, - ]) - }) - - it('keeps balances aligned to input order when an ATA is missing', async () => { - const token2022Ata = ataFor(TOKEN_2022_MINT, TOKEN_2022_PROGRAM_ID) - // The classic mint has no ATA, so it must read as zero without shifting the Token-2022 balance onto it. - const connection = createConnection( - new Map | null>([ - [token2022Ata.toBase58(), encodeTokenAccount(TOKEN_2022_MINT, OWNER, 1234n, TOKEN_2022_PROGRAM_ID)], - ]), - ) - - const result = await fetchSolanaTokenBalances(connection, OWNER.toBase58(), [ - { mint: CLASSIC_MINT.toBase58(), isToken2022: false }, - { mint: TOKEN_2022_MINT.toBase58(), isToken2022: true }, - ]) - - expect(result).toEqual([ - { mint: CLASSIC_MINT.toBase58(), balance: 0n }, - { mint: TOKEN_2022_MINT.toBase58(), balance: 1234n }, - ]) - }) - - it('isolates a malformed mint so valid balances still load', async () => { - // Passes the token-list base58 length/charset check but decodes to 33 bytes, so `new PublicKey` - // throws. It must not prevent the valid mint's balance from loading. - const BAD_MINT = 'z'.repeat(44) - const classicAta = ataFor(CLASSIC_MINT, TOKEN_PROGRAM_ID) - const connection = createConnection( - new Map | null>([ - [classicAta.toBase58(), encodeTokenAccount(CLASSIC_MINT, OWNER, 500n, TOKEN_PROGRAM_ID)], - ]), - ) - - const result = await fetchSolanaTokenBalances(connection, OWNER.toBase58(), [ - { mint: BAD_MINT, isToken2022: false }, - { mint: CLASSIC_MINT.toBase58(), isToken2022: false }, - ]) - - expect(result).toEqual([ - { mint: BAD_MINT, balance: 0n }, - { mint: CLASSIC_MINT.toBase58(), balance: 500n }, - ]) - }) - - it('returns a zero balance when the ATA does not exist', async () => { - const connection = createConnection(new Map | null>()) - - const result = await fetchSolanaTokenBalances(connection, OWNER.toBase58(), [ - { mint: CLASSIC_MINT.toBase58(), isToken2022: false }, - ]) - - expect(result).toEqual([{ mint: CLASSIC_MINT.toBase58(), balance: 0n }]) - }) -}) diff --git a/libs/balances-and-allowances/src/services/fetchSolanaTokenBalances.ts b/libs/balances-and-allowances/src/services/readSolanaTokenAccounts.ts similarity index 61% rename from libs/balances-and-allowances/src/services/fetchSolanaTokenBalances.ts rename to libs/balances-and-allowances/src/services/readSolanaTokenAccounts.ts index 8a64b972d29..e61299ae0a7 100644 --- a/libs/balances-and-allowances/src/services/fetchSolanaTokenBalances.ts +++ b/libs/balances-and-allowances/src/services/readSolanaTokenAccounts.ts @@ -1,4 +1,5 @@ import { + type Account, ASSOCIATED_TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync, TOKEN_2022_PROGRAM_ID, @@ -14,40 +15,32 @@ export interface SolanaTokenMint { isToken2022: boolean } -interface SolanaTokenBalance { - mint: string - balance: bigint -} - // Solana's `getMultipleAccounts` RPC rejects requests for more than 100 accounts, so ATAs must be // read in batches — a single request for a full token list (hundreds of tokens) fails outright. const MAX_ACCOUNTS_PER_REQUEST = 100 /** - * Reads SPL-token balances for `tokens` owned by `ownerAddress`, supporting both the classic SPL Token - * program and Token-2022. + * Reads the owner's SPL-token accounts (ATAs) for `tokens`, aligned to input order. An entry is `null` + * when the ATA does not exist, the mint is malformed, or the account is not a valid token account. + * + * Both the balance and the delegate live on this single account, so one batched read serves both the + * balance and delegation consumers downstream — no separate per-token polling. * - * Balances live on the owner's Associated Token Account (ATA), not on the mint. The ATA address and its - * data layout both depend on the mint's token program, which we take from each token's `isToken2022` - * flag rather than an extra RPC round-trip to read the mint. ATAs are batch-read via - * `getMultipleAccountsInfo` in chunks of {@link MAX_ACCOUNTS_PER_REQUEST}. A missing account means the - * owner never held that token, which is a zero balance rather than an error. + * The ATA address and its data layout depend on the mint's token program, taken from each token's + * `isToken2022` flag rather than an extra RPC round-trip to read the mint. */ -export async function fetchSolanaTokenBalances( +export async function readSolanaTokenAccounts( connection: Connection, ownerAddress: string, tokens: SolanaTokenMint[], -): Promise { +): Promise<(Account | null)[]> { const owner = new PublicKey(ownerAddress) - // Every token defaults to a zero balance, keeping the result aligned to `tokens` order regardless - // of which ATAs resolve or exist. - const balances: SolanaTokenBalance[] = tokens.map(({ mint }) => ({ mint, balance: 0n })) + const accounts: (Account | null)[] = tokens.map(() => null) // Derive each ATA up front, isolating any mint that fails to parse. A malformed mint can pass the // token list's base58 length/charset check yet still not decode to a 32-byte public key, so - // `new PublicKey(mint)` would throw. Building the ATAs in a single `map` would let one bad mint - // reject balances for the entire list — instead we drop it and leave its zero balance in place. + // `new PublicKey(mint)` throws — drop it and leave its `null` in place instead of failing the batch. const resolvable: { index: number; ata: PublicKey; programId: PublicKey }[] = [] tokens.forEach(({ mint, isToken2022 }, index) => { const programId = isToken2022 ? TOKEN_2022_PROGRAM_ID : TOKEN_PROGRAM_ID @@ -61,7 +54,7 @@ export async function fetchSolanaTokenBalances( ) resolvable.push({ index, ata, programId }) } catch { - // Malformed mint: leave the default zero balance so the rest of the list still loads. + // Malformed mint: leave the default `null` so the rest of the list still loads. } }) @@ -76,14 +69,13 @@ export async function fetchSolanaTokenBalances( const { index, ata, programId } = resolvable[i] try { - balances[index].balance = unpackAccount(ata, info, programId).amount + accounts[index] = unpackAccount(ata, info, programId) } catch { - // Account exists but is not a valid token account (e.g., uninitialized lamport transfer). - // Leave the default zero balance. + // Account exists but is not a valid token account (e.g., uninitialized lamport transfer). Leave `null`. } }) - return balances + return accounts } async function getMultipleAccountsInfoBatched( diff --git a/libs/balances-and-allowances/src/state/allowancesAtom.ts b/libs/balances-and-allowances/src/state/allowancesAtom.ts index 58fd5889d04..0a9332016bf 100644 --- a/libs/balances-and-allowances/src/state/allowancesAtom.ts +++ b/libs/balances-and-allowances/src/state/allowancesAtom.ts @@ -1,10 +1,9 @@ -import { atomWithStorage } from 'jotai/utils' +import { atom } from 'jotai' import { erc20Abi, type Address } from 'viem' import { Connector } from 'wagmi' import { asyncAtomFamily, getPublicClientFromProvider } from '@cowprotocol/common-utils' -import { getJotaiMergerStorage } from '@cowprotocol/core' import { getAddressKey, mapSupportedNetworks, SupportedChainId, EvmChains, isEvmChain } from '@cowprotocol/cow-sdk' import { PersistentStateByChain } from '@cowprotocol/types' @@ -47,11 +46,10 @@ async function fetchAllowances( return buildAllowancesState(tokenAddresses, decodedResults) } -export const allowancesAtom = atomWithStorage>>( - 'allowancesAtom:v1', - mapSupportedNetworks({}), - getJotaiMergerStorage(), -) +// In-memory only: values are `bigint` (SPL delegations / EVM allowances), which `JSON.stringify` cannot +// serialize — persisting via `atomWithStorage` throws on write. Delegations are re-fetched each session +// by `usePersistSplViaMulticall`, so persistence is unnecessary here. +export const allowancesAtom = atom>>(mapSupportedNetworks({})) export interface TokenAllowancesFamilyParams { connector?: Connector diff --git a/libs/balances-and-allowances/src/updaters/BalancesResetUpdater.ts b/libs/balances-and-allowances/src/updaters/BalancesResetUpdater.ts index bca043f9c5e..24ca22c6f02 100644 --- a/libs/balances-and-allowances/src/updaters/BalancesResetUpdater.ts +++ b/libs/balances-and-allowances/src/updaters/BalancesResetUpdater.ts @@ -2,8 +2,9 @@ import { useSetAtom } from 'jotai' import { useEffect } from 'react' import { usePrevious } from '@cowprotocol/common-hooks' -import { mapSupportedNetworks } from '@cowprotocol/cow-sdk' +import { mapChainEnum, SupportedChainId } from '@cowprotocol/cow-sdk' +import { allowancesAtom } from '../state/allowancesAtom' import { balancesAtom, balancesCacheAtom, balancesUpdateAtom, DEFAULT_BALANCES_STATE } from '../state/balancesAtom' interface BalancesResetUpdaterProps { @@ -18,15 +19,20 @@ export function BalancesResetUpdater({ account, chainId }: BalancesResetUpdaterP const setBalances = useSetAtom(balancesAtom) const setBalancesUpdate = useSetAtom(balancesUpdateAtom) + const setAllowances = useSetAtom(allowancesAtom) // Reset states when wallet is not connected useEffect(() => { if (prevAccount && prevAccount !== account) { setBalances(DEFAULT_BALANCES_STATE) - setBalancesCache(mapSupportedNetworks({})) - setBalancesUpdate(mapSupportedNetworks({})) + setBalancesCache(mapChainEnum(SupportedChainId, {})) + setBalancesUpdate(mapChainEnum(SupportedChainId, {})) + // Allowances (e.g. Solana SPL delegations) are keyed by chain+token but not by account, so a + // same-chain wallet switch would otherwise surface the previous account's approvals until the new + // fetch lands. Clear them alongside balances. + setAllowances(mapChainEnum(SupportedChainId, {})) } - }, [chainId, account, prevAccount, setBalances, setBalancesCache, setBalancesUpdate]) + }, [chainId, account, prevAccount, setBalances, setBalancesCache, setBalancesUpdate, setAllowances]) /** * Reset balances and allowances when chainId is changed. diff --git a/libs/common-const/package.json b/libs/common-const/package.json index e2f2bd165db..124fe5dc63f 100644 --- a/libs/common-const/package.json +++ b/libs/common-const/package.json @@ -24,7 +24,7 @@ } }, "dependencies": { - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "viem": "2.48.8", "@cowprotocol/types": "workspace:*", "@lingui/core": "5.5.1", diff --git a/libs/common-hooks/package.json b/libs/common-hooks/package.json index 927619bd82b..3a52fd2787a 100644 --- a/libs/common-hooks/package.json +++ b/libs/common-hooks/package.json @@ -24,7 +24,7 @@ } }, "dependencies": { - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@cowprotocol/common-const": "workspace:*", "@cowprotocol/common-utils": "workspace:*", "@cowprotocol/types": "workspace:*", diff --git a/libs/common-utils/package.json b/libs/common-utils/package.json index 5c6e8555376..0c8c5e52390 100644 --- a/libs/common-utils/package.json +++ b/libs/common-utils/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@cowprotocol/common-const": "workspace:*", - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@cowprotocol/currency": "workspace:*", "@cowprotocol/types": "workspace:*", "@lingui/core": "5.5.1", diff --git a/libs/core/package.json b/libs/core/package.json index 4439794e16c..110802000b2 100644 --- a/libs/core/package.json +++ b/libs/core/package.json @@ -24,7 +24,7 @@ } }, "dependencies": { - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@cowprotocol/cms": "https://registry.npmjs.org/@cowprotocol/cms/-/cms-0.11.0.tgz", "@cowprotocol/common-const": "workspace:*", "@cowprotocol/common-utils": "workspace:*", diff --git a/libs/currency/package.json b/libs/currency/package.json index d93ab84f665..93b2cacd02b 100644 --- a/libs/currency/package.json +++ b/libs/currency/package.json @@ -24,7 +24,7 @@ } }, "dependencies": { - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "jsbi": "3.2.5" } } diff --git a/libs/ens/package.json b/libs/ens/package.json index b9a14b10dc2..8c6b6212092 100644 --- a/libs/ens/package.json +++ b/libs/ens/package.json @@ -24,7 +24,7 @@ } }, "dependencies": { - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@cowprotocol/common-const": "workspace:*", "@cowprotocol/common-utils": "workspace:*", "@cowprotocol/cowswap-abis": "workspace:*", diff --git a/libs/events/package.json b/libs/events/package.json index de77a4f104e..37515c1d4ab 100644 --- a/libs/events/package.json +++ b/libs/events/package.json @@ -24,8 +24,8 @@ } }, "dependencies": { - "@cowprotocol/cow-sdk": "9.2.5", - "@cowprotocol/sdk-bridging": "4.4.1", + "@cowprotocol/cow-sdk": "9.2.6", + "@cowprotocol/sdk-bridging": "4.4.2", "@cowprotocol/types": "workspace:*" } } diff --git a/libs/multicall/package.json b/libs/multicall/package.json index c51ec1a7bb3..e24362ba424 100644 --- a/libs/multicall/package.json +++ b/libs/multicall/package.json @@ -24,7 +24,7 @@ } }, "dependencies": { - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@cowprotocol/common-const": "workspace:*", "@cowprotocol/cowswap-abis": "workspace:*", "@cowprotocol/types": "workspace:*", diff --git a/libs/permit-utils/package.json b/libs/permit-utils/package.json index 45f0c03d1b9..6693ac6eb71 100644 --- a/libs/permit-utils/package.json +++ b/libs/permit-utils/package.json @@ -23,7 +23,7 @@ } }, "dependencies": { - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@1inch/permit-signed-approvals-utils": "1.5.2", "@cowprotocol/hook-dapp-lib": "workspace:*", "ms.macro": "2.0.0", diff --git a/libs/tokens/package.json b/libs/tokens/package.json index 5ff8f2b1642..d101b9b36a4 100644 --- a/libs/tokens/package.json +++ b/libs/tokens/package.json @@ -24,7 +24,7 @@ } }, "dependencies": { - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@cowprotocol/common-const": "workspace:*", "@cowprotocol/common-hooks": "workspace:*", "@cowprotocol/common-utils": "workspace:*", diff --git a/libs/types/package.json b/libs/types/package.json index 9ff39c46612..e47d3ed187d 100644 --- a/libs/types/package.json +++ b/libs/types/package.json @@ -24,8 +24,8 @@ } }, "dependencies": { - "@cowprotocol/cow-sdk": "9.2.5", - "@cowprotocol/sdk-bridging": "4.4.1", + "@cowprotocol/cow-sdk": "9.2.6", + "@cowprotocol/sdk-bridging": "4.4.2", "@cowprotocol/currency": "workspace:*", "eventemitter3": "4.0.7" } diff --git a/libs/ui/package.json b/libs/ui/package.json index de1eddf0e2f..883d50f04c1 100644 --- a/libs/ui/package.json +++ b/libs/ui/package.json @@ -31,7 +31,7 @@ "@cowprotocol/common-hooks": "workspace:*", "@cowprotocol/common-utils": "workspace:*", "@cowprotocol/core": "workspace:*", - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@cowprotocol/currency": "workspace:*", "@cowprotocol/types": "workspace:*", "@cowprotocol/ui-utils": "workspace:*", diff --git a/libs/wallet/package.json b/libs/wallet/package.json index d209e849e76..dfb46a62181 100644 --- a/libs/wallet/package.json +++ b/libs/wallet/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@coinbase/wallet-sdk": "4.3.7", - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@reown/appkit": "1.8.19", "@reown/appkit-adapter-solana": "1.8.19", "@reown/appkit-adapter-wagmi": "1.8.19", diff --git a/libs/widget-lib/package.json b/libs/widget-lib/package.json index 08abba65b1d..381ad3bc490 100644 --- a/libs/widget-lib/package.json +++ b/libs/widget-lib/package.json @@ -24,7 +24,7 @@ } }, "dependencies": { - "@cowprotocol/cow-sdk": "9.2.5", + "@cowprotocol/cow-sdk": "9.2.6", "@cowprotocol/events": "workspace:*", "@cowprotocol/iframe-transport": "workspace:*" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 42d3e997d92..88f52f551f5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -567,8 +567,8 @@ importers: specifier: https://registry.npmjs.org/@cowprotocol/cow-runner-game/-/cow-runner-game-0.2.9.tgz version: 0.2.9(react-dom@19.1.2(react@19.1.2))(react@19.1.2) '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/cowswap-abis': specifier: workspace:* version: link:../../libs/abis @@ -594,23 +594,23 @@ importers: specifier: workspace:* version: link:../../libs/permit-utils '@cowprotocol/sdk-bridging': - specifier: 4.4.1 - version: 4.4.1(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 4.4.2 + version: 4.4.2(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/sdk-contracts-ts': - specifier: 3.3.2 - version: 3.3.2 + specifier: 3.3.3 + version: 3.3.3 '@cowprotocol/sdk-cow-shed': - specifier: 0.4.4 - version: 0.4.4 + specifier: 0.4.5 + version: 0.4.5 '@cowprotocol/sdk-order-book': - specifier: 4.0.1 - version: 4.0.1(encoding@0.1.13) + specifier: 4.0.2 + version: 4.0.2(encoding@0.1.13) '@cowprotocol/sdk-trading': - specifier: 2.2.5 - version: 2.2.5(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 2.2.6 + version: 2.2.6(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/sdk-viem-adapter': - specifier: 0.3.25 - version: 0.3.25(viem@2.48.8(bufferutil@4.0.8)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)) + specifier: 0.3.26 + version: 0.3.26(viem@2.48.8(bufferutil@4.0.8)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)) '@cowprotocol/snackbars': specifier: workspace:* version: link:../../libs/snackbars @@ -950,23 +950,23 @@ importers: specifier: workspace:* version: link:../../libs/core '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/hook-dapp-lib': specifier: workspace:* version: link:../../libs/hook-dapp-lib '@cowprotocol/sdk-bridging': - specifier: 4.4.1 - version: 4.4.1(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 4.4.2 + version: 4.4.2(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/sdk-contracts-ts': - specifier: 3.3.2 - version: 3.3.2 + specifier: 3.3.3 + version: 3.3.3 '@cowprotocol/sdk-subgraph': - specifier: 1.2.0 - version: 1.2.0(encoding@0.1.13) + specifier: 1.2.1 + version: 1.2.1(encoding@0.1.13) '@cowprotocol/sdk-viem-adapter': - specifier: 0.3.25 - version: 0.3.25(viem@2.48.8(bufferutil@4.0.8)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)) + specifier: 0.3.26 + version: 0.3.26(viem@2.48.8(bufferutil@4.0.8)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76)) '@cowprotocol/types': specifier: workspace:* version: link:../../libs/types @@ -1152,14 +1152,14 @@ importers: specifier: workspace:* version: link:../../libs/common-const '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/sdk-composable': - specifier: 1.2.2 - version: 1.2.2(encoding@0.1.13) + specifier: 1.2.3 + version: 1.2.3(encoding@0.1.13) '@cowprotocol/sdk-viem-adapter': - specifier: 0.3.25 - version: 0.3.25(viem@2.48.8(bufferutil@4.0.8)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)) + specifier: 0.3.26 + version: 0.3.26(viem@2.48.8(bufferutil@4.0.8)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)) '@cowprotocol/wallet': specifier: workspace:* version: link:../../libs/wallet @@ -1264,8 +1264,8 @@ importers: specifier: workspace:* version: link:../../libs/common-utils '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/events': specifier: workspace:* version: link:../../libs/events @@ -1375,8 +1375,8 @@ importers: specifier: workspace:* version: link:../common-utils '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/currency': specifier: workspace:* version: link:../currency @@ -1424,8 +1424,8 @@ importers: specifier: workspace:* version: link:../core '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/cowswap-abis': specifier: workspace:* version: link:../abis @@ -1491,8 +1491,8 @@ importers: libs/common-const: dependencies: '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/currency': specifier: workspace:* version: link:../currency @@ -1525,8 +1525,8 @@ importers: specifier: workspace:* version: link:../common-utils '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/types': specifier: workspace:* version: link:../types @@ -1589,8 +1589,8 @@ importers: specifier: workspace:* version: link:../common-const '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/currency': specifier: workspace:* version: link:../currency @@ -1680,8 +1680,8 @@ importers: specifier: workspace:* version: link:../common-utils '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@safe-global/api-kit': specifier: 4.2.0 version: 4.2.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76) @@ -1714,8 +1714,8 @@ importers: libs/currency: dependencies: '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) jsbi: specifier: 3.2.5 version: 3.2.5 @@ -1735,8 +1735,8 @@ importers: specifier: workspace:* version: link:../common-utils '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/cowswap-abis': specifier: workspace:* version: link:../abis @@ -1763,11 +1763,11 @@ importers: libs/events: dependencies: '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/sdk-bridging': - specifier: 4.4.1 - version: 4.4.1(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 4.4.2 + version: 4.4.2(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/types': specifier: workspace:* version: link:../types @@ -1793,8 +1793,8 @@ importers: specifier: workspace:* version: link:../common-const '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/cowswap-abis': specifier: workspace:* version: link:../abis @@ -1827,8 +1827,8 @@ importers: specifier: 1.5.2 version: 1.5.2(bufferutil@4.0.8)(utf-8-validate@6.0.6) '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/hook-dapp-lib': specifier: workspace:* version: link:../hook-dapp-lib @@ -1898,8 +1898,8 @@ importers: specifier: workspace:* version: link:../core '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/currency': specifier: workspace:* version: link:../currency @@ -1968,14 +1968,14 @@ importers: libs/types: dependencies: '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/currency': specifier: workspace:* version: link:../currency '@cowprotocol/sdk-bridging': - specifier: 4.4.1 - version: 4.4.1(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 4.4.2 + version: 4.4.2(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) eventemitter3: specifier: 4.0.7 version: 4.0.7 @@ -2004,8 +2004,8 @@ importers: specifier: workspace:* version: link:../core '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/currency': specifier: workspace:* version: link:../currency @@ -2116,8 +2116,8 @@ importers: specifier: workspace:* version: link:../core '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/currency': specifier: workspace:* version: link:../currency @@ -2241,8 +2241,8 @@ importers: libs/widget-lib: dependencies: '@cowprotocol/cow-sdk': - specifier: 9.2.5 - version: 9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + specifier: 9.2.6 + version: 9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) '@cowprotocol/events': specifier: workspace:* version: link:../events @@ -3252,8 +3252,8 @@ packages: multiformats: optional: true - '@cowprotocol/cow-sdk@9.2.5': - resolution: {integrity: sha512-dmFK5vKJdALtWh7mOcelaCrQyLVdQSCK3tofTyZUl8cNuRE2bLTWR/Xf77GvV5LoIWouSQvufsIPMdbKiADGHg==} + '@cowprotocol/cow-sdk@9.2.6': + resolution: {integrity: sha512-OFAd5lTJ5MyTlUmUtOI4kVJTox2Kgsd4TPyzWbRpbJ6pq/NVpiWOYo8d2JcTLZf+N9hI5HvyJn94k5YFzpAl5g==} peerDependencies: '@openzeppelin/merkle-tree': ^1.x cross-fetch: ^3.x @@ -3294,8 +3294,8 @@ packages: cross-fetch: ^3.x multiformats: ^9.x - '@cowprotocol/sdk-app-data@5.3.2': - resolution: {integrity: sha512-3pyj9Nk6HuhvM1WJZG36LilmdPsnVuVGDS5IA99eN1dsfZLR0oU+/3iZJPVJaMhCQflW9Gqd5ELZSvLR2T80Mg==} + '@cowprotocol/sdk-app-data@5.3.3': + resolution: {integrity: sha512-ZqykzUt09z6jXjLTsqbJ7JUZDVZ3POLjhPhzkkbogAcuEv8vh23oN60MEhDIkLHm65gHbFNN0OR1QbQkKrpNPg==} peerDependencies: ajv: ^8.x cross-fetch: ^3.x @@ -3304,8 +3304,8 @@ packages: '@cowprotocol/sdk-bridging@4.2.2': resolution: {integrity: sha512-WCrFxNMwNzExQPTF1o/GuMl3D4MrWIildWip7o2cP66FlbUfSSh3n5c3xSSxmg065woFOlsM+dme/PMGcSU29g==} - '@cowprotocol/sdk-bridging@4.4.1': - resolution: {integrity: sha512-crwa2tpWrk5vmIsKm8tAIMpyRTiUkYTwCov8OPy+gfZbNoYqPbwG+s8NthlK+VddiCFYxZhYvrNshpe8c9UNZQ==} + '@cowprotocol/sdk-bridging@4.4.2': + resolution: {integrity: sha512-E3Lot76bJ1+b/4SP4Vsos2WNPB6VbRZRKxaTtjNcHj8J5aOxlZrRM4LyrzWUCgpKRUYawcU29EPl9330WseurA==} '@cowprotocol/sdk-common@0.10.1': resolution: {integrity: sha512-2EYpgXDwD0F5KR9W+jT2Vr/vzaJ8meAvEPm4fGjJUVr2otrUkhUG7ayx68L1AgKZWYzDtNrlM/+1EeyEjjEaWg==} @@ -3313,8 +3313,11 @@ packages: '@cowprotocol/sdk-common@0.12.0': resolution: {integrity: sha512-1QzVg2qflqeZqOilRwu8YAzmJGzLCtO5BIFWPiAjW03+Em6ndoduYgAHKRWTlsw1z2M5xFHo7ufAzd++/z6vIg==} - '@cowprotocol/sdk-composable@1.2.2': - resolution: {integrity: sha512-CC2HyI6aIB92NkaDP3yNIwqz9flnEOjFb1LvLREDXQOYiDII1ajChxDYkiNiVZVBBH+h397CtEXyLYbGnNWpfQ==} + '@cowprotocol/sdk-common@0.12.1': + resolution: {integrity: sha512-eh8o2b8iLHNRnS7ATRDNOkISp67KHV7JDzYn1qd/reCVPLlnN/lRDnNomT+A8uPU1aYV2eNkCkbLyTkkQ5bT4g==} + + '@cowprotocol/sdk-composable@1.2.3': + resolution: {integrity: sha512-SW9MK6VBkQv4FbL23JGbLASJJeQYBlRv904yvedDEdkzctE6hZLiZKAWY8X+eb5IX5oU3BfG4/wGRQMIbiNpSQ==} '@cowprotocol/sdk-config@1.2.0': resolution: {integrity: sha512-upZ2OPycc+rikwAnfNt58qBMlYb+7zpFPzG6zT/sfE50FS1f2ba4SMtw37HVq+v0e9R32o/rWZFcDZT5Ty5yyQ==} @@ -3322,20 +3325,23 @@ packages: '@cowprotocol/sdk-config@2.3.1': resolution: {integrity: sha512-MSdUbGLJGWjM+7s7j8VoHdpUIIe3FL1xNoyPK2oNnDD2DbzzXpqJkbGsYHAjmIgOrCqP2HNM6yTieLoI0eEMDQ==} + '@cowprotocol/sdk-config@2.4.0': + resolution: {integrity: sha512-NMJOqq3LfIjlFFUHd4zbx3Rc3YJl/oCklEaAxw10VHVDNMFMqcdK3tR6W9CPTILR8zAv5DDy1C2cPErXpcrzkQ==} + '@cowprotocol/sdk-contracts-ts@2.5.0': resolution: {integrity: sha512-UZSmqUO+XPwxQ/w75nwkLBK/sjUHdYgWBPhA4EV5x8y5XdBm5Dk8UqrLUemgAAVKwuXaWcoqhkoJWKrV2/gqGQ==} '@cowprotocol/sdk-contracts-ts@3.2.1': resolution: {integrity: sha512-o4AqK2pVLPY59L0jQ7ZDGeOxA/XgLGzdlkbr3vR61WObeF/jMuSvhLQjJvDI50cyA44oyv1YPEFRDL0htJza4g==} - '@cowprotocol/sdk-contracts-ts@3.3.2': - resolution: {integrity: sha512-eOnfXEKgvgy9xEuiUFRxpmf+blXSXnOpCXlXZjbn6MgIX2U2dcfAjAbYtjsgtja+LyYZBvv+ZWA4FtxqvTOlfw==} + '@cowprotocol/sdk-contracts-ts@3.3.3': + resolution: {integrity: sha512-ejxVq2TJaI5TI6EAJ6kuyjh/3Feob9wHXI+3UpOZ7MJFfX3wDdlb1LTqreC99aKHhjwtBhhYcNm7dYhoLoB1MA==} '@cowprotocol/sdk-cow-shed@0.4.1': resolution: {integrity: sha512-BZuTczqctRhClJ4kGgjM4RQteKAyrjBupwW+CV2rqY7BgXkk8vOyafwYNL+QD4VLwttrgh7yI7TCdSGqfffT/Q==} - '@cowprotocol/sdk-cow-shed@0.4.4': - resolution: {integrity: sha512-PLOpfArtwJT6D25yayXR+UQRVgtHzm/tO7p1toeYhy4xwAYj4kVn7kadzMVK3/JddXJSXJt8J3eAJF4b2BSEjw==} + '@cowprotocol/sdk-cow-shed@0.4.5': + resolution: {integrity: sha512-Ps9Ie/B2quQKa2FWl5ZygjPci01V7vWonLkRXY8jFVo4tRn+wq43LSNnsXzJx/Pl4a9hIDuHUtd8OiAJEODKHQ==} '@cowprotocol/sdk-order-book@2.1.0': resolution: {integrity: sha512-mbWNDV2hRnd9wXT7n5/HOw8RufprusLVOW+Du/u/3syLApDaPUjtUvqTzEg3n3qxeqccAz99OeCW2i8BojUL9A==} @@ -3343,17 +3349,20 @@ packages: '@cowprotocol/sdk-order-book@4.0.1': resolution: {integrity: sha512-sitySiCsPCPGiunMJYplqZ9nvsj7RjpknT0nmg7uKaBwP5Crk208TOHRMCgQlDPmWjieyVcfCvkerVady3QmBQ==} + '@cowprotocol/sdk-order-book@4.0.2': + resolution: {integrity: sha512-IuR6LARLtIrfRNkEqgPRkK5/1HRpR3+YktbkfqrH8B3Bi2YzMQxRVxu+N8KtEdC5fbHvkLixKKDDwN2gKAI3bA==} + '@cowprotocol/sdk-order-signing@0.3.0': resolution: {integrity: sha512-7+SVwsxW7tMipXhu+Se1pzvKm9XfSvHMNZbF28t0VCKigA39bUY9n5LZ6KLF9GTejswK6Rn/BKo6f7sl0RjKFw==} '@cowprotocol/sdk-order-signing@1.1.2': resolution: {integrity: sha512-mhmEOIv6Z8eq16DzkV7B0ylgMSNDRG8Mc5iP48ABwH/jQJ9n5a9ktcUBi1wsxmyS05BHctB6SinLXxB0eRoA4Q==} - '@cowprotocol/sdk-order-signing@1.1.5': - resolution: {integrity: sha512-pgUJUzKFbGJqB57oahYjXk9tRyTM9MJ2Q2u77cBLrIzVjyy1wAB6S2To+hx9Q8LmOw0ZVlavM0jW6JRvjVinrw==} + '@cowprotocol/sdk-order-signing@1.1.6': + resolution: {integrity: sha512-PyHxKuuuSk9lPRfymTydPGXDoWZEzwzgSgZIenShnPcQDyqyanxroUwV98Vv/zklm4Ah6KxUIZVr/lVmlRg4Hw==} - '@cowprotocol/sdk-subgraph@1.2.0': - resolution: {integrity: sha512-kGotBPkAOxQPqpmuq9+rJKymeXY9aiIqdYuIC2trBd5iMj60g53bD1VFufEHDNzw4oWKRUBmhNyTwfzNYG0SPQ==} + '@cowprotocol/sdk-subgraph@1.2.1': + resolution: {integrity: sha512-CVx6HPzZYBYA3Ylx22hGzxSvohl7vkv8mH05zTXAITv91rsmXpZ/RqIB4wuq0GFu76v9k6GnclvHWCKR9Gvo8w==} '@cowprotocol/sdk-trading@1.3.0': resolution: {integrity: sha512-xzBwRWCSTPoKDyc2DjgjMhvE2vUMkSkag3hGNTLDb8smJD0zTVhk0oruEQiX7T0MrgGgwgenxeF4ZpywtWhAZg==} @@ -3361,19 +3370,19 @@ packages: '@cowprotocol/sdk-trading@2.2.2': resolution: {integrity: sha512-QXAJAXuSJH/lyNbD4G7zb4S1gsz7mVWEBJ0dBZ00Z6qRrTXspyjJexrz+MVqj7aNp7Nyc6wDb9HhLZNsytdYzA==} - '@cowprotocol/sdk-trading@2.2.5': - resolution: {integrity: sha512-IhL66LUNdU8wwMqc84zWhD7XErFxyqArhAmqDPYzPf7nvJk6CHCk4LHWnc/7KLdCIU9oHe8AgKjJ1mJfDG7iEg==} + '@cowprotocol/sdk-trading@2.2.6': + resolution: {integrity: sha512-8B//hK6zaRend2h3X4wZnSM1mfhft3mL8fh7nHX9VYyYgBE0u9URsSJXQ8WsL9SYOFlcQxZU/d9AylUeIOcvtw==} - '@cowprotocol/sdk-viem-adapter@0.3.25': - resolution: {integrity: sha512-Qa3jQ35ZpwrR+dodZ5D1CZ/WwRBLRSqvssW7Fuqji2/41EAW17vPdGcB04YeRo1A+TRywq2Xb/+L8YHJI18H0w==} + '@cowprotocol/sdk-viem-adapter@0.3.26': + resolution: {integrity: sha512-pLyGV2YUX3tDonEEScV3Bmt59hLm9ouMpk1SFuEztRrBXp/C/V6hjMsVPr9Q9jgGKtF/lG487QaSAJ29/S2P7g==} peerDependencies: viem: 2.48.8 '@cowprotocol/sdk-weiroll@0.2.0': resolution: {integrity: sha512-TI7U8vVa7RxLtMBkvyj6q5gskB4BTUww2uvn1/ucf7VTK+AJAomgWVXfT/JGNBJeAtaII2PSY4u4Ep4iIc1KhA==} - '@cowprotocol/sdk-weiroll@0.2.1': - resolution: {integrity: sha512-8KNsKYSKBlCPGS5HbU3hJsZyM1B/1cGpVpPxTOo3kjEdK1CTxh2sEYkHJXTJgpGCxu4fmVy3FWKKvjxS6BcCHw==} + '@cowprotocol/sdk-weiroll@0.2.2': + resolution: {integrity: sha512-zsU/LM3PR/fQqsg3y6wY3mu1vLlB6+TSqWOdsCihT05bhGI+a7L8ZgCqkRRgiWksuqOog4IS6dsVaikNObmYpw==} '@cowprotocol/types@1.2.0': resolution: {integrity: sha512-K/jOyLtffgEFs52hRKX7tyDHtIA3asnsB9So6lINCPfNetr1GhM818+kf+f3sPtOHWsBpL3pTkjJphzDVCQntQ==} @@ -5651,17 +5660,17 @@ packages: '@protobufjs/codegen@2.0.5': resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} - '@protobufjs/eventemitter@1.1.1': - resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} - '@protobufjs/fetch@1.1.1': - resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} '@protobufjs/float@1.0.2': resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} - '@protobufjs/inquire@1.1.2': - resolution: {integrity: sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==} + '@protobufjs/inquire@1.1.1': + resolution: {integrity: sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==} '@protobufjs/path@1.1.2': resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} @@ -5669,8 +5678,8 @@ packages: '@protobufjs/pool@1.1.0': resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} - '@protobufjs/utf8@1.1.2': - resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} + '@protobufjs/utf8@1.1.1': + resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==} '@radix-ui/number@1.0.0': resolution: {integrity: sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA==} @@ -19173,15 +19182,15 @@ snapshots: - encoding - supports-color - '@cowprotocol/cow-sdk@9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': + '@cowprotocol/cow-sdk@9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': dependencies: - '@cowprotocol/sdk-app-data': 5.3.2(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) - '@cowprotocol/sdk-common': 0.12.0 - '@cowprotocol/sdk-config': 2.3.1 - '@cowprotocol/sdk-contracts-ts': 3.3.2 - '@cowprotocol/sdk-order-book': 4.0.1(encoding@0.1.13) - '@cowprotocol/sdk-order-signing': 1.1.5(encoding@0.1.13) - '@cowprotocol/sdk-trading': 2.2.5(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + '@cowprotocol/sdk-app-data': 5.3.3(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + '@cowprotocol/sdk-common': 0.12.1 + '@cowprotocol/sdk-config': 2.4.0 + '@cowprotocol/sdk-contracts-ts': 3.3.3 + '@cowprotocol/sdk-order-book': 4.0.2(encoding@0.1.13) + '@cowprotocol/sdk-order-signing': 1.1.6(encoding@0.1.13) + '@cowprotocol/sdk-trading': 2.2.6(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) cross-fetch: 4.0.0(encoding@0.1.13) optionalDependencies: '@openzeppelin/merkle-tree': 1.0.8 @@ -19191,15 +19200,15 @@ snapshots: - encoding - supports-color - '@cowprotocol/cow-sdk@9.2.5(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': + '@cowprotocol/cow-sdk@9.2.6(@openzeppelin/merkle-tree@1.0.8)(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': dependencies: - '@cowprotocol/sdk-app-data': 5.3.2(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) - '@cowprotocol/sdk-common': 0.12.0 - '@cowprotocol/sdk-config': 2.3.1 - '@cowprotocol/sdk-contracts-ts': 3.3.2 - '@cowprotocol/sdk-order-book': 4.0.1(encoding@0.1.13) - '@cowprotocol/sdk-order-signing': 1.1.5(encoding@0.1.13) - '@cowprotocol/sdk-trading': 2.2.5(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + '@cowprotocol/sdk-app-data': 5.3.3(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + '@cowprotocol/sdk-common': 0.12.1 + '@cowprotocol/sdk-config': 2.4.0 + '@cowprotocol/sdk-contracts-ts': 3.3.3 + '@cowprotocol/sdk-order-book': 4.0.2(encoding@0.1.13) + '@cowprotocol/sdk-order-signing': 1.1.6(encoding@0.1.13) + '@cowprotocol/sdk-trading': 2.2.6(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) cross-fetch: 4.0.0(encoding@0.1.13) optionalDependencies: '@openzeppelin/merkle-tree': 1.0.8 @@ -19275,9 +19284,9 @@ snapshots: - encoding - supports-color - '@cowprotocol/sdk-app-data@5.3.2(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': + '@cowprotocol/sdk-app-data@5.3.3(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': dependencies: - '@cowprotocol/sdk-common': 0.12.0 + '@cowprotocol/sdk-common': 0.12.1 ajv: 6.12.6 cross-fetch: 4.0.0(encoding@0.1.13) ipfs-unixfs-importer: 16.1.5(encoding@0.1.13) @@ -19287,9 +19296,9 @@ snapshots: - encoding - supports-color - '@cowprotocol/sdk-app-data@5.3.2(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': + '@cowprotocol/sdk-app-data@5.3.3(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': dependencies: - '@cowprotocol/sdk-common': 0.12.0 + '@cowprotocol/sdk-common': 0.12.1 ajv: 8.17.1 cross-fetch: 4.0.0(encoding@0.1.13) ipfs-unixfs-importer: 16.1.5(encoding@0.1.13) @@ -19319,16 +19328,16 @@ snapshots: - multiformats - supports-color - '@cowprotocol/sdk-bridging@4.4.1(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': + '@cowprotocol/sdk-bridging@4.4.2(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': dependencies: - '@cowprotocol/sdk-app-data': 5.3.2(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) - '@cowprotocol/sdk-common': 0.12.0 - '@cowprotocol/sdk-config': 2.3.1 - '@cowprotocol/sdk-contracts-ts': 3.3.2 - '@cowprotocol/sdk-cow-shed': 0.4.4 - '@cowprotocol/sdk-order-book': 4.0.1(encoding@0.1.13) - '@cowprotocol/sdk-trading': 2.2.5(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) - '@cowprotocol/sdk-weiroll': 0.2.1 + '@cowprotocol/sdk-app-data': 5.3.3(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + '@cowprotocol/sdk-common': 0.12.1 + '@cowprotocol/sdk-config': 2.4.0 + '@cowprotocol/sdk-contracts-ts': 3.3.3 + '@cowprotocol/sdk-cow-shed': 0.4.5 + '@cowprotocol/sdk-order-book': 4.0.2(encoding@0.1.13) + '@cowprotocol/sdk-trading': 2.2.6(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + '@cowprotocol/sdk-weiroll': 0.2.2 '@defuse-protocol/one-click-sdk-typescript': 0.1.1-0.2 json-stable-stringify: 1.3.0 transitivePeerDependencies: @@ -19347,13 +19356,17 @@ snapshots: dependencies: '@cowprotocol/sdk-config': 2.3.1 - '@cowprotocol/sdk-composable@1.2.2(encoding@0.1.13)': + '@cowprotocol/sdk-common@0.12.1': dependencies: - '@cowprotocol/sdk-common': 0.12.0 - '@cowprotocol/sdk-config': 2.3.1 - '@cowprotocol/sdk-contracts-ts': 3.3.2 - '@cowprotocol/sdk-order-book': 4.0.1(encoding@0.1.13) - '@cowprotocol/sdk-order-signing': 1.1.5(encoding@0.1.13) + '@cowprotocol/sdk-config': 2.4.0 + + '@cowprotocol/sdk-composable@1.2.3(encoding@0.1.13)': + dependencies: + '@cowprotocol/sdk-common': 0.12.1 + '@cowprotocol/sdk-config': 2.4.0 + '@cowprotocol/sdk-contracts-ts': 3.3.3 + '@cowprotocol/sdk-order-book': 4.0.2(encoding@0.1.13) + '@cowprotocol/sdk-order-signing': 1.1.6(encoding@0.1.13) '@openzeppelin/merkle-tree': 1.0.8 transitivePeerDependencies: - encoding @@ -19369,6 +19382,11 @@ snapshots: exponential-backoff: 3.1.3 limiter: 2.1.0 + '@cowprotocol/sdk-config@2.4.0': + dependencies: + exponential-backoff: 3.1.3 + limiter: 2.1.0 + '@cowprotocol/sdk-contracts-ts@2.5.0': dependencies: '@cowprotocol/sdk-common': 0.10.1 @@ -19379,10 +19397,10 @@ snapshots: '@cowprotocol/sdk-common': 0.12.0 '@cowprotocol/sdk-config': 2.3.1 - '@cowprotocol/sdk-contracts-ts@3.3.2': + '@cowprotocol/sdk-contracts-ts@3.3.3': dependencies: - '@cowprotocol/sdk-common': 0.12.0 - '@cowprotocol/sdk-config': 2.3.1 + '@cowprotocol/sdk-common': 0.12.1 + '@cowprotocol/sdk-config': 2.4.0 '@cowprotocol/sdk-cow-shed@0.4.1': dependencies: @@ -19390,11 +19408,11 @@ snapshots: '@cowprotocol/sdk-config': 2.3.1 '@cowprotocol/sdk-contracts-ts': 3.2.1 - '@cowprotocol/sdk-cow-shed@0.4.4': + '@cowprotocol/sdk-cow-shed@0.4.5': dependencies: - '@cowprotocol/sdk-common': 0.12.0 - '@cowprotocol/sdk-config': 2.3.1 - '@cowprotocol/sdk-contracts-ts': 3.3.2 + '@cowprotocol/sdk-common': 0.12.1 + '@cowprotocol/sdk-config': 2.4.0 + '@cowprotocol/sdk-contracts-ts': 3.3.3 '@cowprotocol/sdk-order-book@2.1.0(encoding@0.1.13)': dependencies: @@ -19416,6 +19434,16 @@ snapshots: transitivePeerDependencies: - encoding + '@cowprotocol/sdk-order-book@4.0.2(encoding@0.1.13)': + dependencies: + '@cowprotocol/sdk-common': 0.12.1 + '@cowprotocol/sdk-config': 2.4.0 + cross-fetch: 3.2.0(encoding@0.1.13) + exponential-backoff: 3.1.3 + limiter: 3.0.0 + transitivePeerDependencies: + - encoding + '@cowprotocol/sdk-order-signing@0.3.0(encoding@0.1.13)': dependencies: '@cowprotocol/sdk-common': 0.10.1 @@ -19434,19 +19462,19 @@ snapshots: transitivePeerDependencies: - encoding - '@cowprotocol/sdk-order-signing@1.1.5(encoding@0.1.13)': + '@cowprotocol/sdk-order-signing@1.1.6(encoding@0.1.13)': dependencies: - '@cowprotocol/sdk-common': 0.12.0 - '@cowprotocol/sdk-config': 2.3.1 - '@cowprotocol/sdk-contracts-ts': 3.3.2 - '@cowprotocol/sdk-order-book': 4.0.1(encoding@0.1.13) + '@cowprotocol/sdk-common': 0.12.1 + '@cowprotocol/sdk-config': 2.4.0 + '@cowprotocol/sdk-contracts-ts': 3.3.3 + '@cowprotocol/sdk-order-book': 4.0.2(encoding@0.1.13) transitivePeerDependencies: - encoding - '@cowprotocol/sdk-subgraph@1.2.0(encoding@0.1.13)': + '@cowprotocol/sdk-subgraph@1.2.1(encoding@0.1.13)': dependencies: - '@cowprotocol/sdk-common': 0.12.0 - '@cowprotocol/sdk-config': 2.3.1 + '@cowprotocol/sdk-common': 0.12.1 + '@cowprotocol/sdk-config': 2.4.0 graphql: 16.12.0 graphql-request: 4.3.0(encoding@0.1.13)(graphql@16.12.0) transitivePeerDependencies: @@ -19484,14 +19512,14 @@ snapshots: - multiformats - supports-color - '@cowprotocol/sdk-trading@2.2.5(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': + '@cowprotocol/sdk-trading@2.2.6(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': dependencies: - '@cowprotocol/sdk-app-data': 5.3.2(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) - '@cowprotocol/sdk-common': 0.12.0 - '@cowprotocol/sdk-config': 2.3.1 - '@cowprotocol/sdk-contracts-ts': 3.3.2 - '@cowprotocol/sdk-order-book': 4.0.1(encoding@0.1.13) - '@cowprotocol/sdk-order-signing': 1.1.5(encoding@0.1.13) + '@cowprotocol/sdk-app-data': 5.3.3(ajv@6.12.6)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + '@cowprotocol/sdk-common': 0.12.1 + '@cowprotocol/sdk-config': 2.4.0 + '@cowprotocol/sdk-contracts-ts': 3.3.3 + '@cowprotocol/sdk-order-book': 4.0.2(encoding@0.1.13) + '@cowprotocol/sdk-order-signing': 1.1.6(encoding@0.1.13) deepmerge: 4.3.1 transitivePeerDependencies: - ajv @@ -19500,14 +19528,14 @@ snapshots: - multiformats - supports-color - '@cowprotocol/sdk-trading@2.2.5(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': + '@cowprotocol/sdk-trading@2.2.6(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0)': dependencies: - '@cowprotocol/sdk-app-data': 5.3.2(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) - '@cowprotocol/sdk-common': 0.12.0 - '@cowprotocol/sdk-config': 2.3.1 - '@cowprotocol/sdk-contracts-ts': 3.3.2 - '@cowprotocol/sdk-order-book': 4.0.1(encoding@0.1.13) - '@cowprotocol/sdk-order-signing': 1.1.5(encoding@0.1.13) + '@cowprotocol/sdk-app-data': 5.3.3(ajv@8.17.1)(cross-fetch@4.0.0(encoding@0.1.13))(encoding@0.1.13)(multiformats@14.0.0) + '@cowprotocol/sdk-common': 0.12.1 + '@cowprotocol/sdk-config': 2.4.0 + '@cowprotocol/sdk-contracts-ts': 3.3.3 + '@cowprotocol/sdk-order-book': 4.0.2(encoding@0.1.13) + '@cowprotocol/sdk-order-signing': 1.1.6(encoding@0.1.13) deepmerge: 4.3.1 transitivePeerDependencies: - ajv @@ -19516,14 +19544,14 @@ snapshots: - multiformats - supports-color - '@cowprotocol/sdk-viem-adapter@0.3.25(viem@2.48.8(bufferutil@4.0.8)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@cowprotocol/sdk-viem-adapter@0.3.26(viem@2.48.8(bufferutil@4.0.8)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: - '@cowprotocol/sdk-common': 0.12.0 + '@cowprotocol/sdk-common': 0.12.1 viem: 2.48.8(bufferutil@4.0.8)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@cowprotocol/sdk-viem-adapter@0.3.25(viem@2.48.8(bufferutil@4.0.8)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76))': + '@cowprotocol/sdk-viem-adapter@0.3.26(viem@2.48.8(bufferutil@4.0.8)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76))': dependencies: - '@cowprotocol/sdk-common': 0.12.0 + '@cowprotocol/sdk-common': 0.12.1 viem: 2.48.8(bufferutil@4.0.8)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76) '@cowprotocol/sdk-weiroll@0.2.0': @@ -19531,10 +19559,10 @@ snapshots: '@cowprotocol/sdk-common': 0.12.0 '@cowprotocol/sdk-config': 2.3.1 - '@cowprotocol/sdk-weiroll@0.2.1': + '@cowprotocol/sdk-weiroll@0.2.2': dependencies: - '@cowprotocol/sdk-common': 0.12.0 - '@cowprotocol/sdk-config': 2.3.1 + '@cowprotocol/sdk-common': 0.12.1 + '@cowprotocol/sdk-config': 2.4.0 '@cowprotocol/types@1.2.0': {} @@ -22512,21 +22540,22 @@ snapshots: '@protobufjs/codegen@2.0.5': {} - '@protobufjs/eventemitter@1.1.1': {} + '@protobufjs/eventemitter@1.1.0': {} - '@protobufjs/fetch@1.1.1': + '@protobufjs/fetch@1.1.0': dependencies: '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.1 '@protobufjs/float@1.0.2': {} - '@protobufjs/inquire@1.1.2': {} + '@protobufjs/inquire@1.1.1': {} '@protobufjs/path@1.1.2': {} '@protobufjs/pool@1.1.0': {} - '@protobufjs/utf8@1.1.2': {} + '@protobufjs/utf8@1.1.1': {} '@radix-ui/number@1.0.0': dependencies: @@ -34699,13 +34728,13 @@ snapshots: '@protobufjs/aspromise': 1.1.2 '@protobufjs/base64': 1.1.2 '@protobufjs/codegen': 2.0.5 - '@protobufjs/eventemitter': 1.1.1 - '@protobufjs/fetch': 1.1.1 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 '@protobufjs/float': 1.0.2 - '@protobufjs/inquire': 1.1.2 + '@protobufjs/inquire': 1.1.1 '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 - '@protobufjs/utf8': 1.1.2 + '@protobufjs/utf8': 1.1.1 '@types/long': 4.0.2 '@types/node': 24.7.1 long: 4.0.0