@augustdigital/sdk 8.17.0 → 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 (38) hide show
  1. package/lib/adapters/evm/index.js +4 -2
  2. package/lib/adapters/stellar/soroban.d.ts +8 -3
  3. package/lib/adapters/stellar/soroban.js +9 -4
  4. package/lib/adapters/sui/constants.d.ts +1 -1
  5. package/lib/adapters/sui/constants.js +6 -1
  6. package/lib/core/analytics/constants.d.ts +1 -1
  7. package/lib/core/analytics/constants.js +1 -1
  8. package/lib/core/analytics/sentry.d.ts +7 -0
  9. package/lib/core/analytics/sentry.js +182 -1
  10. package/lib/core/analytics/version.d.ts +1 -1
  11. package/lib/core/analytics/version.js +1 -1
  12. package/lib/core/attribution.d.ts +111 -0
  13. package/lib/core/attribution.js +142 -0
  14. package/lib/core/base.class.d.ts +17 -1
  15. package/lib/core/base.class.js +6 -1
  16. package/lib/core/constants/core.js +42 -15
  17. package/lib/core/constants/web3.d.ts +17 -0
  18. package/lib/core/constants/web3.js +22 -1
  19. package/lib/core/fetcher.js +10 -1
  20. package/lib/core/helpers/chain-error.d.ts +140 -0
  21. package/lib/core/helpers/chain-error.js +412 -0
  22. package/lib/core/helpers/chain-support.d.ts +80 -0
  23. package/lib/core/helpers/chain-support.js +115 -0
  24. package/lib/core/helpers/signer.d.ts +21 -0
  25. package/lib/core/helpers/signer.js +52 -0
  26. package/lib/core/helpers/web3.d.ts +172 -3
  27. package/lib/core/helpers/web3.js +357 -49
  28. package/lib/core/index.d.ts +2 -0
  29. package/lib/core/index.js +2 -0
  30. package/lib/evm/methods/crossChainVault.js +4 -0
  31. package/lib/modules/vaults/getters.js +115 -23
  32. package/lib/modules/vaults/main.d.ts +24 -3
  33. package/lib/modules/vaults/main.js +32 -31
  34. package/lib/modules/vaults/write.actions.d.ts +41 -1
  35. package/lib/modules/vaults/write.actions.js +302 -86
  36. package/lib/sdk.d.ts +11315 -10736
  37. package/lib/services/subgraph/vaults.js +85 -14
  38. package/package.json +1 -1
@@ -3,7 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isViemWalletClient = isViemWalletClient;
4
4
  exports.viemToEthersSigner = viemToEthersSigner;
5
5
  exports.normalizeSigner = normalizeSigner;
6
+ exports.wrapSignerWithAttribution = wrapSignerWithAttribution;
6
7
  const ethers_1 = require("ethers");
8
+ const attribution_1 = require("../attribution");
7
9
  /**
8
10
  * Signer Compatibility Helpers
9
11
  *
@@ -90,4 +92,54 @@ async function normalizeSigner(signer) {
90
92
  // If we can't determine the type, throw an error
91
93
  throw new Error('Invalid signer type. Expected ethers Signer, ethers Wallet, or viem WalletClient');
92
94
  }
95
+ /**
96
+ * Wrap an ethers signer so every transaction it sends carries the active
97
+ * ERC-8021 attribution suffix (Base Builder Codes).
98
+ *
99
+ * Every ethers write in the SDK funnels through the wrapped signer's
100
+ * `sendTransaction`, so this single wrap attributes all vault writes. The
101
+ * wrapper is a Proxy — the caller's signer object is never mutated, so a
102
+ * signer reused outside the SDK sends unattributed transactions. Attribution
103
+ * state is read at send time, not wrap time; when no attribution is
104
+ * configured (see `IAugustBase.attribution`) the wrapper is a pass-through.
105
+ *
106
+ * Plain value transfers (no calldata) are never attributed, and calldata
107
+ * already ending in the ERC-8021 marker is left untouched. When the
108
+ * configured `chains` list requires a chain check and the transaction does
109
+ * not carry a `chainId`, the signer's provider network is consulted (one
110
+ * cached RPC call).
111
+ *
112
+ * @param signer Normalized ethers Signer or Wallet.
113
+ * @returns A proxied signer with an attribution-aware `sendTransaction`.
114
+ */
115
+ function wrapSignerWithAttribution(signer) {
116
+ return new Proxy(signer, {
117
+ get(target, prop) {
118
+ if (prop === 'sendTransaction') {
119
+ return async (tx) => {
120
+ if (!(0, attribution_1.getAttributionSuffix)() || typeof tx?.data !== 'string') {
121
+ return target.sendTransaction(tx);
122
+ }
123
+ let chainId = tx.chainId != null ? Number(tx.chainId) : undefined;
124
+ if (chainId === undefined && target.provider) {
125
+ try {
126
+ chainId = Number((await target.provider.getNetwork()).chainId);
127
+ }
128
+ catch {
129
+ // Unknown chain: fall through with chainId undefined, which
130
+ // appends regardless of a `chains` restriction —
131
+ // over-attribution is harmless, under-attribution loses data.
132
+ }
133
+ }
134
+ const data = (0, attribution_1.appendAttributionSuffix)(tx.data, chainId);
135
+ return target.sendTransaction(data === tx.data ? tx : { ...tx, data });
136
+ };
137
+ }
138
+ // `this`-bind reads to the target, not the proxy — ethers classes use
139
+ // private fields, which throw when methods run with a Proxy receiver.
140
+ const value = Reflect.get(target, prop, target);
141
+ return typeof value === 'function' ? value.bind(target) : value;
142
+ },
143
+ });
144
+ }
93
145
  //# sourceMappingURL=signer.js.map
