@w3lib/evm-batch-call 0.1.0 → 0.3.0

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.
Files changed (77) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +194 -12
  3. package/dist/aggregate.d.ts +5 -2
  4. package/dist/aggregate.d.ts.map +1 -1
  5. package/dist/aggregate.js.map +1 -1
  6. package/dist/call.d.ts +8 -2
  7. package/dist/call.d.ts.map +1 -1
  8. package/dist/call.js +25 -1
  9. package/dist/call.js.map +1 -1
  10. package/dist/chains.d.ts +13 -0
  11. package/dist/chains.d.ts.map +1 -0
  12. package/dist/chains.js +35 -0
  13. package/dist/chains.js.map +1 -0
  14. package/dist/detect.d.ts +23 -0
  15. package/dist/detect.d.ts.map +1 -0
  16. package/dist/detect.js +178 -0
  17. package/dist/detect.js.map +1 -0
  18. package/dist/erc20.d.ts +83 -7
  19. package/dist/erc20.d.ts.map +1 -1
  20. package/dist/erc20.js +36 -5
  21. package/dist/erc20.js.map +1 -1
  22. package/dist/fallback.d.ts +25 -0
  23. package/dist/fallback.d.ts.map +1 -1
  24. package/dist/fallback.js +123 -21
  25. package/dist/fallback.js.map +1 -1
  26. package/dist/index.d.ts +10 -3
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +9 -2
  29. package/dist/index.js.map +1 -1
  30. package/dist/nft.d.ts +71 -0
  31. package/dist/nft.d.ts.map +1 -0
  32. package/dist/nft.js +194 -0
  33. package/dist/nft.js.map +1 -0
  34. package/dist/owner.d.ts +136 -0
  35. package/dist/owner.d.ts.map +1 -0
  36. package/dist/owner.js +501 -0
  37. package/dist/owner.js.map +1 -0
  38. package/dist/provider.d.ts +112 -12
  39. package/dist/provider.d.ts.map +1 -1
  40. package/dist/provider.js +343 -48
  41. package/dist/provider.js.map +1 -1
  42. package/dist/scan.d.ts +59 -0
  43. package/dist/scan.d.ts.map +1 -0
  44. package/dist/scan.js +245 -0
  45. package/dist/scan.js.map +1 -0
  46. package/dist/shortcuts.d.ts +113 -0
  47. package/dist/shortcuts.d.ts.map +1 -0
  48. package/dist/shortcuts.js +193 -0
  49. package/dist/shortcuts.js.map +1 -0
  50. package/dist/source.d.ts +23 -1
  51. package/dist/source.d.ts.map +1 -1
  52. package/dist/source.js +110 -3
  53. package/dist/source.js.map +1 -1
  54. package/dist/tron.d.ts +6 -0
  55. package/dist/tron.d.ts.map +1 -1
  56. package/dist/tron.js +16 -1
  57. package/dist/tron.js.map +1 -1
  58. package/dist/util.d.ts +6 -0
  59. package/dist/util.d.ts.map +1 -0
  60. package/dist/util.js +20 -0
  61. package/dist/util.js.map +1 -0
  62. package/package.json +3 -2
  63. package/src/aggregate.ts +5 -2
  64. package/src/call.ts +32 -3
  65. package/src/chains.ts +46 -0
  66. package/src/detect.ts +193 -0
  67. package/src/erc20.ts +111 -9
  68. package/src/fallback.ts +127 -23
  69. package/src/index.ts +90 -4
  70. package/src/nft.ts +298 -0
  71. package/src/owner.ts +651 -0
  72. package/src/provider.ts +458 -54
  73. package/src/scan.ts +293 -0
  74. package/src/shortcuts.ts +278 -0
  75. package/src/source.ts +118 -3
  76. package/src/tron.ts +21 -2
  77. package/src/util.ts +20 -0
