@getomnichain/omnichain 0.2.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 (582) hide show
  1. package/dist/cjs/abstract_gas_pricing.js +27 -0
  2. package/dist/cjs/abstract_gas_pricing.js.map +1 -0
  3. package/dist/cjs/address.factory.js +81 -0
  4. package/dist/cjs/address.factory.js.map +1 -0
  5. package/dist/cjs/address.js +17 -0
  6. package/dist/cjs/address.js.map +1 -0
  7. package/dist/cjs/address_field.decorator.js +37 -0
  8. package/dist/cjs/address_field.decorator.js.map +1 -0
  9. package/dist/cjs/chain.base.js +118 -0
  10. package/dist/cjs/chain.base.js.map +1 -0
  11. package/dist/cjs/chain_ids.js +205 -0
  12. package/dist/cjs/chain_ids.js.map +1 -0
  13. package/dist/cjs/errors.js +118 -0
  14. package/dist/cjs/errors.js.map +1 -0
  15. package/dist/cjs/evm/evm_address.js +63 -0
  16. package/dist/cjs/evm/evm_address.js.map +1 -0
  17. package/dist/cjs/evm/evm_chain.js +1109 -0
  18. package/dist/cjs/evm/evm_chain.js.map +1 -0
  19. package/dist/cjs/evm/evm_chains.js +530 -0
  20. package/dist/cjs/evm/evm_chains.js.map +1 -0
  21. package/dist/cjs/evm/evm_gas_estimate.js +76 -0
  22. package/dist/cjs/evm/evm_gas_estimate.js.map +1 -0
  23. package/dist/cjs/evm/evm_gas_pricing.js +62 -0
  24. package/dist/cjs/evm/evm_gas_pricing.js.map +1 -0
  25. package/dist/cjs/evm/evm_token.js +26 -0
  26. package/dist/cjs/evm/evm_token.js.map +1 -0
  27. package/dist/cjs/evm/evm_tokens.js +109 -0
  28. package/dist/cjs/evm/evm_tokens.js.map +1 -0
  29. package/dist/cjs/evm/evm_transaction_status.js +187 -0
  30. package/dist/cjs/evm/evm_transaction_status.js.map +1 -0
  31. package/dist/cjs/evm/index.js +26 -0
  32. package/dist/cjs/evm/index.js.map +1 -0
  33. package/dist/cjs/evm/unsigned_evm_transaction.js +34 -0
  34. package/dist/cjs/evm/unsigned_evm_transaction.js.map +1 -0
  35. package/dist/cjs/index.js +34 -0
  36. package/dist/cjs/index.js.map +1 -0
  37. package/dist/cjs/is_address.decorator.js +54 -0
  38. package/dist/cjs/is_address.decorator.js.map +1 -0
  39. package/dist/cjs/network_type.js +152 -0
  40. package/dist/cjs/network_type.js.map +1 -0
  41. package/dist/cjs/package.json +3 -0
  42. package/dist/cjs/priority.js +26 -0
  43. package/dist/cjs/priority.js.map +1 -0
  44. package/dist/cjs/solana/index.js +25 -0
  45. package/dist/cjs/solana/index.js.map +1 -0
  46. package/dist/cjs/solana/solana_address.js +49 -0
  47. package/dist/cjs/solana/solana_address.js.map +1 -0
  48. package/dist/cjs/solana/solana_chain.js +1305 -0
  49. package/dist/cjs/solana/solana_chain.js.map +1 -0
  50. package/dist/cjs/solana/solana_chains.js +88 -0
  51. package/dist/cjs/solana/solana_chains.js.map +1 -0
  52. package/dist/cjs/solana/solana_gas_pricing.js +30 -0
  53. package/dist/cjs/solana/solana_gas_pricing.js.map +1 -0
  54. package/dist/cjs/solana/solana_token.js +38 -0
  55. package/dist/cjs/solana/solana_token.js.map +1 -0
  56. package/dist/cjs/solana/solana_tokens.js +29 -0
  57. package/dist/cjs/solana/solana_tokens.js.map +1 -0
  58. package/dist/cjs/solana/solana_transaction_status.js +149 -0
  59. package/dist/cjs/solana/solana_transaction_status.js.map +1 -0
  60. package/dist/cjs/solana/unsigned_solana_transaction.js +63 -0
  61. package/dist/cjs/solana/unsigned_solana_transaction.js.map +1 -0
  62. package/dist/cjs/token.js +66 -0
  63. package/dist/cjs/token.js.map +1 -0
  64. package/dist/cjs/ton/index.js +18 -0
  65. package/dist/cjs/ton/index.js.map +1 -0
  66. package/dist/cjs/ton/ton_address.js +57 -0
  67. package/dist/cjs/ton/ton_address.js.map +1 -0
  68. package/dist/cjs/transaction_status.js +283 -0
  69. package/dist/cjs/transaction_status.js.map +1 -0
  70. package/dist/cjs/unsigned_transaction.js +13 -0
  71. package/dist/cjs/unsigned_transaction.js.map +1 -0
  72. package/dist/cjs/utxo/btc/btc_address.js +43 -0
  73. package/dist/cjs/utxo/btc/btc_address.js.map +1 -0
  74. package/dist/cjs/utxo/btc/btc_chain.js +66 -0
  75. package/dist/cjs/utxo/btc/btc_chain.js.map +1 -0
  76. package/dist/cjs/utxo/btc/btc_chains.js +49 -0
  77. package/dist/cjs/utxo/btc/btc_chains.js.map +1 -0
  78. package/dist/cjs/utxo/btc/btc_token.js +15 -0
  79. package/dist/cjs/utxo/btc/btc_token.js.map +1 -0
  80. package/dist/cjs/utxo/btc/index.js +30 -0
  81. package/dist/cjs/utxo/btc/index.js.map +1 -0
  82. package/dist/cjs/utxo/btc/network_params.js +196 -0
  83. package/dist/cjs/utxo/btc/network_params.js.map +1 -0
  84. package/dist/cjs/utxo/btc/tools/asset_outpoint.js +16 -0
  85. package/dist/cjs/utxo/btc/tools/asset_outpoint.js.map +1 -0
  86. package/dist/cjs/utxo/btc/tools/bitcoin_core.tool.js +179 -0
  87. package/dist/cjs/utxo/btc/tools/bitcoin_core.tool.js.map +1 -0
  88. package/dist/cjs/utxo/btc/tools/esplora.tool.js +120 -0
  89. package/dist/cjs/utxo/btc/tools/esplora.tool.js.map +1 -0
  90. package/dist/cjs/utxo/btc/tools/inscription_index.js +3 -0
  91. package/dist/cjs/utxo/btc/tools/inscription_index.js.map +1 -0
  92. package/dist/cjs/utxo/btc/tools/ordiscan.tool.js +60 -0
  93. package/dist/cjs/utxo/btc/tools/ordiscan.tool.js.map +1 -0
  94. package/dist/cjs/utxo/btc/tools/rare_sat_index.js +3 -0
  95. package/dist/cjs/utxo/btc/tools/rare_sat_index.js.map +1 -0
  96. package/dist/cjs/utxo/btc/tools/rune_index.js +3 -0
  97. package/dist/cjs/utxo/btc/tools/rune_index.js.map +1 -0
  98. package/dist/cjs/utxo/btc/tools/unisat.tool.js +56 -0
  99. package/dist/cjs/utxo/btc/tools/unisat.tool.js.map +1 -0
  100. package/dist/cjs/utxo/coin_selection.js +160 -0
  101. package/dist/cjs/utxo/coin_selection.js.map +1 -0
  102. package/dist/cjs/utxo/doge/doge_chains.js +32 -0
  103. package/dist/cjs/utxo/doge/doge_chains.js.map +1 -0
  104. package/dist/cjs/utxo/doge/index.js +19 -0
  105. package/dist/cjs/utxo/doge/index.js.map +1 -0
  106. package/dist/cjs/utxo/doge/network_params.js +30 -0
  107. package/dist/cjs/utxo/doge/network_params.js.map +1 -0
  108. package/dist/cjs/utxo/ecc.js +47 -0
  109. package/dist/cjs/utxo/ecc.js.map +1 -0
  110. package/dist/cjs/utxo/fee.js +61 -0
  111. package/dist/cjs/utxo/fee.js.map +1 -0
  112. package/dist/cjs/utxo/index.js +36 -0
  113. package/dist/cjs/utxo/index.js.map +1 -0
  114. package/dist/cjs/utxo/ltc/index.js +19 -0
  115. package/dist/cjs/utxo/ltc/index.js.map +1 -0
  116. package/dist/cjs/utxo/ltc/ltc_chains.js +32 -0
  117. package/dist/cjs/utxo/ltc/ltc_chains.js.map +1 -0
  118. package/dist/cjs/utxo/ltc/network_params.js +33 -0
  119. package/dist/cjs/utxo/ltc/network_params.js.map +1 -0
  120. package/dist/cjs/utxo/script.js +59 -0
  121. package/dist/cjs/utxo/script.js.map +1 -0
  122. package/dist/cjs/utxo/tools/broadcaster.js +3 -0
  123. package/dist/cjs/utxo/tools/broadcaster.js.map +1 -0
  124. package/dist/cjs/utxo/tools/chain_tip_provider.js +3 -0
  125. package/dist/cjs/utxo/tools/chain_tip_provider.js.map +1 -0
  126. package/dist/cjs/utxo/tools/fee_estimator.js +3 -0
  127. package/dist/cjs/utxo/tools/fee_estimator.js.map +1 -0
  128. package/dist/cjs/utxo/tools/raw_transaction_provider.js +3 -0
  129. package/dist/cjs/utxo/tools/raw_transaction_provider.js.map +1 -0
  130. package/dist/cjs/utxo/tools/utxo_provider.js +3 -0
  131. package/dist/cjs/utxo/tools/utxo_provider.js.map +1 -0
  132. package/dist/cjs/utxo/unsigned_utxo_transaction.js +36 -0
  133. package/dist/cjs/utxo/unsigned_utxo_transaction.js.map +1 -0
  134. package/dist/cjs/utxo/utxo.js +3 -0
  135. package/dist/{utxo → cjs/utxo}/utxo.js.map +1 -1
  136. package/dist/cjs/utxo/utxo_chain.js +612 -0
  137. package/dist/cjs/utxo/utxo_chain.js.map +1 -0
  138. package/dist/cjs/utxo/utxo_chains.js +68 -0
  139. package/dist/cjs/utxo/utxo_chains.js.map +1 -0
  140. package/dist/cjs/utxo/utxo_gas_pricing.js +24 -0
  141. package/dist/cjs/utxo/utxo_gas_pricing.js.map +1 -0
  142. package/dist/cjs/utxo/utxo_network_params.js +18 -0
  143. package/dist/cjs/utxo/utxo_network_params.js.map +1 -0
  144. package/dist/cjs/utxo/utxo_transaction_status.js +95 -0
  145. package/dist/cjs/utxo/utxo_transaction_status.js.map +1 -0
  146. package/dist/esm/abstract_gas_pricing.d.ts.map +1 -0
  147. package/dist/esm/abstract_gas_pricing.js.map +1 -0
  148. package/dist/esm/address.d.ts.map +1 -0
  149. package/dist/esm/address.factory.d.ts.map +1 -0
  150. package/dist/esm/address.factory.js.map +1 -0
  151. package/dist/esm/address.js.map +1 -0
  152. package/dist/esm/address_field.decorator.d.ts.map +1 -0
  153. package/dist/esm/address_field.decorator.js.map +1 -0
  154. package/dist/{chain.base.d.ts → esm/chain.base.d.ts} +38 -1
  155. package/dist/esm/chain.base.d.ts.map +1 -0
  156. package/dist/esm/chain.base.js.map +1 -0
  157. package/dist/esm/chain_ids.d.ts.map +1 -0
  158. package/dist/esm/chain_ids.js.map +1 -0
  159. package/dist/{errors.d.ts → esm/errors.d.ts} +13 -0
  160. package/dist/esm/errors.d.ts.map +1 -0
  161. package/dist/esm/errors.js +107 -0
  162. package/dist/esm/errors.js.map +1 -0
  163. package/dist/esm/evm/evm_address.d.ts.map +1 -0
  164. package/dist/esm/evm/evm_address.js.map +1 -0
  165. package/dist/{evm → esm/evm}/evm_chain.d.ts +48 -2
  166. package/dist/esm/evm/evm_chain.d.ts.map +1 -0
  167. package/dist/{evm → esm/evm}/evm_chain.js +423 -4
  168. package/dist/esm/evm/evm_chain.js.map +1 -0
  169. package/dist/esm/evm/evm_chains.d.ts.map +1 -0
  170. package/dist/esm/evm/evm_chains.js.map +1 -0
  171. package/dist/esm/evm/evm_gas_estimate.d.ts.map +1 -0
  172. package/dist/esm/evm/evm_gas_estimate.js.map +1 -0
  173. package/dist/esm/evm/evm_gas_pricing.d.ts.map +1 -0
  174. package/dist/esm/evm/evm_gas_pricing.js.map +1 -0
  175. package/dist/esm/evm/evm_token.d.ts.map +1 -0
  176. package/dist/esm/evm/evm_token.js.map +1 -0
  177. package/dist/esm/evm/evm_tokens.d.ts.map +1 -0
  178. package/dist/esm/evm/evm_tokens.js.map +1 -0
  179. package/dist/{evm → esm/evm}/evm_transaction_status.d.ts +4 -0
  180. package/dist/esm/evm/evm_transaction_status.d.ts.map +1 -0
  181. package/dist/{evm → esm/evm}/evm_transaction_status.js +4 -0
  182. package/dist/esm/evm/evm_transaction_status.js.map +1 -0
  183. package/dist/esm/evm/index.d.ts.map +1 -0
  184. package/dist/esm/evm/index.js.map +1 -0
  185. package/dist/{evm → esm/evm}/unsigned_evm_transaction.d.ts +13 -0
  186. package/dist/esm/evm/unsigned_evm_transaction.d.ts.map +1 -0
  187. package/dist/{evm → esm/evm}/unsigned_evm_transaction.js +12 -0
  188. package/dist/esm/evm/unsigned_evm_transaction.js.map +1 -0
  189. package/dist/esm/index.d.ts.map +1 -0
  190. package/dist/esm/index.js.map +1 -0
  191. package/dist/esm/is_address.decorator.d.ts.map +1 -0
  192. package/dist/esm/is_address.decorator.js.map +1 -0
  193. package/dist/esm/network_type.d.ts.map +1 -0
  194. package/dist/esm/network_type.js.map +1 -0
  195. package/dist/esm/package.json +3 -0
  196. package/dist/esm/priority.d.ts.map +1 -0
  197. package/dist/esm/priority.js.map +1 -0
  198. package/dist/esm/solana/index.d.ts.map +1 -0
  199. package/dist/esm/solana/index.js.map +1 -0
  200. package/dist/esm/solana/solana_address.d.ts.map +1 -0
  201. package/dist/esm/solana/solana_address.js.map +1 -0
  202. package/dist/{solana → esm/solana}/solana_chain.d.ts +87 -3
  203. package/dist/esm/solana/solana_chain.d.ts.map +1 -0
  204. package/dist/{solana → esm/solana}/solana_chain.js +618 -23
  205. package/dist/esm/solana/solana_chain.js.map +1 -0
  206. package/dist/esm/solana/solana_chains.d.ts.map +1 -0
  207. package/dist/esm/solana/solana_chains.js.map +1 -0
  208. package/dist/esm/solana/solana_gas_pricing.d.ts.map +1 -0
  209. package/dist/esm/solana/solana_gas_pricing.js.map +1 -0
  210. package/dist/esm/solana/solana_token.d.ts.map +1 -0
  211. package/dist/esm/solana/solana_token.js.map +1 -0
  212. package/dist/esm/solana/solana_tokens.d.ts.map +1 -0
  213. package/dist/esm/solana/solana_tokens.js.map +1 -0
  214. package/dist/esm/solana/solana_transaction_status.d.ts.map +1 -0
  215. package/dist/esm/solana/solana_transaction_status.js.map +1 -0
  216. package/dist/{solana → esm/solana}/unsigned_solana_transaction.d.ts +20 -1
  217. package/dist/esm/solana/unsigned_solana_transaction.d.ts.map +1 -0
  218. package/dist/esm/solana/unsigned_solana_transaction.js +59 -0
  219. package/dist/esm/solana/unsigned_solana_transaction.js.map +1 -0
  220. package/dist/esm/token.d.ts.map +1 -0
  221. package/dist/esm/token.js.map +1 -0
  222. package/dist/esm/ton/index.d.ts.map +1 -0
  223. package/dist/esm/ton/index.js.map +1 -0
  224. package/dist/esm/ton/ton_address.d.ts.map +1 -0
  225. package/dist/esm/ton/ton_address.js.map +1 -0
  226. package/dist/esm/transaction_status.d.ts.map +1 -0
  227. package/dist/esm/transaction_status.js.map +1 -0
  228. package/dist/esm/unsigned_transaction.d.ts.map +1 -0
  229. package/dist/esm/unsigned_transaction.js.map +1 -0
  230. package/dist/esm/utxo/btc/btc_address.d.ts.map +1 -0
  231. package/dist/esm/utxo/btc/btc_address.js.map +1 -0
  232. package/dist/esm/utxo/btc/btc_chain.d.ts.map +1 -0
  233. package/dist/esm/utxo/btc/btc_chain.js.map +1 -0
  234. package/dist/esm/utxo/btc/btc_chains.d.ts.map +1 -0
  235. package/dist/esm/utxo/btc/btc_chains.js.map +1 -0
  236. package/dist/esm/utxo/btc/btc_token.d.ts.map +1 -0
  237. package/dist/esm/utxo/btc/btc_token.js.map +1 -0
  238. package/dist/esm/utxo/btc/index.d.ts.map +1 -0
  239. package/dist/esm/utxo/btc/index.js.map +1 -0
  240. package/dist/esm/utxo/btc/network_params.d.ts.map +1 -0
  241. package/dist/esm/utxo/btc/network_params.js.map +1 -0
  242. package/dist/esm/utxo/btc/tools/asset_outpoint.d.ts.map +1 -0
  243. package/dist/esm/utxo/btc/tools/asset_outpoint.js.map +1 -0
  244. package/dist/esm/utxo/btc/tools/bitcoin_core.tool.d.ts.map +1 -0
  245. package/dist/esm/utxo/btc/tools/bitcoin_core.tool.js.map +1 -0
  246. package/dist/esm/utxo/btc/tools/esplora.tool.d.ts.map +1 -0
  247. package/dist/esm/utxo/btc/tools/esplora.tool.js.map +1 -0
  248. package/dist/esm/utxo/btc/tools/inscription_index.d.ts.map +1 -0
  249. package/dist/esm/utxo/btc/tools/inscription_index.js.map +1 -0
  250. package/dist/esm/utxo/btc/tools/ordiscan.tool.d.ts.map +1 -0
  251. package/dist/esm/utxo/btc/tools/ordiscan.tool.js.map +1 -0
  252. package/dist/esm/utxo/btc/tools/rare_sat_index.d.ts.map +1 -0
  253. package/dist/esm/utxo/btc/tools/rare_sat_index.js.map +1 -0
  254. package/dist/esm/utxo/btc/tools/rune_index.d.ts.map +1 -0
  255. package/dist/esm/utxo/btc/tools/rune_index.js.map +1 -0
  256. package/dist/esm/utxo/btc/tools/unisat.tool.d.ts.map +1 -0
  257. package/dist/esm/utxo/btc/tools/unisat.tool.js.map +1 -0
  258. package/dist/esm/utxo/coin_selection.d.ts.map +1 -0
  259. package/dist/esm/utxo/coin_selection.js.map +1 -0
  260. package/dist/esm/utxo/doge/doge_chains.d.ts.map +1 -0
  261. package/dist/esm/utxo/doge/doge_chains.js.map +1 -0
  262. package/dist/esm/utxo/doge/index.d.ts.map +1 -0
  263. package/dist/esm/utxo/doge/index.js.map +1 -0
  264. package/dist/esm/utxo/doge/network_params.d.ts.map +1 -0
  265. package/dist/esm/utxo/doge/network_params.js.map +1 -0
  266. package/dist/esm/utxo/ecc.d.ts.map +1 -0
  267. package/dist/esm/utxo/ecc.js.map +1 -0
  268. package/dist/esm/utxo/fee.d.ts.map +1 -0
  269. package/dist/esm/utxo/fee.js.map +1 -0
  270. package/dist/esm/utxo/index.d.ts.map +1 -0
  271. package/dist/esm/utxo/index.js.map +1 -0
  272. package/dist/esm/utxo/ltc/index.d.ts.map +1 -0
  273. package/dist/esm/utxo/ltc/index.js.map +1 -0
  274. package/dist/{utxo/doge/doge_chains.d.ts.map → esm/utxo/ltc/ltc_chains.d.ts.map} +1 -1
  275. package/dist/{utxo/doge/doge_chains.js.map → esm/utxo/ltc/ltc_chains.js.map} +1 -1
  276. package/dist/esm/utxo/ltc/network_params.d.ts.map +1 -0
  277. package/dist/esm/utxo/ltc/network_params.js.map +1 -0
  278. package/dist/esm/utxo/script.d.ts.map +1 -0
  279. package/dist/esm/utxo/script.js.map +1 -0
  280. package/dist/esm/utxo/tools/broadcaster.d.ts.map +1 -0
  281. package/dist/esm/utxo/tools/broadcaster.js.map +1 -0
  282. package/dist/esm/utxo/tools/chain_tip_provider.d.ts.map +1 -0
  283. package/dist/esm/utxo/tools/chain_tip_provider.js.map +1 -0
  284. package/dist/esm/utxo/tools/fee_estimator.d.ts.map +1 -0
  285. package/dist/esm/utxo/tools/fee_estimator.js.map +1 -0
  286. package/dist/esm/utxo/tools/raw_transaction_provider.d.ts.map +1 -0
  287. package/dist/esm/utxo/tools/raw_transaction_provider.js.map +1 -0
  288. package/dist/esm/utxo/tools/utxo_provider.d.ts.map +1 -0
  289. package/dist/esm/utxo/tools/utxo_provider.js.map +1 -0
  290. package/dist/esm/utxo/unsigned_utxo_transaction.d.ts.map +1 -0
  291. package/dist/esm/utxo/unsigned_utxo_transaction.js.map +1 -0
  292. package/dist/esm/utxo/utxo.d.ts.map +1 -0
  293. package/dist/esm/utxo/utxo.js.map +1 -0
  294. package/dist/{utxo → esm/utxo}/utxo_chain.d.ts +15 -2
  295. package/dist/esm/utxo/utxo_chain.d.ts.map +1 -0
  296. package/dist/{utxo → esm/utxo}/utxo_chain.js +96 -13
  297. package/dist/esm/utxo/utxo_chain.js.map +1 -0
  298. package/dist/esm/utxo/utxo_chains.d.ts.map +1 -0
  299. package/dist/esm/utxo/utxo_chains.js.map +1 -0
  300. package/dist/esm/utxo/utxo_gas_pricing.d.ts.map +1 -0
  301. package/dist/esm/utxo/utxo_gas_pricing.js.map +1 -0
  302. package/dist/esm/utxo/utxo_network_params.d.ts.map +1 -0
  303. package/dist/esm/utxo/utxo_network_params.js.map +1 -0
  304. package/dist/esm/utxo/utxo_transaction_status.d.ts.map +1 -0
  305. package/dist/esm/utxo/utxo_transaction_status.js.map +1 -0
  306. package/docs/CONNECTIONS.md +33 -0
  307. package/docs/EIP7702.md +77 -0
  308. package/docs/JITO.md +41 -0
  309. package/docs/MULTI_RPC.md +28 -0
  310. package/package.json +32 -16
  311. package/dist/abstract_gas_pricing.d.ts.map +0 -1
  312. package/dist/abstract_gas_pricing.js.map +0 -1
  313. package/dist/address.d.ts.map +0 -1
  314. package/dist/address.factory.d.ts.map +0 -1
  315. package/dist/address.factory.js.map +0 -1
  316. package/dist/address.js.map +0 -1
  317. package/dist/address_field.decorator.d.ts.map +0 -1
  318. package/dist/address_field.decorator.js.map +0 -1
  319. package/dist/chain.base.d.ts.map +0 -1
  320. package/dist/chain.base.js.map +0 -1
  321. package/dist/chain_ids.d.ts.map +0 -1
  322. package/dist/chain_ids.js.map +0 -1
  323. package/dist/errors.d.ts.map +0 -1
  324. package/dist/errors.js +0 -62
  325. package/dist/errors.js.map +0 -1
  326. package/dist/evm/evm_address.d.ts.map +0 -1
  327. package/dist/evm/evm_address.js.map +0 -1
  328. package/dist/evm/evm_chain.d.ts.map +0 -1
  329. package/dist/evm/evm_chain.js.map +0 -1
  330. package/dist/evm/evm_chains.d.ts.map +0 -1
  331. package/dist/evm/evm_chains.js.map +0 -1
  332. package/dist/evm/evm_gas_estimate.d.ts.map +0 -1
  333. package/dist/evm/evm_gas_estimate.js.map +0 -1
  334. package/dist/evm/evm_gas_pricing.d.ts.map +0 -1
  335. package/dist/evm/evm_gas_pricing.js.map +0 -1
  336. package/dist/evm/evm_token.d.ts.map +0 -1
  337. package/dist/evm/evm_token.js.map +0 -1
  338. package/dist/evm/evm_tokens.d.ts.map +0 -1
  339. package/dist/evm/evm_tokens.js.map +0 -1
  340. package/dist/evm/evm_transaction_status.d.ts.map +0 -1
  341. package/dist/evm/evm_transaction_status.js.map +0 -1
  342. package/dist/evm/index.d.ts.map +0 -1
  343. package/dist/evm/index.js.map +0 -1
  344. package/dist/evm/unsigned_evm_transaction.d.ts.map +0 -1
  345. package/dist/evm/unsigned_evm_transaction.js.map +0 -1
  346. package/dist/index.d.ts.map +0 -1
  347. package/dist/index.js.map +0 -1
  348. package/dist/is_address.decorator.d.ts.map +0 -1
  349. package/dist/is_address.decorator.js.map +0 -1
  350. package/dist/network_type.d.ts.map +0 -1
  351. package/dist/network_type.js.map +0 -1
  352. package/dist/priority.d.ts.map +0 -1
  353. package/dist/priority.js.map +0 -1
  354. package/dist/solana/index.d.ts.map +0 -1
  355. package/dist/solana/index.js.map +0 -1
  356. package/dist/solana/solana_address.d.ts.map +0 -1
  357. package/dist/solana/solana_address.js.map +0 -1
  358. package/dist/solana/solana_chain.d.ts.map +0 -1
  359. package/dist/solana/solana_chain.js.map +0 -1
  360. package/dist/solana/solana_chains.d.ts.map +0 -1
  361. package/dist/solana/solana_chains.js.map +0 -1
  362. package/dist/solana/solana_gas_pricing.d.ts.map +0 -1
  363. package/dist/solana/solana_gas_pricing.js.map +0 -1
  364. package/dist/solana/solana_token.d.ts.map +0 -1
  365. package/dist/solana/solana_token.js.map +0 -1
  366. package/dist/solana/solana_tokens.d.ts.map +0 -1
  367. package/dist/solana/solana_tokens.js.map +0 -1
  368. package/dist/solana/solana_transaction_status.d.ts.map +0 -1
  369. package/dist/solana/solana_transaction_status.js.map +0 -1
  370. package/dist/solana/unsigned_solana_transaction.d.ts.map +0 -1
  371. package/dist/solana/unsigned_solana_transaction.js +0 -26
  372. package/dist/solana/unsigned_solana_transaction.js.map +0 -1
  373. package/dist/token.d.ts.map +0 -1
  374. package/dist/token.js.map +0 -1
  375. package/dist/ton/index.d.ts.map +0 -1
  376. package/dist/ton/index.js.map +0 -1
  377. package/dist/ton/ton_address.d.ts.map +0 -1
  378. package/dist/ton/ton_address.js.map +0 -1
  379. package/dist/transaction_status.d.ts.map +0 -1
  380. package/dist/transaction_status.js.map +0 -1
  381. package/dist/unsigned_transaction.d.ts.map +0 -1
  382. package/dist/unsigned_transaction.js.map +0 -1
  383. package/dist/utxo/btc/btc_address.d.ts.map +0 -1
  384. package/dist/utxo/btc/btc_address.js.map +0 -1
  385. package/dist/utxo/btc/btc_chain.d.ts.map +0 -1
  386. package/dist/utxo/btc/btc_chain.js.map +0 -1
  387. package/dist/utxo/btc/btc_chains.d.ts.map +0 -1
  388. package/dist/utxo/btc/btc_chains.js.map +0 -1
  389. package/dist/utxo/btc/btc_token.d.ts.map +0 -1
  390. package/dist/utxo/btc/btc_token.js.map +0 -1
  391. package/dist/utxo/btc/index.d.ts.map +0 -1
  392. package/dist/utxo/btc/index.js.map +0 -1
  393. package/dist/utxo/btc/network_params.d.ts.map +0 -1
  394. package/dist/utxo/btc/network_params.js.map +0 -1
  395. package/dist/utxo/btc/tools/asset_outpoint.d.ts.map +0 -1
  396. package/dist/utxo/btc/tools/asset_outpoint.js.map +0 -1
  397. package/dist/utxo/btc/tools/bitcoin_core.tool.d.ts.map +0 -1
  398. package/dist/utxo/btc/tools/bitcoin_core.tool.js.map +0 -1
  399. package/dist/utxo/btc/tools/esplora.tool.d.ts.map +0 -1
  400. package/dist/utxo/btc/tools/esplora.tool.js.map +0 -1
  401. package/dist/utxo/btc/tools/inscription_index.d.ts.map +0 -1
  402. package/dist/utxo/btc/tools/inscription_index.js.map +0 -1
  403. package/dist/utxo/btc/tools/ordiscan.tool.d.ts.map +0 -1
  404. package/dist/utxo/btc/tools/ordiscan.tool.js.map +0 -1
  405. package/dist/utxo/btc/tools/rare_sat_index.d.ts.map +0 -1
  406. package/dist/utxo/btc/tools/rare_sat_index.js.map +0 -1
  407. package/dist/utxo/btc/tools/rune_index.d.ts.map +0 -1
  408. package/dist/utxo/btc/tools/rune_index.js.map +0 -1
  409. package/dist/utxo/btc/tools/unisat.tool.d.ts.map +0 -1
  410. package/dist/utxo/btc/tools/unisat.tool.js.map +0 -1
  411. package/dist/utxo/coin_selection.d.ts.map +0 -1
  412. package/dist/utxo/coin_selection.js.map +0 -1
  413. package/dist/utxo/doge/index.d.ts.map +0 -1
  414. package/dist/utxo/doge/index.js.map +0 -1
  415. package/dist/utxo/doge/network_params.d.ts.map +0 -1
  416. package/dist/utxo/doge/network_params.js.map +0 -1
  417. package/dist/utxo/ecc.d.ts.map +0 -1
  418. package/dist/utxo/ecc.js.map +0 -1
  419. package/dist/utxo/fee.d.ts.map +0 -1
  420. package/dist/utxo/fee.js.map +0 -1
  421. package/dist/utxo/index.d.ts.map +0 -1
  422. package/dist/utxo/index.js.map +0 -1
  423. package/dist/utxo/ltc/index.d.ts.map +0 -1
  424. package/dist/utxo/ltc/index.js.map +0 -1
  425. package/dist/utxo/ltc/ltc_chains.d.ts.map +0 -1
  426. package/dist/utxo/ltc/ltc_chains.js.map +0 -1
  427. package/dist/utxo/ltc/network_params.d.ts.map +0 -1
  428. package/dist/utxo/ltc/network_params.js.map +0 -1
  429. package/dist/utxo/script.d.ts.map +0 -1
  430. package/dist/utxo/script.js.map +0 -1
  431. package/dist/utxo/tools/broadcaster.d.ts.map +0 -1
  432. package/dist/utxo/tools/broadcaster.js.map +0 -1
  433. package/dist/utxo/tools/chain_tip_provider.d.ts.map +0 -1
  434. package/dist/utxo/tools/chain_tip_provider.js.map +0 -1
  435. package/dist/utxo/tools/fee_estimator.d.ts.map +0 -1
  436. package/dist/utxo/tools/fee_estimator.js.map +0 -1
  437. package/dist/utxo/tools/raw_transaction_provider.d.ts.map +0 -1
  438. package/dist/utxo/tools/raw_transaction_provider.js.map +0 -1
  439. package/dist/utxo/tools/utxo_provider.d.ts.map +0 -1
  440. package/dist/utxo/tools/utxo_provider.js.map +0 -1
  441. package/dist/utxo/unsigned_utxo_transaction.d.ts.map +0 -1
  442. package/dist/utxo/unsigned_utxo_transaction.js.map +0 -1
  443. package/dist/utxo/utxo.d.ts.map +0 -1
  444. package/dist/utxo/utxo_chain.d.ts.map +0 -1
  445. package/dist/utxo/utxo_chain.js.map +0 -1
  446. package/dist/utxo/utxo_chains.d.ts.map +0 -1
  447. package/dist/utxo/utxo_chains.js.map +0 -1
  448. package/dist/utxo/utxo_gas_pricing.d.ts.map +0 -1
  449. package/dist/utxo/utxo_gas_pricing.js.map +0 -1
  450. package/dist/utxo/utxo_network_params.d.ts.map +0 -1
  451. package/dist/utxo/utxo_network_params.js.map +0 -1
  452. package/dist/utxo/utxo_transaction_status.d.ts.map +0 -1
  453. package/dist/utxo/utxo_transaction_status.js.map +0 -1
  454. /package/dist/{abstract_gas_pricing.d.ts → esm/abstract_gas_pricing.d.ts} +0 -0
  455. /package/dist/{abstract_gas_pricing.js → esm/abstract_gas_pricing.js} +0 -0
  456. /package/dist/{address.d.ts → esm/address.d.ts} +0 -0
  457. /package/dist/{address.factory.d.ts → esm/address.factory.d.ts} +0 -0
  458. /package/dist/{address.factory.js → esm/address.factory.js} +0 -0
  459. /package/dist/{address.js → esm/address.js} +0 -0
  460. /package/dist/{address_field.decorator.d.ts → esm/address_field.decorator.d.ts} +0 -0
  461. /package/dist/{address_field.decorator.js → esm/address_field.decorator.js} +0 -0
  462. /package/dist/{chain.base.js → esm/chain.base.js} +0 -0
  463. /package/dist/{chain_ids.d.ts → esm/chain_ids.d.ts} +0 -0
  464. /package/dist/{chain_ids.js → esm/chain_ids.js} +0 -0
  465. /package/dist/{evm → esm/evm}/evm_address.d.ts +0 -0
  466. /package/dist/{evm → esm/evm}/evm_address.js +0 -0
  467. /package/dist/{evm → esm/evm}/evm_chains.d.ts +0 -0
  468. /package/dist/{evm → esm/evm}/evm_chains.js +0 -0
  469. /package/dist/{evm → esm/evm}/evm_gas_estimate.d.ts +0 -0
  470. /package/dist/{evm → esm/evm}/evm_gas_estimate.js +0 -0
  471. /package/dist/{evm → esm/evm}/evm_gas_pricing.d.ts +0 -0
  472. /package/dist/{evm → esm/evm}/evm_gas_pricing.js +0 -0
  473. /package/dist/{evm → esm/evm}/evm_token.d.ts +0 -0
  474. /package/dist/{evm → esm/evm}/evm_token.js +0 -0
  475. /package/dist/{evm → esm/evm}/evm_tokens.d.ts +0 -0
  476. /package/dist/{evm → esm/evm}/evm_tokens.js +0 -0
  477. /package/dist/{evm → esm/evm}/index.d.ts +0 -0
  478. /package/dist/{evm → esm/evm}/index.js +0 -0
  479. /package/dist/{index.d.ts → esm/index.d.ts} +0 -0
  480. /package/dist/{index.js → esm/index.js} +0 -0
  481. /package/dist/{is_address.decorator.d.ts → esm/is_address.decorator.d.ts} +0 -0
  482. /package/dist/{is_address.decorator.js → esm/is_address.decorator.js} +0 -0
  483. /package/dist/{network_type.d.ts → esm/network_type.d.ts} +0 -0
  484. /package/dist/{network_type.js → esm/network_type.js} +0 -0
  485. /package/dist/{priority.d.ts → esm/priority.d.ts} +0 -0
  486. /package/dist/{priority.js → esm/priority.js} +0 -0
  487. /package/dist/{solana → esm/solana}/index.d.ts +0 -0
  488. /package/dist/{solana → esm/solana}/index.js +0 -0
  489. /package/dist/{solana → esm/solana}/solana_address.d.ts +0 -0
  490. /package/dist/{solana → esm/solana}/solana_address.js +0 -0
  491. /package/dist/{solana → esm/solana}/solana_chains.d.ts +0 -0
  492. /package/dist/{solana → esm/solana}/solana_chains.js +0 -0
  493. /package/dist/{solana → esm/solana}/solana_gas_pricing.d.ts +0 -0
  494. /package/dist/{solana → esm/solana}/solana_gas_pricing.js +0 -0
  495. /package/dist/{solana → esm/solana}/solana_token.d.ts +0 -0
  496. /package/dist/{solana → esm/solana}/solana_token.js +0 -0
  497. /package/dist/{solana → esm/solana}/solana_tokens.d.ts +0 -0
  498. /package/dist/{solana → esm/solana}/solana_tokens.js +0 -0
  499. /package/dist/{solana → esm/solana}/solana_transaction_status.d.ts +0 -0
  500. /package/dist/{solana → esm/solana}/solana_transaction_status.js +0 -0
  501. /package/dist/{token.d.ts → esm/token.d.ts} +0 -0
  502. /package/dist/{token.js → esm/token.js} +0 -0
  503. /package/dist/{ton → esm/ton}/index.d.ts +0 -0
  504. /package/dist/{ton → esm/ton}/index.js +0 -0
  505. /package/dist/{ton → esm/ton}/ton_address.d.ts +0 -0
  506. /package/dist/{ton → esm/ton}/ton_address.js +0 -0
  507. /package/dist/{transaction_status.d.ts → esm/transaction_status.d.ts} +0 -0
  508. /package/dist/{transaction_status.js → esm/transaction_status.js} +0 -0
  509. /package/dist/{unsigned_transaction.d.ts → esm/unsigned_transaction.d.ts} +0 -0
  510. /package/dist/{unsigned_transaction.js → esm/unsigned_transaction.js} +0 -0
  511. /package/dist/{utxo → esm/utxo}/btc/btc_address.d.ts +0 -0
  512. /package/dist/{utxo → esm/utxo}/btc/btc_address.js +0 -0
  513. /package/dist/{utxo → esm/utxo}/btc/btc_chain.d.ts +0 -0
  514. /package/dist/{utxo → esm/utxo}/btc/btc_chain.js +0 -0
  515. /package/dist/{utxo → esm/utxo}/btc/btc_chains.d.ts +0 -0
  516. /package/dist/{utxo → esm/utxo}/btc/btc_chains.js +0 -0
  517. /package/dist/{utxo → esm/utxo}/btc/btc_token.d.ts +0 -0
  518. /package/dist/{utxo → esm/utxo}/btc/btc_token.js +0 -0
  519. /package/dist/{utxo → esm/utxo}/btc/index.d.ts +0 -0
  520. /package/dist/{utxo → esm/utxo}/btc/index.js +0 -0
  521. /package/dist/{utxo → esm/utxo}/btc/network_params.d.ts +0 -0
  522. /package/dist/{utxo → esm/utxo}/btc/network_params.js +0 -0
  523. /package/dist/{utxo → esm/utxo}/btc/tools/asset_outpoint.d.ts +0 -0
  524. /package/dist/{utxo → esm/utxo}/btc/tools/asset_outpoint.js +0 -0
  525. /package/dist/{utxo → esm/utxo}/btc/tools/bitcoin_core.tool.d.ts +0 -0
  526. /package/dist/{utxo → esm/utxo}/btc/tools/bitcoin_core.tool.js +0 -0
  527. /package/dist/{utxo → esm/utxo}/btc/tools/esplora.tool.d.ts +0 -0
  528. /package/dist/{utxo → esm/utxo}/btc/tools/esplora.tool.js +0 -0
  529. /package/dist/{utxo → esm/utxo}/btc/tools/inscription_index.d.ts +0 -0
  530. /package/dist/{utxo → esm/utxo}/btc/tools/inscription_index.js +0 -0
  531. /package/dist/{utxo → esm/utxo}/btc/tools/ordiscan.tool.d.ts +0 -0
  532. /package/dist/{utxo → esm/utxo}/btc/tools/ordiscan.tool.js +0 -0
  533. /package/dist/{utxo → esm/utxo}/btc/tools/rare_sat_index.d.ts +0 -0
  534. /package/dist/{utxo → esm/utxo}/btc/tools/rare_sat_index.js +0 -0
  535. /package/dist/{utxo → esm/utxo}/btc/tools/rune_index.d.ts +0 -0
  536. /package/dist/{utxo → esm/utxo}/btc/tools/rune_index.js +0 -0
  537. /package/dist/{utxo → esm/utxo}/btc/tools/unisat.tool.d.ts +0 -0
  538. /package/dist/{utxo → esm/utxo}/btc/tools/unisat.tool.js +0 -0
  539. /package/dist/{utxo → esm/utxo}/coin_selection.d.ts +0 -0
  540. /package/dist/{utxo → esm/utxo}/coin_selection.js +0 -0
  541. /package/dist/{utxo → esm/utxo}/doge/doge_chains.d.ts +0 -0
  542. /package/dist/{utxo → esm/utxo}/doge/doge_chains.js +0 -0
  543. /package/dist/{utxo → esm/utxo}/doge/index.d.ts +0 -0
  544. /package/dist/{utxo → esm/utxo}/doge/index.js +0 -0
  545. /package/dist/{utxo → esm/utxo}/doge/network_params.d.ts +0 -0
  546. /package/dist/{utxo → esm/utxo}/doge/network_params.js +0 -0
  547. /package/dist/{utxo → esm/utxo}/ecc.d.ts +0 -0
  548. /package/dist/{utxo → esm/utxo}/ecc.js +0 -0
  549. /package/dist/{utxo → esm/utxo}/fee.d.ts +0 -0
  550. /package/dist/{utxo → esm/utxo}/fee.js +0 -0
  551. /package/dist/{utxo → esm/utxo}/index.d.ts +0 -0
  552. /package/dist/{utxo → esm/utxo}/index.js +0 -0
  553. /package/dist/{utxo → esm/utxo}/ltc/index.d.ts +0 -0
  554. /package/dist/{utxo → esm/utxo}/ltc/index.js +0 -0
  555. /package/dist/{utxo → esm/utxo}/ltc/ltc_chains.d.ts +0 -0
  556. /package/dist/{utxo → esm/utxo}/ltc/ltc_chains.js +0 -0
  557. /package/dist/{utxo → esm/utxo}/ltc/network_params.d.ts +0 -0
  558. /package/dist/{utxo → esm/utxo}/ltc/network_params.js +0 -0
  559. /package/dist/{utxo → esm/utxo}/script.d.ts +0 -0
  560. /package/dist/{utxo → esm/utxo}/script.js +0 -0
  561. /package/dist/{utxo → esm/utxo}/tools/broadcaster.d.ts +0 -0
  562. /package/dist/{utxo → esm/utxo}/tools/broadcaster.js +0 -0
  563. /package/dist/{utxo → esm/utxo}/tools/chain_tip_provider.d.ts +0 -0
  564. /package/dist/{utxo → esm/utxo}/tools/chain_tip_provider.js +0 -0
  565. /package/dist/{utxo → esm/utxo}/tools/fee_estimator.d.ts +0 -0
  566. /package/dist/{utxo → esm/utxo}/tools/fee_estimator.js +0 -0
  567. /package/dist/{utxo → esm/utxo}/tools/raw_transaction_provider.d.ts +0 -0
  568. /package/dist/{utxo → esm/utxo}/tools/raw_transaction_provider.js +0 -0
  569. /package/dist/{utxo → esm/utxo}/tools/utxo_provider.d.ts +0 -0
  570. /package/dist/{utxo → esm/utxo}/tools/utxo_provider.js +0 -0
  571. /package/dist/{utxo → esm/utxo}/unsigned_utxo_transaction.d.ts +0 -0
  572. /package/dist/{utxo → esm/utxo}/unsigned_utxo_transaction.js +0 -0
  573. /package/dist/{utxo → esm/utxo}/utxo.d.ts +0 -0
  574. /package/dist/{utxo → esm/utxo}/utxo.js +0 -0
  575. /package/dist/{utxo → esm/utxo}/utxo_chains.d.ts +0 -0
  576. /package/dist/{utxo → esm/utxo}/utxo_chains.js +0 -0
  577. /package/dist/{utxo → esm/utxo}/utxo_gas_pricing.d.ts +0 -0
  578. /package/dist/{utxo → esm/utxo}/utxo_gas_pricing.js +0 -0
  579. /package/dist/{utxo → esm/utxo}/utxo_network_params.d.ts +0 -0
  580. /package/dist/{utxo → esm/utxo}/utxo_network_params.js +0 -0
  581. /package/dist/{utxo → esm/utxo}/utxo_transaction_status.d.ts +0 -0
  582. /package/dist/{utxo → esm/utxo}/utxo_transaction_status.js +0 -0
