Skip to content

Commit f745eb3

Browse files
feat: split USDC and USDC.e in starterpack token selection (#2470)
## Summary - Separates USDC into native USDC and bridged USDC.e for starterpack token selection. - Both native USDC and USDC.e are priced at 1:1 against USD in Ekubo quotes and hardcoded to 6 decimals. - Added native USDC to the Torii indexing config and updated old USDC comment to USDC.e. --------- Co-authored-by: broodling-bot <broodling-bot@users.noreply.github.com>
1 parent 1e5389d commit f745eb3

File tree

7 files changed

+91
-11
lines changed

7 files changed

+91
-11
lines changed

packages/keychain/src/components/provider/tokens.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ import {
1414
import { Price } from "@cartridge/ui/utils/api/cartridge";
1515
import { useQuery } from "react-query";
1616
import { getChecksumAddress } from "starknet";
17-
import { fetchSwapQuoteInUsdc, type ExtendedError } from "@/utils/ekubo";
17+
import {
18+
fetchSwapQuoteInUsdc,
19+
type ExtendedError,
20+
USDC_ADDRESSES,
21+
USDCE_ADDRESSES,
22+
} from "@/utils/ekubo";
1823

1924
export const DEFAULT_TOKENS = [
2025
{
@@ -242,7 +247,13 @@ export function TokensProvider({
242247

243248
// USDC price is always 1:1
244249
if (
245-
checksumAddress === getChecksumAddress(USDC_CONTRACT_ADDRESS)
250+
checksumAddress === getChecksumAddress(USDC_CONTRACT_ADDRESS) ||
251+
(USDC_ADDRESSES[chainId] &&
252+
checksumAddress ===
253+
getChecksumAddress(USDC_ADDRESSES[chainId])) ||
254+
(USDCE_ADDRESSES[chainId] &&
255+
checksumAddress ===
256+
getChecksumAddress(USDCE_ADDRESSES[chainId]))
246257
) {
247258
return {
248259
base: address,

packages/keychain/src/components/purchasenew/review/token-utils.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { USDC_CONTRACT_ADDRESS } from "@cartridge/ui/utils";
2+
import { USDC_ADDRESSES, USDCE_ADDRESSES } from "@/utils/ekubo";
23

34
/**
45
* Normalize a token address for comparison
@@ -15,12 +16,26 @@ export function normalizeTokenAddress(address: string): string {
1516
return lower;
1617
}
1718

19+
export function isUsdcToken(tokenAddress: string): boolean {
20+
const normalized = normalizeTokenAddress(tokenAddress);
21+
if (normalized === USDC_CONTRACT_ADDRESS) return true;
22+
if (
23+
Object.values(USDC_ADDRESSES).some(
24+
(addr) => normalizeTokenAddress(addr) === normalized,
25+
)
26+
)
27+
return true;
28+
return Object.values(USDCE_ADDRESSES).some(
29+
(addr) => normalizeTokenAddress(addr) === normalized,
30+
);
31+
}
32+
1833
/**
1934
* Get the number of decimals for a token address
2035
* USDC = 6 decimals, everything else = 18 decimals
2136
*/
2237
export function getTokenDecimals(tokenAddress: string): number {
23-
return normalizeTokenAddress(tokenAddress) === USDC_CONTRACT_ADDRESS ? 6 : 18;
38+
return isUsdcToken(tokenAddress) ? 6 : 18;
2439
}
2540

2641
/**
@@ -48,9 +63,21 @@ export function tokenAmountToUsd(amount: bigint, tokenAddress: string): string {
4863
* Get a human-readable token symbol from address
4964
*/
5065
export function getTokenSymbol(tokenAddress: string): string {
51-
if (normalizeTokenAddress(tokenAddress) === USDC_CONTRACT_ADDRESS) {
66+
const normalized = normalizeTokenAddress(tokenAddress);
67+
if (normalized === USDC_CONTRACT_ADDRESS) return "USDC.e";
68+
if (
69+
Object.values(USDC_ADDRESSES).some(
70+
(addr) => normalizeTokenAddress(addr) === normalized,
71+
)
72+
)
5273
return "USDC";
53-
}
74+
if (
75+
Object.values(USDCE_ADDRESSES).some(
76+
(addr) => normalizeTokenAddress(addr) === normalized,
77+
)
78+
)
79+
return "USDC.e";
80+
5481
// For unknown tokens, show shortened address
5582
return `${tokenAddress.slice(0, 6)}...${tokenAddress.slice(-4)}`;
5683
}
@@ -59,7 +86,7 @@ export function getTokenSymbol(tokenAddress: string): string {
5986
* Get token icon URL
6087
*/
6188
export function getTokenIcon(tokenAddress: string): string | null {
62-
if (normalizeTokenAddress(tokenAddress) === USDC_CONTRACT_ADDRESS) {
89+
if (isUsdcToken(tokenAddress)) {
6390
return "https://static.cartridge.gg/tokens/usdc.svg";
6491
}
6592
return null;

packages/keychain/src/hooks/starterpack/token-selection.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
import { useState, useCallback, useEffect, useMemo } from "react";
22
import { erc20Metadata, ExternalPlatform } from "@cartridge/controller";
33
import { num, getChecksumAddress, constants } from "starknet";
4-
import { ERC20 as ERC20Contract } from "@cartridge/ui/utils";
4+
import {
5+
ERC20 as ERC20Contract,
6+
USDC_CONTRACT_ADDRESS,
7+
} from "@cartridge/ui/utils";
58
import {
69
DEFAULT_TOKENS,
710
type ERC20Metadata,
811
} from "@/components/provider/tokens";
9-
import { fetchSwapQuote, USDC_ADDRESSES, type SwapQuote } from "@/utils/ekubo";
12+
import {
13+
fetchSwapQuote,
14+
USDC_ADDRESSES,
15+
USDCE_ADDRESSES,
16+
type SwapQuote,
17+
} from "@/utils/ekubo";
1018
import {
1119
fetchTokenMetadata,
1220
type TokenMetadata as FullTokenMetadata,
@@ -152,11 +160,14 @@ export function useTokenSelection({
152160
const availableTokens = useMemo(() => {
153161
if (!controller) return [];
154162

155-
// Start with default tokens (ETH, STRK, USDC)
163+
// Start with default tokens (ETH, STRK, USDC, USDC.e)
156164
const usdcAddress =
157165
USDC_ADDRESSES[controller.chainId()] ||
158166
USDC_ADDRESSES[constants.StarknetChainId.SN_MAIN];
159167

168+
const usdceAddress =
169+
USDCE_ADDRESSES[controller.chainId()] || USDC_CONTRACT_ADDRESS;
170+
160171
const tokens: ERC20Metadata[] = [
161172
{
162173
address: usdcAddress,
@@ -165,6 +176,13 @@ export function useTokenSelection({
165176
decimals: 6,
166177
icon: "https://static.cartridge.gg/tokens/usdc.svg",
167178
},
179+
{
180+
address: usdceAddress,
181+
name: "Bridged USDC",
182+
symbol: "USDC.e",
183+
decimals: 6,
184+
icon: "https://static.cartridge.gg/tokens/usdc.svg",
185+
},
168186
...DEFAULT_TOKENS,
169187
];
170188

packages/keychain/src/utils/ekubo/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ export const EKUBO_ROUTER_ADDRESSES: Record<string, string> = {
3535
export const USDC_ADDRESSES: Record<string, string> = {
3636
[constants.StarknetChainId.SN_MAIN]:
3737
"0x033068F6539f8e6e6b131e6B2B814e6c34A5224bC66947c47DaB9dFeE93b35fb",
38+
[constants.StarknetChainId.SN_SEPOLIA]:
39+
"0x0512feac6339ff7889822cb5aa2a86c848e9d392bb0e3e237c008674feed8343",
40+
};
41+
42+
export const USDCE_ADDRESSES: Record<string, string> = {
43+
[constants.StarknetChainId.SN_MAIN]:
44+
"0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8",
3845
[constants.StarknetChainId.SN_SEPOLIA]:
3946
"0x053b40a647cedfca6ca84f542a0fe36736031905a9639a7f19a3c1e66bfd5080",
4047
};

packages/keychain/src/utils/token-metadata.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { Call, RpcProvider, shortString, constants } from "starknet";
2-
import { USDC_ADDRESSES } from "@/utils/ekubo";
2+
import { USDC_ADDRESSES, USDCE_ADDRESSES } from "@/utils/ekubo";
33
import {
44
USDT_CONTRACT_ADDRESS,
55
STRK_CONTRACT_ADDRESS,
66
ETH_CONTRACT_ADDRESS,
7+
USDC_CONTRACT_ADDRESS,
78
} from "@cartridge/ui/utils";
89

910
export interface TokenMetadata {
@@ -33,6 +34,16 @@ const CACHED_TOKEN_METADATA: Record<string, TokenMetadata> = {
3334
symbol: "USDT",
3435
decimals: 6,
3536
},
37+
[USDC_CONTRACT_ADDRESS.toLowerCase()]: {
38+
name: "Bridged USDC",
39+
symbol: "USDC.e",
40+
decimals: 6,
41+
},
42+
[USDCE_ADDRESSES[constants.StarknetChainId.SN_SEPOLIA].toLowerCase()]: {
43+
name: "Bridged USDC",
44+
symbol: "USDC.e",
45+
decimals: 6,
46+
},
3647
[STRK_CONTRACT_ADDRESS.toLowerCase()]: {
3748
name: "Starknet Token",
3849
symbol: "STRK",

packages/torii-config/public-tokens/mainnet.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ contracts = [
99
"erc20:0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
1010
# STRK
1111
"erc20:0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
12-
# USDC
12+
# USDC.e
1313
"erc20:0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8",
14+
# USDC
15+
"erc20:0x033068f6539f8e6e6b131e6b2b814e6c34a5224bc66947c47dab9dfee93b35fb",
1416
# USDT
1517
"erc20:0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8",
1618
# DAI

packages/torii-config/public-tokens/sepolia.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,8 @@ contracts = [
99
"erc20:0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
1010
# STRK
1111
"erc20:0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
12+
# USDC.e
13+
"erc20:0x053b40a647cedfca6ca84f542a0fe36736031905a9639a7f19a3c1e66bfd5080",
14+
# USDC
15+
"erc20:0x0512feac6339ff7889822cb5aa2a86c848e9d392bb0e3e237c008674feed8343",
1216
]

0 commit comments

Comments
 (0)