package/dist/scan.js ADDED
@@ -0,0 +1,245 @@
1
+ import { errorText, GetLogsError } from './fallback.js';
2
+ import { isTronChain } from './source.js';
3
+ /** ERC20 / ERC721 的 Transfer(address,address,uint256) 事件 */
4
+ const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
5
+ /** 内存存储(默认):最多保存 1000 个地址,超出时淘汰最早的 */
6
+ export function memoryScanStorage(limit = 1000) {
7
+ const map = new Map();
8
+ return {
9
+ get: (key) => map.get(key),
10
+ set: (key, state) => {
11
+ map.delete(key);
12
+ map.set(key, state);
13
+ if (map.size > limit) {
14
+ map.delete(map.keys().next().value);
15
+ }
16
+ },
17
+ };
18
+ }
19
+ /**
20
+ * 基于 getItem / setItem 的存储(如浏览器的 localStorage):
21
+ * `transferScan({ storage: keyValueScanStorage(localStorage) })`
22
+ */
23
+ export function keyValueScanStorage(store, prefix = 'w3lib:transfer-scan:') {
24
+ return {
25
+ get: (key) => {
26
+ try {
27
+ const raw = store.getItem(prefix + key);
28
+ return raw ? JSON.parse(raw) : undefined; // 格式在读取后校验
29
+ }
30
+ catch {
31
+ return undefined;
32
+ }
33
+ },
34
+ set: (key, state) => {
35
+ try {
36
+ store.setItem(prefix + key, JSON.stringify(state));
37
+ }
38
+ catch {
39
+ // 存储满或不可用:只影响下次能否接着扫
40
+ }
41
+ },
42
+ };
43
+ }
44
+ const defaultStorage = memoryScanStorage();
45
+ /** 节点不开放 getLogs 时,暂停多久再试 */
46
+ const PAUSE_ON_UNSUPPORTED = 10 * 60 * 1000;
47
+ /** 记下的区块范围上限多久后失效(节点可能换了 / 调整了限制) */
48
+ const RANGE_LIMIT_TTL = 24 * 60 * 60 * 1000;
49
+ /** 连续成功多少次后把范围翻倍 */
50
+ const GROW_AFTER = 2;
51
+ /** 按节点返回的错误信息分类 */
52
+ function kindOf(text) {
53
+ if (/too many|rate.?limit|429|temporarily|unavailable|busy|timed? ?out|timeout|network|ECONN|ENOTFOUND|socket|fetch failed|missing response|bad response|50[234]|quota|credits|compute units/i.test(text)) {
54
+ return 'transient'; // 限频 / 超时 / 连不上:换个时间重试即可
55
+ }
56
+ if (/range|too (?:large|wide|big)|exceed|query returned more than|more than \d+ (?:results|logs)|response size|block limit/i.test(text)) {
57
+ return 'range';
58
+ }
59
+ if (/method not found|-32601|not supported|unsupported|not available|does not exist|not (?:allowed|enabled|whitelisted)|disabled/i.test(text)) {
60
+ return 'unsupported';
61
+ }
62
+ return 'other';
63
+ }
64
+ /** 每个节点的错误;GetLogsError 里没有错误表示没有节点支持 getLogs */
65
+ function errorTexts(err) {
66
+ if (err instanceof GetLogsError) {
67
+ return err.errors.length ? err.errors.map(errorText) : ['getLogs is not supported'];
68
+ }
69
+ return [errorText(err)];
70
+ }
71
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
72
+ /** 从错误信息里找区块范围上限,如 “log query range must not exceed 25 blocks”“maximum block range: 5000” */
73
+ function parseRangeLimit(texts) {
74
+ let best = null;
75
+ for (const raw of texts) {
76
+ const text = raw.replace(/(\d),(?=\d{3}\b)/g, '$1'); // 10,000 → 10000
77
+ const match = /(?:exceed|maximum|max|limit(?:ed)? (?:of|to)?|up to|range)[^\d]{0,40}?(\d{1,7})\s*blocks?/i.exec(text) ??
78
+ /(\d{1,7})\s*blocks?[^.]{0,20}(?:range|limit|maximum)/i.exec(text) ??
79
+ /block range[^\d]{0,20}(\d{1,7})/i.exec(text);
80
+ const n = match ? Number(match[1]) : NaN;
81
+ if (Number.isInteger(n) && n > 0 && (best === null || n > best)) {
82
+ best = n; // 多个节点给了不同上限时取最大的(能用的节点里最宽松的那个)
83
+ }
84
+ }
85
+ return best;
86
+ }
87
+ const isInt = (value, min) => Number.isSafeInteger(value) && value >= min;
88
+ const isTime = (value) => typeof value === 'number' && Number.isFinite(value);
89
+ /** 校验存储里读出的进度:格式不对(旧版本 / 被改坏)时丢弃,重新开始 */
90
+ function parseState(raw) {
91
+ const s = raw;
92
+ if (!s || typeof s !== 'object' || !isInt(s.startBlock, 0) || !isInt(s.cursor, -1) || !isInt(s.blockRange, 1) || !Array.isArray(s.tokens)) {
93
+ return undefined;
94
+ }
95
+ if (!s.tokens.every((t) => typeof t === 'string' && /^0x[0-9a-fA-F]{40}$/.test(t))) {
96
+ return undefined;
97
+ }
98
+ return {
99
+ startBlock: s.startBlock,
100
+ cursor: s.cursor,
101
+ tokens: s.tokens.map((t) => t.toLowerCase()),
102
+ blockRange: s.blockRange,
103
+ ...(isInt(s.rangeLimit, 1) && isTime(s.rangeLimitAt) ? { rangeLimit: s.rangeLimit, rangeLimitAt: s.rangeLimitAt } : {}),
104
+ ...(isTime(s.pausedUntil) ? { pausedUntil: s.pausedUntil } : {}),
105
+ };
106
+ }
107
+ async function loadState(storage, key) {
108
+ try {
109
+ return parseState(await storage.get(key));
110
+ }
111
+ catch {
112
+ return undefined;
113
+ }
114
+ }
115
+ /**
116
+ * 增量扫描地址收到的 ERC20 代币(Transfer 事件,to = 该地址):第一次调用记下当前区块,之后每次从上次的位置往后扫。
117
+ * 用来补充代币列表发现不了的新代币。作为代币来源使用:`combine(defaultTokenSource(), transferScan())`,
118
+ * 或在 getOwnerTokens 里用 `scanTransfers: true`。
119
+ *
120
+ * 局限:只能发现开始扫描之后收到的代币(除非设置 lookbackBlocks);需要节点支持 eth_getLogs,免费公共节点限制较多
121
+ *(BSC 上只有 blockrazor 可用且每次最多 25 个区块);Tron 不支持。
122
+ */
123
+ export function transferScan(options = {}) {
124
+ const storage = options.storage ?? defaultStorage;
125
+ const lookback = Math.max(0, Math.floor(options.lookbackBlocks ?? 0));
126
+ const maxRange = Math.max(1, Math.floor(options.blockRange ?? 1000));
127
+ const maxRequests = Math.max(1, options.maxRequests ?? 20);
128
+ const timeBudget = options.timeBudget ?? 5000;
129
+ const confirmations = Math.max(0, Math.floor(options.confirmations ?? 5));
130
+ return {
131
+ name: 'transfers',
132
+ async discover({ chainId, owner, provider }) {
133
+ if (!provider || isTronChain(chainId) || !/^0x[0-9a-fA-F]{40}$/.test(owner)) {
134
+ return null;
135
+ }
136
+ const key = `${chainId}:${owner.toLowerCase()}`;
137
+ const saved = await loadState(storage, key);
138
+ const toResult = (state) => (state?.tokens ?? []).map((address) => ({ address }));
139
+ if (saved?.pausedUntil && Date.now() < saved.pausedUntil) {
140
+ return toResult(saved);
141
+ }
142
+ const startedAt = Date.now();
143
+ let target;
144
+ try {
145
+ target = (await provider.getBlockNumber()) - confirmations;
146
+ }
147
+ catch {
148
+ return saved ? toResult(saved) : null; // 节点不支持 / 暂时不可用:返回已发现的代币
149
+ }
150
+ const now = Date.now();
151
+ let state;
152
+ if (saved) {
153
+ state = { ...saved, tokens: [...saved.tokens] };
154
+ delete state.pausedUntil;
155
+ if (state.rangeLimitAt !== undefined && now - state.rangeLimitAt > RANGE_LIMIT_TTL) {
156
+ delete state.rangeLimit;
157
+ delete state.rangeLimitAt;
158
+ }
159
+ }
160
+ else {
161
+ const cursor = Math.max(-1, target - lookback);
162
+ state = { startBlock: cursor + 1, cursor, tokens: [], blockRange: maxRange };
163
+ }
164
+ const tokens = new Set(state.tokens);
165
+ const ownerTopic = `0x${owner.slice(2).toLowerCase().padStart(64, '0')}`;
166
+ const cap = () => Math.min(maxRange, state.rangeLimit ?? maxRange);
167
+ const setLimit = (limit) => {
168
+ state.rangeLimit = limit;
169
+ state.rangeLimitAt = Date.now();
170
+ };
171
+ let range = Math.min(state.blockRange, cap());
172
+ let successes = 0;
173
+ let transient = 0;
174
+ for (let requests = 0; requests < maxRequests && state.cursor < target; requests++) {
175
+ if (timeBudget > 0 && Date.now() - startedAt >= timeBudget) {
176
+ break; // 超出时间预算,留到下次调用
177
+ }
178
+ const fromBlock = state.cursor + 1;
179
+ const toBlock = Math.min(target, fromBlock + range - 1);
180
+ try {
181
+ const logs = await provider.getLogs({ fromBlock, toBlock, topics: [TRANSFER_TOPIC, null, ownerTopic] });
182
+ for (const log of logs) {
183
+ // ERC20 的 Transfer 有 3 个 topic;ERC721 的 tokenId 也是 indexed,有 4 个,排除
184
+ if (log.topics.length === 3) {
185
+ tokens.add(log.address.toLowerCase());
186
+ }
187
+ }
188
+ state.cursor = toBlock;
189
+ transient = 0;
190
+ if (++successes >= GROW_AFTER && range < cap()) {
191
+ range = Math.min(cap(), range * 2); // 之前缩小过(偶发错误 / 换了节点):逐步放大回去
192
+ successes = 0;
193
+ }
194
+ }
195
+ catch (err) {
196
+ successes = 0;
197
+ const texts = errorTexts(err);
198
+ const kinds = texts.map(kindOf);
199
+ // 上次成功的节点这次的错误最能说明问题(其他节点可能一直就不能用,它们的报错不代表当前范围有问题)
200
+ const preferred = err instanceof GetLogsError && err.preferred !== undefined ? kindOf(errorText(err.preferred)) : undefined;
201
+ const limit = parseRangeLimit(texts);
202
+ if (limit !== null && limit < range) {
203
+ range = limit; // 节点明确给了范围上限
204
+ setLimit(limit);
205
+ }
206
+ else if (kinds.every((k) => k === 'unsupported')) {
207
+ // 所有节点都不开放 getLogs:暂停一段时间,避免每次调用都白发请求
208
+ state.pausedUntil = Date.now() + PAUSE_ON_UNSUPPORTED;
209
+ break;
210
+ }
211
+ else if (preferred === 'transient' || (preferred === undefined && kinds.every((k) => k === 'transient' || k === 'unsupported'))) {
212
+ // 在用的节点只是限频 / 超时:不缩小范围,退避后重试;连续 3 次就留到下次调用
213
+ const remaining = timeBudget > 0 ? timeBudget - (Date.now() - startedAt) : Infinity;
214
+ if (++transient >= 3 || remaining <= 0) {
215
+ break;
216
+ }
217
+ await sleep(Math.min(500 * transient, remaining));
218
+ }
219
+ else if (range > 1) {
220
+ range = Math.max(1, Math.floor(range / 2)); // 范围超限但没说上限:减半再试
221
+ setLimit(range);
222
+ }
223
+ else {
224
+ state.pausedUntil = Date.now() + PAUSE_ON_UNSUPPORTED; // 连 1 个区块都查不了
225
+ break;
226
+ }
227
+ }
228
+ }
229
+ state.blockRange = range;
230
+ state.tokens = [...tokens];
231
+ try {
232
+ await storage.set(key, state);
233
+ }
234
+ catch {
235
+ // 存储不可用:只影响下次能否接着扫
236
+ }
237
+ return toResult(state);
238
+ },
239
+ };
240
+ }
241
+ /** 读取某地址的扫描进度(不存在时为 undefined) */
242
+ export async function getTransferScanState(chainId, owner, storage = defaultStorage) {
243
+ return loadState(storage, `${chainId}:${owner.toLowerCase()}`);
244
+ }
245
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,113 @@
1
+ import type { CallOverrides } from './aggregate.js';
2
+ import type { OwnedToken, OwnerTokensOptions } from './owner.js';
3
+ import type { BalanceToken, DefaultTokenField, TokenAllowance, TokenBalance, TokenDetails, TokenField } from './erc20.js';
4
+ import type { DefaultNftCollectionField, Erc1155Balance, NftBalance, NftCollection, NftCollectionField, NftCollectionsOptions, NftItem, NftOwner, NftTokenUri } from './nft.js';
5
+ import { Provider, type BalancesOptions, type ProviderConfig, type TokensOptions } from './provider.js';
6
+ import type { ProviderSource } from './source.js';
7
+ /** getBalances / getTokens 共用的节点参数 */
8
+ export interface ShortcutProviderOptions extends ProviderConfig {
9
+ /** 链 ID。传了 provider 时可省略(从节点识别,结果会缓存);不传 provider 时必填(用于选择内置公共节点) */
10
+ chainId?: number | string;
11
+ /**
12
+ * 节点,与 `new Provider(...)` 相同,不传则使用内置公共节点:
13
+ * - RPC URL,或 URL 数组(主节点 + 备用节点)
14
+ * - ethers Provider
15
+ * - 浏览器插件钱包:`window.ethereum`(EIP-1193)、`window.tronWeb`
16
+ * - 混合数组,如 `[window.ethereum, 'https://…']`:钱包出错或不在这条链上时自动用后面的节点
17
+ */
18
+ provider?: ProviderSource | readonly ProviderSource[];
19
+ }
20
+ export interface GetBalancesOptions extends BalancesOptions, ShortcutProviderOptions {
21
+ }
22
+ export interface GetTokensOptions<F extends TokenField = DefaultTokenField> extends TokensOptions<F>, ShortcutProviderOptions {
23
+ }
24
+ export interface ShortcutOptions extends CallOverrides, ShortcutProviderOptions {
25
+ }
26
+ /**
27
+ * 批量查余额(主币 + 代币,一次请求),返回原始余额、decimals 和换算后的数值。
28
+ *
29
+ * ```ts
30
+ * import { NATIVE_TOKEN, getBalances } from '@w3lib/evm-batch-call'
31
+ *
32
+ * await getBalances(user, [NATIVE_TOKEN, USDT], { chainId: 56 }) // 内置公共节点
33
+ * await getBalances(user, tokens, { provider: window.ethereum }) // 钱包,chainId 自动识别
34
+ * await getBalances(user, tokens, { provider: 'https://bsc-dataseed.bnbchain.org' })
35
+ * await getBalances(user, tokens, { chainId: 56, provider: [window.ethereum, 'https://…'] }) // 钱包优先,失败用公共节点
36
+ * await getBalances(user, tokens, { chainId: 56, symbol: true }) // 同时返回 symbol
37
+ * // [{ token: NATIVE_TOKEN, native: true, balance: '1500000000000000000', decimals: 18, formatted: '1.5', success: true }, ...]
38
+ * ```
39
+ */
40
+ export declare function getBalances(owner: string, tokens: readonly BalanceToken[], options?: GetBalancesOptions): Promise<TokenBalance[]>;
41
+ /**
42
+ * 批量查 ERC20 代币详情(一次请求),可以选择返回哪些字段。节点参数与 getBalances 相同。
43
+ *
44
+ * ```ts
45
+ * import { NATIVE_TOKEN, getTokens } from '@w3lib/evm-batch-call'
46
+ *
47
+ * await getTokens([USDT, NATIVE_TOKEN], { chainId: 56 }) // 默认 name / symbol / decimals
48
+ * await getTokens([USDT], { provider: window.ethereum, fields: ['symbol', 'decimals', 'totalSupply'] })
49
+ * // [{ address: USDT, native: false, symbol: 'USDT', decimals: 18, totalSupply: '…', totalSupplyFormatted: '…', success: true }]
50
+ * ```
51
+ */
52
+ export declare function getTokens<const F extends TokenField = DefaultTokenField>(tokens: readonly string[], options?: GetTokensOptions<F>): Promise<TokenDetails<F>[]>;
53
+ /**
54
+ * 批量查 ERC20 授权额度(一次请求)。
55
+ *
56
+ * ```ts
57
+ * const [usdt] = await getAllowances(user, router, [USDT], { chainId: 56 })
58
+ * if (!usdt.unlimited && BigInt(usdt.allowance) < amount) { // 需要 approve
59
+ * ```
60
+ */
61
+ export declare function getAllowances(owner: string, spender: string, tokens: readonly BalanceToken[], options?: ShortcutOptions): Promise<TokenAllowance[]>;
62
+ export interface GetNftCollectionsOptions<F extends NftCollectionField = DefaultNftCollectionField> extends NftCollectionsOptions<F>, ShortcutProviderOptions {
63
+ }
64
+ /**
65
+ * 批量查 NFT 集合信息,字段可选(默认 standard / name / symbol)。
66
+ *
67
+ * ```ts
68
+ * await getNftCollections([BAYC, MAYC], { chainId: 1, fields: ['standard', 'name', 'totalSupply'] })
69
+ * // [{ address: BAYC, standard: 'ERC721', name: 'BoredApeYachtClub', totalSupply: '10000', success: true }, ...]
70
+ * ```
71
+ */
72
+ export declare function getNftCollections<const F extends NftCollectionField = DefaultNftCollectionField>(collections: readonly string[], options?: GetNftCollectionsOptions<F>): Promise<NftCollection<F>[]>;
73
+ /** 批量查 ERC721 持有数量:`await getNftBalances(user, [BAYC, MAYC], { chainId: 1 })` */
74
+ export declare function getNftBalances(owner: string, collections: readonly string[], options?: ShortcutOptions): Promise<NftBalance[]>;
75
+ /** 批量查 ERC721 持有人:`await getNftOwners([{ contract: BAYC, tokenId: 1 }], { chainId: 1 })` */
76
+ export declare function getNftOwners(items: readonly NftItem[], options?: ShortcutOptions): Promise<NftOwner[]>;
77
+ export interface GetNftTokenUrisOptions extends ShortcutOptions {
78
+ /** 把 ipfs://xxx 转成 `${ipfsGateway}xxx`,如 'https://ipfs.io/ipfs/' */
79
+ ipfsGateway?: string;
80
+ }
81
+ /**
82
+ * 批量查 NFT 元数据地址(ERC721 tokenURI / ERC1155 uri 自动兼容)。
83
+ *
84
+ * ```ts
85
+ * await getNftTokenUris([{ contract: BAYC, tokenId: 1 }], { chainId: 1, ipfsGateway: 'https://ipfs.io/ipfs/' })
86
+ * // [{ contract: BAYC, tokenId: '1', uri: 'https://ipfs.io/ipfs/Qm…/1', success: true }]
87
+ * ```
88
+ */
89
+ export declare function getNftTokenUris(items: readonly NftItem[], options?: GetNftTokenUrisOptions): Promise<NftTokenUri[]>;
90
+ /** 批量查 ERC1155 余额:`await getErc1155Balances(user, [{ contract, tokenId: 1 }], { chainId: 137 })` */
91
+ export declare function getErc1155Balances(owner: string, items: readonly NftItem[], options?: ShortcutOptions): Promise<Erc1155Balance[]>;
92
+ export interface GetOwnerTokensOptions extends OwnerTokensOptions, ShortcutProviderOptions {
93
+ }
94
+ /**
95
+ * 列出持有人拥有的代币(资产列表)。默认用免费公开代币列表发现代币,余额用 multicall 在链上核对。
96
+ *
97
+ * ```ts
98
+ * await getOwnerTokens(user, { chainId: 56 }) // 免费,只能发现公开列表里的代币
99
+ * await getOwnerTokens(user, { chainId: 1, prices: true, minUsd: 1 }) // 带美元价值,过滤零头和垃圾币
100
+ * await getOwnerTokens(user, { chainId: 56, source: alchemy({ apiKey }) }) // 用 Alchemy 查全部历史持仓
101
+ * ```
102
+ *
103
+ * @deprecated 不推荐使用:EVM 链上无法只靠节点可靠地列出地址持有的全部代币,这个方法只是尽力而为——
104
+ * 默认来源只能发现公开列表里的代币,依赖第三方免费服务(可能限流、改格式或停止服务),要查几千个代币的余额、耗时数秒,
105
+ * 价格也不一定可信;传 `alchemy` / `nodereal` 来源能查全,但同样受第三方服务的额度和可用性约束。
106
+ * 已知要查哪些代币时请用 `getBalances`;需要可靠的完整持仓请直接接入索引服务的接口或自己的索引。局限性详见 README「资产列表」。
107
+ */
108
+ export declare function getOwnerTokens(owner: string, options?: GetOwnerTokensOptions): Promise<OwnedToken[]>;
109
+ /** 测试用:按参数取(或创建)Provider,用于验证缓存复用(不在包的公开导出里) */
110
+ export declare function resolveProviderForTest(options: ShortcutOptions): Provider;
111
+ /** 测试用:清空 getBalances / getTokens 的 Provider 缓存 */
112
+ export declare function resetBalancesProviderCache(): void;
113
+ //# sourceMappingURL=shortcuts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shortcuts.d.ts","sourceRoot":"","sources":["../src/shortcuts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,193 @@
1
+ import { Provider } from './provider.js';
2
+ const providerCache = new Map();
3
+ /** 缓存上限(分组数、每组 URL 数),超出时淘汰最早加入的;对象来源用 WeakMap,随对象回收 */
4
+ const MAX_CACHED = 32;
5
+ function setBounded(map, key, value) {
6
+ map.set(key, value);
7
+ if (map.size > MAX_CACHED) {
8
+ map.delete(map.keys().next().value);
9
+ }
10
+ }
11
+ function configKey(config) {
12
+ try {
13
+ return JSON.stringify(config, (_key, value) => {
14
+ if (typeof value === 'function') {
15
+ throw new Error('not comparable');
16
+ }
17
+ return typeof value === 'bigint' ? value.toString() : value;
18
+ });
19
+ }
20
+ catch {
21
+ return null;
22
+ }
23
+ }
24
+ function sourceKey(chainId, source) {
25
+ if (source === undefined) {
26
+ return 'default';
27
+ }
28
+ if (typeof source === 'string') {
29
+ return `url:${source}`;
30
+ }
31
+ if (Array.isArray(source)) {
32
+ // URL 数组每次调用都是新数组,按内容缓存
33
+ return source.every((item) => typeof item === 'string') ? `urls:${source.join('\n')}` : null;
34
+ }
35
+ return chainId === undefined ? null : source;
36
+ }
37
+ function getProvider(chainId, source, config) {
38
+ if (chainId === undefined && source === undefined) {
39
+ throw new Error('getBalances / getTokens requires chainId or provider');
40
+ }
41
+ const create = () => (chainId === undefined ? new Provider(source, config) : new Provider(chainId, source, config));
42
+ const cfg = configKey(config);
43
+ const key = sourceKey(chainId, source);
44
+ if (cfg === null || key === null) {
45
+ return create();
46
+ }
47
+ const groupKey = `${chainId ?? 'auto'}|${cfg}`;
48
+ let group = providerCache.get(groupKey);
49
+ if (!group) {
50
+ group = { byString: new Map(), byObject: new WeakMap() };
51
+ setBounded(providerCache, groupKey, group);
52
+ }
53
+ let provider = typeof key === 'string' ? group.byString.get(key) : group.byObject.get(key);
54
+ if (!provider) {
55
+ provider = create();
56
+ if (typeof key === 'string') {
57
+ setBounded(group.byString, key, provider);
58
+ }
59
+ else {
60
+ group.byObject.set(key, provider);
61
+ }
62
+ }
63
+ return provider;
64
+ }
65
+ /** 拆出节点参数、调用参数和函数自己的参数(ownKeys),其余作为 Provider 配置;值为 undefined 的参数忽略 */
66
+ function resolve(options, ownKeys = []) {
67
+ const { chainId, provider, blockTag, from, ...others } = options;
68
+ const own = {};
69
+ const config = {};
70
+ for (const [key, value] of Object.entries(others)) {
71
+ if (value !== undefined) {
72
+ ;
73
+ (ownKeys.includes(key) ? own : config)[key] = value;
74
+ }
75
+ }
76
+ return {
77
+ // null / 空字符串(如状态里还没有 chainId)按“未传”处理,走自动识别,而不是变成 chainId 0
78
+ provider: getProvider(chainId === undefined || chainId === null || chainId === '' ? undefined : Number(chainId), provider, config),
79
+ overrides: { blockTag, from },
80
+ own: own,
81
+ };
82
+ }
83
+ /**
84
+ * 批量查余额(主币 + 代币,一次请求),返回原始余额、decimals 和换算后的数值。
85
+ *
86
+ * ```ts
87
+ * import { NATIVE_TOKEN, getBalances } from '@w3lib/evm-batch-call'
88
+ *
89
+ * await getBalances(user, [NATIVE_TOKEN, USDT], { chainId: 56 }) // 内置公共节点
90
+ * await getBalances(user, tokens, { provider: window.ethereum }) // 钱包,chainId 自动识别
91
+ * await getBalances(user, tokens, { provider: 'https://bsc-dataseed.bnbchain.org' })
92
+ * await getBalances(user, tokens, { chainId: 56, provider: [window.ethereum, 'https://…'] }) // 钱包优先,失败用公共节点
93
+ * await getBalances(user, tokens, { chainId: 56, symbol: true }) // 同时返回 symbol
94
+ * // [{ token: NATIVE_TOKEN, native: true, balance: '1500000000000000000', decimals: 18, formatted: '1.5', success: true }, ...]
95
+ * ```
96
+ */
97
+ export function getBalances(owner, tokens, options = {}) {
98
+ const { provider, overrides, own } = resolve(options, ['symbol']);
99
+ return provider.balances(owner, tokens, { ...overrides, symbol: own.symbol });
100
+ }
101
+ /**
102
+ * 批量查 ERC20 代币详情(一次请求),可以选择返回哪些字段。节点参数与 getBalances 相同。
103
+ *
104
+ * ```ts
105
+ * import { NATIVE_TOKEN, getTokens } from '@w3lib/evm-batch-call'
106
+ *
107
+ * await getTokens([USDT, NATIVE_TOKEN], { chainId: 56 }) // 默认 name / symbol / decimals
108
+ * await getTokens([USDT], { provider: window.ethereum, fields: ['symbol', 'decimals', 'totalSupply'] })
109
+ * // [{ address: USDT, native: false, symbol: 'USDT', decimals: 18, totalSupply: '…', totalSupplyFormatted: '…', success: true }]
110
+ * ```
111
+ */
112
+ export function getTokens(tokens, options = {}) {
113
+ const { provider, overrides, own } = resolve(options, ['fields']);
114
+ return provider.tokens(tokens, { ...overrides, fields: own.fields });
115
+ }
116
+ /**
117
+ * 批量查 ERC20 授权额度(一次请求)。
118
+ *
119
+ * ```ts
120
+ * const [usdt] = await getAllowances(user, router, [USDT], { chainId: 56 })
121
+ * if (!usdt.unlimited && BigInt(usdt.allowance) < amount) { // 需要 approve
122
+ * ```
123
+ */
124
+ export function getAllowances(owner, spender, tokens, options = {}) {
125
+ const { provider, overrides } = resolve(options);
126
+ return provider.allowances(owner, spender, tokens, overrides);
127
+ }
128
+ /**
129
+ * 批量查 NFT 集合信息,字段可选(默认 standard / name / symbol)。
130
+ *
131
+ * ```ts
132
+ * await getNftCollections([BAYC, MAYC], { chainId: 1, fields: ['standard', 'name', 'totalSupply'] })
133
+ * // [{ address: BAYC, standard: 'ERC721', name: 'BoredApeYachtClub', totalSupply: '10000', success: true }, ...]
134
+ * ```
135
+ */
136
+ export function getNftCollections(collections, options = {}) {
137
+ const { provider, overrides, own } = resolve(options, ['fields']);
138
+ return provider.nftCollections(collections, { ...overrides, fields: own.fields });
139
+ }
140
+ /** 批量查 ERC721 持有数量:`await getNftBalances(user, [BAYC, MAYC], { chainId: 1 })` */
141
+ export function getNftBalances(owner, collections, options = {}) {
142
+ const { provider, overrides } = resolve(options);
143
+ return provider.nftBalances(owner, collections, overrides);
144
+ }
145
+ /** 批量查 ERC721 持有人:`await getNftOwners([{ contract: BAYC, tokenId: 1 }], { chainId: 1 })` */
146
+ export function getNftOwners(items, options = {}) {
147
+ const { provider, overrides } = resolve(options);
148
+ return provider.nftOwners(items, overrides);
149
+ }
150
+ /**
151
+ * 批量查 NFT 元数据地址(ERC721 tokenURI / ERC1155 uri 自动兼容)。
152
+ *
153
+ * ```ts
154
+ * await getNftTokenUris([{ contract: BAYC, tokenId: 1 }], { chainId: 1, ipfsGateway: 'https://ipfs.io/ipfs/' })
155
+ * // [{ contract: BAYC, tokenId: '1', uri: 'https://ipfs.io/ipfs/Qm…/1', success: true }]
156
+ * ```
157
+ */
158
+ export function getNftTokenUris(items, options = {}) {
159
+ const { provider, overrides, own } = resolve(options, ['ipfsGateway']);
160
+ return provider.nftTokenUris(items, { ...overrides, ipfsGateway: own.ipfsGateway });
161
+ }
162
+ /** 批量查 ERC1155 余额:`await getErc1155Balances(user, [{ contract, tokenId: 1 }], { chainId: 137 })` */
163
+ export function getErc1155Balances(owner, items, options = {}) {
164
+ const { provider, overrides } = resolve(options);
165
+ return provider.erc1155Balances(owner, items, overrides);
166
+ }
167
+ /**
168
+ * 列出持有人拥有的代币(资产列表)。默认用免费公开代币列表发现代币,余额用 multicall 在链上核对。
169
+ *
170
+ * ```ts
171
+ * await getOwnerTokens(user, { chainId: 56 }) // 免费,只能发现公开列表里的代币
172
+ * await getOwnerTokens(user, { chainId: 1, prices: true, minUsd: 1 }) // 带美元价值,过滤零头和垃圾币
173
+ * await getOwnerTokens(user, { chainId: 56, source: alchemy({ apiKey }) }) // 用 Alchemy 查全部历史持仓
174
+ * ```
175
+ *
176
+ * @deprecated 不推荐使用:EVM 链上无法只靠节点可靠地列出地址持有的全部代币,这个方法只是尽力而为——
177
+ * 默认来源只能发现公开列表里的代币,依赖第三方免费服务(可能限流、改格式或停止服务),要查几千个代币的余额、耗时数秒,
178
+ * 价格也不一定可信;传 `alchemy` / `nodereal` 来源能查全,但同样受第三方服务的额度和可用性约束。
179
+ * 已知要查哪些代币时请用 `getBalances`;需要可靠的完整持仓请直接接入索引服务的接口或自己的索引。局限性详见 README「资产列表」。
180
+ */
181
+ export function getOwnerTokens(owner, options = {}) {
182
+ const { provider, overrides, own } = resolve(options, ['source', 'prices', 'minUsd', 'includeNative', 'fetch', 'scanTransfers']);
183
+ return provider.ownerTokens(owner, { ...overrides, ...own });
184
+ }
185
+ /** 测试用:按参数取(或创建)Provider,用于验证缓存复用(不在包的公开导出里) */
186
+ export function resolveProviderForTest(options) {
187
+ return resolve(options).provider;
188
+ }
189
+ /** 测试用:清空 getBalances / getTokens 的 Provider 缓存 */
190
+ export function resetBalancesProviderCache() {
191
+ providerCache.clear();
192
+ }
193
+ //# sourceMappingURL=shortcuts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shortcuts.js","sourceRoot":"","sources":["../src/shortcuts.ts"],"names":[],"mappings":"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"}
package/dist/source.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type Eip1193Provider } from 'ethers';
1
+ import { type Eip1193Provider, type TransactionRequest } from 'ethers';
2
2
  import type { EthersLikeProvider } from './aggregate.js';