@@ -0,0 +1,1109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EvmChain = void 0;
4
+ exports.decodeRevertData = decodeRevertData;
5
+ const ethers_1 = require("ethers");
6
+ const network_type_ts_1 = require("../network_type.js");
7
+ const chain_base_ts_1 = require("../chain.base.js");
8
+ const errors_ts_1 = require("../errors.js");
9
+ const priority_ts_1 = require("../priority.js");
10
+ const evm_gas_estimate_ts_1 = require("./evm_gas_estimate.js");
11
+ const transaction_status_ts_1 = require("../transaction_status.js");
12
+ const evm_transaction_status_ts_1 = require("./evm_transaction_status.js");
13
+ const evm_address_ts_1 = require("./evm_address.js");
14
+ const evm_token_ts_1 = require("./evm_token.js");
15
+ const unsigned_evm_transaction_ts_1 = require("./unsigned_evm_transaction.js");
16
+ // Priority profile mirrors omnichain-py/impl/evm/base.py:440-444
17
+ // (`_FEE_PRIORITY_PROFILE`): the reward-percentile is used for the 1559
18
+ // path (get_1559_fees's reward_percentile arg); the legacy multiplier
19
+ // applies ONLY when supportsEip1559 is false (Python does not fall back
20
+ // to the multiplier on the 1559 path).
21
+ const PRIORITY_REWARD_PERCENTILE = {
22
+ [priority_ts_1.Priority.SLOW]: 25,
23
+ [priority_ts_1.Priority.NORMAL]: 50,
24
+ [priority_ts_1.Priority.FAST]: 75,
25
+ };
26
+ // Legacy gas-price multiplier per priority tier — for the legacy branch only.
27
+ // Expressed as basis points × 100 so integer bigint arithmetic works.
28
+ const GAS_MULTIPLIER_PCT = {
29
+ [priority_ts_1.Priority.SLOW]: 100n,
30
+ [priority_ts_1.Priority.NORMAL]: 120n,
31
+ [priority_ts_1.Priority.FAST]: 150n,
32
+ };
33
+ // Empty-reward fallback tip: 2 gwei — matches Python `Web3.to_wei(2, 'gwei')`
34
+ // at impl/evm/base.py:1124.
35
+ const EMPTY_REWARD_FALLBACK_TIP = 2000000000n;
36
+ // Number of latest blocks sampled by eth_feeHistory. Python default 10
37
+ // (impl/evm/base.py:1099).
38
+ const FEE_HISTORY_BLOCK_COUNT = 10;
39
+ // Final-tip percentile picked across the sampled blocks after sorting.
40
+ // Python default 90.0 (impl/evm/base.py:1102).
41
+ const FINAL_TIP_PERCENTILE = 90;
42
+ // TS-only safety floor applied to any suggested gas price / tip. Python does
43
+ // NOT enforce a minimum: `sorted_tips[idx]` can be 0 on quiet L2 blocks.
44
+ // Silently unmineable transactions are unacceptable for a signing SDK, so
45
+ // TS clamps to 0.05 gwei.
46
+ const MIN_GAS_PRICE_FLOOR = 50000000n;
47
+ function atLeast(n, min) {
48
+ return n < min ? min : n;
49
+ }
50
+ const ERC20_TRANSFER_TOPIC = evm_transaction_status_ts_1.ERC20_TRANSFER_TOPIC;
51
+ const ERC20_ABI = [
52
+ 'function balanceOf(address owner) view returns (uint256)',
53
+ 'function decimals() view returns (uint8)',
54
+ 'function symbol() view returns (string)',
55
+ 'function transfer(address to, uint256 value)',
56
+ ];
57
+ const ERC20_INTERFACE = new ethers_1.Interface(ERC20_ABI);
58
+ class EvmChain extends chain_base_ts_1.Chain {
59
+ rpcUrl;
60
+ rpcUrls;
61
+ supportsEip1559;
62
+ hasL1Fee;
63
+ /**
64
+ * Default gas limit for native transfers. Matches Python's public attribute
65
+ * at `impl/evm/base.py:495` — v0 does not consume it inside the TS SDK
66
+ * (see `createTransferUnsignedTransaction`) but exposes it so consumers
67
+ * building their own transfer paths get identical numbers to Python. Wired
68
+ * into the SDK-owned transfer builder in a follow-up branch.
69
+ */
70
+ nativeTransferGasLimit;
71
+ /**
72
+ * Legacy `eth_gasPrice` multiplier for native transfers on non-1559 chains.
73
+ * Matches Python's public attribute at `impl/evm/base.py:496`. Same
74
+ * "declarative for consumers, unused internally in v0" note as
75
+ * `nativeTransferGasLimit`.
76
+ */
77
+ nativeTransferGasMultiplier;
78
+ supports7702;
79
+ _nativeToken;
80
+ _provider = null;
81
+ _resolvedRpcUrl = null;
82
+ constructor(init) {
83
+ // Conflict guard — refuse to construct an EvmChain over a chainId that
84
+ // the static family seeds have already registered as non-EVM. Prevents
85
+ // the case where `new EvmChain({ chainId: 728126428, … })` would silently
86
+ // succeed and then contradict `addressFor(728126428, …)` /
87
+ // `networkTypeOf(728126428)` (both return TRON). Mirrors
88
+ // `registerNonEvmChain`'s throw-on-conflict guard.
89
+ const existing = (0, network_type_ts_1.tryNetworkTypeOf)(init.chainId);
90
+ if (existing !== undefined && existing !== network_type_ts_1.NetworkType.EVM) {
91
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `chainId ${init.chainId} is registered as ${existing}; refusing to construct EvmChain for it`, { chainId: init.chainId });
92
+ }
93
+ super(init.chainId, init.name, network_type_ts_1.NetworkType.EVM, init.blockTimeSeconds, init.nativeSymbol, init.explorerBaseUrl);
94
+ this.rpcUrl = init.rpcUrl;
95
+ this.rpcUrls = init.rpcUrls ?? [];
96
+ if (this.rpcUrls.length > 1) {
97
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `EvmChainInit.rpcUrls accepts only ONE endpoint in 0.3.0 (got ${this.rpcUrls.length}). Automatic failover retry is deferred to a follow-up release; passing >1 endpoint would silently discard entries.`, { chainId: init.chainId });
98
+ }
99
+ this.supportsEip1559 = init.supportsEip1559 ?? true;
100
+ this.hasL1Fee = init.hasL1Fee ?? false;
101
+ this.nativeTransferGasLimit = init.nativeTransferGasLimit ?? 21000;
102
+ this.nativeTransferGasMultiplier = init.nativeTransferGasMultiplier ?? 1.4;
103
+ this.supports7702 = init.supports7702 ?? false;
104
+ this._nativeToken = evm_token_ts_1.EvmToken.native(init.chainId, init.nativeSymbol, init.nativeDecimals ?? 18);
105
+ // NOTE: no `registerNonEvmChain(id, EVM)` call — a module-scope write on
106
+ // 48 pre-baked chains would let a consumer's earlier
107
+ // `registerNonEvmChain(id, COSMOS)` turn `import '@getomnichain/omnichain'`
108
+ // into a permanently-poisoned module. Conflict detection lives in a
109
+ // single place: `registerNonEvmChain` reads `tryNetworkTypeOf` (which
110
+ // synthesizes EVM for positive-unregistered ids), so claiming a positive
111
+ // id for a non-EVM family requires `unregisterChain(id)` first.
112
+ }
113
+ get nativeToken() {
114
+ return this._nativeToken;
115
+ }
116
+ getErc20Token(symbol, contractAddress, decimals) {
117
+ // `EvmToken.erc20` → `new EvmToken` normalizes the identifier internally;
118
+ // no need to checksum here as well.
119
+ return evm_token_ts_1.EvmToken.erc20(this.chainId, symbol, contractAddress, decimals);
120
+ }
121
+ getProvider() {
122
+ if (this._provider)
123
+ return this._provider;
124
+ const rpcUrl = this.readRpcUrl();
125
+ this._resolvedRpcUrl = rpcUrl;
126
+ this._provider = new ethers_1.JsonRpcProvider(rpcUrl);
127
+ return this._provider;
128
+ }
129
+ /**
130
+ * Suggest gas fees for a priority tier. Mirrors Python's `_resolve_gas_pricing`
131
+ * dispatch (impl/evm/base.py:807-833):
132
+ *
133
+ * - legacy chains (`supportsEip1559 === false`): scale `eth_gasPrice` by
134
+ * the priority tier's legacy multiplier.
135
+ * - 1559 chains: sample eth_feeHistory across the last 10 blocks at the
136
+ * tier's reward percentile, sort, pick the p90 across blocks. On empty
137
+ * rewards, use 2 gwei. On RPC failure, bubble as `ChainError(RpcError)`
138
+ * (Python bubbles too — no defensive fallback).
139
+ */
140
+ async suggestGas(priority) {
141
+ const provider = this.getProvider();
142
+ if (!this.supportsEip1559) {
143
+ const mult = GAS_MULTIPLIER_PCT[priority];
144
+ // Direct `eth_gasPrice` — one round-trip, matches Python
145
+ // impl/evm/base.py:831-833. Avoids getFeeData's implicit
146
+ // `getBlock("latest")` + potential `eth_maxPriorityFeePerGas` extra
147
+ // calls, and dodges the trap where getFeeData's maxFeePerGas is
148
+ // `2×baseFee + tip` (not a legacy price) — using that as the legacy
149
+ // gasPrice would 3-4× overpay.
150
+ let gasPriceHex;
151
+ try {
152
+ gasPriceHex = (await provider.send('eth_gasPrice', []));
153
+ }
154
+ catch (err) {
155
+ throw this.rpcError('legacy eth_gasPrice transport failed', err);
156
+ }
157
+ let providerHint;
158
+ try {
159
+ providerHint = BigInt(gasPriceHex);
160
+ }
161
+ catch {
162
+ // Genuinely unparseable response — bubble as RpcError so on-call
163
+ // triage sees the RPC returned nonsense, not "0 gas price".
164
+ throw this.rpcError(`legacy eth_gasPrice returned unparseable response`, new Error(`could not parse ${String(gasPriceHex)} as bigint`));
165
+ }
166
+ // Zero-or-negative gasPrice: clamp up to MIN_GAS_PRICE_FLOOR, mirroring
167
+ // the 1559 branch's floor-on-sub-floor-tips behavior (evm_chain.ts:307).
168
+ // Python (`impl/evm/base.py:831-833`) multiplies whatever `eth_gasPrice`
169
+ // returns and never throws; the TS floor is the safety measure that
170
+ // prevents an unmineable suggestion. Consistent policy across branches.
171
+ const base = providerHint > 0n ? providerHint : MIN_GAS_PRICE_FLOOR;
172
+ const scaled = atLeast((base * mult) / 100n, MIN_GAS_PRICE_FLOOR);
173
+ // Legacy chains: only `gasPrice` is authoritative — matches Python
174
+ // (`impl/evm/base.py:830-833` returns `EvmGasPricing(gas_price=...)`).
175
+ // Populating maxFeePerGas/maxPriorityFeePerGas as duplicates would let
176
+ // a consumer build a type-2 tx paying the full gasPrice as a tip on
177
+ // top of base fee.
178
+ return new evm_gas_estimate_ts_1.EvmGasEstimate({ kind: 'legacy', gasPrice: scaled });
179
+ }
180
+ // 1559 path — mirrors omnichain-py get_1559_fees (impl/evm/base.py:1098-1132).
181
+ // NB: Python reads `base_fee_per_gas` from `eth_getBlock("latest")` (line
182
+ // 1109-1110); TS reuses `feeHistory.baseFeePerGas[-1]` — the JSON-RPC
183
+ // "next block projection", up to ±12.5% off. Deliberate: saves an RPC
184
+ // round-trip. (See the local SINAN questions doc for the upstream
185
+ // discussion — TS uses feeHistory's projection to skip the extra RPC.)
186
+ const rewardPercentile = PRIORITY_REWARD_PERCENTILE[priority];
187
+ let raw;
188
+ // Narrow try — only the RPC call. Response-shape and parse errors are
189
+ // distinct from transport failures and get a distinct ChainError kind.
190
+ try {
191
+ raw = (await provider.send('eth_feeHistory', [
192
+ `0x${FEE_HISTORY_BLOCK_COUNT.toString(16)}`,
193
+ 'latest',
194
+ [rewardPercentile],
195
+ ]));
196
+ }
197
+ catch (err) {
198
+ throw this.rpcError('eth_feeHistory transport failed', err);
199
+ }
200
+ // Narrow parse — only the shape checks + BigInt() coercions can throw
201
+ // for structural reasons here. `EvmGasEstimate` construction and the
202
+ // pure-arithmetic tip selection happen outside so that a defect there
203
+ // isn't mislabelled as an RPC-response malformed error.
204
+ let latestBaseFee;
205
+ let tips;
206
+ try {
207
+ const baseFees = raw.baseFeePerGas;
208
+ if (!Array.isArray(baseFees) || baseFees.length === 0) {
209
+ throw new Error('missing baseFeePerGas');
210
+ }
211
+ latestBaseFee = BigInt(baseFees[baseFees.length - 1] ?? '0x0');
212
+ const rewardRows = Array.isArray(raw.reward) ? raw.reward : [];
213
+ tips = rewardRows
214
+ .map((row) => (Array.isArray(row) ? row[0] : undefined))
215
+ .filter((v) => typeof v === 'string')
216
+ .map((v) => BigInt(v));
217
+ }
218
+ catch (err) {
219
+ // Distinct from the RpcError raised by the provider.send catch above:
220
+ // parse/shape failures indict the response, not the transport. Routed
221
+ // through rpcError() so the URL sanitizer scrubs the response body.
222
+ throw this.rpcError(`eth_feeHistory response malformed`, err);
223
+ }
224
+ let selectedTip;
225
+ if (tips.length === 0) {
226
+ selectedTip = EMPTY_REWARD_FALLBACK_TIP;
227
+ }
228
+ else {
229
+ const sortedTips = [...tips].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
230
+ const idx = Math.min(Math.floor((sortedTips.length * FINAL_TIP_PERCENTILE) / 100), sortedTips.length - 1);
231
+ selectedTip = sortedTips[idx] ?? 0n;
232
+ }
233
+ // TS safety floor — Python doesn't clamp (see MIN_GAS_PRICE_FLOOR).
234
+ const finalTip = atLeast(selectedTip, MIN_GAS_PRICE_FLOOR);
235
+ // Safety buffer: base fee can climb 12.5%/block; caller may wait multiple blocks.
236
+ const maxFeePerGas = latestBaseFee * 2n + finalTip;
237
+ return new evm_gas_estimate_ts_1.EvmGasEstimate({
238
+ kind: 'eip1559',
239
+ maxPriorityFeePerGas: finalTip,
240
+ maxFeePerGas,
241
+ });
242
+ }
243
+ readRpcUrl() {
244
+ if (this.rpcUrl && this.rpcUrl.trim().length > 0)
245
+ return this.rpcUrl.trim();
246
+ if (this.rpcUrls.length > 0) {
247
+ for (const candidate of this.rpcUrls) {
248
+ if (candidate && candidate.trim().length > 0)
249
+ return candidate.trim();
250
+ }
251
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcNotConfigured, `${this.name}: rpcUrls was supplied but every entry is blank; refusing to fall back to env or public defaults`, { chainId: this.chainId });
252
+ }
253
+ const env = globalThis.process?.env;
254
+ const candidates = envCandidatesFor(this.name, this.chainId);
255
+ for (const key of candidates) {
256
+ const value = env?.[key];
257
+ if (value && value.trim().length > 0)
258
+ return value.trim();
259
+ }
260
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcNotConfigured, `${this.name} RPC URL is not configured (pass rpcUrl, rpcUrls at construction, or set one of: ${candidates.join(', ')})`, { chainId: this.chainId, envCandidates: candidates });
261
+ }
262
+ rpcHost() {
263
+ const url = this._resolvedRpcUrl ?? this.rpcUrl;
264
+ if (!url)
265
+ return undefined;
266
+ try {
267
+ const u = new URL(url);
268
+ return `${u.protocol}//${u.host}`;
269
+ }
270
+ catch {
271
+ return undefined;
272
+ }
273
+ }
274
+ getWalletExplorerUrl(address) {
275
+ return `${this.explorerBaseUrl}/address/${address}`;
276
+ }
277
+ getTokenExplorerUrl(tokenIdentifier) {
278
+ if (tokenIdentifier === undefined) {
279
+ return this.explorerBaseUrl;
280
+ }
281
+ return `${this.explorerBaseUrl}/token/${tokenIdentifier}`;
282
+ }
283
+ getTransactionExplorerUrl(txHash) {
284
+ const prefixed = txHash.startsWith('0x') ? txHash : `0x${txHash}`;
285
+ return `${this.explorerBaseUrl}/tx/${prefixed}`;
286
+ }
287
+ validateAddress(raw) {
288
+ try {
289
+ new evm_address_ts_1.EvmAddress(raw);
290
+ return true;
291
+ }
292
+ catch {
293
+ return false;
294
+ }
295
+ }
296
+ normalizeAddressOrThrow(raw, field) {
297
+ const body = raw.replace(/^0[xX]/, '');
298
+ try {
299
+ return (0, ethers_1.getAddress)(`0x${body}`);
300
+ }
301
+ catch (err) {
302
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM address for ${field}: ${raw}`, { chainId: this.chainId, address: raw }, err instanceof Error ? err : undefined);
303
+ }
304
+ }
305
+ validateTokenIdentifier(raw) {
306
+ if (raw === undefined)
307
+ return true;
308
+ return this.validateAddress(raw);
309
+ }
310
+ async getBalance(owner, tokenIdentifier) {
311
+ if (!this.validateAddress(owner)) {
312
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM address: ${owner}`, {
313
+ chainId: this.chainId,
314
+ address: owner,
315
+ });
316
+ }
317
+ if (!this.validateTokenIdentifier(tokenIdentifier)) {
318
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidTokenIdentifier, `Invalid EVM token identifier: ${tokenIdentifier}`, { chainId: this.chainId, identifier: tokenIdentifier });
319
+ }
320
+ const provider = this.getProvider();
321
+ try {
322
+ if (tokenIdentifier === undefined) {
323
+ return await provider.getBalance(owner);
324
+ }
325
+ const contract = new ethers_1.Contract(tokenIdentifier, ERC20_ABI, provider);
326
+ return (await contract.balanceOf(owner));
327
+ }
328
+ catch (err) {
329
+ throw this.rpcError(`Failed to read balance for ${owner}`, err);
330
+ }
331
+ }
332
+ async createTransferUnsignedTransaction(req) {
333
+ if (!this.validateAddress(req.to)) {
334
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid recipient address: ${req.to}`, {
335
+ chainId: this.chainId,
336
+ address: req.to,
337
+ });
338
+ }
339
+ if (req.from !== undefined && !this.validateAddress(req.from)) {
340
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid sender address: ${req.from}`, {
341
+ chainId: this.chainId,
342
+ address: req.from,
343
+ });
344
+ }
345
+ if (!this.validateTokenIdentifier(req.tokenIdentifier)) {
346
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidTokenIdentifier, `Invalid token identifier: ${req.tokenIdentifier}`, { chainId: this.chainId, identifier: req.tokenIdentifier });
347
+ }
348
+ // gasPricing is on the CreateTransferRequest interface (Python
349
+ // parity) but per-chain wiring is deferred to a follow-up card.
350
+ // Rejecting it here rather than silently ignoring — a money knob
351
+ // that fails open is worse than not shipping it.
352
+ if (req.gasPricing !== undefined) {
353
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'CreateTransferRequest.gasPricing is not yet consumed by EvmChain (Phase 2 follow-up). Use ethers tx builder options directly for now.', { chainId: this.chainId });
354
+ }
355
+ // isFullBalance is on the CreateTransferRequest interface (Python
356
+ // parity) but needs a fee-reserve computation before it can be
357
+ // safely wired — sending `value = balance` on native leaves 0 for
358
+ // gas → guaranteed insufficient-funds; on SPL it leaves 0 for rent.
359
+ // Deferred to a follow-up card that lands the estimated-fee subtract.
360
+ if (req.isFullBalance === true) {
361
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'CreateTransferRequest.isFullBalance is not yet supported on EvmChain — pass `amount` or `amountHr` explicitly and reserve fees yourself.', { chainId: this.chainId });
362
+ }
363
+ // Only fetch decimals when amountHr is the input form — avoids two
364
+ // extra eth_calls on every bigint-amount transfer. Native path uses
365
+ // the SDK-declared decimals; ERC-20 path uses a STRICT resolver
366
+ // that throws on RPC failure (the defensive fallback to decimals=0
367
+ // would silently produce a wildly wrong minor-units amount).
368
+ let tokenDecimals = 0;
369
+ if (req.amountHr !== undefined) {
370
+ tokenDecimals =
371
+ req.tokenIdentifier === undefined
372
+ ? this._nativeToken.decimals
373
+ : await this.resolveErc20DecimalsStrict(req.tokenIdentifier);
374
+ }
375
+ const resolved = (0, chain_base_ts_1.resolveTransferAmount)(req, tokenDecimals);
376
+ const amountMr = resolved.kind === 'exact' ? resolved.amountMr : 0n;
377
+ if (req.tokenIdentifier === undefined) {
378
+ return new unsigned_evm_transaction_ts_1.UnsignedEvmTransaction({
379
+ chainId: this.chainId,
380
+ from: req.from,
381
+ to: req.to,
382
+ value: amountMr,
383
+ data: '0x',
384
+ });
385
+ }
386
+ const data = ERC20_INTERFACE.encodeFunctionData('transfer', [req.to, amountMr]);
387
+ return new unsigned_evm_transaction_ts_1.UnsignedEvmTransaction({
388
+ chainId: this.chainId,
389
+ from: req.from,
390
+ to: req.tokenIdentifier,
391
+ value: 0n,
392
+ data,
393
+ });
394
+ }
395
+ async getChainTipHeight() {
396
+ try {
397
+ return await this.getProvider().getBlockNumber();
398
+ }
399
+ catch (err) {
400
+ throw this.rpcError('Failed to read chain tip', err);
401
+ }
402
+ }
403
+ async broadcast(signed, opts) {
404
+ if (opts && opts.signal !== undefined) {
405
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.FeatureNotSupported, `EVM broadcast: signal is not honored in 0.3.0 (silently ignoring would let a caller conclude 'not sent' while the tx still lands). Cancellation returns in 0.3.1.`, { chainId: this.chainId });
406
+ }
407
+ let hex;
408
+ if (typeof signed === 'string') {
409
+ const stripped = signed.startsWith('0x') ? signed.slice(2) : signed;
410
+ if (!/^[0-9a-fA-F]+$/.test(stripped) || stripped.length % 2 !== 0 || stripped.length === 0) {
411
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `EVM broadcast: signed transaction must be 0x-prefixed hex or Uint8Array (got malformed string of length ${signed.length})`, { chainId: this.chainId });
412
+ }
413
+ hex = `0x${stripped}`;
414
+ }
415
+ else {
416
+ if (signed.length === 0) {
417
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `EVM broadcast: signed transaction bytes are empty`, { chainId: this.chainId });
418
+ }
419
+ hex = (0, ethers_1.hexlify)(signed);
420
+ }
421
+ try {
422
+ const resp = await this.getProvider().broadcastTransaction(hex);
423
+ return resp.hash;
424
+ }
425
+ catch (err) {
426
+ const rawMsg = (err instanceof Error ? err.message : String(err)).toLowerCase();
427
+ if (/already[-_ ]?known|known\s+transaction|transaction[-_ ]?already[-_ ]?known|already\s+in\s+(?:the\s+)?(?:mempool|pool)|already[-_ ]?present/.test(rawMsg)) {
428
+ // Node "already known" is authoritative for THAT node's mempool —
429
+ // the identical signed bytes are pending or landed. Return the
430
+ // deterministic hash so the consumer stays on the polling path.
431
+ // Do NOT gate on a follow-up getTransaction read: load-balanced
432
+ // providers (Alchemy/Infura/QuickNode round-robin) routinely serve
433
+ // the confirmation read from a different backend that has not yet
434
+ // seen the pending tx → null → falsely-terminal BroadcastRejected
435
+ // → consumer re-signs against a fresh nonce → double-send while
436
+ // the original is live. If the tx really never lands, the
437
+ // consumer's getTransactionStatus poll will surface NotFound and
438
+ // the safe-broadcast rule (re-broadcast same bytes, never re-sign)
439
+ // still applies. Matches SolanaChain/UtxoChain already-known paths.
440
+ return (0, ethers_1.keccak256)(hex);
441
+ }
442
+ throw this.classifyBroadcastError(err);
443
+ }
444
+ }
445
+ async getPendingNonce(address) {
446
+ if (!this.validateAddress(address)) {
447
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM address for getPendingNonce: ${address}`, { chainId: this.chainId, address });
448
+ }
449
+ const normalized = this.normalizeAddressOrThrow(address, 'getPendingNonce.address');
450
+ try {
451
+ const n = await this.getProvider().getTransactionCount(normalized, 'pending');
452
+ return BigInt(n);
453
+ }
454
+ catch (err) {
455
+ throw this.rpcError(`Failed to read pending nonce for ${normalized}`, err, { address: normalized });
456
+ }
457
+ }
458
+ async getDelegation(address) {
459
+ if (!this.supports7702) {
460
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.FeatureNotSupported, `EVM chain ${this.name} was not initialized with supports7702: true`, { chainId: this.chainId });
461
+ }
462
+ try {
463
+ (0, ethers_1.getAddress)(address);
464
+ }
465
+ catch (err) {
466
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM address: ${address}`, { chainId: this.chainId, address }, err instanceof Error ? err : undefined);
467
+ }
468
+ let code;
469
+ try {
470
+ code = await this.getProvider().getCode(address);
471
+ }
472
+ catch (err) {
473
+ throw this.rpcError(`Failed to read code for ${address}`, err, { address });
474
+ }
475
+ if (!code.startsWith('0x'))
476
+ return null;
477
+ const stripped = code.slice(2).toLowerCase();
478
+ if (stripped.length !== 46)
479
+ return null;
480
+ if (!stripped.startsWith('ef0100'))
481
+ return null;
482
+ return { delegate: (0, ethers_1.getAddress)(`0x${stripped.slice(6)}`) };
483
+ }
484
+ async call(req) {
485
+ if (!this.validateAddress(req.to)) {
486
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM 'to' address for call: ${req.to}`, { chainId: this.chainId, address: req.to });
487
+ }
488
+ if (req.from !== undefined && !this.validateAddress(req.from)) {
489
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM 'from' address for call: ${req.from}`, { chainId: this.chainId, address: req.from });
490
+ }
491
+ if (!/^0x([0-9a-fA-F]{2})*$/.test(req.data)) {
492
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `EvmCallRequest.data must be 0x-prefixed even-length hex`, { chainId: this.chainId });
493
+ }
494
+ const provider = this.getProvider();
495
+ const tx = {
496
+ to: this.normalizeAddressOrThrow(req.to, 'call.to'),
497
+ data: req.data,
498
+ from: req.from === undefined ? undefined : this.normalizeAddressOrThrow(req.from, 'call.from'),
499
+ value: req.value,
500
+ };
501
+ if (req.estimateGas && req.blockTag !== undefined) {
502
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `EvmChain.call: blockTag is not honored when estimateGas: true (ethers v6 eth_estimateGas has no block-tag plumbing). Split the call: use estimateGas without blockTag, or drop estimateGas to run eth_call at the tag.`, { chainId: this.chainId });
503
+ }
504
+ try {
505
+ if (req.estimateGas) {
506
+ const g = await provider.estimateGas(tx);
507
+ return { gasEstimate: BigInt(g) };
508
+ }
509
+ const result = await provider.call(req.blockTag !== undefined ? { ...tx, blockTag: req.blockTag } : tx);
510
+ return { result };
511
+ }
512
+ catch (err) {
513
+ const strCode = ethersErrCode(err);
514
+ const rawData = err.data
515
+ ?? err.info?.error?.data;
516
+ const revertData = typeof rawData === 'string' && /^0x[0-9a-fA-F]*$/.test(rawData) ? rawData : undefined;
517
+ if (strCode === 'CALL_EXCEPTION' || revertData !== undefined) {
518
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.SimulationFailed, (0, errors_ts_1.sanitizeMessage)(`eth_${req.estimateGas ? 'estimateGas' : 'call'} on ${req.to} reverted`, this._resolvedRpcUrl), { chainId: this.chainId, revertData }, (0, errors_ts_1.sanitizeCause)(err, this._resolvedRpcUrl));
519
+ }
520
+ if (strCode === 'INSUFFICIENT_FUNDS') {
521
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InsufficientFunds, (0, errors_ts_1.sanitizeMessage)(`eth_${req.estimateGas ? 'estimateGas' : 'call'} on ${req.to}: insufficient funds`, this._resolvedRpcUrl), { chainId: this.chainId }, (0, errors_ts_1.sanitizeCause)(err, this._resolvedRpcUrl));
522
+ }
523
+ throw this.rpcError(`eth_${req.estimateGas ? 'estimateGas' : 'call'} on ${req.to} failed`, err);
524
+ }
525
+ }
526
+ buildAuthorizationDigest(input) {
527
+ if (!this.supports7702) {
528
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.FeatureNotSupported, `EVM chain ${this.name} was not initialized with supports7702: true`, { chainId: this.chainId });
529
+ }
530
+ if (input.chainId !== this.chainId) {
531
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization chainId ${input.chainId} does not match ${this.chainId}. Cross-chain replay guard: chainId=0 wildcards are rejected by default.`, { chainId: this.chainId });
532
+ }
533
+ if (input.nonce < 0n) {
534
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization nonce must be >= 0`, { chainId: this.chainId });
535
+ }
536
+ let normalizedDelegate;
537
+ try {
538
+ normalizedDelegate = (0, ethers_1.getAddress)(input.delegate);
539
+ }
540
+ catch (err) {
541
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `buildAuthorizationDigest: delegate is not a valid EVM address: ${input.delegate}`, { chainId: this.chainId, address: input.delegate }, err instanceof Error ? err : undefined);
542
+ }
543
+ const rlp = (0, ethers_1.encodeRlp)([
544
+ (0, ethers_1.toBeArray)(BigInt(input.chainId)),
545
+ normalizedDelegate,
546
+ (0, ethers_1.toBeArray)(input.nonce),
547
+ ]);
548
+ const payload = (0, ethers_1.concat)(['0x05', rlp]);
549
+ return (0, ethers_1.getBytes)((0, ethers_1.keccak256)(payload));
550
+ }
551
+ async createUnsignedTransaction(req) {
552
+ if (req && req.signal !== undefined) {
553
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.FeatureNotSupported, `EVM createUnsignedTransaction: signal is not honored in 0.3.0 (silently ignoring would let a caller conclude 'not built' while the blockhash fetch/build proceeds against stale state). Cancellation returns in 0.3.1.`, { chainId: this.chainId });
554
+ }
555
+ if (!req.from) {
556
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'CreateEvmUnsignedTransactionRequest.from is required', { chainId: this.chainId });
557
+ }
558
+ if (!this.validateAddress(req.from)) {
559
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM 'from' address (fails EIP-55 checksum or byte length): ${req.from}`, { chainId: this.chainId, address: req.from });
560
+ }
561
+ if (!req.to) {
562
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'CreateEvmUnsignedTransactionRequest.to is required', { chainId: this.chainId });
563
+ }
564
+ if (!this.validateAddress(req.to)) {
565
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Invalid EVM 'to' address (fails EIP-55 checksum or byte length): ${req.to}`, { chainId: this.chainId, address: req.to });
566
+ }
567
+ if (req.data !== undefined && !/^0x([0-9a-fA-F]{2})*$/.test(req.data)) {
568
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `CreateEvmUnsignedTransactionRequest.data must be a 0x-prefixed even-length hex string`, { chainId: this.chainId });
569
+ }
570
+ if (req.authorizationList !== undefined) {
571
+ if (!Array.isArray(req.authorizationList) || req.authorizationList.length === 0) {
572
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, 'authorizationList must be a non-empty array when provided', { chainId: this.chainId });
573
+ }
574
+ if (!this.supports7702) {
575
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.FeatureNotSupported, `EVM chain ${this.name} was not initialized with supports7702: true`, { chainId: this.chainId });
576
+ }
577
+ for (let i = 0; i < req.authorizationList.length; i++) {
578
+ const auth = req.authorizationList[i];
579
+ if (auth.chainId !== this.chainId) {
580
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization[${i}].chainId ${auth.chainId} does not match ${this.chainId}. Cross-chain replay guard: chainId=0 wildcards are rejected by default.`, { chainId: this.chainId });
581
+ }
582
+ if (!this.validateAddress(auth.address)) {
583
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidAddress, `Authorization[${i}].address is not a valid EVM address: ${auth.address}`, { chainId: this.chainId, address: auth.address });
584
+ }
585
+ if (typeof auth.nonce !== 'bigint' || auth.nonce < 0n) {
586
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization[${i}].nonce must be a non-negative bigint (got ${typeof auth.nonce})`, { chainId: this.chainId });
587
+ }
588
+ const sig = auth.signature;
589
+ if (!sig || typeof sig !== 'object'
590
+ || typeof sig.r !== 'string' || !/^0x[0-9a-fA-F]{64}$/.test(sig.r)
591
+ || typeof sig.s !== 'string' || !/^0x[0-9a-fA-F]{64}$/.test(sig.s)
592
+ || (sig.yParity !== 0 && sig.yParity !== 1)) {
593
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization[${i}].signature must be { r: 0x + 64-hex, s: 0x + 64-hex, yParity: 0 | 1 }`, { chainId: this.chainId });
594
+ }
595
+ const rBig = BigInt(sig.r);
596
+ const sBig = BigInt(sig.s);
597
+ if (rBig === 0n || sBig === 0n) {
598
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization[${i}].signature: r and s must both be non-zero`, { chainId: this.chainId });
599
+ }
600
+ // EIP-2 low-s canonical form. An authorization with s > secp256k1n/2
601
+ // is silently rejected by the EVM at execution — tx lands, gas is
602
+ // spent, no delegation installed. Catch at build time.
603
+ const SECP256K1_HALF_N = 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0n;
604
+ if (sBig > SECP256K1_HALF_N) {
605
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `Authorization[${i}].signature.s violates EIP-2 low-s canonical form (s must be <= secp256k1n/2). Non-canonical authorizations are silently skipped by the EVM.`, { chainId: this.chainId });
606
+ }
607
+ }
608
+ }
609
+ if (!this.supportsEip1559 && (req.maxFeePerGas !== undefined || req.maxPriorityFeePerGas !== undefined)) {
610
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `EVM chain ${this.name} is legacy (supportsEip1559=false); maxFeePerGas/maxPriorityFeePerGas are not accepted. Use gasPrice via UnsignedEvmTransaction consumers.`, { chainId: this.chainId });
611
+ }
612
+ const emittedType = req.authorizationList !== undefined ? 4 : this.supportsEip1559 ? 2 : 0;
613
+ return new unsigned_evm_transaction_ts_1.UnsignedEvmTransaction({
614
+ chainId: this.chainId,
615
+ from: this.normalizeAddressOrThrow(req.from, 'createUnsignedTransaction.from'),
616
+ to: this.normalizeAddressOrThrow(req.to, 'createUnsignedTransaction.to'),
617
+ value: req.value ?? 0n,
618
+ data: req.data ?? '0x',
619
+ type: emittedType,
620
+ authorizationList: req.authorizationList,
621
+ gasLimit: req.gasLimit,
622
+ nonce: req.nonce,
623
+ maxFeePerGas: req.maxFeePerGas,
624
+ maxPriorityFeePerGas: req.maxPriorityFeePerGas,
625
+ });
626
+ }
627
+ classifyBroadcastError(err) {
628
+ const rpc = this._resolvedRpcUrl;
629
+ const strCode = ethersErrCode(err);
630
+ const numCode = errCode(err);
631
+ const rawMsg = err instanceof Error ? err.message : String(err);
632
+ const msg = rawMsg.toLowerCase();
633
+ const safeCause = (0, errors_ts_1.sanitizeCause)(err, rpc);
634
+ if (strCode === 'NONCE_EXPIRED' || msg.includes('nonce too low') || msg.includes('nonce_too_low') || msg.includes('nonce has already been used')) {
635
+ return new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.NonceTooLow, (0, errors_ts_1.sanitizeMessage)(`EVM broadcast rejected: nonce too low on ${this.name}`, rpc), { chainId: this.chainId, rpcHost: this.rpcHost() }, safeCause);
636
+ }
637
+ if (strCode === 'INSUFFICIENT_FUNDS' || msg.includes('insufficient funds')) {
638
+ return new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InsufficientFunds, (0, errors_ts_1.sanitizeMessage)(`EVM broadcast rejected: insufficient funds on ${this.name}`, rpc), { chainId: this.chainId, rpcHost: this.rpcHost() }, safeCause);
639
+ }
640
+ if (strCode === 'REPLACEMENT_UNDERPRICED' || msg.includes('replacement') || msg.includes('underpriced')) {
641
+ return new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.BroadcastRejected, (0, errors_ts_1.sanitizeMessage)(`EVM broadcast rejected on ${this.name} (replacement/known-nonce)`, rpc), { chainId: this.chainId, rpcHost: this.rpcHost() }, safeCause);
642
+ }
643
+ const rateLimitCodes = new Set([-32005, -32007, -32016, -32029, 429]);
644
+ if (numCode !== undefined && rateLimitCodes.has(numCode)) {
645
+ return this.rpcError(`EVM broadcast rate-limited on ${this.name}`, err);
646
+ }
647
+ const transportSignals = /econnreset|econnrefused|econnaborted|etimedout|enotfound|network request failed|fetch failed|socket hang up|too\s+many\s+requests|rate.?limit|network error/;
648
+ const httpStatus = err.info?.status
649
+ ?? err.status;
650
+ const isTransportHttp = typeof httpStatus === 'number' && (httpStatus === 429 || httpStatus === 502 || httpStatus === 503 || httpStatus === 504);
651
+ if (transportSignals.test(msg) || isTransportHttp
652
+ || strCode === 'NETWORK_ERROR' || strCode === 'SERVER_ERROR' || strCode === 'TIMEOUT') {
653
+ return this.rpcError(`EVM broadcast transport failure on ${this.name}`, err);
654
+ }
655
+ // Default terminal: any unrecognized rejection is a node reject, NOT a
656
+ // transient transport failure. This matches Solana/UTXO defaults and
657
+ // prevents a relayer retry-loop from re-broadcasting a permanently-
658
+ // invalid tx forever.
659
+ return new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.BroadcastRejected, (0, errors_ts_1.sanitizeMessage)(`EVM broadcast rejected on ${this.name}`, rpc), { chainId: this.chainId, rpcHost: this.rpcHost() }, safeCause);
660
+ }
661
+ async getTransactionStatus(txHash, opts) {
662
+ if (Array.isArray(txHash)) {
663
+ return runBatchStatus(txHash, (h, batchSignal) => {
664
+ const composedSignal = opts?.signal
665
+ ? anySignal(opts.signal, batchSignal)
666
+ : batchSignal;
667
+ return this.getSingleTransactionStatus(h, { ...opts, signal: composedSignal });
668
+ });
669
+ }
670
+ return this.getSingleTransactionStatus(txHash, opts);
671
+ }
672
+ async getSingleTransactionStatus(txHash, opts) {
673
+ if (opts?.confirmations !== undefined && opts.confirmations > 1 && !opts.wait) {
674
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `getTransactionStatus: confirmations > 1 requires wait: true (a single status read cannot enforce block depth)`, { chainId: this.chainId, txHash });
675
+ }
676
+ if (!opts?.wait)
677
+ return this.getTransactionStatusOnce(txHash);
678
+ if (opts.signal?.aborted) {
679
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `getTransactionStatus aborted before first poll`, { chainId: this.chainId, txHash });
680
+ }
681
+ if (opts.timeoutMs === undefined) {
682
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `getTransactionStatus: wait: true requires an explicit timeoutMs. Unbounded polling would pin an RPC worker + connection forever if the tx is dropped.`, { chainId: this.chainId, txHash });
683
+ }
684
+ if (opts.timeoutMs < 0) {
685
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `getTransactionStatus: timeoutMs must be >= 0`, { chainId: this.chainId, txHash });
686
+ }
687
+ const deadline = Date.now() + opts.timeoutMs;
688
+ const pollMs = Math.max(500, this.blockTimeSeconds * 1000);
689
+ const minConfirmations = Math.max(1, opts.confirmations ?? 1);
690
+ let last;
691
+ while (true) {
692
+ last = await this.getTransactionStatusOnce(txHash);
693
+ if (last.status === 'Success' || last.status === 'Failed') {
694
+ if (minConfirmations <= 1)
695
+ return last;
696
+ let tip;
697
+ try {
698
+ tip = await this.getProvider().getBlockNumber();
699
+ }
700
+ catch (err) {
701
+ throw this.rpcError(`Failed to read chain tip for confirmations check`, err, { txHash });
702
+ }
703
+ const depth = last.blockNumber === null ? 0 : tip - last.blockNumber + 1;
704
+ if (depth >= minConfirmations)
705
+ return last;
706
+ if (Date.now() >= deadline) {
707
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, `getTransactionStatus timed out after ${opts.timeoutMs}ms with only ${depth} confirmation(s); required ${minConfirmations}. Consumer must NOT credit as final.`, { chainId: this.chainId, txHash });
708
+ }
709
+ }
710
+ else if (Date.now() >= deadline) {
711
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, `getTransactionStatus timed out after ${opts.timeoutMs}ms; last observed status was ${last.status}. Consumer must NOT credit as final AND must NOT re-sign — the tx may still land. Re-broadcast the same signed bytes or continue polling with the same txHash.`, { chainId: this.chainId, txHash });
712
+ }
713
+ await interruptibleSleep(pollMs, opts.signal);
714
+ if (opts.signal?.aborted) {
715
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.InvalidArgument, `getTransactionStatus aborted mid-poll`, { chainId: this.chainId, txHash });
716
+ }
717
+ }
718
+ }
719
+ async getTransactionStatusOnce(txHash) {
720
+ const provider = this.getProvider();
721
+ let tx = null;
722
+ let receipt = null;
723
+ try {
724
+ [tx, receipt] = await Promise.all([
725
+ provider.getTransaction(txHash),
726
+ provider.getTransactionReceipt(txHash),
727
+ ]);
728
+ }
729
+ catch (err) {
730
+ throw this.rpcError(`Failed to read tx ${txHash}`, err, { txHash });
731
+ }
732
+ if (tx === null && receipt === null)
733
+ return evm_transaction_status_ts_1.EvmTransactionStatus.notFound(this.chainId, null);
734
+ if (receipt === null)
735
+ return evm_transaction_status_ts_1.EvmTransactionStatus.pending(this.chainId);
736
+ // Receipt exists but the tx body doesn't — real race on load-balanced/
737
+ // pruned RPC endpoints where getTransactionReceipt succeeds while
738
+ // getTransactionByHash returns null. `tx.value` and `tx.to` are load-
739
+ // bearing for the native transfer legs of decodeBalanceChanges; falling
740
+ // back to `?? 0n` / `?? null` would emit a Success with a silently
741
+ // truncated balanceChanges map (recipient row missing entirely,
742
+ // sender debit off by the transfer value). Python parity: omnichain-py's
743
+ // impl/evm/base.py accesses `tx.value` directly and blows up on a
744
+ // missing body. TS returns Pending — receipt-only is transient node
745
+ // state; the consumer's next poll will land on a node with the full tx.
746
+ if (tx === null)
747
+ return evm_transaction_status_ts_1.EvmTransactionStatus.pending(this.chainId);
748
+ const succeeded = receipt.status === 1;
749
+ // Parallelize the two independent post-receipt lookups: getBlock (for
750
+ // inclusionAt) and the OP-stack raw-receipt fetch (for l1Fee). Both
751
+ // depend only on receipt.blockNumber / txHash, not on each other.
752
+ const [inclusionAt, l1Fee] = await Promise.all([
753
+ (async () => {
754
+ try {
755
+ const block = await provider.getBlock(receipt.blockNumber);
756
+ if (block?.timestamp !== undefined) {
757
+ return new Date(Number(block.timestamp) * 1000);
758
+ }
759
+ return null;
760
+ }
761
+ catch {
762
+ // leave null — a 1970-01-01 sentinel would silently pass
763
+ // through consumer SLA/age math as a real inclusion time.
764
+ return null;
765
+ }
766
+ })(),
767
+ (async () => {
768
+ // OP-stack rollups charge an L1 data fee (`l1Fee` on the raw
769
+ // receipt). ethers v6 strips it in its parsed TransactionReceipt
770
+ // shape, so a second raw fetch is required. Gated on `hasL1Fee`.
771
+ // Return undefined for "provider did not surface it" (either
772
+ // hasL1Fee=false or the raw send failed/omitted the field) —
773
+ // tracked separately from "l1Fee is genuinely 0n" so
774
+ // fees.l1FeeWei reflects presence, not value.
775
+ if (!this.hasL1Fee)
776
+ return undefined;
777
+ try {
778
+ const raw = (await provider.send('eth_getTransactionReceipt', [txHash]));
779
+ const rawL1 = raw?.l1Fee;
780
+ if (rawL1 === undefined || rawL1 === null)
781
+ return undefined;
782
+ if (typeof rawL1 === 'bigint')
783
+ return rawL1;
784
+ if (typeof rawL1 === 'number')
785
+ return BigInt(rawL1);
786
+ if (typeof rawL1 === 'string' && rawL1.length > 0)
787
+ return BigInt(rawL1);
788
+ return undefined;
789
+ }
790
+ catch {
791
+ return undefined;
792
+ }
793
+ })(),
794
+ ]);
795
+ // gasLimit: the sender-set limit from tx.gasLimit. `null` when the tx
796
+ // body isn't available (pruned/receipt-only) — falling back to
797
+ // receipt.gasUsed here would fabricate a "100% utilization" that
798
+ // consumers can't distinguish from a real observation.
799
+ const fees = new evm_transaction_status_ts_1.EvmTransactionGasFees({
800
+ gasLimit: tx?.gasLimit ?? null,
801
+ gasLimitUsed: receipt.gasUsed,
802
+ effectiveGasPrice: receipt.gasPrice,
803
+ gasPrice: tx?.gasPrice ?? undefined,
804
+ maxFeePerGas: tx?.maxFeePerGas ?? undefined,
805
+ maxPriorityFeePerGas: tx?.maxPriorityFeePerGas ?? undefined,
806
+ l1FeeWei: l1Fee,
807
+ });
808
+ if (!succeeded) {
809
+ const errorInfo = await extractRevertInfo(provider, tx, receipt);
810
+ return evm_transaction_status_ts_1.EvmTransactionStatus.failed({
811
+ chainId: this.chainId,
812
+ inclusionAt,
813
+ error: errorInfo,
814
+ fees,
815
+ blockNumber: receipt.blockNumber,
816
+ });
817
+ }
818
+ // Only allocated on the Success path — failed txs carry logs: null.
819
+ const logs = (receipt.logs ?? []).map((l) => new evm_transaction_status_ts_1.EvmParsedTransactionLog(l.address, [...l.topics], l.data));
820
+ const nativeValue = tx?.value ?? 0n;
821
+ let balanceChanges;
822
+ try {
823
+ balanceChanges = await this.decodeBalanceChanges({
824
+ from: tx ? tx.from : (receipt.from ?? ''),
825
+ to: tx?.to ?? receipt.to ?? null,
826
+ value: nativeValue,
827
+ gasCost: fees.totalNativeDebitWei,
828
+ receipt,
829
+ });
830
+ }
831
+ catch (err) {
832
+ if (err instanceof errors_ts_1.ChainError)
833
+ throw err;
834
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.TransactionDecodeFailed, `Failed to decode receipt logs for tx ${txHash}`, { chainId: this.chainId, txHash, rpcHost: this.rpcHost() }, err);
835
+ }
836
+ return evm_transaction_status_ts_1.EvmTransactionStatus.successful({
837
+ chainId: this.chainId,
838
+ inclusionAt,
839
+ balanceChanges,
840
+ logs,
841
+ fees,
842
+ blockNumber: receipt.blockNumber,
843
+ });
844
+ }
845
+ async decodeBalanceChanges(args) {
846
+ const { from, to, value, gasCost, receipt } = args;
847
+ if (!receipt || !Array.isArray(receipt.logs)) {
848
+ throw new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.TransactionDecodeFailed, 'Receipt is missing required fields', { chainId: this.chainId, txHash: receipt?.hash, rpcHost: this.rpcHost() });
849
+ }
850
+ const rawChanges = new Map();
851
+ const fromAddr = (from ?? '').toLowerCase();
852
+ const toAddr = to ? to.toLowerCase() : null;
853
+ // Sender's native debit = value + gasCost (matches Python
854
+ // impl/evm/base.py:_get_balance_changes fee-inclusive semantics).
855
+ // Credit toAddr whenever value>0 — for self-transfers (from===to) the
856
+ // per-(wallet,token) netting in upsert cancels the +value against the
857
+ // -value component of the debit, leaving the -gasCost we actually want.
858
+ if (fromAddr) {
859
+ addRaw(rawChanges, fromAddr, '', -(value + gasCost));
860
+ }
861
+ if (value > 0n && toAddr) {
862
+ addRaw(rawChanges, toAddr, '', value);
863
+ }
864
+ const tokenContracts = new Set();
865
+ const transferLogs = [];
866
+ for (const log of receipt.logs) {
867
+ if (log.topics.length !== 3)
868
+ continue;
869
+ if (log.topics[0].toLowerCase() !== ERC20_TRANSFER_TOPIC)
870
+ continue;
871
+ const contractAddr = log.address.toLowerCase();
872
+ const logFrom = `0x${log.topics[1].slice(26)}`.toLowerCase();
873
+ const logTo = `0x${log.topics[2].slice(26)}`.toLowerCase();
874
+ let amount;
875
+ try {
876
+ amount = BigInt(log.data);
877
+ }
878
+ catch {
879
+ continue;
880
+ }
881
+ tokenContracts.add(contractAddr);
882
+ transferLogs.push({ contract: contractAddr, from: logFrom, to: logTo, amount });
883
+ }
884
+ const tokensByContract = new Map();
885
+ const resolved = await Promise.all([...tokenContracts].map((addr) => this.resolveErc20TokenDefensive(addr).then((t) => ({ addr, token: t }))));
886
+ for (const { addr, token } of resolved)
887
+ tokensByContract.set(addr, token);
888
+ for (const t of transferLogs) {
889
+ // Symmetric with the native path: always add both legs. Self-transfer
890
+ // nets to zero at the per-(wallet, contract) map level and is dropped
891
+ // by the `delta === 0n` filter below — the explicit gate here would
892
+ // over-suppress the credit if a future decoder gained non-cancelling
893
+ // side effects.
894
+ addRaw(rawChanges, t.from, t.contract, -t.amount);
895
+ addRaw(rawChanges, t.to, t.contract, t.amount);
896
+ }
897
+ const result = new Map();
898
+ for (const [wallet, perTokenAddr] of rawChanges) {
899
+ for (const [tokenAddr, delta] of perTokenAddr) {
900
+ if (delta === 0n)
901
+ continue;
902
+ const token = tokenAddr === '' ? this._nativeToken : tokensByContract.get(tokenAddr);
903
+ if (!token)
904
+ continue;
905
+ transaction_status_ts_1.AssetBalanceChange.upsert(result, wallet, token, transaction_status_ts_1.AssetBalanceChange.fromMr(delta, token.decimals));
906
+ }
907
+ }
908
+ return result;
909
+ }
910
+ async resolveErc20TokenDefensive(contractAddress) {
911
+ const checksum = (() => {
912
+ try {
913
+ return new evm_address_ts_1.EvmAddress(contractAddress).toChecksum();
914
+ }
915
+ catch {
916
+ return contractAddress;
917
+ }
918
+ })();
919
+ const placeholder = () => new evm_token_ts_1.EvmToken(this.chainId, `UNKNOWN_${checksum.slice(2, 8)}`, checksum, 0);
920
+ let provider;
921
+ try {
922
+ provider = this.getProvider();
923
+ }
924
+ catch {
925
+ return placeholder();
926
+ }
927
+ const contract = new ethers_1.Contract(contractAddress, ERC20_ABI, provider);
928
+ try {
929
+ const [symbol, decimals] = await Promise.all([
930
+ contract.symbol(),
931
+ contract.decimals(),
932
+ ]);
933
+ return new evm_token_ts_1.EvmToken(this.chainId, symbol, checksum, Number(decimals));
934
+ }
935
+ catch {
936
+ return placeholder();
937
+ }
938
+ }
939
+ /**
940
+ * STRICT decimals resolver for the transfer builder — throws
941
+ * `ChainError(RpcError)` on any failure to reach the contract.
942
+ * Used exclusively when converting `amountHr: Decimal` →
943
+ * `amountMr: bigint`, where a defensive fallback to `decimals=0`
944
+ * would silently sign a transaction for a wildly wrong amount
945
+ * (e.g. `1.5 USDC` → `1n` minor units instead of `1_500_000n`).
946
+ * The receipt-decoder still uses the defensive variant, since a
947
+ * placeholder token there is a display concern, not a money one.
948
+ */
949
+ async resolveErc20DecimalsStrict(contractAddress) {
950
+ const provider = this.getProvider();
951
+ const contract = new ethers_1.Contract(contractAddress, ERC20_ABI, provider);
952
+ try {
953
+ const decimals = (await contract.decimals());
954
+ return Number(decimals);
955
+ }
956
+ catch (err) {
957
+ throw this.rpcError(`Failed to read ERC-20 decimals for ${contractAddress}`, err);
958
+ }
959
+ }
960
+ rpcError(message, cause, extra = {}) {
961
+ const sanitizedMessage = (0, errors_ts_1.sanitizeMessage)(`${message}: ${stringifyErr(cause)}`, this._resolvedRpcUrl);
962
+ return new errors_ts_1.ChainError(errors_ts_1.ChainErrorKinds.RpcError, sanitizedMessage, { chainId: this.chainId, rpcHost: this.rpcHost(), ...extra }, (0, errors_ts_1.sanitizeCause)(cause, this._resolvedRpcUrl));
963
+ }
964
+ }
965
+ exports.EvmChain = EvmChain;
966
+ function addRaw(container, wallet, tokenAddr, delta) {
967
+ let perToken = container.get(wallet);
968
+ if (!perToken) {
969
+ perToken = new Map();
970
+ container.set(wallet, perToken);
971
+ }
972
+ perToken.set(tokenAddr, (perToken.get(tokenAddr) ?? 0n) + delta);
973
+ }
974
+ const ERROR_STRING_SELECTOR = '0x08c379a0';
975
+ const PANIC_UINT256_SELECTOR = '0x4e487b71';
976
+ const ABI_CODER = ethers_1.AbiCoder.defaultAbiCoder();
977
+ function decodeRevertData(data) {
978
+ if (typeof data !== 'string' || data.length < 10)
979
+ return undefined;
980
+ const selector = data.slice(0, 10).toLowerCase();
981
+ const payload = '0x' + data.slice(10);
982
+ if (selector === ERROR_STRING_SELECTOR) {
983
+ try {
984
+ const reason = ABI_CODER.decode(['string'], payload)[0];
985
+ return typeof reason === 'string' ? reason : undefined;
986
+ }
987
+ catch {
988
+ return undefined;
989
+ }
990
+ }
991
+ if (selector === PANIC_UINT256_SELECTOR) {
992
+ try {
993
+ const code = ABI_CODER.decode(['uint256'], payload)[0];
994
+ return typeof code === 'bigint' ? `Panic(0x${code.toString(16)})` : undefined;
995
+ }
996
+ catch {
997
+ return undefined;
998
+ }
999
+ }
1000
+ return undefined;
1001
+ }
1002
+ async function extractRevertInfo(provider, tx, receipt) {
1003
+ if (!tx)
1004
+ return { code: 'REVERTED' };
1005
+ try {
1006
+ await provider.call({
1007
+ from: tx.from,
1008
+ to: tx.to ?? undefined,
1009
+ data: tx.data,
1010
+ value: tx.value,
1011
+ blockTag: receipt.blockNumber,
1012
+ });
1013
+ return { code: 'REVERTED' };
1014
+ }
1015
+ catch (err) {
1016
+ const data = err?.data ??
1017
+ err?.info?.error?.data;
1018
+ const reason = typeof data === 'string' ? decodeRevertData(data) : undefined;
1019
+ return reason !== undefined ? { code: 'REVERTED', reason } : { code: 'REVERTED' };
1020
+ }
1021
+ }
1022
+ function stringifyErr(err) {
1023
+ if (err instanceof Error)
1024
+ return err.message;
1025
+ return String(err);
1026
+ }
1027
+ const BATCH_STATUS_CONCURRENCY = 8;
1028
+ async function runBatchStatus(items, fetchOne) {
1029
+ const results = new Array(items.length);
1030
+ const ac = new AbortController();
1031
+ let cursor = 0;
1032
+ const workers = [];
1033
+ const spawn = async () => {
1034
+ while (!ac.signal.aborted) {
1035
+ const idx = cursor++;
1036
+ if (idx >= items.length)
1037
+ return;
1038
+ try {
1039
+ results[idx] = await fetchOne(items[idx], ac.signal);
1040
+ }
1041
+ catch (err) {
1042
+ ac.abort();
1043
+ throw err;
1044
+ }
1045
+ }
1046
+ };
1047
+ const workerCount = Math.min(BATCH_STATUS_CONCURRENCY, items.length);
1048
+ for (let i = 0; i < workerCount; i++)
1049
+ workers.push(spawn());
1050
+ await Promise.all(workers);
1051
+ return results;
1052
+ }
1053
+ function anySignal(a, b) {
1054
+ if (typeof AbortSignal.any === 'function')
1055
+ return AbortSignal.any([a, b]);
1056
+ const ac = new AbortController();
1057
+ const onAbort = () => ac.abort();
1058
+ if (a.aborted || b.aborted)
1059
+ ac.abort();
1060
+ else {
1061
+ a.addEventListener('abort', onAbort, { once: true });
1062
+ b.addEventListener('abort', onAbort, { once: true });
1063
+ }
1064
+ return ac.signal;
1065
+ }
1066
+ async function interruptibleSleep(ms, signal) {
1067
+ if (signal?.aborted)
1068
+ return;
1069
+ await new Promise((resolve) => {
1070
+ const t = setTimeout(() => {
1071
+ signal?.removeEventListener('abort', onAbort);
1072
+ resolve();
1073
+ }, ms);
1074
+ const onAbort = () => {
1075
+ clearTimeout(t);
1076
+ resolve();
1077
+ };
1078
+ signal?.addEventListener('abort', onAbort, { once: true });
1079
+ });
1080
+ }
1081
+ function errCode(err) {
1082
+ if (typeof err !== 'object' || err === null)
1083
+ return undefined;
1084
+ const e = err;
1085
+ const candidates = [
1086
+ typeof e.code === 'number' ? e.code : undefined,
1087
+ e.error?.code,
1088
+ e.info?.error?.code,
1089
+ typeof e.code === 'string' && /^-?\d+$/.test(e.code) ? e.code : undefined,
1090
+ ];
1091
+ for (const raw of candidates) {
1092
+ if (typeof raw === 'number')
1093
+ return raw;
1094
+ if (typeof raw === 'string' && /^-?\d+$/.test(raw))
1095
+ return Number(raw);
1096
+ }
1097
+ return undefined;
1098
+ }
1099
+ function ethersErrCode(err) {
1100
+ if (typeof err !== 'object' || err === null)
1101
+ return undefined;
1102
+ const e = err;
1103
+ return typeof e.code === 'string' ? e.code : undefined;
1104
+ }
1105
+ function envCandidatesFor(name, chainId) {
1106
+ const normalized = name.replace(/ /g, '_').toUpperCase() + '_RPC_URL';
1107
+ return [normalized, `EVM_${chainId}_RPC_URL`];
1108
+ }
1109
+ //# sourceMappingURL=evm_chain.js.map