@pancakeswap/token-lists 0.0.17 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +13 -13
- package/CHANGELOG.md +19 -0
- package/dist/{chunk-DC45HQOL.mjs → chunk-UUVLERWJ.mjs} +1 -60
- package/dist/{chunk-YOAEDKQH.js → chunk-Y2NTTLTJ.js} +0 -62
- package/dist/index.d.ts +35 -3
- package/dist/index.js +74 -15
- package/dist/index.mjs +72 -1
- package/dist/react.d.ts +51 -10
- package/dist/react.js +325 -92
- package/dist/react.mjs +311 -85
- package/dist/{types-92a8b029.d.ts → types-dcc7ec4a.d.ts} +1 -0
- package/package.json +4 -3
- package/react/actions.ts +11 -0
- package/react/geoBlock.test.ts +68 -0
- package/react/getTokenList.test.ts +54 -0
- package/react/getTokenList.ts +2 -3
- package/react/index.test.ts +6 -0
- package/react/lists.ts +307 -27
- package/react/reducer.ts +34 -53
- package/react/reducerHelpers.ts +111 -0
- package/react/useFetchListCallback.ts +1 -1
- package/schema/pancakeswap.json +18 -9
- package/src/index.test.ts +1 -0
- package/src/index.ts +1 -0
- package/src/scaledUIAmount.ts +41 -0
- package/src/types.ts +1 -0
- package/src/wrappedTokenInfo.ts +8 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { getVersionUpgrade, VersionUpgrade } from '../src/getVersionUpgrade'
|
|
2
|
+
import { TokenList } from '../src/types'
|
|
3
|
+
|
|
4
|
+
// Mutable state type for reducer operations
|
|
5
|
+
type MutableListsState = {
|
|
6
|
+
byUrl: {
|
|
7
|
+
[url: string]: {
|
|
8
|
+
current: TokenList | null
|
|
9
|
+
pendingUpdate: TokenList | null
|
|
10
|
+
loadingRequestId: string | null
|
|
11
|
+
error: string | null
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
lastInitializedDefaultListOfLists?: string[]
|
|
15
|
+
activeListUrls: string[] | undefined
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Core function to set a single list to pending state
|
|
20
|
+
*/
|
|
21
|
+
export const setPendingTokenList = (state: MutableListsState, url: string, requestId: string): void => {
|
|
22
|
+
const current = state.byUrl[url]?.current ?? null
|
|
23
|
+
const pendingUpdate = state.byUrl[url]?.pendingUpdate ?? null
|
|
24
|
+
|
|
25
|
+
state.byUrl[url] = {
|
|
26
|
+
current,
|
|
27
|
+
pendingUpdate,
|
|
28
|
+
loadingRequestId: requestId,
|
|
29
|
+
error: null,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Core function to set a single list to fulfilled state
|
|
35
|
+
*/
|
|
36
|
+
export const setFulfilledTokenList = (
|
|
37
|
+
state: MutableListsState,
|
|
38
|
+
url: string,
|
|
39
|
+
tokenList: TokenList,
|
|
40
|
+
requestId: string,
|
|
41
|
+
DEFAULT_ACTIVE_LIST_URLS: string[],
|
|
42
|
+
): boolean => {
|
|
43
|
+
const current = state.byUrl[url]?.current
|
|
44
|
+
const loadingRequestId = state.byUrl[url]?.loadingRequestId
|
|
45
|
+
|
|
46
|
+
// no-op if update does nothing
|
|
47
|
+
if (current) {
|
|
48
|
+
const upgradeType = getVersionUpgrade(current.version, tokenList.version)
|
|
49
|
+
|
|
50
|
+
if (upgradeType === VersionUpgrade.NONE) return false
|
|
51
|
+
if (loadingRequestId === null || loadingRequestId === requestId) {
|
|
52
|
+
state.byUrl[url] = {
|
|
53
|
+
...state.byUrl[url],
|
|
54
|
+
loadingRequestId: null,
|
|
55
|
+
error: null,
|
|
56
|
+
current,
|
|
57
|
+
pendingUpdate: tokenList,
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return false // not a new list, so no activation needed
|
|
61
|
+
}
|
|
62
|
+
// activate if on default active
|
|
63
|
+
if (DEFAULT_ACTIVE_LIST_URLS.includes(url) && state.activeListUrls && !state.activeListUrls.includes(url)) {
|
|
64
|
+
state.activeListUrls.push(url)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
state.byUrl[url] = {
|
|
68
|
+
...state.byUrl[url],
|
|
69
|
+
loadingRequestId: null,
|
|
70
|
+
error: null,
|
|
71
|
+
current: tokenList,
|
|
72
|
+
pendingUpdate: null,
|
|
73
|
+
}
|
|
74
|
+
return true // new list, might need activation
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Core function to set a single list to rejected state
|
|
79
|
+
*/
|
|
80
|
+
export const setRejectedTokenList = (
|
|
81
|
+
state: MutableListsState,
|
|
82
|
+
url: string,
|
|
83
|
+
requestId: string,
|
|
84
|
+
errorMessage: string,
|
|
85
|
+
): void => {
|
|
86
|
+
if (state.byUrl[url]?.loadingRequestId !== requestId) {
|
|
87
|
+
// no-op since it's not the latest request
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
state.byUrl[url] = {
|
|
92
|
+
...state.byUrl[url],
|
|
93
|
+
loadingRequestId: null,
|
|
94
|
+
error: errorMessage,
|
|
95
|
+
current: null,
|
|
96
|
+
pendingUpdate: null,
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Batch activate URLs if needed
|
|
102
|
+
*/
|
|
103
|
+
export const batchActivateUrls = (state: MutableListsState, urls: string[]): void => {
|
|
104
|
+
if (urls.length > 0 && state.activeListUrls) {
|
|
105
|
+
urls.forEach((url) => {
|
|
106
|
+
if (!state.activeListUrls!.includes(url)) {
|
|
107
|
+
state.activeListUrls!.push(url)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -26,7 +26,7 @@ function useFetchListCallback(
|
|
|
26
26
|
return tokenList
|
|
27
27
|
})
|
|
28
28
|
.catch((error) => {
|
|
29
|
-
console.
|
|
29
|
+
console.warn(`Failed to get list at url ${listUrl}`, error)
|
|
30
30
|
if (sendDispatch) {
|
|
31
31
|
dispatch(fetchTokenList.rejected({ url: listUrl, requestId, errorMessage: error.message }))
|
|
32
32
|
}
|
package/schema/pancakeswap.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
{
|
|
12
12
|
"major": 1,
|
|
13
13
|
"minor": 0,
|
|
14
|
-
"patch":
|
|
14
|
+
"patch": 1
|
|
15
15
|
}
|
|
16
16
|
],
|
|
17
17
|
"additionalProperties": false,
|
|
@@ -196,17 +196,17 @@
|
|
|
196
196
|
"type": "string",
|
|
197
197
|
"description": "The name of the token",
|
|
198
198
|
"minLength": 1,
|
|
199
|
-
"maxLength":
|
|
200
|
-
"pattern": "^[ \\w.'
|
|
201
|
-
"examples": ["USD Coin"]
|
|
199
|
+
"maxLength": 60,
|
|
200
|
+
"pattern": "^[ \\w.'+\\-%/,\\$À-ÖØ-öø-ÿ:&\\[\\]\\(\\)\\u4e00-\\u9fa5]+$",
|
|
201
|
+
"examples": ["USD Coin", "币安币"]
|
|
202
202
|
},
|
|
203
203
|
"symbol": {
|
|
204
204
|
"type": "string",
|
|
205
205
|
"description": "The symbol for the token; must be alphanumeric",
|
|
206
|
-
"pattern": "^[a-zA-Z0-9+\\-%/$.\\
|
|
206
|
+
"pattern": "^[a-zA-Z0-9+\\-%/$.\\s_\\u4e00-\\u9fa5]+$",
|
|
207
207
|
"minLength": 1,
|
|
208
208
|
"maxLength": 20,
|
|
209
|
-
"examples": ["USDC"]
|
|
209
|
+
"examples": ["USDC", "币安"]
|
|
210
210
|
},
|
|
211
211
|
"logoURI": {
|
|
212
212
|
"type": "string",
|
|
@@ -256,14 +256,14 @@
|
|
|
256
256
|
"type": "string",
|
|
257
257
|
"description": "The name of the token",
|
|
258
258
|
"minLength": 1,
|
|
259
|
-
"maxLength":
|
|
260
|
-
"pattern": "^[ \\w.'
|
|
259
|
+
"maxLength": 60,
|
|
260
|
+
"pattern": "^[ \\w.'+\\-%/,\\$À-ÖØ-öø-ÿ:&\\[\\]\\(\\)]+$",
|
|
261
261
|
"examples": ["USD Coin"]
|
|
262
262
|
},
|
|
263
263
|
"symbol": {
|
|
264
264
|
"type": "string",
|
|
265
265
|
"description": "The symbol for the token; must be alphanumeric",
|
|
266
|
-
"pattern": "^[a-zA-Z0-9+\\-%/$.]+$",
|
|
266
|
+
"pattern": "^[a-zA-Z0-9+\\-%/$._]+$",
|
|
267
267
|
"minLength": 1,
|
|
268
268
|
"maxLength": 20,
|
|
269
269
|
"examples": ["USDC"]
|
|
@@ -356,6 +356,15 @@
|
|
|
356
356
|
"description": "A URI for the logo of the token list; prefer SVG or PNG of size 256x256",
|
|
357
357
|
"format": "uri",
|
|
358
358
|
"examples": ["ipfs://QmXfzKRvjZz3u5JRgC4v5mGVbm9ahrUiB4DgzHBsnWbTMM"]
|
|
359
|
+
},
|
|
360
|
+
"extensions": {
|
|
361
|
+
"type": "object",
|
|
362
|
+
"description": "An object containing arbitrary or vendor-specific token list metadata",
|
|
363
|
+
"propertyNames": {
|
|
364
|
+
"$ref": "#/definitions/ExtensionIdentifier"
|
|
365
|
+
},
|
|
366
|
+
"additionalProperties": true,
|
|
367
|
+
"maxProperties": 10
|
|
359
368
|
}
|
|
360
369
|
},
|
|
361
370
|
"if": {
|
package/src/index.test.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Token-list `extensions.scaledUIAmount` metadata for ERC-8056 (Scaled UI Amount) tokens.
|
|
2
|
+
//
|
|
3
|
+
// Curated by the indexer/CMS at ingestion time. The boolean `enabled` flag is the
|
|
4
|
+
// load-bearing FE-side check; other fields are snapshots / hints (the live multiplier
|
|
5
|
+
// is always re-read from chain via the `useScaledUIAmountMetadata` hook).
|
|
6
|
+
//
|
|
7
|
+
// See BNB Chain partner integration doc v1.0 (8 Apr 2026) §8.2.4 for the upstream
|
|
8
|
+
// shape this is modeled after.
|
|
9
|
+
|
|
10
|
+
import type { TokenInfo } from './types'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Static metadata identifying an ERC-8056 (Scaled UI Amount) token in a token list.
|
|
14
|
+
* `enabled: true` is the only field FE consumes for routing decisions; everything
|
|
15
|
+
* else is hint/snapshot data refreshed live from chain.
|
|
16
|
+
*/
|
|
17
|
+
export interface ScaledUIAmountExtension {
|
|
18
|
+
/** Set to `true` for tokens that implement ERC-8056. The load-bearing FE check. */
|
|
19
|
+
enabled: boolean
|
|
20
|
+
/** Optional snapshot of the live multiplier at the time of indexing (18-decimal fixed). */
|
|
21
|
+
multiplier?: string
|
|
22
|
+
/** Optional human-readable multiplier (e.g. `"2.0"`). Display hint only. */
|
|
23
|
+
multiplierFormatted?: string
|
|
24
|
+
/** ERC-165 interface IDs the contract claims to support. */
|
|
25
|
+
interfaceIds?: string[]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Returns true if a token-list entry is flagged as ERC-8056 enabled by the indexer.
|
|
30
|
+
* Tokens lacking the extension or with `enabled: false` are treated as standard ERC-20s
|
|
31
|
+
* (identity multiplier `1.0×`); the FE never falls into ScaledUI math for these.
|
|
32
|
+
*
|
|
33
|
+
* Note: the load-bearing decision lives here, not on the `Token` class. Token
|
|
34
|
+
* instances stay pure identity objects per the architectural decision in the
|
|
35
|
+
* implementation doc.
|
|
36
|
+
*/
|
|
37
|
+
export function isScaledUIAmountToken(token: Pick<TokenInfo, 'extensions'>): boolean {
|
|
38
|
+
const ext = token.extensions?.scaledUIAmount
|
|
39
|
+
if (!ext || typeof ext !== 'object' || Array.isArray(ext)) return false
|
|
40
|
+
return (ext as { enabled?: unknown }).enabled === true
|
|
41
|
+
}
|
package/src/types.ts
CHANGED
package/src/wrappedTokenInfo.ts
CHANGED
|
@@ -17,9 +17,17 @@ export interface SerializedWrappedToken extends SerializedToken {
|
|
|
17
17
|
export class WrappedTokenInfo extends Token {
|
|
18
18
|
public readonly logoURI: string | undefined
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Preserves the token-list `extensions` bag (curator-set metadata like
|
|
22
|
+
* `bridgeInfo`, `scaledUIAmount.enabled`, etc.). Stored as a readonly reference;
|
|
23
|
+
* not serialised back out of the class (kept in-memory only).
|
|
24
|
+
*/
|
|
25
|
+
public readonly extensions: TokenInfo['extensions']
|
|
26
|
+
|
|
20
27
|
constructor(tokenInfo: TokenInfo) {
|
|
21
28
|
super(tokenInfo.chainId, tokenInfo.address, tokenInfo.decimals, tokenInfo.symbol, tokenInfo.name)
|
|
22
29
|
this.logoURI = tokenInfo.logoURI
|
|
30
|
+
this.extensions = tokenInfo.extensions
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
public get serialize(): SerializedWrappedToken {
|