@@ -33,7 +33,26 @@ export declare const determineSecondsPerBlock: (chain: number) => number;
33
33
  * @param chain Chain ID
34
34
  * @returns Block interval for pagination
35
35
  */
36
- export declare const determineBlockSkipInternal: (chain: number) => 1000 | 8000 | 50000;
36
+ export declare const determineBlockSkipInternal: (chain: number) => 1000 | 8000 | 10000;
37
+ /**
38
+ * Maximum JSON-RPC calls ethers may coalesce into a single batched HTTP
39
+ * request for a given endpoint.
40
+ *
41
+ * Providers advertise wildly different batch limits and reject the whole batch
42
+ * — not the excess — when exceeded, so one oversized batch fails every call
43
+ * inside it. dRPC's free tier caps batches at 3, which made every Mezo read
44
+ * fail with `server response 500 … "Batch of more than 3 requests are not
45
+ * allowed"` (the single highest-volume SDK error in production).
46
+ *
47
+ * Detection is host-based rather than chain-based because the limit is a
48
+ * property of the endpoint, not the chain: the same chain served by a
49
+ * self-hosted node has no such cap.
50
+ *
51
+ * @param rpcUrl - The RPC endpoint URL. Unparseable values fall back to the
52
+ * conservative default rather than throwing.
53
+ * @returns Batch size cap to pass to ethers as `batchMaxCount`.
54
+ */
55
+ export declare const determineRpcBatchMaxCount: (rpcUrl: string) => number;
37
56
  /**
38
57
  * Retrieve chain ID from web3 provider.
39
58
  * Handles both initialized and uninitialized provider states.
@@ -75,11 +94,84 @@ export { explorerLink } from './explorer-link';
75
94
  /**
76
95
  * Fetch token decimals from contract or Solana mint.
77
96
  * Results are cached to minimize RPC calls.
97
+ *
98
+ * **Never throws** — a failed read logs at error level and resolves
99
+ * `undefined`. Callers that must not silently proceed on an unknown scale (any
100
+ * path that encodes an amount) should use {@link getDecimalsOrThrow} instead:
101
+ * feeding `undefined` into `toNormalizedBn` silently defaults to 18 decimals.
102
+ *
78
103
  * @param provider Web3 provider
79
104
  * @param address Token contract address or Solana mint
80
- * @returns Number of decimals for the token
105
+ * @param isVault Resolve `address` as a vault (evm-2 vaults redirect to the
106
+ * receipt token) rather than reading it as a plain ERC-20. Defaults to `true`.
107
+ * @returns Number of decimals for the token, or `undefined` when the read failed.
81
108
  */
82
109
  export declare const getDecimals: (provider: IContractRunner, address: IAddress, isVault?: boolean) => Promise<number>;
