@w3lib/evm-batch-call 0.6.0 → 0.8.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 (248) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +367 -3
  3. package/contracts/TokenProbe.sol +103 -0
  4. package/dist/aggregate.d.ts.map +1 -1
  5. package/dist/aggregate.js +114 -3
  6. package/dist/aggregate.js.map +1 -1
  7. package/dist/approvals.d.ts +169 -0
  8. package/dist/approvals.d.ts.map +1 -0
  9. package/dist/approvals.js +310 -0
  10. package/dist/approvals.js.map +1 -0
  11. package/dist/chains.d.ts.map +1 -1
  12. package/dist/chains.js +4 -0
  13. package/dist/chains.js.map +1 -1
  14. package/dist/dividends.d.ts +135 -0
  15. package/dist/dividends.d.ts.map +1 -0
  16. package/dist/dividends.js +253 -0
  17. package/dist/dividends.js.map +1 -0
  18. package/dist/fees.d.ts +97 -0
  19. package/dist/fees.d.ts.map +1 -0
  20. package/dist/fees.js +115 -0
  21. package/dist/fees.js.map +1 -0
  22. package/dist/history.d.ts +154 -0
  23. package/dist/history.d.ts.map +1 -0
  24. package/dist/history.js +247 -0
  25. package/dist/history.js.map +1 -0
  26. package/dist/historySources.d.ts +32 -0
  27. package/dist/historySources.d.ts.map +1 -0
  28. package/dist/historySources.js +319 -0
  29. package/dist/historySources.js.map +1 -0
  30. package/dist/http.d.ts +10 -0
  31. package/dist/http.d.ts.map +1 -0
  32. package/dist/http.js +30 -0
  33. package/dist/http.js.map +1 -0
  34. package/dist/liquidity/v3.d.ts +2 -0
  35. package/dist/liquidity/v3.d.ts.map +1 -1
  36. package/dist/liquidity/v3.js +1 -1
  37. package/dist/liquidity/v3.js.map +1 -1
  38. package/dist/liquidity/v4.d.ts +21 -0
  39. package/dist/liquidity/v4.d.ts.map +1 -1
  40. package/dist/liquidity/v4.js +4 -3
  41. package/dist/liquidity/v4.js.map +1 -1
  42. package/dist/lp.d.ts +10 -1
  43. package/dist/lp.d.ts.map +1 -1
  44. package/dist/lp.js +19 -2
  45. package/dist/lp.js.map +1 -1
  46. package/dist/lpV4.d.ts +4 -0
  47. package/dist/lpV4.d.ts.map +1 -1
  48. package/dist/lpV4.js +27 -3
  49. package/dist/lpV4.js.map +1 -1
  50. package/dist/multicall.d.ts.map +1 -1
  51. package/dist/multicall.js +3 -0
  52. package/dist/multicall.js.map +1 -1
  53. package/dist/names.d.ts +55 -0
  54. package/dist/names.d.ts.map +1 -0
  55. package/dist/names.js +93 -0
  56. package/dist/names.js.map +1 -0
  57. package/dist/owner.d.ts +4 -26
  58. package/dist/owner.d.ts.map +1 -1
  59. package/dist/owner.js +7 -112
  60. package/dist/owner.js.map +1 -1
  61. package/dist/permit.d.ts +137 -0
  62. package/dist/permit.d.ts.map +1 -0
  63. package/dist/permit.js +355 -0
  64. package/dist/permit.js.map +1 -0
  65. package/dist/portfolio.d.ts +56 -0
  66. package/dist/portfolio.d.ts.map +1 -0
  67. package/dist/portfolio.js +54 -0
  68. package/dist/portfolio.js.map +1 -0
  69. package/dist/price.d.ts +95 -0
  70. package/dist/price.d.ts.map +1 -0
  71. package/dist/price.js +329 -0
  72. package/dist/price.js.map +1 -0
  73. package/dist/rewards/farms.d.ts +26 -0
  74. package/dist/rewards/farms.d.ts.map +1 -0
  75. package/dist/rewards/farms.js +210 -0
  76. package/dist/rewards/farms.js.map +1 -0
  77. package/dist/rewards/index.d.ts +42 -0
  78. package/dist/rewards/index.d.ts.map +1 -0
  79. package/dist/rewards/index.js +382 -0
  80. package/dist/rewards/index.js.map +1 -0
  81. package/dist/rewards/types.d.ts +170 -0
  82. package/dist/rewards/types.d.ts.map +1 -0
  83. package/dist/rewards/types.js +2 -0
  84. package/dist/rewards/types.js.map +1 -0
  85. package/dist/risk.d.ts +42 -0
  86. package/dist/risk.d.ts.map +1 -0
  87. package/dist/risk.js +134 -0
  88. package/dist/risk.js.map +1 -0
  89. package/dist/rpcNodes.d.ts.map +1 -1
  90. package/dist/rpcNodes.js +18 -0
  91. package/dist/rpcNodes.js.map +1 -1
  92. package/dist/simulate.d.ts +186 -0
  93. package/dist/simulate.d.ts.map +1 -0
  94. package/dist/simulate.js +559 -0
  95. package/dist/simulate.js.map +1 -0
  96. package/dist/simulateDecode.d.ts +33 -0
  97. package/dist/simulateDecode.d.ts.map +1 -0
  98. package/dist/simulateDecode.js +321 -0
  99. package/dist/simulateDecode.js.map +1 -0
  100. package/dist/smartAccount/account.d.ts +31 -0
  101. package/dist/smartAccount/account.d.ts.map +1 -0
  102. package/dist/smartAccount/account.js +33 -0
  103. package/dist/smartAccount/account.js.map +1 -0
  104. package/dist/smartAccount/clients.d.ts +77 -0
  105. package/dist/smartAccount/clients.d.ts.map +1 -0
  106. package/dist/smartAccount/clients.js +122 -0
  107. package/dist/smartAccount/clients.js.map +1 -0
  108. package/dist/smartAccount/eip5792.d.ts +77 -0
  109. package/dist/smartAccount/eip5792.d.ts.map +1 -0
  110. package/dist/smartAccount/eip5792.js +152 -0
  111. package/dist/smartAccount/eip5792.js.map +1 -0
  112. package/dist/smartAccount/send.d.ts +40 -0
  113. package/dist/smartAccount/send.d.ts.map +1 -0
  114. package/dist/smartAccount/send.js +271 -0
  115. package/dist/smartAccount/send.js.map +1 -0
  116. package/dist/smartAccount/userOp.d.ts +91 -0
  117. package/dist/smartAccount/userOp.d.ts.map +1 -0
  118. package/dist/smartAccount/userOp.js +124 -0
  119. package/dist/smartAccount/userOp.js.map +1 -0
  120. package/dist/subpaths/approvals.d.ts +26 -0
  121. package/dist/subpaths/approvals.d.ts.map +1 -0
  122. package/dist/subpaths/approvals.js +27 -0
  123. package/dist/subpaths/approvals.js.map +1 -0
  124. package/dist/subpaths/dividends.d.ts +28 -0
  125. package/dist/subpaths/dividends.d.ts.map +1 -0
  126. package/dist/subpaths/dividends.js +29 -0
  127. package/dist/subpaths/dividends.js.map +1 -0
  128. package/dist/subpaths/fees.d.ts +23 -0
  129. package/dist/subpaths/fees.d.ts.map +1 -0
  130. package/dist/subpaths/fees.js +25 -0
  131. package/dist/subpaths/fees.js.map +1 -0
  132. package/dist/subpaths/history.d.ts +22 -0
  133. package/dist/subpaths/history.d.ts.map +1 -0
  134. package/dist/subpaths/history.js +23 -0
  135. package/dist/subpaths/history.js.map +1 -0
  136. package/dist/subpaths/names.d.ts +35 -0
  137. package/dist/subpaths/names.d.ts.map +1 -0
  138. package/dist/subpaths/names.js +39 -0
  139. package/dist/subpaths/names.js.map +1 -0
  140. package/dist/subpaths/permit.d.ts +14 -0
  141. package/dist/subpaths/permit.d.ts.map +1 -0
  142. package/dist/subpaths/permit.js +14 -0
  143. package/dist/subpaths/permit.js.map +1 -0
  144. package/dist/subpaths/price.d.ts +38 -0
  145. package/dist/subpaths/price.d.ts.map +1 -0
  146. package/dist/subpaths/price.js +40 -0
  147. package/dist/subpaths/price.js.map +1 -0
  148. package/dist/subpaths/rewards.d.ts +27 -0
  149. package/dist/subpaths/rewards.d.ts.map +1 -0
  150. package/dist/subpaths/rewards.js +25 -0
  151. package/dist/subpaths/rewards.js.map +1 -0
  152. package/dist/subpaths/risk.d.ts +19 -0
  153. package/dist/subpaths/risk.d.ts.map +1 -0
  154. package/dist/subpaths/risk.js +20 -0
  155. package/dist/subpaths/risk.js.map +1 -0
  156. package/dist/subpaths/simulate.d.ts +25 -0
  157. package/dist/subpaths/simulate.d.ts.map +1 -0
  158. package/dist/subpaths/simulate.js +28 -0
  159. package/dist/subpaths/simulate.js.map +1 -0
  160. package/dist/subpaths/smart-account.d.ts +24 -0
  161. package/dist/subpaths/smart-account.d.ts.map +1 -0
  162. package/dist/subpaths/smart-account.js +24 -0
  163. package/dist/subpaths/smart-account.js.map +1 -0
  164. package/dist/subpaths/swap.d.ts +19 -0
  165. package/dist/subpaths/swap.d.ts.map +1 -0
  166. package/dist/subpaths/swap.js +20 -0
  167. package/dist/subpaths/swap.js.map +1 -0
  168. package/dist/swap.d.ts +168 -0
  169. package/dist/swap.d.ts.map +1 -0
  170. package/dist/swap.js +387 -0
  171. package/dist/swap.js.map +1 -0
  172. package/dist/tokenProbe.d.ts +3 -0
  173. package/dist/tokenProbe.d.ts.map +1 -0
  174. package/dist/tokenProbe.js +4 -0
  175. package/dist/tokenProbe.js.map +1 -0
  176. package/dist/write/batch.d.ts +34 -2
  177. package/dist/write/batch.d.ts.map +1 -1
  178. package/dist/write/batch.js +22 -3
  179. package/dist/write/batch.js.map +1 -1
  180. package/dist/write/collect.d.ts +9 -0
  181. package/dist/write/collect.d.ts.map +1 -1
  182. package/dist/write/collect.js +41 -1
  183. package/dist/write/collect.js.map +1 -1
  184. package/dist/write/send.d.ts +4 -0
  185. package/dist/write/send.d.ts.map +1 -1
  186. package/dist/write/send.js.map +1 -1
  187. package/dist/write/signer.d.ts +5 -1
  188. package/dist/write/signer.d.ts.map +1 -1
  189. package/dist/write/signer.js.map +1 -1
  190. package/dist/write/transfer.d.ts +5 -3
  191. package/dist/write/transfer.d.ts.map +1 -1
  192. package/dist/write/transfer.js +12 -6
  193. package/dist/write/transfer.js.map +1 -1
  194. package/dist/write/tron.d.ts +25 -0
  195. package/dist/write/tron.d.ts.map +1 -1
  196. package/dist/write/tron.js +26 -0
  197. package/dist/write/tron.js.map +1 -1
  198. package/package.json +73 -16
  199. package/src/aggregate.ts +110 -3
  200. package/src/approvals.ts +462 -0
  201. package/src/chains.ts +4 -0
  202. package/src/dividends.ts +360 -0
  203. package/src/fees.ts +201 -0
  204. package/src/history.ts +367 -0
  205. package/src/historySources.ts +360 -0
  206. package/src/http.ts +34 -0
  207. package/src/liquidity/v3.ts +1 -1
  208. package/src/liquidity/v4.ts +4 -3
  209. package/src/lp.ts +21 -2
  210. package/src/lpV4.ts +32 -2
  211. package/src/multicall.ts +3 -0
  212. package/src/names.ts +141 -0
  213. package/src/owner.ts +7 -138
  214. package/src/permit.ts +457 -0
  215. package/src/portfolio.ts +98 -0
  216. package/src/price.ts +415 -0
  217. package/src/rewards/farms.ts +229 -0
  218. package/src/rewards/index.ts +431 -0
  219. package/src/rewards/types.ts +179 -0
  220. package/src/risk.ts +166 -0
  221. package/src/rpcNodes.ts +18 -0
  222. package/src/simulate.ts +727 -0
  223. package/src/simulateDecode.ts +352 -0
  224. package/src/smartAccount/account.ts +63 -0
  225. package/src/smartAccount/clients.ts +180 -0
  226. package/src/smartAccount/eip5792.ts +187 -0
  227. package/src/smartAccount/send.ts +341 -0
  228. package/src/smartAccount/userOp.ts +180 -0
  229. package/src/subpaths/approvals.ts +48 -0
  230. package/src/subpaths/dividends.ts +47 -0
  231. package/src/subpaths/fees.ts +43 -0
  232. package/src/subpaths/history.ts +41 -0
  233. package/src/subpaths/names.ts +43 -0
  234. package/src/subpaths/permit.ts +39 -0
  235. package/src/subpaths/price.ts +60 -0
  236. package/src/subpaths/rewards.ts +46 -0
  237. package/src/subpaths/risk.ts +23 -0
  238. package/src/subpaths/simulate.ts +51 -0
  239. package/src/subpaths/smart-account.ts +40 -0
  240. package/src/subpaths/swap.ts +36 -0
  241. package/src/swap.ts +534 -0
  242. package/src/tokenProbe.ts +5 -0
  243. package/src/write/batch.ts +44 -5
  244. package/src/write/collect.ts +60 -1
  245. package/src/write/send.ts +4 -0
  246. package/src/write/signer.ts +5 -1
  247. package/src/write/transfer.ts +17 -10
  248. package/src/write/tron.ts +43 -0
