Skip to content

Commit e2dcaa2

Browse files
authored
fix: group assets for sui and tron (#11453)
1 parent 4f2dd78 commit e2dcaa2

File tree

7 files changed

+66
-62
lines changed

7 files changed

+66
-62
lines changed

packages/types/src/zerion.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@ import {
66
bscChainId,
77
ethChainId,
88
gnosisChainId,
9+
monadChainId,
910
optimismChainId,
11+
plasmaChainId,
1012
polygonChainId,
13+
solanaChainId,
14+
suiChainId,
15+
tronChainId,
1116
} from '@shapeshiftoss/caip'
1217

1318
export const ZERION_CHAINS = [
@@ -20,10 +25,14 @@ export const ZERION_CHAINS = [
2025
'arbitrum',
2126
'xdai',
2227
'base',
28+
'solana',
29+
'tron',
30+
'monad',
31+
'sui',
32+
'plasma',
2333
// not yet
2434
// 'aurora',
2535
// 'fantom',
26-
// 'solana',
2736
] as const
2837

2938
export type ZerionChainId = (typeof ZERION_CHAINS)[number]
@@ -37,6 +46,11 @@ export const ZERION_CHAINS_MAP: Record<ZerionChainId, ChainId> = {
3746
arbitrum: arbitrumChainId,
3847
xdai: gnosisChainId,
3948
base: baseChainId,
49+
solana: solanaChainId,
50+
tron: tronChainId,
51+
monad: monadChainId,
52+
sui: suiChainId,
53+
plasma: plasmaChainId,
4054
}
4155

4256
export const zerionChainIdToChainId = (chainId: ZerionChainId): ChainId | undefined =>

packages/utils/src/getAssetNamespaceFromChainId.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ export const getAssetNamespaceFromChainId = (chainId: KnownChainIds): AssetNames
99
case KnownChainIds.SolanaMainnet:
1010
return ASSET_NAMESPACE.splToken
1111
case KnownChainIds.SuiMainnet:
12-
return ASSET_NAMESPACE.slip44
12+
return ASSET_NAMESPACE.suiCoin
13+
case KnownChainIds.TronMainnet:
14+
return ASSET_NAMESPACE.trc20
1315
case KnownChainIds.EthereumMainnet:
1416
case KnownChainIds.AvalancheMainnet:
1517
case KnownChainIds.OptimismMainnet:
@@ -31,7 +33,6 @@ export const getAssetNamespaceFromChainId = (chainId: KnownChainIds): AssetNames
3133
case KnownChainIds.ZcashMainnet:
3234
case KnownChainIds.ThorchainMainnet:
3335
case KnownChainIds.MayachainMainnet:
34-
case KnownChainIds.TronMainnet:
3536
throw Error(`Unhandled case '${chainId}'`)
3637
default:
3738
return assertUnreachable(chainId)

scripts/generateAssetData/generateRelatedAssetIndex/generateRelatedAssetIndex.ts

Lines changed: 39 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
fromAssetId,
1212
optimismAssetId,
1313
} from '@shapeshiftoss/caip'
14-
import { isEvmChainId } from '@shapeshiftoss/chain-adapters'
1514
import type { Asset } from '@shapeshiftoss/types'
1615
import {
1716
createThrottle,
@@ -92,6 +91,8 @@ const chunkArray = <T>(array: T[], chunkSize: number) => {
9291
return result
9392
}
9493

94+
const PLASMA_USDT0_ASSET_ID = 'eip155:9745/erc20:0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb'
95+
9596
const getZerionRelatedAssetIds = async (
9697
assetId: AssetId,
9798
assetData: Record<AssetId, PartialFields<Asset, 'relatedAssetKey'>>,
@@ -106,9 +107,9 @@ const getZerionRelatedAssetIds = async (
106107
},
107108
}
108109

109-
const { chainId, assetReference } = fromAssetId(assetId)
110+
const { assetReference } = fromAssetId(assetId)
110111

111-
if (!isEvmChainId(chainId) || FEE_ASSET_IDS.includes(assetId)) return
112+
if (FEE_ASSET_IDS.includes(assetId)) return
112113

113114
const filter = { params: { 'filter[implementation_address]': assetReference } }
114115
const url = '/fungibles'
@@ -131,11 +132,14 @@ const getZerionRelatedAssetIds = async (
131132

132133
const implementations = firstEntry.attributes.implementations
133134

134-
// Use all assetIds actually present in the dataset
135+
// Use all assetIds actually present in the dataset, excluding Plasma USDT0 (corrupt CoinGecko data)
135136
const allRelatedAssetIds = implementations
136137
?.map(zerionImplementationToMaybeAssetId)
137138
.filter(isSome)
138-
.filter(relatedAssetId => assetData[relatedAssetId] !== undefined)
139+
.filter(relatedAssetId => {
140+
return assetData[relatedAssetId] !== undefined
141+
})
142+
.filter(relatedAssetId => relatedAssetId !== PLASMA_USDT0_ASSET_ID)
139143

140144
if (!allRelatedAssetIds || allRelatedAssetIds.length <= 1) {
141145
return
@@ -161,11 +165,12 @@ const getCoingeckoRelatedAssetIds = async (
161165

162166
const platforms = data.platforms
163167

164-
// Use all assetIds actually present in the dataset
168+
// Use all assetIds actually present in the dataset, excluding Plasma USDT0 (corrupt CoinGecko data)
165169
const allRelatedAssetIds = Object.entries(platforms)
166170
?.map(coingeckoPlatformDetailsToMaybeAssetId)
167171
.filter(isSome)
168172
.filter(relatedAssetId => assetData[relatedAssetId] !== undefined)
173+
.filter(relatedAssetId => relatedAssetId !== PLASMA_USDT0_ASSET_ID)
169174

170175
if (allRelatedAssetIds.length <= 1) {
171176
return
@@ -185,12 +190,11 @@ const processRelatedAssetIds = async (
185190
assetId: AssetId,
186191
assetData: Record<AssetId, PartialFields<Asset, 'relatedAssetKey'>>,
187192
relatedAssetIndex: Record<AssetId, AssetId[]>,
188-
coingeckoPlatformsByAssetId: Record<AssetId, number>,
189193
throttle: () => Promise<void>,
190194
): Promise<void> => {
191195
// Skip related asset generation for Plasma usdt0 - Coingecko has corrupt data claiming
192196
// it shares the same Arbitrum/Polygon contracts as real USDT, which corrupts groupings
193-
if (assetId === 'eip155:9745/erc20:0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb') {
197+
if (assetId === PLASMA_USDT0_ASSET_ID) {
194198
assetData[assetId].relatedAssetKey = null
195199
await throttle()
196200
return
@@ -202,18 +206,6 @@ const processRelatedAssetIds = async (
202206
return
203207
}
204208

205-
// For assets with relatedAssetKey: null or undefined, check if CoinGecko now has multiple platforms
206-
// This optimization skips expensive API calls for assets that only exist on one chain
207-
if (existingRelatedAssetKey === null || existingRelatedAssetKey === undefined) {
208-
const platformCount = coingeckoPlatformsByAssetId[assetId]
209-
if (platformCount === undefined || platformCount <= 1) {
210-
assetData[assetId].relatedAssetKey = null
211-
// Still no related assets upstream, skip expensive API calls
212-
await throttle()
213-
return
214-
}
215-
}
216-
217209
console.log(`Processing related assetIds for ${assetId}`)
218210

219211
// Check if this asset is already in the relatedAssetIndex
@@ -225,7 +217,7 @@ const processRelatedAssetIds = async (
225217
)
226218
assetData[assetId].relatedAssetKey = key
227219
}
228-
return // Else, early return as this asset is already processed
220+
return // Early return - asset already processed and grouped
229221
}
230222
}
231223

@@ -264,22 +256,37 @@ const processRelatedAssetIds = async (
264256
relatedAssetIds: [],
265257
}
266258

267-
const relatedAssetKey =
259+
let relatedAssetKey =
268260
manualRelatedAssetsResult?.relatedAssetKey ||
269261
zerionRelatedAssetsResult?.relatedAssetKey ||
270262
coingeckoRelatedAssetsResult?.relatedAssetKey ||
271263
assetId
272264

265+
// If the relatedAssetKey itself points to another key, follow the chain to find the actual key
266+
// This handles the case where Tron WETH -> ETH WETH, but ETH WETH -> Arbitrum WETH
267+
const relatedAssetKeyData = assetData[relatedAssetKey]?.relatedAssetKey
268+
if (relatedAssetKeyData) {
269+
relatedAssetKey = relatedAssetKeyData
270+
}
271+
272+
// If the relatedAssetKey is Plasma USDT0, reject this entire grouping
273+
if (relatedAssetKey === PLASMA_USDT0_ASSET_ID) {
274+
assetData[assetId].relatedAssetKey = null
275+
await throttle()
276+
return
277+
}
278+
273279
const zerionRelatedAssetIds = zerionRelatedAssetsResult?.relatedAssetIds ?? []
274280
const coingeckoRelatedAssetIds = coingeckoRelatedAssetsResult?.relatedAssetIds ?? []
281+
275282
const mergedRelatedAssetIds = Array.from(
276283
new Set([
277284
...manualRelatedAssetIds,
278285
...zerionRelatedAssetIds,
279286
...coingeckoRelatedAssetIds,
280287
assetId,
281288
]),
282-
)
289+
).filter(id => id !== PLASMA_USDT0_ASSET_ID) // Filter out Plasma USDT0 from final merged array
283290

284291
// Has zerion-provided related assets, or manually added ones
285292
const hasRelatedAssets = mergedRelatedAssetIds.length > 1
@@ -290,13 +297,17 @@ const processRelatedAssetIds = async (
290297
const isAlreadyGrouped = existingGroup && existingGroup.includes(assetId)
291298

292299
if (!isAlreadyGrouped) {
293-
// This is the first asset in this group to be processed, set up the group
294-
relatedAssetIndex[relatedAssetKey] = mergedRelatedAssetIds
300+
// Merge with existing group instead of replacing it
301+
const currentGroup = relatedAssetIndex[relatedAssetKey] || []
302+
relatedAssetIndex[relatedAssetKey] = Array.from(
303+
new Set([...currentGroup, ...mergedRelatedAssetIds]),
304+
)
295305
}
296306

297307
// Always ensure all assets in the group have the correct relatedAssetKey
298308
// This handles both new groups and updates from parallel processing
299-
for (const relatedAssetId of mergedRelatedAssetIds) {
309+
const allAssetsInGroup = relatedAssetIndex[relatedAssetKey]
310+
for (const relatedAssetId of allAssetsInGroup) {
300311
if (assetData[relatedAssetId]) {
301312
assetData[relatedAssetId].relatedAssetKey = relatedAssetKey
302313
}
@@ -321,26 +332,6 @@ export const generateRelatedAssetIndex = async () => {
321332
const { assetData: generatedAssetData, sortedAssetIds } = decodeAssetData(encodedAssetData)
322333
const relatedAssetIndex = decodeRelatedAssetIndex(encodedRelatedAssetIndex, sortedAssetIds)
323334

324-
const coingeckoData = await adapters.fetchCoingeckoData(adapters.coingeckoUrl)
325-
326-
const coingeckoPlatformsByAssetId = coingeckoData.reduce<Record<AssetId, number>>((acc, coin) => {
327-
const supportedPlatforms = Object.entries(coin.platforms)
328-
.map(([platform, address]) => {
329-
try {
330-
return coingeckoPlatformDetailsToMaybeAssetId([platform, address])
331-
} catch {
332-
return undefined
333-
}
334-
})
335-
.filter(isSome)
336-
337-
for (const assetId of supportedPlatforms) {
338-
acc[assetId] = supportedPlatforms.length
339-
}
340-
341-
return acc
342-
}, {})
343-
344335
// Remove stale related asset data from the assetData where:
345336
// a) the primary related asset no longer exists in the dataset
346337
// b) the related asset key is Plasma usdt0 (corrupt Coingecko data)
@@ -376,18 +367,13 @@ export const generateRelatedAssetIndex = async () => {
376367
drainPerInterval: 25, // Adjusted drain rate to replenish at a sustainable pace
377368
intervalMs: 2000,
378369
})
370+
379371
const chunks = chunkArray(Object.keys(generatedAssetData), BATCH_SIZE)
380372
for (const [i, batch] of chunks.entries()) {
381373
console.log(`Processing chunk: ${i} of ${chunks.length}`)
382374
await Promise.all(
383375
batch.map(async assetId => {
384-
await processRelatedAssetIds(
385-
assetId,
386-
generatedAssetData,
387-
relatedAssetIndex,
388-
coingeckoPlatformsByAssetId,
389-
throttle,
390-
)
376+
await processRelatedAssetIds(assetId, generatedAssetData, relatedAssetIndex, throttle)
391377
return
392378
}),
393379
)

scripts/generateAssetData/generateRelatedAssetIndex/validators/fungible.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ const ImplementationSchema = z.object({
2020
export type ZerionImplementation = Infer<typeof ImplementationSchema>
2121

2222
const ChangesSchema = z.object({
23-
percent_1d: z.number().nullable(),
24-
percent_30d: z.number().nullable(),
25-
percent_90d: z.number().nullable(),
26-
percent_365d: z.number().nullable(),
23+
percent_1d: z.number().nullable().optional(),
24+
percent_30d: z.number().nullable().optional(),
25+
percent_90d: z.number().nullable().optional(),
26+
percent_365d: z.number().nullable().optional(),
2727
})
2828

2929
const MarketDataSchema = z.object({
@@ -67,6 +67,7 @@ const RelationshipsSchema = z.object({
6767
chart_month: ChartSchema,
6868
chart_week: ChartSchema,
6969
chart_year: ChartSchema,
70+
chart_3months: ChartSchema,
7071
})
7172

7273
const LinksSchema = z.object({

src/lib/asset-service/service/encodedAssetData.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

src/lib/asset-service/service/encodedRelatedAssetIndex.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

src/state/migrations/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,8 @@ export const clearAssetsMigrations = {
291291
244: clearAssets,
292292
245: clearAssets,
293293
246: clearAssets,
294+
247: clearAssets,
295+
248: clearAssets,
294296
} as unknown as Omit<MigrationManifest, '_persist'>
295297

296298
export const clearMarketDataMigrations = {

0 commit comments

Comments
 (0)