110
+ /**
111
+ * Read a token's `decimals()` with the **same cache and stampede protection as
112
+ * {@link getDecimals}**, but surfacing failures instead of swallowing them, and
113
+ * retrying the transient ones.
114
+ *
115
+ * Two reasons this exists rather than a flag on `getDecimals`:
116
+ *
117
+ * 1. **`getDecimals` must keep returning `undefined` on failure** — a dozen
118
+ * read paths depend on that. Amount-encoding paths need the opposite: an
119
+ * `undefined` reaching `toNormalizedBn` silently means 18 decimals, which
120
+ * misencodes the transaction. Here the original error propagates, so the
121
+ * caller's `AugustSDKError` keeps its cause and its Sentry grouping.
122
+ * 2. **Retry.** Providers intermittently return an empty response to
123
+ * `decimals()`, which ethers reports as
124
+ * `missing revert data (action="call", data="0x313ce567", …)` — a shape a
125
+ * deployed ERC-20 cannot legitimately produce, since `decimals()` takes no
126
+ * arguments. That is retried here via {@link isEmptyViewResponse} scoped to
127
+ * this exact selector, alongside ordinary transport faults
128
+ * ({@link isRetryableRpcError}). The empty-view widening applies **only**
129
+ * here; everywhere else the strict transport definition stands. A genuine
130
+ * revert (`CALL_EXCEPTION` carrying revert data) is never retried.
131
+ *
132
+ * Cache is shared with `getDecimals`, so a read-then-write flow against the
133
+ * same token costs one `decimals()` RPC in total, and N concurrent callers for
134
+ * an uncached token collapse to one.
135
+ *
136
+ * **Exception — an unresolvable chain scope bypasses the cache entirely.** When
137
+ * {@link resolveProviderScope} cannot determine the chain (a runner with no
138
+ * resolved network and no connection URL, e.g. a browser provider before its
139
+ * first request), the only available key is the shared `unknown` bucket. Read
140
+ * paths happily use that bucket, and this function deliberately does not: the
141
+ * two paths have different blast radii. A wrong cached `decimals` on a read
142
+ * renders a wrong number on screen; on a write it misencodes an amount the user
143
+ * then *signs*. The collision needed — the same address being a different token
144
+ * with different decimals on two chains, within one process, across a
145
+ * mid-session chain switch — is narrow, but "no worse than the read path" is
146
+ * not the bar for a value that ends up in a transaction. In that case the read
147
+ * is neither served from nor written to the cache, and it also skips the
148
+ * in-flight dedup map, since joining another caller under an untrusted key
149
+ * would reintroduce exactly the collision being avoided. Retries still apply;
150
+ * the only thing forgone is the RPC saving.
151
+ *
152
+ * RPC cost: 1 on a cache miss, 0 on a hit, up to 3 on a miss that keeps
153
+ * faulting (~750ms of added latency in the worst case before it gives up).
154
+ * Always ≥1 when the chain scope is unresolvable.
155
+ *
156
+ * @param runner - Provider or signer to read through. A signer is unwrapped to
157
+ * its provider for cache scoping, so it shares entries with reads on the
158
+ * same chain.
159
+ * @param address - Token address. Read directly as an ERC-20 — pass the
160
+ * receipt-token address yourself for an `evm-2` vault's share scale.
161
+ * @param tag - Low-cardinality label for retry breadcrumbs (e.g.
162
+ * `'vaultDeposit:poolDecimals'`).
163
+ * @returns The token's decimals.
164
+ * @throws The underlying read error once retries are exhausted, or immediately
165
+ * when the failure is neither a transport fault nor an empty view response.
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * // Amount encoding must not proceed on a guessed scale.
170
+ * const decimals = await getDecimalsOrThrow(signer, token, 'deposit:decimals');
171
+ * const amount = toNormalizedBn(userInput, decimals);
172
+ * ```
173
+ */
174
+ export declare const getDecimalsOrThrow: (runner: IContractRunner, address: IAddress, tag: string) => Promise<number>;
83
175
  /**
84
176
  * Fetch the whitelisted deposit-asset addresses from a vault's whitelist
85
177
  * contract. Cached with a 5-minute TTL; a fresh fetch fans out into N
@@ -87,12 +179,89 @@ export declare const getDecimals: (provider: IContractRunner, address: IAddress,
87
179
  * @internal
88
180
  */
89
181
  export declare const getWhitelistedAssets: (provider: IContractRunner, whitelistAddress: IAddress) => Promise<IAddress[]>;
