diff --git a/.env b/.env index 5f424cb4679..55c3e3014f1 100644 --- a/.env +++ b/.env @@ -108,6 +108,7 @@ VITE_FEATURE_BOB=false VITE_FEATURE_MODE=false VITE_FEATURE_SONEIUM=false VITE_FEATURE_SEI=false +VITE_FEATURE_CITREA=false VITE_FEATURE_YIELD_MULTI_ACCOUNT=true VITE_FEATURE_YIELD_XYZ=true VITE_FEATURE_YIELDS_PAGE=true @@ -235,6 +236,7 @@ VITE_TRON_NODE_URL=https://api.trongrid.io VITE_UNICHAIN_NODE_URL=https://mainnet.unichain.org VITE_WORLDCHAIN_NODE_URL=https://worldchain-mainnet.g.alchemy.com/public VITE_ZKSYNC_ERA_NODE_URL=https://mainnet.era.zksync.io +VITE_CITREA_NODE_URL=https://rpc.mainnet.citrea.xyz # midgard VITE_THORCHAIN_MIDGARD_URL=https://api.thorchain.shapeshift.com/midgard/v2 diff --git a/.env.development b/.env.development index 48d2f40d91b..bae66759c83 100644 --- a/.env.development +++ b/.env.development @@ -39,6 +39,7 @@ VITE_FEATURE_YIELD_MULTI_ACCOUNT=true VITE_FEATURE_AGENTIC_CHAT=true VITE_FEATURE_MM_NATIVE_MULTICHAIN=true VITE_FEATURE_NOTIFICATIONS_WEBSERVICES=true +VITE_FEATURE_CITREA=true # mixpanel VITE_MIXPANEL_TOKEN=a867ce40912a6b7d01d088cf62b0e1ff @@ -92,6 +93,7 @@ VITE_BASE_NODE_URL=https://dev-api.base.shapeshift.com/api/v1/jsonrpc VITE_THORCHAIN_NODE_URL=https://dev-api.thorchain.shapeshift.com/lcd VITE_MAYACHAIN_NODE_URL=https://dev-api.mayachain.shapeshift.com/lcd VITE_SOLANA_NODE_URL=https://dev-api.solana.shapeshift.com/api/v1/jsonrpc +VITE_CITREA_NODE_URL=https://rpc.mainnet.citrea.xyz # midgard VITE_THORCHAIN_MIDGARD_URL=https://dev-api.thorchain.shapeshift.com/midgard/v2 diff --git a/chains/citrea.json b/chains/citrea.json new file mode 100644 index 00000000000..b3a96ad91f4 --- /dev/null +++ b/chains/citrea.json @@ -0,0 +1,30 @@ +{ + "camelName": "citrea", + "pascalName": "Citrea", + "upperName": "CITREA", + "chainId": 4114, + "viemChainName": "citrea", + "nativeSymbol": "cBTC", + "nativeName": "Citrea Bitcoin", + "nativePrecision": 18, + "isNativeEth": false, + "color": "#F7931A", + "networkIconUrl": "https://assets.coingecko.com/asset_platforms/images/102132293/small/citrea.jpg", + "nativeIconUrl": "https://assets.coingecko.com/coins/images/102172844/large/cBTC.png", + "explorerUrl": "https://explorer.mainnet.citrea.xyz", + "explorerAddressLink": "https://explorer.mainnet.citrea.xyz/address/", + "explorerTxLink": "https://explorer.mainnet.citrea.xyz/tx/", + "rpcUrl": "https://rpc.mainnet.citrea.xyz", + "publicRpcUrls": ["https://rpc.mainnet.citrea.xyz"], + "coingeckoPlatform": "citrea", + "wrappedNativeAddress": "0x3100000000000000000000000000000000000006", + "relatedAssetKey": "eip155:4114/slip44:60", + "shortName": "citrea", + "swappers": { + "relay": { "supported": false }, + "across": { "supported": false }, + "portals": { "supported": false }, + "zerion": { "supported": false }, + "yieldxyz": { "supported": false } + } +} diff --git a/headers/csps/chains/citrea.ts b/headers/csps/chains/citrea.ts new file mode 100644 index 00000000000..2ab4c67581b --- /dev/null +++ b/headers/csps/chains/citrea.ts @@ -0,0 +1,11 @@ +import { loadEnv } from 'vite' + +import { PUBLIC_RPC_URLS } from '../../../packages/contracts/src/publicRpcUrls' +import type { Csp } from '../../types' + +const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' +const env = loadEnv(mode, process.cwd(), '') + +export const csp: Csp = { + 'connect-src': [env.VITE_CITREA_NODE_URL, ...PUBLIC_RPC_URLS.citrea], +} diff --git a/headers/csps/index.ts b/headers/csps/index.ts index 93352adb685..0e84d132c34 100644 --- a/headers/csps/index.ts +++ b/headers/csps/index.ts @@ -14,6 +14,7 @@ import { csp as blast } from './chains/blast' import { csp as bnbsmartchain } from './chains/bnbsmartchain' import { csp as bob } from './chains/bob' import { csp as celo } from './chains/celo' +import { csp as citrea } from './chains/citrea' import { csp as cosmos } from './chains/cosmos' import { csp as cronos } from './chains/cronos' import { csp as dogecoin } from './chains/dogecoin' @@ -206,4 +207,5 @@ export const csps = [ railway, discord, yieldxyz, + citrea, ] diff --git a/packages/caip/src/adapters/coingecko/generated/eip155_4114/adapter.json b/packages/caip/src/adapters/coingecko/generated/eip155_4114/adapter.json new file mode 100644 index 00000000000..5c28a5a2519 --- /dev/null +++ b/packages/caip/src/adapters/coingecko/generated/eip155_4114/adapter.json @@ -0,0 +1 @@ +{"eip155:4114/slip44:60":"citrea","eip155:4114/erc20:0x547afd93b9c47d552059feb556909e017f8a9b25":"citrea","eip155:4114/erc20:0xe045e6c36cf77faa2cfb54466d71a3aef7bbe839":"citrea-bridged-usdc","eip155:4114/erc20:0x9f3096bac87e7f03dc09b0b416eb0df837304dc4":"citrea-bridged-usdt","eip155:4114/erc20:0xdf240dc08b0fdad1d93b74d5048871232f6bea3d":"citrea-bridged-wbtc-citrea","eip155:4114/erc20:0x8d82c4e3c936c7b5724a382a9c5a4e6eb7ab6d5d":"citrea-usd","eip155:4114/erc20:0xac8c1aeb584765db16ac3e08d4736cfce198589b":"generic-usd","eip155:4114/erc20:0x2a36f2b204b46fd82653cd06d00c7ff757c99ae4":"juice-protocol","eip155:4114/erc20:0x1b70ae756b1089cc5948e4f8a2ad498df30e897d":"savings-vault-jusd-citrea","eip155:4114/erc20:0x384157027b1cdeac4e26e3709667bb28735379bb":"symbiosis-btc-citrea","eip155:4114/erc20:0x3100000000000000000000000000000000000006":"wrapped-citrea-bitcoin"} \ No newline at end of file diff --git a/packages/caip/src/adapters/coingecko/generated/index.ts b/packages/caip/src/adapters/coingecko/generated/index.ts index e8e5bb68b88..923daa376c3 100644 --- a/packages/caip/src/adapters/coingecko/generated/index.ts +++ b/packages/caip/src/adapters/coingecko/generated/index.ts @@ -36,6 +36,7 @@ import flowevm from "./eip155_747/adapter.json"; import celo from "./eip155_42220/adapter.json"; import sei from "./eip155_1329/adapter.json"; import abstract from "./eip155_2741/adapter.json"; +import citrea from "./eip155_4114/adapter.json"; import cosmos from "./cosmos_cosmoshub-4/adapter.json"; import thorchain from "./cosmos_thorchain-1/adapter.json"; import mayachain from "./cosmos_mayachain-mainnet-v1/adapter.json"; @@ -86,6 +87,7 @@ export { celo, sei, abstract, + citrea, cosmos, thorchain, mayachain, diff --git a/packages/caip/src/adapters/coingecko/index.ts b/packages/caip/src/adapters/coingecko/index.ts index 59983dcca4e..3644a2afe4f 100644 --- a/packages/caip/src/adapters/coingecko/index.ts +++ b/packages/caip/src/adapters/coingecko/index.ts @@ -16,6 +16,7 @@ import { celoChainId, CHAIN_NAMESPACE, CHAIN_REFERENCE, + citreaChainId, cosmosChainId, cronosChainId, ethChainId, @@ -100,6 +101,7 @@ export enum CoingeckoAssetPlatform { Ton = 'the-open-network', Near = 'near-protocol', Abstract = 'abstract', + Citrea = 'citrea', } type CoinGeckoId = string @@ -198,6 +200,8 @@ export const chainIdToCoingeckoAssetPlatform = (chainId: ChainId): string => { return CoingeckoAssetPlatform.Soneium case CHAIN_REFERENCE.SeiMainnet: return CoingeckoAssetPlatform.Sei + case CHAIN_REFERENCE.CitreaMainnet: + return CoingeckoAssetPlatform.Citrea default: throw new Error( `chainNamespace ${chainNamespace}, chainReference ${chainReference} not supported.`, @@ -367,6 +371,8 @@ export const coingeckoAssetPlatformToChainId = ( return tonChainId case CoingeckoAssetPlatform.Near: return nearChainId + case CoingeckoAssetPlatform.Citrea: + return citreaChainId default: return undefined } diff --git a/packages/caip/src/adapters/coingecko/utils.test.ts b/packages/caip/src/adapters/coingecko/utils.test.ts index 2a2d92b2dec..8f467b5f367 100644 --- a/packages/caip/src/adapters/coingecko/utils.test.ts +++ b/packages/caip/src/adapters/coingecko/utils.test.ts @@ -242,6 +242,9 @@ describe('adapters:coingecko:utils', () => { 'eip155:2741': { 'eip155:2741/slip44:60': 'ethereum', }, + 'eip155:4114': { + 'eip155:4114/slip44:60': 'citrea-bridged-bitcoin', + }, 'near:mainnet': { 'near:mainnet/slip44:397': 'near', }, diff --git a/packages/caip/src/adapters/coingecko/utils.ts b/packages/caip/src/adapters/coingecko/utils.ts index 66a2846f900..d9b3185d75e 100644 --- a/packages/caip/src/adapters/coingecko/utils.ts +++ b/packages/caip/src/adapters/coingecko/utils.ts @@ -28,6 +28,8 @@ import { celoChainId, CHAIN_NAMESPACE, CHAIN_REFERENCE, + citreaAssetId, + citreaChainId, cosmosChainId, cronosAssetId, cronosChainId, @@ -665,6 +667,20 @@ export const parseData = (coins: CoingeckoCoin[]): AssetMap => { } } + if (Object.keys(platforms).includes(CoingeckoAssetPlatform.Citrea)) { + try { + const assetId = toAssetId({ + chainNamespace: CHAIN_NAMESPACE.Evm, + chainReference: CHAIN_REFERENCE.CitreaMainnet, + assetNamespace: 'erc20', + assetReference: platforms[CoingeckoAssetPlatform.Citrea], + }) + prev[citreaChainId][assetId] = id + } catch { + // unable to create assetId, skip token + } + } + return prev }, { @@ -707,6 +723,7 @@ export const parseData = (coins: CoingeckoCoin[]): AssetMap => { [suiChainId]: { [suiAssetId]: 'sui' }, [nearChainId]: { [nearAssetId]: 'near' }, [tonChainId]: { [tonAssetId]: 'the-open-network' }, + [citreaChainId]: { [citreaAssetId]: 'citrea-bridged-bitcoin' }, }, ) diff --git a/packages/caip/src/constants.ts b/packages/caip/src/constants.ts index 7bed0cf1c18..962c67b0035 100644 --- a/packages/caip/src/constants.ts +++ b/packages/caip/src/constants.ts @@ -50,6 +50,7 @@ export const suiAssetId: AssetId = 'sui:35834a8a/slip44:784' export const nearAssetId: AssetId = 'near:mainnet/slip44:397' export const starknetAssetId: AssetId = 'starknet:SN_MAIN/slip44:9004' export const tonAssetId: AssetId = 'ton:mainnet/slip44:607' +export const citreaAssetId: AssetId = 'eip155:4114/slip44:60' export const uniV2EthFoxArbitrumAssetId: AssetId = 'eip155:42161/erc20:0x5f6ce0ca13b87bd738519545d3e018e70e339c24' @@ -142,6 +143,7 @@ export const suiChainId: ChainId = 'sui:35834a8a' export const nearChainId: ChainId = 'near:mainnet' export const starknetChainId: ChainId = 'starknet:SN_MAIN' export const tonChainId: ChainId = 'ton:mainnet' +export const citreaChainId: ChainId = 'eip155:4114' export const CHAIN_NAMESPACE = { Evm: 'eip155', @@ -210,6 +212,7 @@ export const CHAIN_REFERENCE = { StarknetMainnet: 'SN_MAIN', // https://namespaces.chainagnostic.org/starknet/caip2 TonMainnet: 'mainnet', // TON Mainnet AbstractMainnet: '2741', // https://abscan.org + CitreaMainnet: '4114', // https://explorer.mainnet.citrea.xyz } as const export const ASSET_NAMESPACE = { @@ -277,6 +280,7 @@ export const ASSET_REFERENCE = { Starknet: '9004', Ton: '607', Abstract: '60', // evm chain which uses ethereum derivation path as common practice + Citrea: '60', // evm chain which uses ethereum derivation path as common practice } as const export const VALID_CHAIN_IDS: ValidChainMap = Object.freeze({ @@ -323,6 +327,7 @@ export const VALID_CHAIN_IDS: ValidChainMap = Object.freeze({ CHAIN_REFERENCE.SeiMainnet, CHAIN_REFERENCE.CeloMainnet, CHAIN_REFERENCE.AbstractMainnet, + CHAIN_REFERENCE.CitreaMainnet, ], [CHAIN_NAMESPACE.CosmosSdk]: [ CHAIN_REFERENCE.CosmosHubMainnet, @@ -407,4 +412,5 @@ export const FEE_ASSET_IDS = [ katanaAssetId, etherealAssetId, flowEvmAssetId, + citreaAssetId, ] diff --git a/packages/chain-adapters/src/evm/EvmBaseAdapter.ts b/packages/chain-adapters/src/evm/EvmBaseAdapter.ts index 9d4cde8bfb8..45f505a8722 100644 --- a/packages/chain-adapters/src/evm/EvmBaseAdapter.ts +++ b/packages/chain-adapters/src/evm/EvmBaseAdapter.ts @@ -18,6 +18,7 @@ import { supportsBob, supportsBSC, supportsCelo, + supportsCitrea, supportsCronos, supportsETH, supportsEthereal, @@ -135,6 +136,7 @@ export const evmChainIds = [ KnownChainIds.SoneiumMainnet, KnownChainIds.SeiMainnet, KnownChainIds.AbstractMainnet, + KnownChainIds.CitreaMainnet, ] as const export type EvmChainAdapter = EvmBaseAdapter @@ -283,6 +285,8 @@ export abstract class EvmBaseAdapter implements IChainAdap return supportsSoneium(wallet) case Number(fromChainId(KnownChainIds.SeiMainnet).chainReference): return supportsSei(wallet) + case Number(fromChainId(KnownChainIds.CitreaMainnet).chainReference): + return supportsCitrea(wallet) default: return false } @@ -490,6 +494,11 @@ export abstract class EvmBaseAdapter implements IChainAdap symbol: 'ETH', explorer: 'https://abscan.org', }, + [KnownChainIds.CitreaMainnet]: { + name: 'Citrea Bitcoin', + symbol: 'cBTC', + explorer: 'https://explorer.mainnet.citrea.xyz', + }, }[this.chainId] try { diff --git a/packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts b/packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts index 8e77bf917f5..6593e689de9 100644 --- a/packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts +++ b/packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts @@ -5,6 +5,7 @@ import { blastChainId, bobChainId, celoChainId, + citreaChainId, cronosChainId, flowEvmChainId, hemiChainId, @@ -75,6 +76,7 @@ const WRAPPED_NATIVE_CONTRACT_BY_CHAIN_ID: Partial> = { [storyChainId]: '0x1514000000000000000000000000000000000000', [plumeChainId]: '0xea237441c92cae6fc17caaf9a7acb3f953be4bd1', [seiChainId]: '0xE30feDd158A2e3b13e9badaeABaFc5516e95e8C7', + [citreaChainId]: '0x3100000000000000000000000000000000000006', } const BATCH_SIZE = 500 diff --git a/packages/chain-adapters/src/evm/citrea/CitreaChainAdapter.ts b/packages/chain-adapters/src/evm/citrea/CitreaChainAdapter.ts new file mode 100644 index 00000000000..5effab35c14 --- /dev/null +++ b/packages/chain-adapters/src/evm/citrea/CitreaChainAdapter.ts @@ -0,0 +1,57 @@ +import type { AssetId } from '@shapeshiftoss/caip' +import { ASSET_REFERENCE, citreaAssetId } from '@shapeshiftoss/caip' +import type { RootBip44Params } from '@shapeshiftoss/types' +import { KnownChainIds } from '@shapeshiftoss/types' + +import { ChainAdapterDisplayName } from '../../types' +import type { TokenInfo } from '../SecondClassEvmAdapter' +import { SecondClassEvmAdapter } from '../SecondClassEvmAdapter' + +const SUPPORTED_CHAIN_IDS = [KnownChainIds.CitreaMainnet] +const DEFAULT_CHAIN_ID = KnownChainIds.CitreaMainnet + +export type ChainAdapterArgs = { + rpcUrl: string + getKnownTokens: () => TokenInfo[] +} + +export const isCitreaChainAdapter = (adapter: unknown): adapter is ChainAdapter => { + return (adapter as ChainAdapter).getType() === KnownChainIds.CitreaMainnet +} + +export class ChainAdapter extends SecondClassEvmAdapter { + public static readonly rootBip44Params: RootBip44Params = { + purpose: 44, + coinType: Number(ASSET_REFERENCE.Citrea), + accountNumber: 0, + } + + constructor(args: ChainAdapterArgs) { + super({ + assetId: citreaAssetId, + chainId: DEFAULT_CHAIN_ID, + rootBip44Params: ChainAdapter.rootBip44Params, + supportedChainIds: SUPPORTED_CHAIN_IDS, + rpcUrl: args.rpcUrl, + getKnownTokens: args.getKnownTokens, + }) + } + + getDisplayName() { + return ChainAdapterDisplayName.Citrea + } + + getName() { + return 'Citrea' + } + + getType(): KnownChainIds.CitreaMainnet { + return KnownChainIds.CitreaMainnet + } + + getFeeAssetId(): AssetId { + return this.assetId + } +} + +export type { TokenInfo } diff --git a/packages/chain-adapters/src/evm/citrea/index.ts b/packages/chain-adapters/src/evm/citrea/index.ts new file mode 100644 index 00000000000..e1562615315 --- /dev/null +++ b/packages/chain-adapters/src/evm/citrea/index.ts @@ -0,0 +1 @@ +export * from './CitreaChainAdapter' diff --git a/packages/chain-adapters/src/evm/index.ts b/packages/chain-adapters/src/evm/index.ts index defef25e97d..111a9f8f492 100644 --- a/packages/chain-adapters/src/evm/index.ts +++ b/packages/chain-adapters/src/evm/index.ts @@ -4,6 +4,7 @@ export { isSecondClassEvmAdapter, SecondClassEvmAdapter } from './SecondClassEvm export type { SecondClassEvmAdapterArgs, TokenInfo } from './SecondClassEvmAdapter' export * as evm from './evm' +export * as citrea from './citrea' export * as abstract from './abstract' export * as ethereum from './ethereum' diff --git a/packages/chain-adapters/src/types.ts b/packages/chain-adapters/src/types.ts index fbdd05171fb..a21e1f6c5d1 100644 --- a/packages/chain-adapters/src/types.ts +++ b/packages/chain-adapters/src/types.ts @@ -71,6 +71,8 @@ type ChainSpecificAccount = ChainSpecific< [KnownChainIds.SoneiumMainnet]: evm.Account [KnownChainIds.SeiMainnet]: evm.Account [KnownChainIds.AbstractMainnet]: evm.Account + [KnownChainIds.CitreaMainnet]: evm.Account + [KnownChainIds.BitcoinMainnet]: utxo.Account [KnownChainIds.BitcoinCashMainnet]: utxo.Account [KnownChainIds.DogecoinMainnet]: utxo.Account @@ -145,6 +147,8 @@ type ChainSpecificFeeData = ChainSpecific< [KnownChainIds.SoneiumMainnet]: evm.FeeData [KnownChainIds.SeiMainnet]: evm.FeeData [KnownChainIds.AbstractMainnet]: evm.FeeData + [KnownChainIds.CitreaMainnet]: evm.FeeData + [KnownChainIds.BitcoinMainnet]: utxo.FeeData [KnownChainIds.BitcoinCashMainnet]: utxo.FeeData [KnownChainIds.DogecoinMainnet]: utxo.FeeData @@ -252,6 +256,8 @@ export type ChainSignTx = { [KnownChainIds.SoneiumMainnet]: ETHSignTx [KnownChainIds.SeiMainnet]: ETHSignTx [KnownChainIds.AbstractMainnet]: ETHSignTx + [KnownChainIds.CitreaMainnet]: ETHSignTx + [KnownChainIds.BitcoinMainnet]: BTCSignTx [KnownChainIds.BitcoinCashMainnet]: BTCSignTx [KnownChainIds.DogecoinMainnet]: BTCSignTx @@ -331,6 +337,8 @@ export type ChainSpecificBuildTxData = ChainSpecific< [KnownChainIds.SoneiumMainnet]: evm.BuildTxInput [KnownChainIds.SeiMainnet]: evm.BuildTxInput [KnownChainIds.AbstractMainnet]: evm.BuildTxInput + [KnownChainIds.CitreaMainnet]: evm.BuildTxInput + [KnownChainIds.BitcoinMainnet]: utxo.BuildTxInput [KnownChainIds.BitcoinCashMainnet]: utxo.BuildTxInput [KnownChainIds.DogecoinMainnet]: utxo.BuildTxInput @@ -460,6 +468,8 @@ type ChainSpecificGetFeeDataInput = ChainSpecific< [KnownChainIds.SoneiumMainnet]: evm.GetFeeDataInput [KnownChainIds.SeiMainnet]: evm.GetFeeDataInput [KnownChainIds.AbstractMainnet]: evm.GetFeeDataInput + [KnownChainIds.CitreaMainnet]: evm.GetFeeDataInput + [KnownChainIds.BitcoinMainnet]: utxo.GetFeeDataInput [KnownChainIds.BitcoinCashMainnet]: utxo.GetFeeDataInput [KnownChainIds.DogecoinMainnet]: utxo.GetFeeDataInput @@ -566,6 +576,7 @@ export enum ChainAdapterDisplayName { Starknet = 'Starknet', Ton = 'TON', Abstract = 'Abstract', + Citrea = 'Citrea', } export type BroadcastTransactionInput = { diff --git a/packages/contracts/src/ethersProviderSingleton.ts b/packages/contracts/src/ethersProviderSingleton.ts index 1d512384c78..93494eaa34f 100644 --- a/packages/contracts/src/ethersProviderSingleton.ts +++ b/packages/contracts/src/ethersProviderSingleton.ts @@ -82,6 +82,8 @@ export const rpcUrlByChainId = (chainId: EvmChainId): string => { return PUBLIC_RPC_URLS.sei[0] case KnownChainIds.AbstractMainnet: return PUBLIC_RPC_URLS.abstract[0] + case KnownChainIds.CitreaMainnet: + return PUBLIC_RPC_URLS.citrea[0] default: return assertUnreachable(chainId) } diff --git a/packages/contracts/src/publicRpcUrls.ts b/packages/contracts/src/publicRpcUrls.ts index 12d5a518b2e..8a066ba40f3 100644 --- a/packages/contracts/src/publicRpcUrls.ts +++ b/packages/contracts/src/publicRpcUrls.ts @@ -95,4 +95,5 @@ export const PUBLIC_RPC_URLS = { 'https://zksync.drpc.org', 'https://zksync.api.onfinality.io/public', ], + citrea: ['https://rpc.mainnet.citrea.xyz'], } as const diff --git a/packages/contracts/src/viemClient.ts b/packages/contracts/src/viemClient.ts index 076dbc2c0dd..85e6a1a6921 100644 --- a/packages/contracts/src/viemClient.ts +++ b/packages/contracts/src/viemClient.ts @@ -187,6 +187,19 @@ export const ethereal = defineChain({ }, }) +export const citrea = defineChain({ + id: 4114, + name: 'Citrea Mainnet', + nativeCurrency: { name: 'Citrea Bitcoin', symbol: 'cBTC', decimals: 18 }, + rpcUrls: { default: { http: ['https://rpc.mainnet.citrea.xyz'] } }, + blockExplorers: { + default: { + name: 'Citrea Explorer', + url: 'https://explorer.mainnet.citrea.xyz', + }, + }, +}) + export const viemEtherealClient = createPublicClient({ chain: ethereal, transport: createRpcTransport(undefined, PUBLIC_RPC_URLS.ethereal), @@ -257,6 +270,11 @@ export const viemSoneiumClient = createPublicClient({ transport: createRpcTransport(undefined, PUBLIC_RPC_URLS.soneium), }) as PublicClient +export const viemCitreaClient = createPublicClient({ + chain: citrea, + transport: createRpcTransport(undefined, PUBLIC_RPC_URLS.citrea), +}) as PublicClient + export const viemClientByChainId: Record = { [KnownChainIds.EthereumMainnet]: viemEthMainnetClient, [KnownChainIds.BnbSmartChainMainnet]: viemBscClient, @@ -293,6 +311,7 @@ export const viemClientByChainId: Record = { [KnownChainIds.SoneiumMainnet]: viemSoneiumClient, [KnownChainIds.SeiMainnet]: viemSeiClient, [KnownChainIds.AbstractMainnet]: viemAbstractClient, + [KnownChainIds.CitreaMainnet]: viemCitreaClient, } export const viemNetworkIdByChainId: Record = { @@ -331,6 +350,7 @@ export const viemNetworkIdByChainId: Record = { [KnownChainIds.SoneiumMainnet]: soneium.id, [KnownChainIds.SeiMainnet]: sei.id, [KnownChainIds.AbstractMainnet]: abstract.id, + [KnownChainIds.CitreaMainnet]: citrea.id, } export const viemClientByNetworkId: Record = { @@ -369,6 +389,7 @@ export const viemClientByNetworkId: Record = { [soneium.id]: viemSoneiumClient, [sei.id]: viemSeiClient, [abstract.id]: viemAbstractClient, + [citrea.id]: viemCitreaClient, } export const assertGetViemClient = (chainId: ChainId): PublicClient => { diff --git a/packages/hdwallet-coinbase/src/coinbase.ts b/packages/hdwallet-coinbase/src/coinbase.ts index 3c783737f6f..b752997658d 100644 --- a/packages/hdwallet-coinbase/src/coinbase.ts +++ b/packages/hdwallet-coinbase/src/coinbase.ts @@ -154,6 +154,7 @@ export class CoinbaseHDWallet implements core.HDWallet, core.ETHWallet { readonly _supportsKavaInfo = false readonly _supportsTerra = false readonly _supportsTerraInfo = false + readonly _supportsCitrea = false info: CoinbaseHDWalletInfo & core.HDWalletInfo ethAddress?: Address | null diff --git a/packages/hdwallet-core/src/ethereum.ts b/packages/hdwallet-core/src/ethereum.ts index 74cd9211e48..4a892a26adb 100644 --- a/packages/hdwallet-core/src/ethereum.ts +++ b/packages/hdwallet-core/src/ethereum.ts @@ -232,6 +232,7 @@ export interface ETHWallet extends ETHWalletInfo, HDWallet { readonly _supportsCronos: boolean readonly _supportsUnichain: boolean readonly _supportsSoneium: boolean + readonly _supportsCitrea: boolean ethGetAddress(msg: ETHGetAddress): Promise
ethGetAddresses?(msgs: ETHGetAddress[]): Promise diff --git a/packages/hdwallet-core/src/wallet.ts b/packages/hdwallet-core/src/wallet.ts index 97ec2596115..c384243b9db 100644 --- a/packages/hdwallet-core/src/wallet.ts +++ b/packages/hdwallet-core/src/wallet.ts @@ -277,6 +277,10 @@ export function supportsSoneium(wallet: HDWallet): wallet is ETHWallet { return isObject(wallet) && (wallet as any)._supportsSoneium } +export function supportsCitrea(wallet: HDWallet): wallet is ETHWallet { + return isObject(wallet) && (wallet as any)._supportsCitrea +} + export function infoCosmos(info: HDWalletInfo): info is CosmosWalletInfo { return isObject(info) && (info as any)._supportsCosmosInfo } diff --git a/packages/hdwallet-gridplus/src/gridplus.ts b/packages/hdwallet-gridplus/src/gridplus.ts index 054bf4b4b08..2c0cc1a129e 100644 --- a/packages/hdwallet-gridplus/src/gridplus.ts +++ b/packages/hdwallet-gridplus/src/gridplus.ts @@ -390,6 +390,7 @@ export class GridPlusHDWallet readonly _supportsCosmos = true readonly _supportsETH = true readonly _supportsEthSwitchChain = false + readonly _supportsCitrea = false readonly _supportsGnosis = true readonly _supportsMayachain = true readonly _supportsOptimism = true diff --git a/packages/hdwallet-keepkey/src/keepkey.ts b/packages/hdwallet-keepkey/src/keepkey.ts index 4afe565a53a..215eff17eb5 100644 --- a/packages/hdwallet-keepkey/src/keepkey.ts +++ b/packages/hdwallet-keepkey/src/keepkey.ts @@ -576,6 +576,7 @@ export class KeepKeyHDWallet readonly _supportsCronos = false readonly _supportsUnichain = false readonly _supportsSoneium = false + readonly _supportsCitrea = false readonly _supportsBTC = true _supportsCosmos = true _supportsOsmosis = true diff --git a/packages/hdwallet-ledger/src/ledger.ts b/packages/hdwallet-ledger/src/ledger.ts index a9d4e1b9343..620b5865ee9 100644 --- a/packages/hdwallet-ledger/src/ledger.ts +++ b/packages/hdwallet-ledger/src/ledger.ts @@ -460,6 +460,7 @@ export class LedgerHDWallet readonly _supportsSui = true readonly _supportsTron = true readonly _supportsNear = true + readonly _supportsCitrea = true _isLedger = true diff --git a/packages/hdwallet-metamask-multichain/src/native-multichain.ts b/packages/hdwallet-metamask-multichain/src/native-multichain.ts index b970148202f..d012074c9c1 100644 --- a/packages/hdwallet-metamask-multichain/src/native-multichain.ts +++ b/packages/hdwallet-metamask-multichain/src/native-multichain.ts @@ -304,6 +304,7 @@ export class MetaMaskNativeMultiChainHDWallet readonly _supportsCronos = true readonly _supportsUnichain = true readonly _supportsSoneium = true + readonly _supportsCitrea = true readonly _supportsOsmosisInfo = false readonly _supportsOsmosis = false readonly _supportsBinanceInfo = false diff --git a/packages/hdwallet-metamask-multichain/src/shapeshift-multichain.ts b/packages/hdwallet-metamask-multichain/src/shapeshift-multichain.ts index 472fcee7638..5172aeacf66 100644 --- a/packages/hdwallet-metamask-multichain/src/shapeshift-multichain.ts +++ b/packages/hdwallet-metamask-multichain/src/shapeshift-multichain.ts @@ -316,6 +316,7 @@ export class MetaMaskMultiChainHDWallet readonly _supportsEos = false readonly _supportsThorchainInfo = true readonly _supportsThorchain = true + readonly _supportsCitrea = true info: MetaMaskMultiChainHDWalletInfo & core.HDWalletInfo bitcoinAddress?: string | null diff --git a/packages/hdwallet-native/src/ethereum.ts b/packages/hdwallet-native/src/ethereum.ts index f01d48ac42e..8fcbd59e5ce 100644 --- a/packages/hdwallet-native/src/ethereum.ts +++ b/packages/hdwallet-native/src/ethereum.ts @@ -92,6 +92,7 @@ export function MixinNativeETHWallet { - return [1, 10, 56, 100, 137, 43114, 2741].includes(chainId) + return [1, 10, 56, 100, 137, 43114, 2741, 4114].includes(chainId) } public async ethSupportsSecureTransfer(): Promise { @@ -234,6 +234,7 @@ export class WalletConnectV2HDWallet implements HDWallet, ETHWallet, BTCWallet { readonly _supportsCronos = true readonly _supportsUnichain = true readonly _supportsSoneium = true + readonly _supportsCitrea = true info: WalletConnectV2WalletInfo & HDWalletInfo provider: EthereumProvider diff --git a/packages/types/src/base.ts b/packages/types/src/base.ts index eeeb6313fb3..8125b4009d4 100644 --- a/packages/types/src/base.ts +++ b/packages/types/src/base.ts @@ -63,6 +63,7 @@ export enum KnownChainIds { StarknetMainnet = 'starknet:SN_MAIN', TonMainnet = 'ton:mainnet', AbstractMainnet = 'eip155:2741', + CitreaMainnet = 'eip155:4114', } export type EvmChainId = @@ -101,6 +102,7 @@ export type EvmChainId = | KnownChainIds.ModeMainnet | KnownChainIds.SoneiumMainnet | KnownChainIds.AbstractMainnet + | KnownChainIds.CitreaMainnet export type CosmosSdkChainId = | KnownChainIds.CosmosMainnet diff --git a/packages/utils/src/assetData/baseAssets.ts b/packages/utils/src/assetData/baseAssets.ts index 2274323a451..d88fd639b4c 100644 --- a/packages/utils/src/assetData/baseAssets.ts +++ b/packages/utils/src/assetData/baseAssets.ts @@ -857,3 +857,20 @@ export const ton: Readonly = Object.freeze({ explorerTxLink: 'https://tonscan.org/tx/', relatedAssetKey: null, }) + +export const citrea: Readonly = Object.freeze({ + assetId: caip.citreaAssetId, + chainId: caip.citreaChainId, + name: 'Citrea Bitcoin', + networkName: 'Citrea', + symbol: 'cBTC', + precision: 18, + color: '#F7931A', + networkColor: '#F7931A', + icon: 'https://assets.coingecko.com/coins/images/102172844/large/cBTC.png', + networkIcon: 'https://assets.coingecko.com/asset_platforms/images/102132293/small/citrea.jpg', + explorer: 'https://explorer.mainnet.citrea.xyz', + explorerAddressLink: 'https://explorer.mainnet.citrea.xyz/address/', + explorerTxLink: 'https://explorer.mainnet.citrea.xyz/tx/', + relatedAssetKey: null, +}) diff --git a/packages/utils/src/assetData/getBaseAsset.ts b/packages/utils/src/assetData/getBaseAsset.ts index 33e613002c7..fe0ea391c48 100644 --- a/packages/utils/src/assetData/getBaseAsset.ts +++ b/packages/utils/src/assetData/getBaseAsset.ts @@ -16,6 +16,7 @@ import { bnbsmartchain, bobChain, celo, + citrea, cronos, dogecoin, ethereal, @@ -156,6 +157,8 @@ export const getBaseAsset = (chainId: ChainId): Readonly => { return ton case KnownChainIds.AbstractMainnet: return abstract + case KnownChainIds.CitreaMainnet: + return citrea default: return assertUnreachable(knownChainId) } diff --git a/packages/utils/src/chainIdToFeeAssetId.ts b/packages/utils/src/chainIdToFeeAssetId.ts index 01a9bfab4bb..3ac7ef1ac2e 100644 --- a/packages/utils/src/chainIdToFeeAssetId.ts +++ b/packages/utils/src/chainIdToFeeAssetId.ts @@ -11,6 +11,7 @@ import { bscAssetId, btcAssetId, celoAssetId, + citreaAssetId, cosmosAssetId, cronosAssetId, dogeAssetId, @@ -155,6 +156,8 @@ export const chainIdToFeeAssetId = (_chainId: ChainId): AssetId => { return tonAssetId case KnownChainIds.AbstractMainnet: return abstractAssetId + case KnownChainIds.CitreaMainnet: + return citreaAssetId default: return assertUnreachable(chainId) } diff --git a/packages/utils/src/getAssetNamespaceFromChainId.ts b/packages/utils/src/getAssetNamespaceFromChainId.ts index 107b891cb36..db1a413817d 100644 --- a/packages/utils/src/getAssetNamespaceFromChainId.ts +++ b/packages/utils/src/getAssetNamespaceFromChainId.ts @@ -49,6 +49,7 @@ export const getAssetNamespaceFromChainId = (chainId: KnownChainIds): AssetNames case KnownChainIds.FlowEvmMainnet: case KnownChainIds.CeloMainnet: case KnownChainIds.AbstractMainnet: + case KnownChainIds.CitreaMainnet: return ASSET_NAMESPACE.erc20 case KnownChainIds.StarknetMainnet: return ASSET_NAMESPACE.starknetToken diff --git a/packages/utils/src/getChainShortName.ts b/packages/utils/src/getChainShortName.ts index a5012b04e34..7e1b7f3b8e1 100644 --- a/packages/utils/src/getChainShortName.ts +++ b/packages/utils/src/getChainShortName.ts @@ -102,6 +102,8 @@ export const getChainShortName = (chainId: KnownChainIds) => { return 'TON' case KnownChainIds.AbstractMainnet: return 'ABS' + case KnownChainIds.CitreaMainnet: + return 'citrea' default: { assertUnreachable(chainId) } diff --git a/packages/utils/src/getNativeFeeAssetReference.ts b/packages/utils/src/getNativeFeeAssetReference.ts index 53862e88e3d..f4ec5789097 100644 --- a/packages/utils/src/getNativeFeeAssetReference.ts +++ b/packages/utils/src/getNativeFeeAssetReference.ts @@ -94,6 +94,8 @@ export const getNativeFeeAssetReference = ( return ASSET_REFERENCE.Mode case CHAIN_REFERENCE.SoneiumMainnet: return ASSET_REFERENCE.Soneium + case CHAIN_REFERENCE.CitreaMainnet: + return ASSET_REFERENCE.Citrea default: throw new Error(`Chain namespace ${chainNamespace} on ${chainReference} not supported.`) } diff --git a/public/generated/asset-manifest.json b/public/generated/asset-manifest.json index 3cc2743eebb..93d0c5069c1 100644 --- a/public/generated/asset-manifest.json +++ b/public/generated/asset-manifest.json @@ -1,4 +1,4 @@ { - "assetData": "d38a9fe9", - "relatedAssetIndex": "b8be8a11" + "assetData": "57569f03", + "relatedAssetIndex": "6aa3811a" } \ No newline at end of file diff --git a/public/generated/asset-manifest.json.br b/public/generated/asset-manifest.json.br index 37b0ed113fa..c220e89bd0e 100644 Binary files a/public/generated/asset-manifest.json.br and b/public/generated/asset-manifest.json.br differ diff --git a/public/generated/asset-manifest.json.gz b/public/generated/asset-manifest.json.gz index 0264e9900c9..f246bf9cf39 100644 Binary files a/public/generated/asset-manifest.json.gz and b/public/generated/asset-manifest.json.gz differ diff --git a/public/generated/generatedAssetData.json b/public/generated/generatedAssetData.json index 1bcf05249aa..0f6e048bb8e 100644 --- a/public/generated/generatedAssetData.json +++ b/public/generated/generatedAssetData.json @@ -341388,6 +341388,152 @@ "explorerAddressLink": "https://tronscan.org/#/address/", "explorerTxLink": "https://tronscan.org/#/transaction/", "relatedAssetKey": null + }, + "eip155:4114/erc20:0x1b70ae756b1089cc5948e4f8a2ad498df30e897d": { + "assetId": "eip155:4114/erc20:0x1b70ae756b1089cc5948e4f8a2ad498df30e897d", + "chainId": "eip155:4114", + "name": "Savings Vault JUSD (Citrea)", + "precision": 18, + "color": "#FFFFFF", + "icon": "https://assets.coingecko.com/coins/images/102172892/large/JuiceDollar_Coinlogo.png?1776439475", + "symbol": "SVJUSD", + "explorer": "https://explorer.mainnet.citrea.xyz", + "explorerAddressLink": "https://explorer.mainnet.citrea.xyz/address/", + "explorerTxLink": "https://explorer.mainnet.citrea.xyz/tx/", + "relatedAssetKey": null + }, + "eip155:4114/erc20:0x2a36f2b204b46fd82653cd06d00c7ff757c99ae4": { + "assetId": "eip155:4114/erc20:0x2a36f2b204b46fd82653cd06d00c7ff757c99ae4", + "chainId": "eip155:4114", + "name": "Juice Protocol", + "precision": 18, + "color": "#FFFFFF", + "icon": "https://assets.coingecko.com/coins/images/102172950/large/juice.png?1776783178", + "symbol": "JUICE", + "explorer": "https://explorer.mainnet.citrea.xyz", + "explorerAddressLink": "https://explorer.mainnet.citrea.xyz/address/", + "explorerTxLink": "https://explorer.mainnet.citrea.xyz/tx/", + "relatedAssetKey": null + }, + "eip155:4114/erc20:0x3100000000000000000000000000000000000006": { + "assetId": "eip155:4114/erc20:0x3100000000000000000000000000000000000006", + "chainId": "eip155:4114", + "name": "Wrapped Citrea Bitcoin", + "precision": 18, + "color": "#FFFFFF", + "icon": "https://assets.coingecko.com/coins/images/102172843/large/cBTC.png?1776227743", + "symbol": "WCBTC", + "explorer": "https://explorer.mainnet.citrea.xyz", + "explorerAddressLink": "https://explorer.mainnet.citrea.xyz/address/", + "explorerTxLink": "https://explorer.mainnet.citrea.xyz/tx/", + "relatedAssetKey": null + }, + "eip155:4114/erc20:0x384157027b1cdeac4e26e3709667bb28735379bb": { + "assetId": "eip155:4114/erc20:0x384157027b1cdeac4e26e3709667bb28735379bb", + "chainId": "eip155:4114", + "name": "Symbiosis BTC (Citrea)", + "precision": 8, + "color": "#FFFFFF", + "icon": "https://assets.coingecko.com/coins/images/102172893/large/syBTC.png?1776440292", + "symbol": "SYBTC", + "explorer": "https://explorer.mainnet.citrea.xyz", + "explorerAddressLink": "https://explorer.mainnet.citrea.xyz/address/", + "explorerTxLink": "https://explorer.mainnet.citrea.xyz/tx/", + "relatedAssetKey": null + }, + "eip155:4114/erc20:0x547afd93b9c47d552059feb556909e017f8a9b25": { + "assetId": "eip155:4114/erc20:0x547afd93b9c47d552059feb556909e017f8a9b25", + "chainId": "eip155:4114", + "name": "Citrea", + "precision": 18, + "color": "#FFFFFF", + "icon": "https://assets.coingecko.com/coins/images/102173169/large/CTR.png?1778226916", + "symbol": "CTR", + "explorer": "https://explorer.mainnet.citrea.xyz", + "explorerAddressLink": "https://explorer.mainnet.citrea.xyz/address/", + "explorerTxLink": "https://explorer.mainnet.citrea.xyz/tx/", + "relatedAssetKey": null + }, + "eip155:4114/erc20:0x8d82c4e3c936c7b5724a382a9c5a4e6eb7ab6d5d": { + "assetId": "eip155:4114/erc20:0x8d82c4e3c936c7b5724a382a9c5a4e6eb7ab6d5d", + "chainId": "eip155:4114", + "name": "Citrea USD", + "precision": 6, + "color": "#FFFFFF", + "icon": "https://assets.coingecko.com/coins/images/71615/large/ctUSD.png?1776133927", + "symbol": "CTUSD", + "explorer": "https://explorer.mainnet.citrea.xyz", + "explorerAddressLink": "https://explorer.mainnet.citrea.xyz/address/", + "explorerTxLink": "https://explorer.mainnet.citrea.xyz/tx/", + "relatedAssetKey": null + }, + "eip155:4114/erc20:0x9f3096bac87e7f03dc09b0b416eb0df837304dc4": { + "assetId": "eip155:4114/erc20:0x9f3096bac87e7f03dc09b0b416eb0df837304dc4", + "chainId": "eip155:4114", + "name": "Citrea Bridged USDT (Citrea)", + "precision": 6, + "color": "#FFFFFF", + "icon": "https://assets.coingecko.com/coins/images/102172831/large/usdt.png?1776134144", + "symbol": "USDT.E", + "explorer": "https://explorer.mainnet.citrea.xyz", + "explorerAddressLink": "https://explorer.mainnet.citrea.xyz/address/", + "explorerTxLink": "https://explorer.mainnet.citrea.xyz/tx/", + "relatedAssetKey": "eip155:1/erc20:0xdac17f958d2ee523a2206206994597c13d831ec7" + }, + "eip155:4114/erc20:0xac8c1aeb584765db16ac3e08d4736cfce198589b": { + "assetId": "eip155:4114/erc20:0xac8c1aeb584765db16ac3e08d4736cfce198589b", + "chainId": "eip155:4114", + "name": "Generic USD", + "precision": 18, + "color": "#FFFFFF", + "icon": "https://assets.coingecko.com/coins/images/71672/large/GUSD.png?1769242841", + "symbol": "GUSD", + "explorer": "https://explorer.mainnet.citrea.xyz", + "explorerAddressLink": "https://explorer.mainnet.citrea.xyz/address/", + "explorerTxLink": "https://explorer.mainnet.citrea.xyz/tx/", + "relatedAssetKey": null + }, + "eip155:4114/erc20:0xdf240dc08b0fdad1d93b74d5048871232f6bea3d": { + "assetId": "eip155:4114/erc20:0xdf240dc08b0fdad1d93b74d5048871232f6bea3d", + "chainId": "eip155:4114", + "name": "Citrea Bridged WBTC (Citrea)", + "precision": 8, + "color": "#FFFFFF", + "icon": "https://assets.coingecko.com/coins/images/102172832/large/wbtc.png?1776134474", + "symbol": "WBTC.E", + "explorer": "https://explorer.mainnet.citrea.xyz", + "explorerAddressLink": "https://explorer.mainnet.citrea.xyz/address/", + "explorerTxLink": "https://explorer.mainnet.citrea.xyz/tx/", + "relatedAssetKey": "eip155:1/erc20:0x2260fac5e5542a773aa44fbcfedf7c193bc2c599" + }, + "eip155:4114/erc20:0xe045e6c36cf77faa2cfb54466d71a3aef7bbe839": { + "assetId": "eip155:4114/erc20:0xe045e6c36cf77faa2cfb54466d71a3aef7bbe839", + "chainId": "eip155:4114", + "name": "Citrea Bridged USDC (Citrea)", + "precision": 6, + "color": "#FFFFFF", + "icon": "https://assets.coingecko.com/coins/images/102172830/large/usdc.png?1776133757", + "symbol": "USDC.E", + "explorer": "https://explorer.mainnet.citrea.xyz", + "explorerAddressLink": "https://explorer.mainnet.citrea.xyz/address/", + "explorerTxLink": "https://explorer.mainnet.citrea.xyz/tx/", + "relatedAssetKey": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + }, + "eip155:4114/slip44:60": { + "assetId": "eip155:4114/slip44:60", + "chainId": "eip155:4114", + "name": "Citrea Bitcoin", + "networkName": "Citrea", + "symbol": "cBTC", + "precision": 18, + "color": "#F7931A", + "networkColor": "#F7931A", + "icon": "https://assets.coingecko.com/coins/images/102172844/large/cBTC.png", + "networkIcon": "https://assets.coingecko.com/asset_platforms/images/102132293/small/citrea.jpg", + "explorer": "https://explorer.mainnet.citrea.xyz", + "explorerAddressLink": "https://explorer.mainnet.citrea.xyz/address/", + "explorerTxLink": "https://explorer.mainnet.citrea.xyz/tx/", + "relatedAssetKey": null } }, "ids": [ @@ -366473,6 +366619,17 @@ "eip155:1/erc20:0x750c3a0a0ce9984eeb8c5d146dff024b584e5e33", "eip155:324/erc20:0x3355df6d4c9c3035724fd0e3914de96a5a83aaf4", "eip155:324/erc20:0xbbeb516fb02a01611cbbe0453fe3c580d7281011", - "eip155:8453/erc20:0x3054e8f8fba3055a42e5f5228a2a4e2ab1326933" + "eip155:8453/erc20:0x3054e8f8fba3055a42e5f5228a2a4e2ab1326933", + "eip155:4114/erc20:0x1b70ae756b1089cc5948e4f8a2ad498df30e897d", + "eip155:4114/erc20:0x2a36f2b204b46fd82653cd06d00c7ff757c99ae4", + "eip155:4114/erc20:0x3100000000000000000000000000000000000006", + "eip155:4114/erc20:0x384157027b1cdeac4e26e3709667bb28735379bb", + "eip155:4114/erc20:0x547afd93b9c47d552059feb556909e017f8a9b25", + "eip155:4114/erc20:0x8d82c4e3c936c7b5724a382a9c5a4e6eb7ab6d5d", + "eip155:4114/erc20:0x9f3096bac87e7f03dc09b0b416eb0df837304dc4", + "eip155:4114/erc20:0xac8c1aeb584765db16ac3e08d4736cfce198589b", + "eip155:4114/erc20:0xdf240dc08b0fdad1d93b74d5048871232f6bea3d", + "eip155:4114/erc20:0xe045e6c36cf77faa2cfb54466d71a3aef7bbe839", + "eip155:4114/slip44:60" ] } \ No newline at end of file diff --git a/public/generated/generatedAssetData.json.br b/public/generated/generatedAssetData.json.br index 337a2bb3a9a..1ea8f395bc7 100644 Binary files a/public/generated/generatedAssetData.json.br and b/public/generated/generatedAssetData.json.br differ diff --git a/public/generated/generatedAssetData.json.gz b/public/generated/generatedAssetData.json.gz index 2af0bb92960..2617708180f 100644 Binary files a/public/generated/generatedAssetData.json.gz and b/public/generated/generatedAssetData.json.gz differ diff --git a/public/generated/relatedAssetIndex.json b/public/generated/relatedAssetIndex.json index d22e056cc41..f37bd9efb4b 100644 --- a/public/generated/relatedAssetIndex.json +++ b/public/generated/relatedAssetIndex.json @@ -1403,7 +1403,8 @@ "eip155:42220/erc20:0xd629eb00deced2a080b7ec630ef6ac117e614f1b", "eip155:534352/erc20:0x3c1bca5a656e69edcd0d4e36bebb3fcdaca60cf1", "eip155:8453/erc20:0x0555e30da8f98308edb960aa94c0db47230d2b9c", - "starknet:SN_MAIN/token:0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac" + "starknet:SN_MAIN/token:0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac", + "eip155:4114/erc20:0xdf240dc08b0fdad1d93b74d5048871232f6bea3d" ], "eip155:8453/erc20:0xc5fed7c8ccc75d8a72b601a66dffd7a489073f0b": [ "eip155:56/erc20:0x6ef2ffb38d64afe18ce782da280b300e358cfeaf", @@ -6017,7 +6018,8 @@ "eip155:42220/erc20:0xeb466342c4d449bc9f53a865d5cb90586f405215", "eip155:2741/erc20:0x84a71ccd554cc1b02749b35d22f684cc8ec987e1", "starknet:SN_MAIN/token:0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", - "starknet:SN_MAIN/token:0x033068f6539f8e6e6b131e6b2b814e6c34a5224bc66947c47dab9dfee93b35fb" + "starknet:SN_MAIN/token:0x033068f6539f8e6e6b131e6b2b814e6c34a5224bc66947c47dab9dfee93b35fb", + "eip155:4114/erc20:0xe045e6c36cf77faa2cfb54466d71a3aef7bbe839" ], "eip155:8453/erc20:0x9c632e6aaa3ea73f91554f8a3cb2ed2f29605e0c": [ "eip155:56/erc20:0x7324c7c0d95cebc73eea7e85cbaac0dbdf88a05b", @@ -8298,7 +8300,8 @@ "eip155:42220/erc20:0x48065fbbe25f71c9282ddf5e1cd6d6a887483d5e", "eip155:1/erc20:0x0f6b862e05a9b528b0002261f9eb616e6c4452e9", "ton:mainnet/jetton:EQBynBO23ywHy_CgarY9NK9FTz0yDsG82PtcbSTQgGoXwiuA", - "starknet:SN_MAIN/token:0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8" + "starknet:SN_MAIN/token:0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8", + "eip155:4114/erc20:0x9f3096bac87e7f03dc09b0b416eb0df837304dc4" ], "eip155:1/erc20:0xdb9783ca04bbd64fe2c6d7b9503a979b3de30729": [ "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:XsAsZLF4MmsvS1sDxRMrUz7REjHfwbC9UAMXSRBqgEB", diff --git a/public/generated/relatedAssetIndex.json.br b/public/generated/relatedAssetIndex.json.br index 443ea5ccd8a..d0258737803 100644 Binary files a/public/generated/relatedAssetIndex.json.br and b/public/generated/relatedAssetIndex.json.br differ diff --git a/public/generated/relatedAssetIndex.json.gz b/public/generated/relatedAssetIndex.json.gz index 6f16e038b44..0a1fbec0e3c 100644 Binary files a/public/generated/relatedAssetIndex.json.gz and b/public/generated/relatedAssetIndex.json.gz differ diff --git a/scripts/generateAssetData/citrea/index.ts b/scripts/generateAssetData/citrea/index.ts new file mode 100644 index 00000000000..ad2a2865442 --- /dev/null +++ b/scripts/generateAssetData/citrea/index.ts @@ -0,0 +1,11 @@ +import { citreaChainId } from '@shapeshiftoss/caip' +import type { Asset } from '@shapeshiftoss/types' +import { citrea, unfreeze } from '@shapeshiftoss/utils' + +import * as coingecko from '../coingecko' + +export const getAssets = async (): Promise => { + const assets = await coingecko.getAssets(citreaChainId) + + return [...assets, unfreeze(citrea)] +} diff --git a/scripts/generateAssetData/coingecko.ts b/scripts/generateAssetData/coingecko.ts index 8c83dbfeab8..4a88286b042 100644 --- a/scripts/generateAssetData/coingecko.ts +++ b/scripts/generateAssetData/coingecko.ts @@ -11,6 +11,7 @@ import { bobChainId, bscChainId, celoChainId, + citreaChainId, cronosChainId, ethChainId, flowEvmChainId, @@ -55,6 +56,7 @@ import { bnbsmartchain, bobChain, celo, + citrea, cronos, ethereum, flowEvm, @@ -443,6 +445,14 @@ export async function getAssets(chainId: ChainId): Promise { explorerAddressLink: ton.explorerAddressLink, explorerTxLink: ton.explorerTxLink, } + case citreaChainId: + return { + assetNamespace: ASSET_NAMESPACE.erc20, + category: adapters.chainIdToCoingeckoAssetPlatform(chainId), + explorer: citrea.explorer, + explorerAddressLink: citrea.explorerAddressLink, + explorerTxLink: citrea.explorerTxLink, + } default: throw new Error(`no coingecko token support for chainId: ${chainId}`) } diff --git a/scripts/generateAssetData/generateAssetData.ts b/scripts/generateAssetData/generateAssetData.ts index 6554fbd430e..c2cb298876e 100644 --- a/scripts/generateAssetData/generateAssetData.ts +++ b/scripts/generateAssetData/generateAssetData.ts @@ -32,6 +32,7 @@ import * as blast from './blast' import * as bnbsmartchain from './bnbsmartchain' import * as bob from './bob' import * as celo from './celo' +import * as citrea from './citrea' import { compressGeneratedAssets } from './compressAssets' import { ASSET_DATA_PATH, GENERATED_DIR, RELATED_ASSET_INDEX_PATH } from './constants' import * as cronos from './cronos' @@ -123,6 +124,7 @@ const generateAssetData = async () => { const suiAssets = await sui.getAssets() const tonAssets = await tonModule.getAssets() const nearAssets = await near.getAssets() + const citreaAssets = await citrea.getAssets() // all assets, included assets to be blacklisted const unfilteredAssetData: Asset[] = [ @@ -178,6 +180,7 @@ const generateAssetData = async () => { ...suiAssets, ...tonAssets, ...nearAssets, + ...citreaAssets, ] // remove blacklisted assets diff --git a/scripts/generateAssetData/generateRelatedAssetIndex/generateChainRelatedAssetIndex.ts b/scripts/generateAssetData/generateRelatedAssetIndex/generateChainRelatedAssetIndex.ts index 2f0592b6878..01278632db4 100644 --- a/scripts/generateAssetData/generateRelatedAssetIndex/generateChainRelatedAssetIndex.ts +++ b/scripts/generateAssetData/generateRelatedAssetIndex/generateChainRelatedAssetIndex.ts @@ -98,6 +98,10 @@ const manualRelatedAssetIndex: Record = { 'eip155:1/erc20:0x6b175474e89094c44da98b954eedeac495271d0f': [ 'eip155:59144/erc20:0x4af15ec2a0bd43db75dd04e62faa3b8ef36b00d5', ], + // Citrea Bridged WBTC (Zerion algo mis-mapped to ETH USDT — manual override to canonical ETH WBTC) + 'eip155:1/erc20:0x2260fac5e5542a773aa44fbcfedf7c193bc2c599': [ + 'eip155:4114/erc20:0xdf240dc08b0fdad1d93b74d5048871232f6bea3d', + ], // CRO on Ethereum <-> CRO native on Cronos 'eip155:1/erc20:0xa0b73e1ff0b80914ab6fe0444e65848c4c34450b': ['eip155:25/slip44:60'], // Native chain tokens as keys (isPrimary=true) with their Ethereum ERC20 counterparts as values diff --git a/scripts/generateAssetData/generateRelatedAssetIndex/generateRelatedAssetIndex.ts b/scripts/generateAssetData/generateRelatedAssetIndex/generateRelatedAssetIndex.ts index 8c6b98e686b..0f9e25760cc 100644 --- a/scripts/generateAssetData/generateRelatedAssetIndex/generateRelatedAssetIndex.ts +++ b/scripts/generateAssetData/generateRelatedAssetIndex/generateRelatedAssetIndex.ts @@ -93,6 +93,10 @@ const manualRelatedAssetIndex: Record = { 'eip155:1/erc20:0xdac17f958d2ee523a2206206994597c13d831ec7': [ 'eip155:146/erc20:0x6047828dc181963ba44974801ff68e538da5eaf9', ], + // Citrea Bridged WBTC (Zerion algo mis-mapped to ETH USDT — manual override to canonical ETH WBTC) + 'eip155:1/erc20:0x2260fac5e5542a773aa44fbcfedf7c193bc2c599': [ + 'eip155:4114/erc20:0xdf240dc08b0fdad1d93b74d5048871232f6bea3d', + ], } // Category → Canonical Asset mapping for bridged tokens diff --git a/src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx b/src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx index 5dce4648192..545b15eae25 100644 --- a/src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx +++ b/src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx @@ -5,6 +5,7 @@ import { blastAssetId, bobAssetId, celoAssetId, + citreaAssetId, cronosAssetId, etherealAssetId, flowEvmAssetId, @@ -91,6 +92,7 @@ export const queryFn = async () => { if (enabledFlags.Tron) assetIds.push(tronAssetId) if (enabledFlags.Berachain) assetIds.push(berachainAssetId) if (enabledFlags.Sui) assetIds.push(suiAssetId) + if (enabledFlags.Citrea) assetIds.push(citreaAssetId) for (const assetId of [...new Set(assetIds)]) { const asset = primaryAssets[assetId] diff --git a/src/config.ts b/src/config.ts index 662cb529474..c02650d29fe 100644 --- a/src/config.ts +++ b/src/config.ts @@ -91,6 +91,7 @@ const validators = { VITE_SUI_NODE_URL: url(), VITE_TON_NODE_URL: url(), VITE_NEAR_NODE_URL: url(), + VITE_CITREA_NODE_URL: url(), VITE_NEAR_NODE_URL_FALLBACK_1: url({ default: '' }), VITE_NEAR_NODE_URL_FALLBACK_2: url({ default: '' }), VITE_FASTNEAR_API_URL: url(), @@ -302,6 +303,7 @@ const validators = { VITE_FEATURE_PERFORMANCE_PROFILER: bool({ default: false }), VITE_FEATURE_AGENTIC_CHAT: bool({ default: false }), VITE_FEATURE_MM_NATIVE_MULTICHAIN: bool({ default: false }), + VITE_FEATURE_CITREA: bool({ default: false }), VITE_AGENTIC_SERVER_BASE_URL: url({ default: 'https://api.agent.shapeshift.com', }), diff --git a/src/constants/chains.ts b/src/constants/chains.ts index 53df38a0159..d4963e42ba3 100644 --- a/src/constants/chains.ts +++ b/src/constants/chains.ts @@ -38,6 +38,7 @@ export const SECOND_CLASS_CHAINS: readonly KnownChainIds[] = [ KnownChainIds.FlowEvmMainnet, KnownChainIds.CeloMainnet, KnownChainIds.AbstractMainnet, + KnownChainIds.CitreaMainnet, ] // returns known ChainIds as an array, excluding the ones that are currently flagged off @@ -82,6 +83,7 @@ export const knownChainIds = Object.values(KnownChainIds).filter(chainId => { if (chainId === KnownChainIds.CeloMainnet && !enabledFlags.Celo) return false if (chainId === KnownChainIds.TonMainnet && !enabledFlags.Ton) return false if (chainId === KnownChainIds.ZcashMainnet && !enabledFlags.Zcash) return false + if (chainId === KnownChainIds.CitreaMainnet && !enabledFlags.Citrea) return false return true }) diff --git a/src/context/PluginProvider/PluginProvider.tsx b/src/context/PluginProvider/PluginProvider.tsx index 4828d09a47b..0b4e0f6f999 100644 --- a/src/context/PluginProvider/PluginProvider.tsx +++ b/src/context/PluginProvider/PluginProvider.tsx @@ -149,6 +149,7 @@ export const PluginProvider = ({ children }: PluginProviderProps): JSX.Element = if (!featureFlags.Ton && chainId === KnownChainIds.TonMainnet) return false if (!featureFlags.Near && chainId === KnownChainIds.NearMainnet) return false if (!featureFlags.Zcash && chainId === KnownChainIds.ZcashMainnet) return false + if (!featureFlags.Citrea && chainId === KnownChainIds.CitreaMainnet) return false return true }) diff --git a/src/context/WalletProvider/WalletConnectV2/config.ts b/src/context/WalletProvider/WalletConnectV2/config.ts index 7e92034e8e1..9d4cfd01411 100644 --- a/src/context/WalletProvider/WalletConnectV2/config.ts +++ b/src/context/WalletProvider/WalletConnectV2/config.ts @@ -1,5 +1,5 @@ import { CHAIN_REFERENCE } from '@shapeshiftoss/caip' -import { flowEvmChain } from '@shapeshiftoss/contracts' +import { citrea, flowEvmChain } from '@shapeshiftoss/contracts' import type { WalletConnectV2Adapter } from '@shapeshiftoss/hdwallet-walletconnectv2' import type { Chain } from 'viem/chains' import { @@ -66,6 +66,8 @@ export const walletConnectV2OptionalChains: AtLeastOneViemChain = (() => { sei, abstract, + + citrea, ] if (optionalViemChains.length === 0) throw new Error('Array must contain at least one element.') return optionalViemChains as AtLeastOneViemChain @@ -90,6 +92,7 @@ const { VITE_INK_NODE_URL, VITE_FLOWEVM_NODE_URL, VITE_ABSTRACT_NODE_URL, + VITE_CITREA_NODE_URL, } = getConfig() export const walletConnectV2ProviderConfig: EthereumProviderOptions = { @@ -123,6 +126,7 @@ export const walletConnectV2ProviderConfig: EthereumProviderOptions = { [CHAIN_REFERENCE.InkMainnet]: VITE_INK_NODE_URL, [CHAIN_REFERENCE.FlowEvmMainnet]: VITE_FLOWEVM_NODE_URL, [CHAIN_REFERENCE.AbstractMainnet]: VITE_ABSTRACT_NODE_URL, + [CHAIN_REFERENCE.CitreaMainnet]: VITE_CITREA_NODE_URL, }, } diff --git a/src/hooks/useWalletSupportsChain/useWalletSupportsChain.ts b/src/hooks/useWalletSupportsChain/useWalletSupportsChain.ts index 61b56d3114a..96369389b7d 100644 --- a/src/hooks/useWalletSupportsChain/useWalletSupportsChain.ts +++ b/src/hooks/useWalletSupportsChain/useWalletSupportsChain.ts @@ -11,6 +11,7 @@ import { bscChainId, btcChainId, celoChainId, + citreaChainId, cosmosChainId, cronosChainId, dogeChainId, @@ -67,6 +68,7 @@ import { supportsBSC, supportsBTC, supportsCelo, + supportsCitrea, supportsCosmos, supportsCronos, supportsETH, @@ -224,6 +226,7 @@ export const walletSupportsChain = ({ const isStarknetEnabled = selectFeatureFlag(store.getState(), 'Starknet') const isWorldChainEnabled = selectFeatureFlag(store.getState(), 'WorldChain') const isTonEnabled = selectFeatureFlag(store.getState(), 'Ton') + const isCitreaEnabled = selectFeatureFlag(store.getState(), 'Citrea') switch (chainId) { case btcChainId: @@ -327,6 +330,8 @@ export const walletSupportsChain = ({ return isStarknetEnabled && supportsStarknet(wallet) case tonChainId: return isTonEnabled && supportsTon(wallet) + case citreaChainId: + return isCitreaEnabled && supportsCitrea(wallet) default: { return false } diff --git a/src/lib/account/evm.ts b/src/lib/account/evm.ts index 69b1b8240ba..85783233225 100644 --- a/src/lib/account/evm.ts +++ b/src/lib/account/evm.ts @@ -9,6 +9,7 @@ import { bobChainId, bscChainId, celoChainId, + citreaChainId, cronosChainId, ethChainId, etherealChainId, @@ -50,6 +51,7 @@ import { supportsBob, supportsBSC, supportsCelo, + supportsCitrea, supportsCronos, supportsETH, supportsEthereal, @@ -193,6 +195,7 @@ export const deriveEvmAccountIdsAndMetadata: DeriveAccountIdsAndMetadata = async if (chainId === bobChainId && !supportsBob(wallet)) continue if (chainId === modeChainId && !supportsMode(wallet)) continue if (chainId === soneiumChainId && !supportsSoneium(wallet)) continue + if (chainId === citreaChainId && !supportsCitrea(wallet)) continue if ( isMetaMask(wallet) && !canAddMetaMaskAccount({ accountNumber, chainId, wallet, isSnapInstalled }) diff --git a/src/lib/asset-service/service/AssetService.ts b/src/lib/asset-service/service/AssetService.ts index d1d79e0c90e..fe0758f5486 100644 --- a/src/lib/asset-service/service/AssetService.ts +++ b/src/lib/asset-service/service/AssetService.ts @@ -9,6 +9,7 @@ import { bobChainId, bscChainId, celoChainId, + citreaChainId, cronosChainId, etherealChainId, flowEvmChainId, @@ -172,6 +173,7 @@ class _AssetService { if (!config.VITE_FEATURE_ZCASH && asset.chainId === zecChainId) return false if (!config.VITE_FEATURE_STARKNET && asset.chainId === starknetChainId) return false if (!config.VITE_FEATURE_TON && asset.chainId === tonChainId) return false + if (!config.VITE_FEATURE_CITREA && asset.chainId === citreaChainId) return false return true }) diff --git a/src/lib/coingecko/utils.ts b/src/lib/coingecko/utils.ts index 67f9c11b98d..b58dfe78e0d 100644 --- a/src/lib/coingecko/utils.ts +++ b/src/lib/coingecko/utils.ts @@ -11,6 +11,7 @@ import { bscChainId, btcChainId, celoChainId, + citreaChainId, cosmosChainId, cronosChainId, dogeChainId, @@ -254,5 +255,6 @@ export const getCoingeckoSupportedChainIds = () => { ...(getConfig().VITE_FEATURE_TON ? [tonChainId] : []), ...(getConfig().VITE_FEATURE_FLOWEVM ? [flowEvmChainId] : []), ...(getConfig().VITE_FEATURE_CELO ? [celoChainId] : []), + ...(getConfig().VITE_FEATURE_CITREA ? [citreaChainId] : []), ] } diff --git a/src/lib/market-service/market-service-manager.ts b/src/lib/market-service/market-service-manager.ts index 57715596191..da0225f2779 100644 --- a/src/lib/market-service/market-service-manager.ts +++ b/src/lib/market-service/market-service-manager.ts @@ -19,6 +19,7 @@ import { ZerionMarketService } from './zerion/zerion' import type { AssetService } from '@/lib/asset-service' import { getAssetService } from '@/lib/asset-service' +import { bnOrZero } from '@/lib/bignumber/bignumber' export type ProviderUrls = { jsonRpcProviderUrl: string @@ -91,10 +92,12 @@ export class MarketServiceManager { : this.marketProviders // Loop through market providers and look for asset market data. Once found, exit loop. + // Treat price=0 as not-found so we fall through to related-asset lookup; some providers + // surface partial data (changePercent, marketCap) with a zero price. for (const provider of prioritizedProviders) { try { const data = await provider.findByAssetId({ assetId }) - if (data) return data + if (data && bnOrZero(data.price).gt(0)) return data } catch (e) { // Swallow error, not every asset will be with every provider. } diff --git a/src/pages/Markets/components/MarketsRow.tsx b/src/pages/Markets/components/MarketsRow.tsx index 03af8ca0daf..4fdbae6ae6e 100644 --- a/src/pages/Markets/components/MarketsRow.tsx +++ b/src/pages/Markets/components/MarketsRow.tsx @@ -106,6 +106,7 @@ export const MarketsRow: React.FC = ({ const isFlowEvmEnabled = useAppSelector(state => selectFeatureFlag(state, 'FlowEvm')) const isCeloEnabled = useAppSelector(state => selectFeatureFlag(state, 'Celo')) const isSeiEnabled = useAppSelector(state => selectFeatureFlag(state, 'Sei')) + const isCitreaEnabled = useAppSelector(state => selectFeatureFlag(state, 'Citrea')) const [isSmallerThanLg] = useMediaQuery(`(max-width: ${breakpoints.lg})`) const chainIds = useMemo(() => { @@ -139,6 +140,7 @@ export const MarketsRow: React.FC = ({ if (!isEtherealEnabled && chainId === KnownChainIds.EtherealMainnet) return false if (!isFlowEvmEnabled && chainId === KnownChainIds.FlowEvmMainnet) return false if (!isCeloEnabled && chainId === KnownChainIds.CeloMainnet) return false + if (!isCitreaEnabled && chainId === KnownChainIds.CitreaMainnet) return false return true }) }, [ @@ -170,6 +172,7 @@ export const MarketsRow: React.FC = ({ isFlowEvmEnabled, isCeloEnabled, isSeiEnabled, + isCitreaEnabled, ]) const Title = useMemo(() => { diff --git a/src/plugins/activePlugins.ts b/src/plugins/activePlugins.ts index 1e3aef28105..f2500975f8e 100644 --- a/src/plugins/activePlugins.ts +++ b/src/plugins/activePlugins.ts @@ -9,6 +9,7 @@ import blast from '@/plugins/blast' import bnbsmartchain from '@/plugins/bnbsmartchain' import bob from '@/plugins/bob' import celo from '@/plugins/celo' +import citrea from '@/plugins/citrea' import cosmos from '@/plugins/cosmos' import cronos from '@/plugins/cronos' import dogecoin from '@/plugins/dogecoin' @@ -102,4 +103,5 @@ export const activePlugins = [ zcash, zksyncera, abstract, + citrea, ] diff --git a/src/plugins/citrea/index.tsx b/src/plugins/citrea/index.tsx new file mode 100644 index 00000000000..63f59842cee --- /dev/null +++ b/src/plugins/citrea/index.tsx @@ -0,0 +1,49 @@ +import { citreaChainId, fromAssetId } from '@shapeshiftoss/caip' +import { citrea } from '@shapeshiftoss/chain-adapters' +import { KnownChainIds } from '@shapeshiftoss/types' + +import { getConfig } from '@/config' +import { getAssetService } from '@/lib/asset-service' +import type { Plugins } from '@/plugins/types' + +// eslint-disable-next-line import/no-default-export +export default function register(): Plugins { + return [ + [ + 'citreaChainAdapter', + { + name: 'citreaChainAdapter', + featureFlag: ['Citrea'], + providers: { + chainAdapters: [ + [ + KnownChainIds.CitreaMainnet, + () => { + const getKnownTokens = () => { + const assetService = getAssetService() + return assetService.assets + .filter(asset => { + const { chainId, assetNamespace } = fromAssetId(asset.assetId) + return chainId === citreaChainId && assetNamespace === 'erc20' + }) + .map(asset => ({ + assetId: asset.assetId, + contractAddress: fromAssetId(asset.assetId).assetReference, + symbol: asset.symbol, + name: asset.name, + precision: asset.precision, + })) + } + + return new citrea.ChainAdapter({ + rpcUrl: getConfig().VITE_CITREA_NODE_URL, + getKnownTokens, + }) + }, + ], + ], + }, + }, + ], + ] +} diff --git a/src/state/migrations/index.ts b/src/state/migrations/index.ts index 58c3c6d23ab..9353829d1bd 100644 --- a/src/state/migrations/index.ts +++ b/src/state/migrations/index.ts @@ -380,6 +380,8 @@ export const clearAssetsMigrations = { 331: clearAssets, 332: clearAssets, 333: clearAssets, + 334: clearAssets, + 335: clearAssets, } as unknown as Omit export const clearMarketDataMigrations = { diff --git a/src/state/slices/opportunitiesSlice/mappings.ts b/src/state/slices/opportunitiesSlice/mappings.ts index 5c02c9ef1c3..3d7dc1a0910 100644 --- a/src/state/slices/opportunitiesSlice/mappings.ts +++ b/src/state/slices/opportunitiesSlice/mappings.ts @@ -217,6 +217,7 @@ export const CHAIN_ID_TO_SUPPORTED_DEFI_OPPORTUNITIES: Record< [KnownChainIds.BlastMainnet]: [], [KnownChainIds.AbstractMainnet]: [], [KnownChainIds.HemiMainnet]: [], + [KnownChainIds.CitreaMainnet]: [], } // Single opportunity metadata resolvers diff --git a/src/state/slices/portfolioSlice/utils/index.ts b/src/state/slices/portfolioSlice/utils/index.ts index 9e4d64108b1..9a8bd1c8dec 100644 --- a/src/state/slices/portfolioSlice/utils/index.ts +++ b/src/state/slices/portfolioSlice/utils/index.ts @@ -13,6 +13,7 @@ import { btcChainId, celoChainId, CHAIN_NAMESPACE, + citreaChainId, cosmosChainId, cronosChainId, dogeChainId, @@ -73,6 +74,7 @@ import { supportsBSC, supportsBTC, supportsCelo, + supportsCitrea, supportsCosmos, supportsCronos, supportsETH, @@ -625,6 +627,8 @@ export const isAssetSupportedByWallet = (assetId: AssetId, wallet: HDWallet): bo return supportsNear(wallet) case tonChainId: return supportsTon(wallet) + case citreaChainId: + return supportsCitrea(wallet) default: return false } diff --git a/src/state/slices/preferencesSlice/preferencesSlice.ts b/src/state/slices/preferencesSlice/preferencesSlice.ts index 898fad5e6f8..4278ce9ecdc 100644 --- a/src/state/slices/preferencesSlice/preferencesSlice.ts +++ b/src/state/slices/preferencesSlice/preferencesSlice.ts @@ -60,6 +60,7 @@ export type FeatureFlags = { Bob: boolean Mode: boolean Soneium: boolean + Citrea: boolean Zcash: boolean ThorSwap: boolean WalletConnectToDapps: boolean @@ -312,6 +313,7 @@ const initialState: Preferences = { YieldMultiAccount: getConfig().VITE_FEATURE_YIELD_MULTI_ACCOUNT, EarnTab: getConfig().VITE_FEATURE_EARN_TAB, MmNativeMultichain: getConfig().VITE_FEATURE_MM_NATIVE_MULTICHAIN, + Citrea: getConfig().VITE_FEATURE_CITREA, }, selectedLocale: simpleLocale(), hasWalletSeenTcyClaimAlert: {}, diff --git a/src/test/mocks/store.ts b/src/test/mocks/store.ts index 8ee38716dcf..77ca9323e37 100644 --- a/src/test/mocks/store.ts +++ b/src/test/mocks/store.ts @@ -212,6 +212,7 @@ export const mockStore: ReduxState = { EarnTab: false, AgenticChat: false, MmNativeMultichain: false, + Citrea: false, }, showTopAssetsCarousel: true, quickBuyAmounts: [10, 50, 100], diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 6d9e156f17c..e4dc950d855 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -220,8 +220,10 @@ interface ImportMetaEnv { readonly VITE_ETHEREAL_NODE_URL: string readonly VITE_FEATURE_ETHEREAL: string readonly VITE_SEI_NODE_URL: string + readonly VITE_CITREA_NODE_URL: string readonly VITE_FEATURE_SEI: string readonly VITE_FEATURE_NOTIFICATIONS_WEBSERVICES: string + readonly VITE_FEATURE_CITREA: string // Only present in *some* envs readonly VITE_MIXPANEL_TOKEN?: string