augustdigital-sdk 8.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +349 -0
  3. package/lib/abis/AddressResolver.d.ts +28 -0
  4. package/lib/abis/AddressResolver.js +23 -0
  5. package/lib/abis/ChainlinkV3.d.ts +87 -0
  6. package/lib/abis/ChainlinkV3.js +117 -0
  7. package/lib/abis/ERC20.d.ts +168 -0
  8. package/lib/abis/ERC20.js +226 -0
  9. package/lib/abis/ERC20_Bytes32.d.ts +139 -0
  10. package/lib/abis/ERC20_Bytes32.js +196 -0
  11. package/lib/abis/ERC4626.d.ts +364 -0
  12. package/lib/abis/ERC4626.js +507 -0
  13. package/lib/abis/ERC721.d.ts +231 -0
  14. package/lib/abis/ERC721.js +321 -0
  15. package/lib/abis/FeeOracle.d.ts +120 -0
  16. package/lib/abis/FeeOracle.js +162 -0
  17. package/lib/abis/LendingPool.d.ts +1393 -0
  18. package/lib/abis/LendingPool.js +1807 -0
  19. package/lib/abis/LendingPoolV2.d.ts +1413 -0
  20. package/lib/abis/LendingPoolV2.js +1833 -0
  21. package/lib/abis/LendingPoolV3.d.ts +1677 -0
  22. package/lib/abis/LendingPoolV3.js +1160 -0
  23. package/lib/abis/Loan.d.ts +837 -0
  24. package/lib/abis/Loan.js +1080 -0
  25. package/lib/abis/MultiAssetNativeDepositWrapper.d.ts +137 -0
  26. package/lib/abis/MultiAssetNativeDepositWrapper.js +125 -0
  27. package/lib/abis/Multicall3.d.ts +30 -0
  28. package/lib/abis/Multicall3.js +97 -0
  29. package/lib/abis/OFT.d.ts +116 -0
  30. package/lib/abis/OFT.js +85 -0
  31. package/lib/abis/PoolAdapter.d.ts +36 -0
  32. package/lib/abis/PoolAdapter.js +51 -0
  33. package/lib/abis/RewardDistributor.d.ts +267 -0
  34. package/lib/abis/RewardDistributor.js +352 -0
  35. package/lib/abis/RwaRedeemSubaccount.d.ts +747 -0
  36. package/lib/abis/RwaRedeemSubaccount.js +548 -0
  37. package/lib/abis/SmartAccount.d.ts +17 -0
  38. package/lib/abis/SmartAccount.js +19 -0
  39. package/lib/abis/SwapRouter.d.ts +1043 -0
  40. package/lib/abis/SwapRouter.js +740 -0
  41. package/lib/abis/TextResolver.d.ts +16 -0
  42. package/lib/abis/TextResolver.js +16 -0
  43. package/lib/abis/TokenizedVaultV2.d.ts +1364 -0
  44. package/lib/abis/TokenizedVaultV2.js +1041 -0
  45. package/lib/abis/TokenizedVaultV2DepositWithPermit.d.ts +1456 -0
  46. package/lib/abis/TokenizedVaultV2DepositWithPermit.js +1878 -0
  47. package/lib/abis/TokenizedVaultV2Receipt.d.ts +1568 -0
  48. package/lib/abis/TokenizedVaultV2Receipt.js +1061 -0
  49. package/lib/abis/TokenizedVaultV2SenderAllocationWhitelist.d.ts +454 -0
  50. package/lib/abis/TokenizedVaultV2SenderAllocationWhitelist.js +327 -0
  51. package/lib/abis/TokenizedVaultV2WhitelistedAllocation.d.ts +1466 -0
  52. package/lib/abis/TokenizedVaultV2WhitelistedAllocation.js +1092 -0
  53. package/lib/abis/TokenizedVaultV2WhitelistedAssets.d.ts +274 -0
  54. package/lib/abis/TokenizedVaultV2WhitelistedAssets.js +167 -0
  55. package/lib/abis/UniversalResolverResolve.d.ts +69 -0
  56. package/lib/abis/UniversalResolverResolve.js +35 -0
  57. package/lib/abis/UniversalSignatureValidator.d.ts +17 -0
  58. package/lib/abis/UniversalSignatureValidator.js +30 -0
  59. package/lib/abis/WrapperAdapter.d.ts +71 -0
  60. package/lib/abis/WrapperAdapter.js +77 -0
  61. package/lib/abis/index.d.ts +34 -0
  62. package/lib/abis/index.js +51 -0
  63. package/lib/adapters/evm/getters.d.ts +19 -0
  64. package/lib/adapters/evm/getters.js +209 -0
  65. package/lib/adapters/evm/index.d.ts +353 -0
  66. package/lib/adapters/evm/index.js +434 -0
  67. package/lib/adapters/evm/utils.d.ts +8 -0
  68. package/lib/adapters/evm/utils.js +51 -0
  69. package/lib/adapters/solana/constants.d.ts +33 -0
  70. package/lib/adapters/solana/constants.js +52 -0
  71. package/lib/adapters/solana/getters.d.ts +11 -0
  72. package/lib/adapters/solana/getters.js +165 -0
  73. package/lib/adapters/solana/idl/vault-idl.d.ts +272 -0
  74. package/lib/adapters/solana/idl/vault-idl.js +1084 -0
  75. package/lib/adapters/solana/index.d.ts +233 -0
  76. package/lib/adapters/solana/index.js +291 -0
  77. package/lib/adapters/solana/types.d.ts +67 -0
  78. package/lib/adapters/solana/types.js +3 -0
  79. package/lib/adapters/solana/utils.d.ts +141 -0
  80. package/lib/adapters/solana/utils.js +595 -0
  81. package/lib/adapters/solana/vault.actions.d.ts +57 -0
  82. package/lib/adapters/solana/vault.actions.js +379 -0
  83. package/lib/adapters/stellar/actions.d.ts +28 -0
  84. package/lib/adapters/stellar/actions.js +77 -0
  85. package/lib/adapters/stellar/constants.d.ts +43 -0
  86. package/lib/adapters/stellar/constants.js +53 -0
  87. package/lib/adapters/stellar/getters.d.ts +68 -0
  88. package/lib/adapters/stellar/getters.js +290 -0
  89. package/lib/adapters/stellar/index.d.ts +114 -0
  90. package/lib/adapters/stellar/index.js +175 -0
  91. package/lib/adapters/stellar/soroban.d.ts +123 -0
  92. package/lib/adapters/stellar/soroban.js +613 -0
  93. package/lib/adapters/stellar/submit.d.ts +34 -0
  94. package/lib/adapters/stellar/submit.js +149 -0
  95. package/lib/adapters/stellar/types.d.ts +58 -0
  96. package/lib/adapters/stellar/types.js +6 -0
  97. package/lib/adapters/stellar/utils.d.ts +24 -0
  98. package/lib/adapters/stellar/utils.js +34 -0
  99. package/lib/adapters/sui/constants.d.ts +14 -0
  100. package/lib/adapters/sui/constants.js +29 -0
  101. package/lib/adapters/sui/getters.d.ts +9 -0
  102. package/lib/adapters/sui/getters.js +60 -0
  103. package/lib/adapters/sui/index.d.ts +45 -0
  104. package/lib/adapters/sui/index.js +101 -0
  105. package/lib/adapters/sui/transformer.d.ts +10 -0
  106. package/lib/adapters/sui/transformer.js +107 -0
  107. package/lib/adapters/sui/types.d.ts +66 -0
  108. package/lib/adapters/sui/types.js +3 -0
  109. package/lib/adapters/sui/utils.d.ts +10 -0
  110. package/lib/adapters/sui/utils.js +29 -0
  111. package/lib/core/analytics/chain-name.d.ts +9 -0
  112. package/lib/core/analytics/chain-name.js +34 -0
  113. package/lib/core/analytics/constants.d.ts +5 -0
  114. package/lib/core/analytics/constants.js +9 -0
  115. package/lib/core/analytics/env.d.ts +29 -0
  116. package/lib/core/analytics/env.js +59 -0
  117. package/lib/core/analytics/index.d.ts +36 -0
  118. package/lib/core/analytics/index.js +79 -0
  119. package/lib/core/analytics/instrumentation.d.ts +29 -0
  120. package/lib/core/analytics/instrumentation.js +277 -0
  121. package/lib/core/analytics/method-taxonomy.d.ts +19 -0
  122. package/lib/core/analytics/method-taxonomy.js +128 -0
  123. package/lib/core/analytics/metrics.d.ts +33 -0
  124. package/lib/core/analytics/metrics.js +116 -0
  125. package/lib/core/analytics/sanitize.d.ts +44 -0
  126. package/lib/core/analytics/sanitize.js +260 -0
  127. package/lib/core/analytics/sentry-runtime.d.ts +15 -0
  128. package/lib/core/analytics/sentry-runtime.js +97 -0
  129. package/lib/core/analytics/sentry.d.ts +67 -0
  130. package/lib/core/analytics/sentry.js +613 -0
  131. package/lib/core/analytics/types.d.ts +48 -0
  132. package/lib/core/analytics/types.js +3 -0
  133. package/lib/core/analytics/user-identity.d.ts +41 -0
  134. package/lib/core/analytics/user-identity.js +141 -0
  135. package/lib/core/analytics/version.d.ts +6 -0
  136. package/lib/core/analytics/version.js +10 -0
  137. package/lib/core/attribution.d.ts +111 -0
  138. package/lib/core/attribution.js +142 -0
  139. package/lib/core/auth/index.d.ts +1 -0
  140. package/lib/core/auth/index.js +18 -0
  141. package/lib/core/auth/verify.d.ts +2 -0
  142. package/lib/core/auth/verify.js +31 -0
  143. package/lib/core/base.class.d.ts +152 -0
  144. package/lib/core/base.class.js +172 -0
  145. package/lib/core/cache.d.ts +9 -0
  146. package/lib/core/cache.js +31 -0
  147. package/lib/core/constants/adapters.d.ts +103 -0
  148. package/lib/core/constants/adapters.js +180 -0
  149. package/lib/core/constants/core.d.ts +133 -0
  150. package/lib/core/constants/core.js +209 -0
  151. package/lib/core/constants/swap-router.d.ts +150 -0
  152. package/lib/core/constants/swap-router.js +169 -0
  153. package/lib/core/constants/vaults.d.ts +93 -0
  154. package/lib/core/constants/vaults.js +273 -0
  155. package/lib/core/constants/web3.d.ts +91 -0
  156. package/lib/core/constants/web3.js +229 -0
  157. package/lib/core/errors/index.d.ts +114 -0
  158. package/lib/core/errors/index.js +183 -0
  159. package/lib/core/fetcher.d.ts +198 -0
  160. package/lib/core/fetcher.js +903 -0
  161. package/lib/core/helpers/adapters.d.ts +13 -0
  162. package/lib/core/helpers/adapters.js +39 -0
  163. package/lib/core/helpers/chain-address.d.ts +13 -0
  164. package/lib/core/helpers/chain-address.js +47 -0
  165. package/lib/core/helpers/chain-error.d.ts +207 -0
  166. package/lib/core/helpers/chain-error.js +682 -0
  167. package/lib/core/helpers/chain-support.d.ts +80 -0
  168. package/lib/core/helpers/chain-support.js +115 -0
  169. package/lib/core/helpers/core.d.ts +68 -0
  170. package/lib/core/helpers/core.js +285 -0
  171. package/lib/core/helpers/explorer-link.d.ts +16 -0
  172. package/lib/core/helpers/explorer-link.js +26 -0
  173. package/lib/core/helpers/multicall.d.ts +68 -0
  174. package/lib/core/helpers/multicall.js +103 -0
  175. package/lib/core/helpers/revert-decode.d.ts +248 -0
  176. package/lib/core/helpers/revert-decode.js +515 -0
  177. package/lib/core/helpers/signer.d.ts +52 -0
  178. package/lib/core/helpers/signer.js +145 -0
  179. package/lib/core/helpers/swap-router.d.ts +211 -0
  180. package/lib/core/helpers/swap-router.js +480 -0
  181. package/lib/core/helpers/vault-version.d.ts +23 -0
  182. package/lib/core/helpers/vault-version.js +75 -0
  183. package/lib/core/helpers/vaults.d.ts +89 -0
  184. package/lib/core/helpers/vaults.js +235 -0
  185. package/lib/core/helpers/web3.d.ts +353 -0
  186. package/lib/core/helpers/web3.js +992 -0
  187. package/lib/core/index.d.ts +23 -0
  188. package/lib/core/index.js +40 -0
  189. package/lib/core/logger/index.d.ts +98 -0
  190. package/lib/core/logger/index.js +144 -0
  191. package/lib/core/logger/slack.d.ts +16 -0
  192. package/lib/core/logger/slack.js +57 -0
  193. package/lib/core/vault-metadata.d.ts +12 -0
  194. package/lib/core/vault-metadata.js +42 -0
  195. package/lib/core/version-check.d.ts +58 -0
  196. package/lib/core/version-check.js +182 -0
  197. package/lib/evm/index.d.ts +2 -0
  198. package/lib/evm/index.js +19 -0
  199. package/lib/evm/methods/crossChainVault.d.ts +128 -0
  200. package/lib/evm/methods/crossChainVault.js +853 -0
  201. package/lib/evm/methods/crossChainVaultRegistry.d.ts +93 -0
  202. package/lib/evm/methods/crossChainVaultRegistry.js +240 -0
  203. package/lib/evm/methods/index.d.ts +2 -0
  204. package/lib/evm/methods/index.js +19 -0
  205. package/lib/evm/types/crossChain.d.ts +363 -0
  206. package/lib/evm/types/crossChain.js +20 -0
  207. package/lib/evm/types/index.d.ts +1 -0
  208. package/lib/evm/types/index.js +18 -0
  209. package/lib/index.d.ts +30 -0
  210. package/lib/index.js +52 -0
  211. package/lib/main.d.ts +527 -0
  212. package/lib/main.js +601 -0
  213. package/lib/modules/api/fetcher.d.ts +82 -0
  214. package/lib/modules/api/fetcher.js +150 -0
  215. package/lib/modules/api/index.d.ts +1 -0
  216. package/lib/modules/api/index.js +6 -0
  217. package/lib/modules/api/main.d.ts +313 -0
  218. package/lib/modules/api/main.js +479 -0
  219. package/lib/modules/sub-accounts/fetcher.d.ts +53 -0
  220. package/lib/modules/sub-accounts/fetcher.js +120 -0
  221. package/lib/modules/sub-accounts/index.d.ts +2 -0
  222. package/lib/modules/sub-accounts/index.js +19 -0
  223. package/lib/modules/sub-accounts/main.d.ts +243 -0
  224. package/lib/modules/sub-accounts/main.js +205 -0
  225. package/lib/modules/sub-accounts/utils.d.ts +106 -0
  226. package/lib/modules/sub-accounts/utils.js +112 -0
  227. package/lib/modules/vaults/adapter.helpers.d.ts +64 -0
  228. package/lib/modules/vaults/adapter.helpers.js +184 -0
  229. package/lib/modules/vaults/fetcher.d.ts +147 -0
  230. package/lib/modules/vaults/fetcher.js +368 -0
  231. package/lib/modules/vaults/getters.d.ts +570 -0
  232. package/lib/modules/vaults/getters.js +3051 -0
  233. package/lib/modules/vaults/index.d.ts +20 -0
  234. package/lib/modules/vaults/index.js +44 -0
  235. package/lib/modules/vaults/main.d.ts +601 -0
  236. package/lib/modules/vaults/main.js +1623 -0
  237. package/lib/modules/vaults/prefetch.d.ts +65 -0
  238. package/lib/modules/vaults/prefetch.js +120 -0
  239. package/lib/modules/vaults/read.actions.d.ts +225 -0
  240. package/lib/modules/vaults/read.actions.js +596 -0
  241. package/lib/modules/vaults/types.d.ts +71 -0
  242. package/lib/modules/vaults/types.js +3 -0
  243. package/lib/modules/vaults/utils/call-data-decoder.d.ts +61 -0
  244. package/lib/modules/vaults/utils/call-data-decoder.js +194 -0
  245. package/lib/modules/vaults/utils/date-utils.d.ts +50 -0
  246. package/lib/modules/vaults/utils/date-utils.js +84 -0
  247. package/lib/modules/vaults/utils.d.ts +140 -0
  248. package/lib/modules/vaults/utils.js +799 -0
  249. package/lib/modules/vaults/write.actions.d.ts +529 -0
  250. package/lib/modules/vaults/write.actions.js +1749 -0
  251. package/lib/polyfills.d.ts +1 -0
  252. package/lib/polyfills.js +12 -0
  253. package/lib/sdk.d.ts +26721 -0
  254. package/lib/services/coingecko/fetcher.d.ts +15 -0
  255. package/lib/services/coingecko/fetcher.js +67 -0
  256. package/lib/services/coingecko/index.d.ts +2 -0
  257. package/lib/services/coingecko/index.js +19 -0
  258. package/lib/services/coingecko/utils.d.ts +1 -0
  259. package/lib/services/coingecko/utils.js +24 -0
  260. package/lib/services/debank/fetcher.d.ts +126 -0
  261. package/lib/services/debank/fetcher.js +47 -0
  262. package/lib/services/debank/index.d.ts +2 -0
  263. package/lib/services/debank/index.js +19 -0
  264. package/lib/services/debank/utils.d.ts +38 -0
  265. package/lib/services/debank/utils.js +297 -0
  266. package/lib/services/layerzero/deposits.d.ts +49 -0
  267. package/lib/services/layerzero/deposits.js +166 -0
  268. package/lib/services/layerzero/redeems.d.ts +20 -0
  269. package/lib/services/layerzero/redeems.js +92 -0
  270. package/lib/services/layerzero/utils.d.ts +9 -0
  271. package/lib/services/layerzero/utils.js +22 -0
  272. package/lib/services/octavfi/fetcher.d.ts +9 -0
  273. package/lib/services/octavfi/fetcher.js +103 -0
  274. package/lib/services/octavfi/index.d.ts +3 -0
  275. package/lib/services/octavfi/index.js +20 -0
  276. package/lib/services/octavfi/types.d.ts +34 -0
  277. package/lib/services/octavfi/types.js +3 -0
  278. package/lib/services/octavfi/utils.d.ts +16 -0
  279. package/lib/services/octavfi/utils.js +212 -0
  280. package/lib/services/subgraph/fetcher.d.ts +2 -0
  281. package/lib/services/subgraph/fetcher.js +61 -0
  282. package/lib/services/subgraph/index.d.ts +2 -0
  283. package/lib/services/subgraph/index.js +19 -0
  284. package/lib/services/subgraph/schema.d.ts +45 -0
  285. package/lib/services/subgraph/schema.js +75 -0
  286. package/lib/services/subgraph/vaults.d.ts +25 -0
  287. package/lib/services/subgraph/vaults.js +1106 -0
  288. package/lib/services/swap-quotes/index.d.ts +105 -0
  289. package/lib/services/swap-quotes/index.js +77 -0
  290. package/lib/services/swap-quotes/paraswap.d.ts +51 -0
  291. package/lib/services/swap-quotes/paraswap.js +138 -0
  292. package/lib/types/api.d.ts +280 -0
  293. package/lib/types/api.js +3 -0
  294. package/lib/types/index.d.ts +12 -0
  295. package/lib/types/index.js +28 -0
  296. package/lib/types/points.d.ts +28 -0
  297. package/lib/types/points.js +3 -0
  298. package/lib/types/pools.d.ts +144 -0
  299. package/lib/types/pools.js +3 -0
  300. package/lib/types/staking.d.ts +28 -0
  301. package/lib/types/staking.js +3 -0
  302. package/lib/types/sub-accounts.d.ts +140 -0
  303. package/lib/types/sub-accounts.js +3 -0
  304. package/lib/types/subgraph.d.ts +74 -0
  305. package/lib/types/subgraph.js +3 -0
  306. package/lib/types/typed-contract.d.ts +102 -0
  307. package/lib/types/typed-contract.js +3 -0
  308. package/lib/types/user.d.ts +1 -0
  309. package/lib/types/user.js +3 -0
  310. package/lib/types/vaults.d.ts +714 -0
  311. package/lib/types/vaults.js +24 -0
  312. package/lib/types/web3.d.ts +51 -0
  313. package/lib/types/web3.js +14 -0
  314. package/lib/types/webserver.d.ts +698 -0
  315. package/lib/types/webserver.js +3 -0
  316. package/package.json +78 -0