package/src/risk.ts ADDED
@@ -0,0 +1,166 @@
1
+ /**
2
+ * 代币风险检查(子路径 `@w3lib/evm-batch-call/risk`):在 eth_call 里模拟“买入 → 转账 → 卖出”(deployless 的探测合约,不部署、不发交易),
3
+ * 算出买入税、转账税、卖出税,判断能不能卖(貔貅盘);另外看合约是不是可升级的代理、owner 有没有放弃。
4
+ * 只能检查在内置 V2 协议里有 代币 / 包装主币 池子的代币;Tron 不支持
5
+ */
6
+ import { AbiCoder, Interface, concat } from 'ethers'
7
+
8
+ import { LP_PROTOCOLS, LP_QUOTE_TOKENS, type LpProtocol } from './lp.js'
9
+ import type { Provider } from './provider.js'
10
+ import { TOKEN_PROBE_BYTECODE } from './tokenProbe.js'
11
+ import { isExecutionError } from './errors.js'
12
+ import { isTronChain } from './tron.js'
13
+
14
+ export type ProbeStage = 'ok' | 'buy-failed' | 'transfer-failed' | 'approve-failed' | 'sell-failed'
15
+
16
+ export interface TokenRisk {
17
+ token: string
18
+ /** 模拟用的 V2 协议和池子(代币 / 包装主币里包装主币一侧最深的);没有池子时为 null */
19
+ protocol: string | null
20
+ pool: string | null
21
+ /** 模拟到哪一步:ok 全部成功;buy-failed 买不进(可能还没开放交易、限制了合约地址);sell-failed 卖不出(貔貅盘) */
22
+ stage: ProbeStage | null
23
+ /** 卖不出,或卖出税 ≥ 90% */
24
+ honeypot: boolean | null
25
+ /** 税率(0~1):实际数量比 Router 报价少多少;对应的步骤没跑到时为 null */
26
+ buyTax: number | null
27
+ sellTax: number | null
28
+ transferTax: number | null
29
+ /** 买入 / 卖出消耗的 gas(异常高可能有额外逻辑) */
30
+ buyGas: number | null
31
+ sellGas: number | null
32
+ /** EIP-1967 代理的实现合约(可升级:规则以后可以改);不是代理时为 null */
33
+ implementation: string | null
34
+ /** owner():没有这个方法时为 null;零地址表示已放弃 */
35
+ owner: string | null
36
+ /** 汇总的风险标记:honeypot、cannot-buy、high-buy-tax / high-sell-tax / high-transfer-tax(> 10%)、has-tax(> 0.5%)、proxy、owned、no-pool */
37
+ flags: string[]
38
+ }
39
+
40
+ export interface TokenRiskOptions {
41
+ /** 模拟买入用的主币数量(最小单位),默认包装主币储备的 1 / 1000,最多 1 个主币 */
42
+ amount?: bigint
43
+ /** 用哪些 V2 协议的池子,默认这条链内置表里有 Router 的 V2 协议 */
44
+ protocols?: readonly LpProtocol[]
45
+ }
46
+
47
+ const coder = AbiCoder.defaultAbiCoder()
48
+ const factoryInterface = new Interface(['function getPair(address tokenA, address tokenB) view returns (address)'])
49
+ const pairInterface = new Interface(['function token0() view returns (address)', 'function getReserves() view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)'])
50
+ const ownerInterface = new Interface(['function owner() view returns (address)'])
51
+ /** EIP-1967 的实现合约槽位:bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1) */
52
+ const IMPLEMENTATION_SLOT = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc'
53
+ const STAGES: readonly ProbeStage[] = ['ok', 'buy-failed', 'transfer-failed', 'approve-failed', 'sell-failed']
54
+ const ZERO = '0x0000000000000000000000000000000000000000'
55
+
56
+ type Node = { call(tx: { from?: string; to?: string; data: string; value?: bigint }): Promise<string>; getStorage?(address: string, slot: string): Promise<string> }
57
+
58
+ /**
59
+ * 检查代币的风险(每个代币一次模拟的 eth_call,加上一次 multicall 找池子、读 owner)。
60
+ *
61
+ * ```ts
62
+ * const [risk] = await tokenRisks(provider, [token])
63
+ * // { stage: 'ok', honeypot: false, buyTax: 0.05, sellTax: 0.05, transferTax: 0, flags: ['has-tax', 'owned'], … }
64
+ * ```
65
+ */
66
+ export async function tokenRisks(provider: Provider, tokens: readonly string[], options: TokenRiskOptions = {}): Promise<TokenRisk[]> {
67
+ const chainId = await provider.getChainId()
68
+ if (isTronChain(chainId)) throw new Error('tokenRisks is not supported on Tron')
69
+ const wrapped = LP_QUOTE_TOKENS[chainId]?.[0]
70
+ const protocols = (options.protocols ?? LP_PROTOCOLS.filter((p) => p.chainId === chainId)).filter((p) => p.version === 'v2' && p.router && p.factory)
71
+ if (!wrapped || !protocols.length) throw new Error(`No V2 protocol with a router on chain ${chainId}`)
72
+
73
+ // 1. 每个代币在每个 V2 协议里和包装主币的池子,以及 owner()
74
+ const pairCalls = tokens.flatMap((t) => protocols.map((p) => provider.contract(p.factory as string, factoryInterface).getPair(t, wrapped)))
75
+ const ownerCalls = tokens.map((t) => provider.contract(t, ownerInterface).owner())
76
+ const first = await provider.tryAll([...pairCalls, ...ownerCalls])
77
+ const pairs = first.slice(0, pairCalls.length) as Array<string | null>
78
+ const owners = first.slice(pairCalls.length) as Array<string | null>
79
+ const found = pairs.flatMap((pair, i) => (pair && pair.toLowerCase() !== ZERO ? [{ i, pair }] : []))
80
+ const reserves = found.length
81
+ ? await provider.tryAll(found.flatMap(({ pair }) => [provider.contract(pair, pairInterface).token0(), provider.contract(pair, pairInterface).getReserves()]))
82
+ : []
83
+ // 每个代币:包装主币一侧最深的池子
84
+ const best: Array<{ protocol: LpProtocol; pair: string; wrappedReserve: bigint } | null> = tokens.map(() => null)
85
+ found.forEach(({ i, pair }, k) => {
86
+ const token0 = reserves[k * 2] as string | null
87
+ const r = reserves[k * 2 + 1] as { 0: bigint; 1: bigint } | null
88
+ if (!token0 || !r) return
89
+ const wrappedReserve = token0.toLowerCase() === wrapped.toLowerCase() ? r[0] : r[1]
90
+ const t = Math.floor(i / protocols.length)
91
+ const current = best[t]
92
+ if (wrappedReserve > 0n && (!current || wrappedReserve > current.wrappedReserve)) best[t] = { protocol: protocols[i % protocols.length] as LpProtocol, pair, wrappedReserve }
93
+ })
94
+
95
+ const { runOnNodes } = await import('./write/rpc.js')
96
+ const node = <T>(method: string, fn: (n: Node) => Promise<T>, isFinal?: (err: unknown) => boolean) => runOnNodes(provider.rpc, method, (n) => fn(n as unknown as Node), isFinal)
97
+ const ONE = 10n ** 18n
98
+
99
+ return Promise.all(
100
+ tokens.map(async (token, t): Promise<TokenRisk> => {
101
+ const pick = best[t]
102
+ const owner = owners[t] ?? null
103
+ const implementation = await node('getStorage', (n) => (n.getStorage ? n.getStorage(token, IMPLEMENTATION_SLOT) : Promise.resolve('0x')))
104
+ .then((slot) => (slot && BigInt(slot) !== 0n ? `0x${slot.slice(-40)}` : null))
105
+ .catch(() => null)
106
+ const base = { token, implementation, owner, buyTax: null, sellTax: null, transferTax: null, buyGas: null, sellGas: null }
107
+ if (!pick) return { ...base, protocol: null, pool: null, stage: null, honeypot: null, flags: flagsOf({ ...base, stage: null, honeypot: null }, true) }
108
+
109
+ const amount = options.amount ?? min(pick.wrappedReserve / 1000n, ONE)
110
+ // deployless:没有 to 的 eth_call 执行构造函数;从包装主币合约发起(它持有大量主币,eth_call 不需要签名)
111
+ const data = concat([TOKEN_PROBE_BYTECODE, coder.encode(['address', 'address', 'address'], [pick.protocol.router, token, pick.pair])])
112
+ let decoded: bigint[] | null = null
113
+ try {
114
+ // 探测合约自己不会 revert(每一步都 try);执行出错(如买入时代币合约把调用方拒之门外导致整体 revert)算买不进,
115
+ // 节点、网络、限频的错误照常抛出,不当成代币的风险
116
+ const out = await node('call', (n) => n.call({ from: wrapped, data, value: amount }), isExecutionError)
117
+ decoded = coder.decode(new Array<string>(11).fill('uint256'), out).toArray() as bigint[]
118
+ } catch (err) {
119
+ if (!isExecutionError(err)) throw err
120
+ decoded = null
121
+ }
122
+ if (!decoded) {
123
+ const failed = { ...base, protocol: pick.protocol.id, pool: pick.pair, stage: 'buy-failed' as const, honeypot: null }
124
+ return { ...failed, flags: flagsOf(failed, false) }
125
+ }
126
+ const [stageIndex, buyQuote, bought, transferSent, transferReceived, sellAmount, sellQuote, sold, buyGas, sellGas, pairReceived] = decoded as [bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint, bigint]
127
+ const stage = STAGES[Number(stageIndex)] ?? 'buy-failed'
128
+ const tax = (actual: bigint, expected: bigint) => (expected > 0n ? Math.max(0, 1 - Number((actual * 1_000_000n) / expected) / 1_000_000) : null)
129
+ const result = {
130
+ ...base,
131
+ protocol: pick.protocol.id,
132
+ pool: pick.pair,
133
+ stage,
134
+ buyTax: stage === 'buy-failed' ? null : tax(bought, buyQuote),
135
+ transferTax: stage === 'ok' || stage === 'approve-failed' || stage === 'sell-failed' ? tax(transferReceived, transferSent) : null,
136
+ // 卖出税:池子实际收到的代币(转账时扣的税,精确),和实际换回的主币比报价少多少(有的代币卖出时顺便把收来的税也卖进同一个池子,
137
+ // 池子那边看不出来),取较大的
138
+ sellTax: stage === 'ok' ? Math.max(tax(pairReceived, sellAmount) ?? 0, tax(sold, sellQuote) ?? 0) : null,
139
+ buyGas: stage === 'buy-failed' ? null : Number(buyGas),
140
+ sellGas: stage === 'ok' ? Number(sellGas) : null,
141
+ honeypot: stage === 'sell-failed' || stage === 'transfer-failed' || stage === 'approve-failed' ? true : stage === 'ok' ? (tax(sold, sellQuote) ?? 0) >= 0.9 : null,
142
+ }
143
+ return { ...result, flags: flagsOf(result, false) }
144
+ }),
145
+ )
146
+ }
147
+
148
+ const min = (a: bigint, b: bigint) => (a < b ? a : b)
149
+
150
+ function flagsOf(r: Omit<TokenRisk, 'flags' | 'protocol' | 'pool'>, noPool: boolean): string[] {
151
+ const flags: string[] = []
152
+ if (noPool) flags.push('no-pool')
153
+ if (r.honeypot) flags.push('honeypot')
154
+ if (r.stage === 'buy-failed') flags.push('cannot-buy')
155
+ for (const [name, value] of [
156
+ ['buy', r.buyTax],
157
+ ['sell', r.sellTax],
158
+ ['transfer', r.transferTax],
159
+ ] as const) {
160
+ if (value !== null && value > 0.1) flags.push(`high-${name}-tax`)
161
+ }
162
+ if ([r.buyTax, r.sellTax, r.transferTax].some((v) => v !== null && v > 0.005)) flags.push('has-tax')
163
+ if (r.implementation) flags.push('proxy')
164
+ if (r.owner && r.owner.toLowerCase() !== ZERO) flags.push('owned')
165
+ return flags
166
+ }
package/src/rpcNodes.ts CHANGED
@@ -183,6 +183,24 @@ export const DEFAULT_RPC_URLS: Readonly<Record<number, readonly string[]>> = {
183
183
  'https://rpc-qnd.inkonchain.com',
184
184
  'https://ink.api.pocket.network',
185
185
  ],
186
+ // 星空链(Starry)
187
+ 202308: [
188
+ 'https://rpc.starryscan.com',
189
+ ],
190
+ // conflux
191
+ 1030: [
192
+ 'https://evm.confluxrpc.com',
193
+ ],
194
+ // injective
195
+ 1776: [
196
+ 'https://sentry.evm-rpc.injective.network',
197
+ 'https://injectiveevm-rpc.polkachu.com',
198
+ ],
199
+ // pharos
200
+ 1672: [
201
+ 'https://rpc.pharos.xyz',
202
+ 'https://infra.originstake.com/pharos/evm',
203
+ ],
186
204
  }
187
205
 
188
206
  /** Tron 主网全节点 HTTP API(均支持跨域与 deployless) */