3
3
  import { type FallbackOptions } from './fallback.js';
4
4
  import { type TronProviderOptions, type TronWebLike } from './tron.js';
@@ -20,4 +20,26 @@ export declare function isTronChain(chainId: number): boolean;
20
20
  /** 链的默认节点:EVM 用内置公共节点表,Tron 主网用内置全节点列表 */
21
21
  export declare function getDefaultRpcUrls(chainId: number): readonly string[];
22
22
  export declare function resolveSource(chainId: number, source: ProviderSource | readonly ProviderSource[] | undefined, options?: SourceOptions): EthersLikeProvider;
23
+ /**
24
+ * 校验节点所在的链与 Provider 的 chainId 一致,避免把另一条链的数据当成这条链的返回:
25
+ * 比如 [钱包, 公共节点] 自动识别出钱包的链后,公共节点其实在另一条链上;或者配错了节点 URL。
26
+ *
27
+ * - 不一致时抛 NETWORK_ERROR(多节点时 FallbackRpc 会换下一个节点)
28
+ * - 通过已配置好的节点连接识别(带 Tron apiKey / 限流等),结果按来源缓存,每个节点只多一次请求
29
+ * - 识别与实际请求并行发出,不增加延迟;不一致时丢弃请求结果
30
+ * - 识别本身失败时不拦截(交给实际请求去报错),并在一段时间内不再重试,避免每次请求都多一次识别
31
+ */
32
+ export declare class ChainCheckedProvider implements EthersLikeProvider {
33
+ #private;
34
+ readonly inner: EthersLikeProvider;
35
+ readonly chainId: number;
36
+ readonly source: ProviderSource;
37
+ readonly timeout: number;
38
+ constructor(inner: EthersLikeProvider, chainId: number, source: ProviderSource, timeout: number);
39
+ call(tx: TransactionRequest): Promise<string>;
40
+ getBalance(...args: Parameters<EthersLikeProvider['getBalance']>): Promise<bigint>;
41
+ getBlockNumber(): Promise<number>;
42
+ getLogs(filter: Parameters<NonNullable<EthersLikeProvider['getLogs']>>[0]): Promise<Awaited<ReturnType<NonNullable<EthersLikeProvider['getLogs']>>>>;
43
+ getChainId(): Promise<number>;
44
+ }
23
45
  //# sourceMappingURL=source.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../src/source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkD,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAA;AAE7F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACxD,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AAEjE,OAAO,EAA+B,KAAK,mBAAmB,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAEnG;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,kBAAkB,GAAG,eAAe,GAAG,WAAW,CAAA;AAExF,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,uDAAuD;IACvD,IAAI,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,GAAG,SAAS,CAAC,CAAA;CACzD;AAID,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,0CAA0C;AAC1C,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAKpE;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,GAAG,SAAS,cAAc,EAAE,GAAG,SAAS,EAC9D,OAAO,GAAE,aAAkB,GAC1B,kBAAkB,CAapB"}
1
+ {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../src/source.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6D,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAE,MAAM,QAAQ,CAAA;AAEjI,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAExD,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AAEjE,OAAO,EAA+B,KAAK,mBAAmB,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAEnG;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,kBAAkB,GAAG,eAAe,GAAG,WAAW,CAAA;AAExF,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,uDAAuD;IACvD,IAAI,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,GAAG,SAAS,CAAC,CAAA;CACzD;AAID,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,0CAA0C;AAC1C,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAKpE;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,GAAG,SAAS,cAAc,EAAE,GAAG,SAAS,EAC9D,OAAO,GAAE,aAAkB,GAC1B,kBAAkB,CAkBpB;AAKD;;;;;;;;GAQG;AACH,qBAAa,oBAAqB,YAAW,kBAAkB;;IAI3D,QAAQ,CAAC,KAAK,EAAE,kBAAkB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM;IACxB,QAAQ,CAAC,MAAM,EAAE,cAAc;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM;gBAHf,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,MAAM;IAiC1B,IAAI,CAAC,EAAE,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IAI7C,UAAU,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAIlF,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAQjC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAQ9I,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;CAGpC"}