From 9e63e63b7b35b408f2e52bde3636eb203c6ec8b8 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Sat, 31 May 2025 22:49:45 +1200 Subject: [PATCH 1/3] [SDK] Include native tokens in Insight.getOwnedTokens --- .changeset/shaky-seals-cheer.md | 5 +++++ packages/thirdweb/src/insight/get-tokens.ts | 21 ++++++++++--------- .../Buy/swap/fetchBalancesForWallet.tsx | 5 ++++- 3 files changed, 20 insertions(+), 11 deletions(-) create mode 100644 .changeset/shaky-seals-cheer.md diff --git a/.changeset/shaky-seals-cheer.md b/.changeset/shaky-seals-cheer.md new file mode 100644 index 00000000000..8b727ae2dd9 --- /dev/null +++ b/.changeset/shaky-seals-cheer.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +Include native tokens in Insight.getOwnedTokens diff --git a/packages/thirdweb/src/insight/get-tokens.ts b/packages/thirdweb/src/insight/get-tokens.ts index f41b54ad4ef..a74360e116c 100644 --- a/packages/thirdweb/src/insight/get-tokens.ts +++ b/packages/thirdweb/src/insight/get-tokens.ts @@ -1,5 +1,5 @@ import type { - GetV1TokensErc20ByOwnerAddressData, + GetV1TokensData, GetV1TokensErc20ByOwnerAddressResponse, } from "@thirdweb-dev/insight"; import type { Chain } from "../chains/types.js"; @@ -26,10 +26,13 @@ export async function getOwnedTokens(args: { client: ThirdwebClient; chains: Chain[]; ownerAddress: string; - queryOptions?: GetV1TokensErc20ByOwnerAddressData["query"]; + queryOptions?: Omit< + GetV1TokensData["query"], + "owner_address" | "chain_id" | "chain" + >; }): Promise { const [ - { getV1TokensErc20ByOwnerAddress }, + { getV1Tokens }, { getThirdwebDomains }, { getClientFetch }, { assertInsightEnabled }, @@ -46,19 +49,17 @@ export async function getOwnedTokens(args: { await assertInsightEnabled(chains); - const defaultQueryOptions: GetV1TokensErc20ByOwnerAddressData["query"] = { - chain: chains.map((chain) => chain.id), - include_spam: "false", + const defaultQueryOptions: GetV1TokensData["query"] = { + owner_address: ownerAddress, + chain_id: chains.map((chain) => chain.id), + include_native: "true", metadata: "true", limit: 50, }; - const result = await getV1TokensErc20ByOwnerAddress({ + const result = await getV1Tokens({ baseUrl: `https://${getThirdwebDomains().insight}`, fetch: getClientFetch(client), - path: { - ownerAddress: ownerAddress, - }, query: { ...defaultQueryOptions, ...queryOptions, diff --git a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx index 08791991035..c36ba75fece 100644 --- a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx +++ b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx @@ -145,6 +145,9 @@ async function fetchBalancesForWallet({ ownerAddress: account.address, chains: chunk, client, + queryOptions: { + limit: 100, + }, }); for (const b of owned) { @@ -194,7 +197,7 @@ async function fetchBalancesForWallet({ b.chain.id === chainId && b.token.address.toLowerCase() === token.address.toLowerCase(), ); - if (isAlreadyFetched && !isNative) { + if (isAlreadyFetched) { // ERC20 on insight-enabled chain already handled by insight call continue; } From 8380a59e9e830b691e592c050d117868eb49cdb9 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Sat, 31 May 2025 22:55:36 +1200 Subject: [PATCH 2/3] [SDK] Filter out zero-value token balances in swap UI (#7244) --- .../ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx index c36ba75fece..e7d1ca0e424 100644 --- a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx +++ b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx @@ -154,7 +154,7 @@ async function fetchBalancesForWallet({ const matching = sourceSupportedTokens[b.chainId]?.find( (t) => t.address.toLowerCase() === b.tokenAddress.toLowerCase(), ); - if (matching) { + if (matching && b.value > 0n) { balances.push({ balance: b, chain: getCachedChain(b.chainId), From 5856cf01ba15cb3aed39059e3614a961f800b780 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Sun, 1 Jun 2025 15:20:42 +1200 Subject: [PATCH 3/3] more optimizations --- packages/thirdweb/src/insight/get-tokens.ts | 5 ++- .../Buy/swap/fetchBalancesForWallet.tsx | 39 ++++++++++++++----- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/packages/thirdweb/src/insight/get-tokens.ts b/packages/thirdweb/src/insight/get-tokens.ts index a74360e116c..70475cc87b2 100644 --- a/packages/thirdweb/src/insight/get-tokens.ts +++ b/packages/thirdweb/src/insight/get-tokens.ts @@ -1,12 +1,12 @@ import type { GetV1TokensData, - GetV1TokensErc20ByOwnerAddressResponse, + GetV1TokensResponse, } from "@thirdweb-dev/insight"; import type { Chain } from "../chains/types.js"; import type { ThirdwebClient } from "../client/client.js"; import type { GetWalletBalanceResult } from "../wallets/utils/getWalletBalance.js"; -type OwnedToken = GetV1TokensErc20ByOwnerAddressResponse["data"][number]; +type OwnedToken = GetV1TokensResponse["data"][number]; /** * Get ERC20 tokens owned by an address @@ -53,6 +53,7 @@ export async function getOwnedTokens(args: { owner_address: ownerAddress, chain_id: chains.map((chain) => chain.id), include_native: "true", + include_spam: "false", metadata: "true", limit: 50, }; diff --git a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx index e7d1ca0e424..2e10c3d2dcf 100644 --- a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx +++ b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/fetchBalancesForWallet.tsx @@ -141,14 +141,31 @@ async function fetchBalancesForWallet({ const insightChunks = chunkChains(insightEnabledChains); await Promise.all( insightChunks.map(async (chunk) => { - const owned = await getOwnedTokens({ - ownerAddress: account.address, - chains: chunk, - client, - queryOptions: { - limit: 100, - }, - }); + let owned: GetWalletBalanceResult[] = []; + let page = 0; + const limit = 100; + + while (true) { + const batch = await getOwnedTokens({ + ownerAddress: account.address, + chains: chunk, + client, + queryOptions: { + limit, + page, + }, + }).catch((err) => { + console.error("error fetching balances from insight", err); + return []; + }); + + if (batch.length === 0) { + break; + } + + owned = [...owned, ...batch]; + page += 1; + } for (const b of owned) { const matching = sourceSupportedTokens[b.chainId]?.find( @@ -190,6 +207,10 @@ async function fetchBalancesForWallet({ const chainId = Number(chainIdStr); const chain = getCachedChain(chainId); + if (insightEnabledChains.some((c) => c.id === chainId)) { + continue; + } + for (const token of tokens) { const isNative = isNativeToken(token); const isAlreadyFetched = balances.some( @@ -225,7 +246,7 @@ async function fetchBalancesForWallet({ } } catch (err) { console.warn( - `Failed to fetch balance for ${token.symbol} on chain ${chainId}`, + `Failed to fetch RPC balance for ${token.symbol} on chain ${chainId}`, err, ); }