@@ -0,0 +1,682 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LP_TOKEN_ADDRESS_SELECTOR = void 0;
4
+ exports.isUserRejectionError = isUserRejectionError;
5
+ exports.isExpectedRevertError = isExpectedRevertError;
6
+ exports.isInsufficientFundsError = isInsufficientFundsError;
7
+ exports.isRetryableRpcError = isRetryableRpcError;
8
+ exports.isEmptyViewResponse = isEmptyViewResponse;
9
+ exports.retryOnTransientRpc = retryOnTransientRpc;
10
+ exports.logChainError = logChainError;
11
+ const logger_1 = require("../logger");
12
+ /**
13
+ * Classification of caught chain/RPC/wallet errors so the SDK can decide
14
+ * whether a failure is worth a standalone Sentry issue or is routine, expected
15
+ * noise that should ride along as a breadcrumb instead.
16
+ *
17
+ * Why this exists: most of the SDK's read/write paths `catch` and re-throw, and
18
+ * historically logged every caught error at `error` level — which the SDK's
19
+ * Sentry sink turns into a billed issue (see the severity policy on
20
+ * `SDKSentrySink` in `core/logger`). Two large, low-signal categories dominate
21
+ * that volume:
22
+ *
23
+ * 1. **User-rejected transactions** — the user clicked "reject" in their wallet.
24
+ * This is normal product behaviour, not an SDK fault, yet it fires on every
25
+ * cancelled deposit/redeem/approve.
26
+ * 2. **Expected on-chain read reverts** — reading a function a vault doesn't
27
+ * implement, or an address with no/incompatible bytecode, reverts. This is a
28
+ * routine outcome of probing heterogeneous vaults, not a defect.
29
+ * 3. **Underfunded sender accounts** — the node rejects the transaction because
30
+ * the sender can't cover gas (or, on rollups such as Citrea, the extra L1
31
+ * data-availability fee). This is a "top up your wallet" prompt, not a bug.
32
+ *
33
+ * These predicates let call sites demote exactly those cases to `warn` while
34
+ * leaving genuine failures at `error`. They are intentionally dependency-free
35
+ * (no `ethers`/Sentry imports) so they stay cheap and safe in both browser and
36
+ * Node, and classify purely by inspecting the error's `code`/`message` shape.
37
+ *
38
+ * @module
39
+ */
40
+ /**
41
+ * Best-effort message extraction from an unknown thrown value. Reads
42
+ * `error.message` for `Error` and error-like objects, passes strings through,
43
+ * and falls back to `String(error)` for everything else. Never throws.
44
+ *
45
+ * @param error - The caught value, of unknown type.
46
+ * @returns The error's message text (never `undefined`).
47
+ */
48
+ function errorText(error) {
49
+ if (typeof error === 'string')
50
+ return error;
51
+ if (error instanceof Error)
52
+ return error.message;
53
+ if (error && typeof error === 'object') {
54
+ const maybe = error.message;
55
+ if (typeof maybe === 'string')
56
+ return maybe;
57
+ }
58
+ return String(error);
59
+ }
60
+ /**
61
+ * Collect the `code` fields an error-like value may carry. Wallet/provider
62
+ * errors stash their machine-readable code in different places depending on the
63
+ * stack: ethers sets a top-level string `code` (e.g. `'ACTION_REJECTED'`),
64
+ * EIP-1193 providers use a numeric `code` (e.g. `4001`), and some wrap the
65
+ * original under `error`/`info.error`/`cause`. We scan the common locations so
66
+ * callers needn't know which library produced the error.
67
+ *
68
+ * @param error - The caught value, of unknown type.
69
+ * @returns Every string/number `code` found (possibly empty).
70
+ */
71
+ function errorCodes(error) {
72
+ const codes = [];
73
+ if (error && typeof error === 'object') {
74
+ const e = error;
75
+ const candidates = [
76
+ e.code,
77
+ e.error?.code,
78
+ e.info?.error?.code,
79
+ e.cause?.code,
80
+ ];
81
+ for (const c of candidates) {
82
+ if (typeof c === 'string' || typeof c === 'number')
83
+ codes.push(c);
84
+ }
85
+ }
86
+ return codes;
87
+ }
88
+ /**
89
+ * Collect every human-readable message string an error-like value carries,
90
+ * across the nested locations providers stash them in.
91
+ *
92
+ * Why this is separate from {@link errorText}: ethers v6 flattens a rejected
93
+ * `eth_estimateGas`/`eth_call` to a generic *top-level* `message` (e.g.
94
+ * `"missing revert data"`) while preserving the node's original JSON-RPC error
95
+ * one level down at `info.error.message`. The real reason (an insufficient-funds
96
+ * report, say) is therefore invisible to a top-level `.message` read. We scan
97
+ * the top-level message plus `error.message`, `info.error.message`,
98
+ * `cause.message`, and `cause.info.error.message` so a caller catches the reason
99
+ * whether it holds the raw provider error or an SDK error that wrapped it as
100
+ * `cause`.
101
+ *
102
+ * @param error - The caught value, of unknown type.
103
+ * @returns Every non-empty message string found (possibly empty array).
104
+ */
105
+ function nestedMessages(error) {
106
+ const out = [];
107
+ const push = (value) => {
108
+ if (typeof value === 'string' && value.length > 0)
109
+ out.push(value);
110
+ };
111
+ push(errorText(error));
112
+ if (error && typeof error === 'object') {
113
+ const e = error;
114
+ push(e.error?.message);
115
+ push(e.info?.error?.message);
116
+ push(e.cause?.message);
117
+ push(e.cause?.info?.error?.message);
118
+ }
119
+ return out;
120
+ }
121
+ /**
122
+ * Is this error a wallet/user rejection of a transaction or signature request?
123
+ *
124
+ * Detects ethers v6's `ACTION_REJECTED` code, the EIP-1193 `4001`
125
+ * ("User rejected the request") code (top-level or nested), and the common
126
+ * human-readable phrasings as a fallback for providers that omit a code.
127
+ *
128
+ * @param error - The caught value, of unknown type.
129
+ * @returns `true` when the failure was the user declining in their wallet.
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * try { await vault.deposit(...); }
134
+ * catch (e) {
135
+ * if (isUserRejectionError(e)) return; // user cancelled — not an error
136
+ * throw e;
137
+ * }
138
+ * ```
139
+ */
140
+ function isUserRejectionError(error) {
141
+ const codes = errorCodes(error);
142
+ if (codes.includes('ACTION_REJECTED') || codes.includes(4001))
143
+ return true;
144
+ const msg = errorText(error).toLowerCase();
145
+ return (msg.includes('user rejected') ||
146
+ msg.includes('user denied') ||
147
+ msg.includes('rejected the request') ||
148
+ msg.includes('request rejected'));
149
+ }
150
+ /**
151
+ * Is this error a routine on-chain read revert rather than a real failure?
152
+ *
153
+ * Reading a function a contract doesn't implement, or an address that holds no
154
+ * (or incompatible) bytecode, reverts — a normal outcome when the SDK probes
155
+ * heterogeneous vaults. Matches ethers' `CALL_EXCEPTION` code and the
156
+ * message variants emitted by ethers and viem (`missing revert data`,
157
+ * `execution reverted`, `call revert exception`, and the bare `reverted`
158
+ * phrasing such as `the contract function "totalAssets" reverted`).
159
+ *
160
+ * Scope note: callers apply this on **read** paths only. A reverted *write*
161
+ * (a tx that failed on-chain) is a genuine error and is intentionally not
162
+ * demoted by this predicate's use in `write.actions`.
163
+ *
164
+ * @param error - The caught value, of unknown type.
165
+ * @returns `true` when the failure is an expected/benign contract revert.
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * try { return await vaultContract.maxDepositAmount(); }
170
+ * catch (e) {
171
+ * logChainError('maxDeposit', e, isExpectedRevertError(e));
172
+ * throw e;
173
+ * }
174
+ * ```
175
+ */
176
+ function isExpectedRevertError(error) {
177
+ const codes = errorCodes(error);
178
+ if (codes.includes('CALL_EXCEPTION'))
179
+ return true;
180
+ const msg = errorText(error).toLowerCase();
181
+ return (msg.includes('call_exception') ||
182
+ msg.includes('missing revert data') ||
183
+ msg.includes('execution reverted') ||
184
+ msg.includes('call revert exception') ||
185
+ msg.includes('reverted'));
186
+ }
187
+ /**
188
+ * Is this error the chain node reporting that the sender can't afford the
189
+ * transaction's gas/fee — i.e. the account needs topping up, not a defect?
190
+ *
191
+ * This is distinct from a contract revert, and easy to misclassify. When the
192
+ * node rejects `eth_estimateGas` for an underfunded account, ethers v6 discards
193
+ * the node's reason and surfaces a generic `CALL_EXCEPTION` / `"missing revert
194
+ * data"` at the top level — which {@link isExpectedRevertError} matches. The
195
+ * real reason survives only in the nested JSON-RPC error, so this predicate
196
+ * scans there (via `nestedMessages`). On a write path, check this **before**
197
+ * {@link isExpectedRevertError}, or a genuine funds shortfall reads as a benign
198
+ * revert.
199
+ *
200
+ * Matching is anchored to the node's pre-execution funds-check phrasings (see
201
+ * `INSUFFICIENT_FUNDS_PHRASES`), each of which carries a `for <purpose>`
202
+ * qualifier — `insufficient funds for gas`, `insufficient funds for transfer`,
203
+ * `not enough funds for L1 fee` (Citrea's data-availability fee), etc. This is
204
+ * deliberately narrower than a bare `"insufficient funds"` substring: a
205
+ * *contract revert reason* that merely contains the word "funds" (e.g.
206
+ * `execution reverted: insufficient funds in pool`) must stay a genuine failure,
207
+ * not be demoted to an ACCOUNT_NOT_FUNDED "top up gas" prompt.
208
+ *
209
+ * @param error - The caught value, of unknown type.
210
+ * @returns `true` when the failure is an unfunded/underfunded sender account.
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * try { await vault.requestRedeem(...); }
215
+ * catch (e) {
216
+ * if (isInsufficientFundsError(e))
217
+ * throw new AugustValidationError(
218
+ * 'ACCOUNT_NOT_FUNDED',
219
+ * 'Add gas to continue',
220
+ * { cause: e },
221
+ * );
222
+ * throw e;
223
+ * }
224
+ * ```
225
+ */
226
+ /**
227
+ * The node pre-execution funds-check phrasings {@link isInsufficientFundsError}
228
+ * recognises, lower-cased. Each keeps the `for <purpose>` qualifier so the match
229
+ * is anchored to a funding rejection and can't be tripped by a contract revert
230
+ * reason that merely mentions "funds". `insufficient funds for gas` covers the
231
+ * geth/reth `"... for gas * price + value"` message; `not enough funds for l1
232
+ * fee` is the rollup (Citrea) data-availability-fee shortfall.
233
+ */
234
+ const INSUFFICIENT_FUNDS_PHRASES = [
235
+ 'insufficient funds for gas',
236
+ 'insufficient funds for transfer',
237
+ 'insufficient funds for intrinsic transaction cost',
238
+ 'not enough funds for l1 fee',
239
+ ];
240
+ function isInsufficientFundsError(error) {
241
+ return nestedMessages(error).some((raw) => {
242
+ const msg = raw.toLowerCase();
243
+ return INSUFFICIENT_FUNDS_PHRASES.some((phrase) => msg.includes(phrase));
244
+ });
245
+ }
246
+ /**
247
+ * Collect the HTTP status codes an error-like value may carry. Transport
248
+ * failures that reach us through ethers' `FetchRequest` keep the upstream
249
+ * status on the error (`status`), on the wrapped fetch response
250
+ * (`info.status` / `response.status`), or on a `statusCode` alias depending on
251
+ * which layer produced it. We scan all of them so a caller needn't know.
252
+ *
253
+ * @param error - The caught value, of unknown type.
254
+ * @returns Every numeric status found (possibly empty).
255
+ */
256
+ function errorStatuses(error) {
257
+ const out = [];
258
+ const push = (value) => {
259
+ if (typeof value === 'number' && Number.isFinite(value))
260
+ out.push(value);
261
+ };
262
+ if (error && typeof error === 'object') {
263
+ const e = error;
264
+ push(e.status);
265
+ push(e.statusCode);
266
+ push(e.info?.status);
267
+ push(e.info?.statusCode);
268
+ push(e.response?.status);
269
+ push(e.response?.statusCode);
270
+ }
271
+ return out;
272
+ }
273
+ /**
274
+ * Does this error carry evidence that the EVM actually executed and reverted?
275
+ *
276
+ * Used as a **veto** by {@link isRetryableRpcError}: nodes reuse the generic
277
+ * JSON-RPC codes (`-32603`, `-32000`) for genuine execution reverts as well as
278
+ * for internal/transport faults, so a positive transport match must never win
279
+ * over a real revert. Evidence of real execution is:
280
+ *
281
+ * - a `CALL_EXCEPTION` that carries non-empty revert `data` (the ABI-encoded
282
+ * custom error / `Error(string)` payload),
283
+ * - an `execution reverted` / `call revert exception` message anywhere in the
284
+ * nested error chain,
285
+ * - an attached receipt with `status === 0` (the tx mined and failed).
286
+ *
287
+ * Note that a bare `CALL_EXCEPTION` with **no** revert data (ethers' `missing
288
+ * revert data`) is deliberately *not* evidence — see {@link isRetryableRpcError}.
289
+ *
290
+ * @param error - The caught value, of unknown type.
291
+ * @returns `true` when the error proves on-chain execution reverted.
292
+ */
293
+ function hasRevertEvidence(error) {
294
+ if (error && typeof error === 'object') {
295
+ const e = error;
296
+ const codes = errorCodes(error);
297
+ if (codes.includes('CALL_EXCEPTION') &&
298
+ typeof e.data === 'string' &&
299
+ e.data.length > 2) {
300
+ return true;
301
+ }
302
+ if (e.receipt?.status === 0)
303
+ return true;
304
+ }
305
+ return nestedMessages(error).some((raw) => {
306
+ const msg = raw.toLowerCase();
307
+ return (msg.includes('execution reverted') ||
308
+ msg.includes('call revert exception'));
309
+ });
310
+ }
311
+ /**
312
+ * JSON-RPC error codes that indicate the *node or its transport* failed, not
313
+ * that the EVM rejected the call. `-32603` is the spec's "Internal error" and
314
+ * `-32000` the de-facto "Server error" both Alchemy and Infura emit for
315
+ * transient upstream faults (including while serving
316
+ * `eth_getTransactionReceipt` for a freshly broadcast tx).
317
+ */
318
+ const RETRYABLE_RPC_CODES = [
319
+ -32603,
320
+ -32000,
321
+ 'NETWORK_ERROR',
322
+ 'SERVER_ERROR',
323
+ 'TIMEOUT',
324
+ 'ETIMEDOUT',
325
+ 'ECONNRESET',
326
+ 'ECONNREFUSED',
327
+ 'ENOTFOUND',
328
+ 'EAI_AGAIN',
329
+ ];
330
+ /**
331
+ * Message fragments (lower-cased) that identify a transient transport failure.
332
+ *
333
+ * `could not coalesce error` is ethers v6's catch-all when it cannot map a
334
+ * node's JSON-RPC payload onto a typed error — in practice this is what a
335
+ * flaky provider looks like from inside `tx.wait()`. `eth_gettransactionreceipt`
336
+ * is included because a failure *naming that method* is by definition a receipt
337
+ * poll, which is safe to repeat: the transaction is already broadcast and
338
+ * polling is idempotent.
339
+ *
340
+ * `missing revert data` is deliberately **absent**. It is a `CALL_EXCEPTION`,
341
+ * not a transport frame, and {@link isExpectedRevertError} already treats it as
342
+ * a revert — having this predicate disagree would make the two classifiers
343
+ * contradict each other. The narrow subset of `missing revert data` that really
344
+ * is a transport artefact (an empty response to an argument-free view call) has
345
+ * its own predicate: {@link isEmptyViewResponse}.
346
+ */
347
+ const RETRYABLE_RPC_PHRASES = [
348
+ 'could not coalesce error',
349
+ 'eth_gettransactionreceipt',
350
+ 'timeout',
351
+ 'timed out',
352
+ 'etimedout',
353
+ 'econnreset',
354
+ 'econnrefused',
355
+ 'enotfound',
356
+ 'socket hang up',
357
+ 'network error',
358
+ 'network request failed',
359
+ 'failed to fetch',
360
+ 'fetch failed',
361
+ 'load failed',
362
+ 'connection closed',
363
+ 'connection reset',
364
+ 'too many requests',
365
+ 'rate limit',
366
+ 'service unavailable',
367
+ 'bad gateway',
368
+ 'gateway timeout',
369
+ 'internal server error',
370
+ 'internal error',
371
+ 'server error',
372
+ ];
373
+ /**
374
+ * Is this error a transient RPC **transport** failure that is safe to retry,
375
+ * rather than a decision the chain made?
376
+ *
377
+ * Why this exists: the SDK's write paths poll `eth_getTransactionReceipt` to
378
+ * confirm a broadcast transaction. When the provider hiccups mid-poll, ethers
379
+ * surfaces `could not coalesce error (error={ "code": -32603, … "method":
380
+ * "eth_getTransactionReceipt" … })`. Historically that propagated out of
381
+ * `safeWaitForTx` and the SDK reported the write as **failed** — even though
382
+ * the transaction was broadcast, its hash was known, and it mined fine. Users
383
+ * then retried and hit `ERC20InsufficientBalance` because the first attempt had
384
+ * in fact succeeded. Classifying the failure as transport-level lets callers
385
+ * re-poll instead of lying to the user.
386
+ *
387
+ * Matches, in order of precedence:
388
+ * 1. **Veto** — anything with revert evidence ({@link hasRevertEvidence}:
389
+ * `CALL_EXCEPTION` carrying revert `data`, an `execution reverted` message,
390
+ * or an attached `receipt.status === 0`) returns `false`. Nodes reuse
391
+ * `-32603`/`-32000` for real reverts, so the veto must come first.
392
+ * 2. JSON-RPC / ethers transport codes — see `RETRYABLE_RPC_CODES`.
393
+ * 3. HTTP `429` and any `5xx` carried on the error.
394
+ * 4. Transport message fragments — see `RETRYABLE_RPC_PHRASES`.
395
+ *
396
+ * Retrying is only safe for **idempotent** work: re-reading an immutable value
397
+ * (`decimals()`) or re-polling a receipt for a hash that is already on the
398
+ * wire. Never use this to re-send a transaction.
399
+ *
400
+ * @param error - The caught value, of unknown type.
401
+ * @returns `true` when the failure is a transient transport fault worth
402
+ * retrying with backoff; `false` for chain-level decisions (reverts) and for
403
+ * anything unrecognised — the safe default is to surface the error.
404
+ *
405
+ * @example
406
+ * ```ts
407
+ * try {
408
+ * return await provider.waitForTransaction(hash, 1, 120_000);
409
+ * } catch (e) {
410
+ * if (!isRetryableRpcError(e)) throw e; // real revert — surface it
411
+ * await sleep(250);
412
+ * return await provider.waitForTransaction(hash, 1, 120_000);
413
+ * }
414
+ * ```
415
+ */
416
+ function isRetryableRpcError(error) {
417
+ if (error === null || error === undefined)
418
+ return false;
419
+ // A chain-level decision is never a transport fault. Check first: nodes
420
+ // reuse -32603/-32000 for genuine execution reverts.
421
+ if (hasRevertEvidence(error))
422
+ return false;
423
+ const codes = errorCodes(error);
424
+ if (codes.some((code) => RETRYABLE_RPC_CODES.includes(code)))
425
+ return true;
426
+ // 429 (rate limited) and any 5xx are upstream faults, not our request being
427
+ // wrong — 4xx other than 429 means retrying would fail identically.
428
+ if (errorStatuses(error).some((status) => status === 429 || (status >= 500 && status < 600))) {
429
+ return true;
430
+ }
431
+ return nestedMessages(error).some((raw) => {
432
+ const msg = raw.toLowerCase();
433
+ return RETRYABLE_RPC_PHRASES.some((phrase) => msg.includes(phrase));
434
+ });
435
+ }
436
+ /**
437
+ * `lpTokenAddress()` — `keccak256("lpTokenAddress()")[0..4]`. The August `evm-2`
438
+ * tokenized vault's receipt-token getter, exported so the readers that invoke it
439
+ * can scope {@link isEmptyViewResponse} to exactly this call instead of
440
+ * duplicating the literal.
441
+ */
442
+ exports.LP_TOKEN_ADDRESS_SELECTOR = '0xf5ae497a';
443
+ /**
444
+ * Four-byte selectors for the argument-free view functions that a correctly
445
+ * addressed contract **cannot** legitimately revert on. Each is
446
+ * `keccak256(signature)[0..4]`.
447
+ *
448
+ * These are the only calls for which an empty RPC response is unambiguously a
449
+ * provider artefact rather than a contract decision — the metadata they return
450
+ * is fixed at deployment and takes no arguments, so there is no input that
451
+ * could make them fail.
452
+ *
453
+ * **Caveat for `lpTokenAddress()`.** The four ERC-20 entries hold that property
454
+ * absolutely: any deployed, conforming token implements them. `lpTokenAddress()`
455
+ * holds it only *given correct routing* — the function exists on `evm-2` vaults
456
+ * and nowhere else, so a vault wrongly routed into the `evm-2` branch returns
457
+ * empty returndata **deterministically**, producing a byte-identical error to a
458
+ * provider blip. That ambiguity is resolved not by this predicate but by the
459
+ * caller: every reader that retries on this selector is bounded (3 attempts) and
460
+ * rethrows the original error once they are spent, so a deterministic misroute
461
+ * still surfaces unchanged — only a transient blip is absorbed. Never pair this
462
+ * selector with an unbounded retry or a fallback value.
463
+ */
464
+ const ARGUMENT_FREE_VIEW_SELECTORS = new Set([
465
+ '0x313ce567', // decimals()
466
+ '0x95d89b41', // symbol()
467
+ '0x06fdde03', // name()
468
+ '0x18160ddd', // totalSupply()
469
+ exports.LP_TOKEN_ADDRESS_SELECTOR, // lpTokenAddress()
470
+ ]);
471
+ /**
472
+ * Extract the 4-byte selector of the call an ethers `CALL_EXCEPTION` describes.
473
+ *
474
+ * ethers v6 attaches the attempted call as `error.transaction.data`, and also
475
+ * embeds it in the human-readable message as `data="0x…"`. We read the
476
+ * structured field first and fall back to the message so the predicate still
477
+ * works on an error that has been serialized and rehydrated (which is how these
478
+ * arrive from a logging pipeline).
479
+ *
480
+ * @param error - The caught value, of unknown type.
481
+ * @returns The lower-cased `0x`-prefixed 4-byte selector, or `null` when the
482
+ * error does not name a call.
483
+ */
484
+ function callSelector(error) {
485
+ if (error && typeof error === 'object') {
486
+ const e = error;
487
+ const data = e.transaction?.data;
488
+ if (typeof data === 'string' && /^0x[0-9a-fA-F]{8}/.test(data)) {
489
+ return data.slice(0, 10).toLowerCase();
490
+ }
491
+ }
492
+ // ethers renders the same field two ways depending on nesting depth:
493
+ // `data="0x313ce567"` at the top level and `"data": "0x313ce567"` inside the
494
+ // serialized `transaction={…}` blob. Accept both.
495
+ for (const raw of nestedMessages(error)) {
496
+ const match = raw.match(/data"?\s*[:=]\s*"(0x[0-9a-fA-F]{8})/);
497
+ if (match?.[1])
498
+ return match[1].toLowerCase();
499
+ }
500
+ return null;
501
+ }
502
+ /**
503
+ * Is this error an **empty RPC response to an argument-free view call** —
504
+ * i.e. a transport artefact wearing a revert's clothes?
505
+ *
506
+ * Why this is separate from {@link isRetryableRpcError}: when a provider
507
+ * truncates or 500s a response to `eth_call`, ethers reports
508
+ * `missing revert data (action="call", data="0x313ce567", …)` with a `null`
509
+ * `data` field. That is byte-for-byte the shape of a genuine revert with no
510
+ * reason string, so a general "transport" predicate cannot safely claim it —
511
+ * doing so would retry every data-less `CALL_EXCEPTION` in the SDK. This
512
+ * predicate narrows the claim to the one case where the ambiguity resolves:
513
+ * a **deployed ERC-20's `decimals()`/`symbol()`/`name()`/`totalSupply()` cannot
514
+ * legitimately revert**, because it takes no arguments and returns state fixed
515
+ * at deployment. An empty response there is the provider's fault, full stop.
516
+ *
517
+ * A match requires all of:
518
+ * 1. no revert evidence ({@link hasRevertEvidence}) — anything carrying real
519
+ * revert `data`, an `execution reverted` message, or a failed receipt is out;
520
+ * 2. a `missing revert data` message;
521
+ * 3. an `action` of `call` or `staticCall` — a read, never a state change;
522
+ * 4. **when a selector is derivable** from the error, that it is
523
+ * `expectedSelector` (if given) or one of
524
+ * {@link ARGUMENT_FREE_VIEW_SELECTORS}. When no selector can be recovered,
525
+ * conditions 1–3 stand on their own.
526
+ *
527
+ * Note the cost of a false positive is bounded and small: the caller retries an
528
+ * idempotent read a couple of times before surfacing the same error. The cost
529
+ * of a false negative is the production flood this predicate exists to stop.
530
+ *
531
+ * @param error - The caught value, of unknown type.
532
+ * @param expectedSelector - Optional `0x`-prefixed 4-byte selector the caller
533
+ * knows it invoked (e.g. `'0x313ce567'` for `decimals()`). When supplied, the
534
+ * error's own selector must match it — this stops a `decimals()` retry from
535
+ * firing on an unrelated view call that happened to fail the same way.
536
+ * @returns `true` when the failure is an empty provider response to a view call
537
+ * that cannot revert, and is therefore safe to retry.
538
+ *
539
+ * @example
540
+ * ```ts
541
+ * try { return Number(await erc20.decimals()); }
542
+ * catch (e) {
543
+ * if (!isEmptyViewResponse(e, '0x313ce567')) throw e; // real problem
544
+ * return Number(await erc20.decimals()); // provider blip
545
+ * }
546
+ * ```
547
+ */
548
+ function isEmptyViewResponse(error, expectedSelector) {
549
+ if (error === null || error === undefined)
550
+ return false;
551
+ if (hasRevertEvidence(error))
552
+ return false;
553
+ const messages = nestedMessages(error).map((raw) => raw.toLowerCase());
554
+ if (!messages.some((msg) => msg.includes('missing revert data')))
555
+ return false;
556
+ // The call must be a read. ethers exposes this as a structured `action`
557
+ // ('call' | 'estimateGas' | 'sendTransaction' | …) and mirrors it in the
558
+ // message as action="call".
559
+ const action = error && typeof error === 'object'
560
+ ? error.action
561
+ : undefined;
562
+ const isRead = action === 'call' ||
563
+ action === 'staticCall' ||
564
+ messages.some((msg) => msg.includes('action="call"') || msg.includes('action="staticcall"'));
565
+ if (!isRead)
566
+ return false;
567
+ const selector = callSelector(error);
568
+ // Nothing to check against — conditions 1-3 already establish "empty response
569
+ // to a read", which is the signal we act on.
570
+ if (!selector)
571
+ return true;
572
+ if (expectedSelector)
573
+ return selector === expectedSelector.toLowerCase();
574
+ return ARGUMENT_FREE_VIEW_SELECTORS.has(selector);
575
+ }
576
+ /**
577
+ * How many times an idempotent RPC read is attempted in total (1 initial call +
578
+ * 2 retries) before the transport error is surfaced. Deliberately small:
579
+ * CLAUDE.md §4.2 — retrying harder during a provider outage amplifies load
580
+ * rather than recovering from it.
581
+ */
582
+ const RPC_RETRY_ATTEMPTS = 3;
583
+ /**
584
+ * Base backoff between retry attempts, in milliseconds. Doubles per attempt
585
+ * (250ms, then 500ms), so a fully-failed read costs ~750ms of added latency.
586
+ */
587
+ const RPC_RETRY_BASE_DELAY_MS = 250;
588
+ /**
589
+ * Run an **idempotent** RPC read, retrying with exponential backoff while the
590
+ * failure classifies as a transient transport fault
591
+ * ({@link isRetryableRpcError}).
592
+ *
593
+ * Lives next to the classifiers it consumes so there is exactly one retry
594
+ * implementation in the SDK: both the receipt-poll fallback in the vault write
595
+ * paths and the cached `decimals()` reader in `core/helpers/web3.ts` call this.
596
+ *
597
+ * Only safe for operations that can be repeated without side effects: polling
598
+ * `eth_getTransactionReceipt` for an already-broadcast hash, or re-reading an
599
+ * immutable value such as `decimals()`. **Never wrap a transaction send in
600
+ * this.**
601
+ *
602
+ * Anything that is not a transport fault (a genuine revert, a user rejection,
603
+ * an insufficient-funds rejection) is rethrown on the first attempt with no
604
+ * delay, so real failures still fail fast.
605
+ *
606
+ * @param tag - Low-cardinality log label for the retry breadcrumb.
607
+ * @param operation - The idempotent async read to run.
608
+ * @param context - Extra structured context for the retry breadcrumb (e.g.
609
+ * `{ hash }`). Sanitized by the logger before transport.
610
+ * @param isRetryable - Predicate deciding whether a caught error warrants
611
+ * another attempt. Defaults to the strict transport definition
612
+ * ({@link isRetryableRpcError}); pass a wider one only where the call site
613
+ * can prove the extra shape is also a provider artefact — the only such case
614
+ * today is the selector-scoped {@link isEmptyViewResponse} used by
615
+ * `getDecimalsOrThrow`.
616
+ * @returns Whatever `operation` resolves to on the first successful attempt.
617
+ * @throws The last error thrown by `operation` once retries are exhausted, or
618
+ * immediately when the error is not retryable.
619
+ *
620
+ * @example
621
+ * ```ts
622
+ * const receipt = await retryOnTransientRpc(
623
+ * 'safeWaitForTx:transport-retry',
624
+ * () => provider.waitForTransaction(hash, 1, 120_000),
625
+ * { hash },
626
+ * );
627
+ * ```
628
+ */
629
+ async function retryOnTransientRpc(tag, operation, context = {}, isRetryable = isRetryableRpcError) {
630
+ let lastError;
631
+ for (let attempt = 1; attempt <= RPC_RETRY_ATTEMPTS; attempt += 1) {
632
+ try {
633
+ return await operation();
634
+ }
635
+ catch (error) {
636
+ lastError = error;
637
+ if (!isRetryable(error) || attempt === RPC_RETRY_ATTEMPTS) {
638
+ throw error;
639
+ }
640
+ const delayMs = RPC_RETRY_BASE_DELAY_MS * 2 ** (attempt - 1);
641
+ logger_1.Logger.log.warn(tag, 'transient RPC error; retrying', {
642
+ ...context,
643
+ attempt,
644
+ attempts: RPC_RETRY_ATTEMPTS,
645
+ delayMs,
646
+ message: error instanceof Error ? error.message : String(error),
647
+ });
648
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
649
+ }
650
+ }
651
+ // Unreachable: the loop either returns or throws on its final attempt.
652
+ throw lastError;
653
+ }
654
+ /**
655
+ * Log a caught chain error at the severity its category warrants, without
656
+ * swallowing it. When `isBenign` is `true` the failure is recorded as a `warn`
657
+ * (a Sentry breadcrumb that rides along with the next real issue, not a billed
658
+ * standalone issue); otherwise it is logged at `error` (a Sentry issue). The
659
+ * caller is still responsible for re-throwing — this only routes telemetry.
660
+ *
661
+ * Pass the benign decision explicitly (via {@link isUserRejectionError} or
662
+ * {@link isExpectedRevertError}) so the call site documents *why* the demotion
663
+ * is safe and each path opts into only the category that applies to it.
664
+ *
665
+ * @param tag - Low-cardinality call-site label (e.g. `'deposit'`), used as the
666
+ * Sentry breadcrumb/issue grouping key.
667
+ * @param error - The caught value, of unknown type.
668
+ * @param isBenign - `true` to demote to `warn`; `false` to keep at `error`.
669
+ * @param context - Optional structured context attached to the log entry. It is
670
+ * sanitized by the logger before transport.
671
+ */
672
+ function logChainError(tag, error, isBenign, context) {
673
+ if (isBenign) {
674
+ // Demote to a breadcrumb: the SDK's Sentry sink forwards `warn` as a
675
+ // breadcrumb, so this no longer creates its own billed issue while still
676
+ // preserving the trail if a genuine error follows.
677
+ logger_1.Logger.log.warn(tag, { message: errorText(error), ...(context ?? {}) });
678
+ return;
679
+ }
680
+ logger_1.Logger.log.error(tag, error, context);
681
+ }
682
+ //# sourceMappingURL=chain-error.js.map