182
+ /**
183
+ * Read an `evm-2` vault's receipt (LP) token address via `lpTokenAddress()`,
184
+ * retrying only the transient transport faults and surfacing everything else
185
+ * unchanged.
186
+ *
187
+ * Why this exists: `lpTokenAddress()` sits immediately before the receipt-token
188
+ * `decimals()` read on every `evm-2` write path (approve / deposit / request
189
+ * redeem / swap-router deposit). Those `decimals()` reads were hardened against
190
+ * provider blips ({@link getDecimalsOrThrow}); the `lpTokenAddress()` read one
191
+ * line above them was not, so a single truncated `eth_call` response still
192
+ * failed the whole write with
193
+ * `missing revert data (action="call", data="0xf5ae497a", …)` — observed in
194
+ * production against a mainnet vault whose `lpTokenAddress()` demonstrably
195
+ * returns a real address when the provider is healthy.
196
+ *
197
+ * **This must never hide a misrouted vault, and does not.** `lpTokenAddress()`
198
+ * exists *only* on `evm-2` vaults. A vault wrongly classified as `evm-2` returns
199
+ * empty returndata for it, deterministically and forever, and that empty
200
+ * response is byte-identical to the transient one — it is the *only* signal the
201
+ * SDK gets that its version routing was wrong. So the retry here is deliberately
202
+ * shaped to preserve that signal:
203
+ *
204
+ * - it is **bounded** (3 attempts, ~750ms of backoff in total — see
205
+ * `retryOnTransientRpc`), never open-ended;
206
+ * - on exhaustion it **rethrows the original error object**, with its identity,
207
+ * message, `code` and `transaction.data` intact, so the caller's
208
+ * `AugustSDKError` cause and Sentry grouping are exactly what they are today;
209
+ * - it has **no fallback**: it never substitutes another address, never resolves
210
+ * the vault address itself, and never resolves `null`/`undefined`. It either
211
+ * returns a real receipt-token address or throws.
212
+ *
213
+ * Net effect: a blip costs a retry, a misroute costs three `eth_call`s and then
214
+ * fails exactly as loudly as before.
215
+ *
216
+ * **Deliberately not cached.** Unlike `decimals()`, the vault→receipt-token
217
+ * mapping is not memoized here. Caching it would make a misroute's first
218
+ * (failed) probe and every subsequent one diverge, and would put a
219
+ * vault-identity mapping in the cache on the money path. The lenient, cached
220
+ * reader is {@link getReceiptTokenAddress} — use that on read paths that can
221
+ * tolerate `undefined`.
222
+ *
223
+ * RPC cost: exactly 1 `eth_call` on success; at most 3 when the provider keeps
224
+ * faulting.
225
+ *
226
+ * @param runner - Provider or signer to read through.
227
+ * @param vault - Address of the `evm-2` tokenized vault.
228
+ * @param tag - Low-cardinality label for retry breadcrumbs (e.g.
229
+ * `'vaultRequestRedeem:receiptToken'`).
230
+ * @returns The vault's receipt (LP) token address. Never `null`/`undefined`.
231
+ * @throws The underlying read error, unmodified, once the bounded retries are
232
+ * exhausted — or immediately when the failure is neither a transport fault nor
233
+ * an empty response to this exact selector (e.g. a genuine revert carrying
234
+ * revert data).
235
+ *
236
+ * @example
237
+ * ```ts
238
+ * const receiptToken = await getReceiptTokenAddressOrThrow(
239
+ * signer,
240
+ * vault,
241
+ * 'vaultRequestRedeem:receiptToken',
242
+ * );
243
+ * const decimals = await getDecimalsOrThrow(signer, receiptToken, 'tag');
244
+ * ```
245
+ */
246
+ export declare const getReceiptTokenAddressOrThrow: (runner: IContractRunner, vault: IAddress, tag: string) => Promise<IAddress>;
90
247
  /**
91
248
  * Fetch receipt token address from tokenized vault contract.
92
249
  * Results are cached to minimize RPC calls.
250
+ *
251
+ * **Never throws** — a failed read logs at error level and resolves
252
+ * `undefined`, which several read paths depend on. The underlying
253
+ * `lpTokenAddress()` call is made through
254
+ * {@link getReceiptTokenAddressOrThrow}, so a transient provider blip is
255
+ * absorbed by a bounded retry before that happens; a deterministic failure (a
256
+ * vault that has no `lpTokenAddress()` because it is not `evm-2`) still resolves
257
+ * `undefined` after the attempts are spent, exactly as before. Callers on a
258
+ * money path must use {@link getReceiptTokenAddressOrThrow} directly instead —
259
+ * an `undefined` receipt-token address there would silently mis-address a
260
+ * `decimals()` read.
261
+ *
93
262
  * @param provider Web3 provider
94
263
  * @param address Tokenized vault contract address
95
- * @returns Receipt token address
264
+ * @returns Receipt token address, or `undefined` when the read failed.
96
265
  */
97
266
  export declare const getReceiptTokenAddress: (provider: IContractRunner, address: IAddress) => Promise<`0x${string}`>;
98
267
  /**