Changelog
8.0.0
Major Changes
ebeb2c6: chore: remove two unused symbols from the published type surface β the
@deprecated StellarNetworkalias (useIStellarNetworkinstead; the alias existed for back-compat and has 0 internal consumers across our repos) and theoctavfi?: stringfield on the SDK constructor'skeysconfig (the field was never read; the octavfi service uses a hardcoded API key, not this config). No runtime behavior changes. Consumers that referencedStellarNetworkshould switch toIStellarNetwork; consumers that passedkeys.octavfican drop it β it was a no-op.
Patch Changes
66b18f2: fix:
fetchTokenPricesFromCoinGeckonow returns the latest price on the success path. The previousif (data && data.length)guard checked thelengthproperty on an object response ({ prices, market_caps, total_volumes }) and silently collapsed every successful response tonullβ only the hardcodedmusdshort-circuit was returning a real value. Fixes defect #1 fromtodo/32-coingecko-fetcher-defects.md; defects #2 (typed errors on non-2xx) and #3 (up-front symbol validation) remain pending.175da88: fix:
fetchVaultsBatchno longer mis-routes successful fetches that resolve to a falsy value (0,'',0n,null,false) into the failed pile. The success/failure branch now keys onresult.successonly, respecting the function's documented contract thatdatais the source of truth whensuccess === true.10b3b85: fix: break circular dependency
core/index.ts β core/auth β core/fetcher.ts β services/coingecko/fetcher.ts β core/index.tsby importingLoggerfrom thecore/loggerleaf module inservices/coingecko/fetcher.tsinstead of thecorebarrel. Restores the zero-cycle invariant enforced by theCircular Dependency CheckCI job.66b18f2: chore: route all
console.*calls underpackages/sdk/src.ts/services/(coingecko, debank, octavfi, subgraph) throughLogger.log.{info,error}. Each call is now tagged with the originating function name and carries structured context (status, statusText, pool, address, etc.) instead of the previous raw, unsanitized strings. Errors now flow throughsanitizeErrorbefore reaching Sentry, and dashboards can group by function tag rather than by error-message text. A newtests/services/services-logger-hygiene.test.tsregression-tests the floor: noconsole.*inservices/.
7.0.1
Patch Changes
ddbfa62: fix: restore
explorerLinkreturn type tostring(regression in 7.0.0)The circular-dependency cleanup unintentionally tightened
explorerLink's return type tostring | undefinedby surfacing a branch that was previously masked bystrictNullChecks: false. Consumers had always compiled againststringvia the emitted.d.ts. Restore the historical public shape by returning''whenchainis falsy or unknown.
7.0.0
Major Changes
7ede403: fix(audit): correctness, validation, and observability hardening across deposit / withdraw / redeem flows
Breaking β write helpers now throw
AugustValidationErroron bad input andAugustSDKErroron downstream failures (previously returnedundefinedor threw a plainError). Callers that depended on the silent no-op or were matching onErrormessage strings need to wrap calls intry/catchand narrow onAugustValidationError/AugustSDKError.Breaking β
handleSolanaDepositandhandleSolanaRedeem(the Solana adapter'svaultDeposit/vaultRedeem) nowthrowon failure instead of returningnull. Callers checking for anullreturn must convert totry/catch.EVMwrite.actionsvaultDeposit: amount is now encoded against the deposit token's decimals (not the vault's share decimals). Fixes a silent mis-scaling on EVM-2 multi-asset vaults and any native-token deposit into a vault whose share decimals β 18. Native deposits always use 18 decimals.
vaultApprove: now mirrors
vaultDeposit's routing β picks the wrapper as spender for adapter deposits and the vault for multi-asset / standard deposits. Compares the existing on-chain allowance against the required amount (was: only re-approved when allowance was exactly0).vaultRequestRedeem: receipt-token approval now goes through
safeSendTxso Monad-style RPCs that return malformed pending-tx fields don't throw during parsing.vaultRedeem (dated-claim flow) and rwaRedeemAsset: both now use
safeSendTx+tryRecoverTxHashfor nonce-fallback parity withvaultDeposit/vaultRequestRedeem.rwaRedeemAsset: doc fix β the vault share must be approved to the subaccount, not the redeemable (output) asset. Caller responsibility unchanged; the comment was wrong.
All write helpers (
vaultApprove,vaultDeposit,vaultRequestRedeem,vaultRedeem,depositNative,rwaRedeemAsset) now throwAugustValidationErroron invalid wallet/target/wrapper addresses or missing required inputs, and reject JSnumberamounts that exceedNumber.MAX_SAFE_INTEGER.vaultDepositandvaultRequestRedeemnow requireamount(previously silently encoded as0viatoNormalizedBn(undefined)).vaultDepositthrowsAugustValidationErrorwhendepositAssetdiffers from the vault's underlying but no adapter is configured for the vault (previously fell through to a cryptic on-chain revert).vaultDepositandvaultRequestRedeemalways wait for the ERC-20 approval receipt before sending the deposit/redeem tx, regardless of the caller'swaitflag β closes a race window where a follow-up tx could be re-ordered ahead of the approval on some RPCs.Downstream tx failures (e.g. on-chain reverts) are now wrapped in
AugustSDKErrorwith the original error preserved oncauseand a structuredcontextpayload, instead of a plainError("Deposit failed: β¦").safeBigIntallowance read insidevaultDepositnow passes a'vaultDeposit:allowance'context so flaky-RPC warnings are discriminable from approve-path warnings.safeBigInt: emits a
Logger.warnon malformed RPC responses (e.g. bare"0x") so flaky RPCs don't cause silent gas waste from spurious approvals.
EVM cross-chain (crossChainVault)crossChainVaultDeposit: now rejects unsupported user chains up front with a clear error (was: cryptic config-lookup or gas-estimation revert).
approveCrossChain: throws when the approval receipt reports
reverted(was: returned the hash unconditionally).Monkey-patch lock: timing out now throws instead of silently proceeding with conflicting concurrent patches.
Fee patch: warns via
Logger.warnwhen the LayerZero SDK returns an unexpectedcontractFunctionName, so the in-place LZ-fee buffer being silently no-op'd is visible in telemetry.TSDoc on
crossChainVaultDeposit,crossChainVaultRedeem,buildCrossChainVaultTx, andneedsCrossChainApprovalnow states the default slippage / fee / gas buffers and documents the "approval needed on RPC failure" defensive behavior.
SolanahandleSolanaRedeem: replaced
parseIntwith the newuiAmountToRawBnBN-based helper. Fixes precision loss for any 18-decimal mint above a few thousandths or any 9-decimal mint above ~9M tokens.handleSolanaDeposit: now uses the same helper for consistency.
Both handlers now throw
AugustValidationError/AugustSDKErroron failure instead of returningnull, matching the EVM helpers' error contract.
StellarsubmitStellarTransaction: polling now backs off geometrically (1.5x, capped at 8s) instead of fixed 2s β same worst-case ceiling on attempts, lower RPC pressure on long waits.
handleStellarRedeemTSDoc now documents the exact Soroban contract interface it assumes (redeem(shares: i128, receiver, owner, operator)).
TelemetryrwaRedeemAssetis now classified underwrite.redeeminMETHOD_CATEGORIES(previously fell back to'unknown').
New exportsuiAmountToRawBn(fromadapters/solana/utils).resolveDepositTokenDecimals,resolveSpender,validateAmountPrecision,safeBigInt,safeSendTx,safeWaitForTx,tryRecoverTxHash,isNonceParsingfrommodules/vaults/write.actions(marked@internalβ exported for unit testing).New polling constants:
POLL_INTERVAL_MAX_MS,POLL_INTERVAL_BACKOFF.
Minor Changes
ae03a7b: feat(sdk): new
approvemethod returns a discriminatedApproveResultAdds
augustSdk.evm.approve(...)(and the underlyingapproveexport frommodules/vaults/write.actions) that returns one of:type ApproveResult = | { kind: 'sent'; hash: string } | { kind: 'sufficient'; existing: bigint } | { kind: 'native' };Lets callers tell apart "we sent a tx", "existing allowance already covers the amount", and "the resolved deposit asset is native (msg.value, no allowance applies)" without re-reading on-chain state.
vaultApproveis unchanged β samePromise<string | undefined>shape, same spender routing, same allowance / native short-circuits. Both functions share the routing implementation via an internal helper so behavior stays identical.Method-taxonomy entry
approve β write.approveadded so Sentry rolls the new method up next tovaultApprove.dee70e0: feat(AUG-6139): partner-usage telemetry β isomorphic Sentry bootstrap, method taxonomy, dimension tags, and arg-shape capture
Node + browser Sentry resolved at runtime (
@sentry/nodeadded alongside@sentry/browser); CLI now emits telemetry from its top-level error handler.Every method span carries
sdk.category,sdk.chain, andsdk.argShapeso dashboards can slice partner usage by intent, chain, and call shape without leaking values.Fallback
partner.id = 'unverified:<appName>'andpartner.tier = 'unverified'tags ship until the verified-partner endpoint exists.setMeasurement('sdk.method.invocation' | 'sdk.method.error', β¦)adds counter-style aggregates for sum-based dashboards.New public exports:
getSentrySDK,getSentryRuntime,getMethodCategory,METHOD_CATEGORIES,chainIdToTagValue,computeArgShape,captureSdkException.
ae03a7b: feat(sdk): preview / allowance / balance / maxDeposit read helpers on the EVM adapter
Adds five additive read methods to
augustSdk.evmso consumers can stop reaching into raw ABIs for the most common vault reads:previewDeposit({ vault, amount, asset? })β shares returned by a deposit. Routes EVM-1 vaults toIERC4626.previewDeposit(uint256)and EVM-2 multi- asset vaults topreviewDeposit(address, uint256)(returns the share slot of the tuple).previewRedeem({ vault, shares })β assets returned by a redeem. Routes EVM-1 vaults toIERC4626.previewRedeem(uint256)and EVM-2 topreviewRedemption(uint256, false)(gross slot).allowance({ vault, owner, asset? })β raw ERC-20 allowance the owner has granted the vault. Whenassetis omitted the SDK resolves the vault's underlying viaIERC4626.asset().balanceOf({ asset, owner })β raw ERC-20 balance.maxDeposit({ vault, receiver? })β vault deposit cap. EVM-2 multi-asset vaults resolve viamaxDepositAmount(); EVM-1 vaults usemaxDeposit(receiver)with a zero-address default.
All helpers return a raw
bigintso BigInt math stays precise. Existing helpers (vaultAllowance,previewRedemption) are unchanged.Notes:
These methods require a signer because they live on
EVMAdapter, matching the existing read pattern (vaultAllowance,sendersWhitelistAddress, etc.). A read-onlyJsonRpcProviderwrapped viaWallet.createRandom().connect(provider)works for query-only use.Method-taxonomy entries (
previewDeposit,previewRedeem,allowance,balanceOf,maxDeposit) added so Sentry rolls them up correctly.Benchmarks for these helpers are deferred β they need a signer plumbed into
packages/sdk/benchmarks/suites/sdk-methods.js; unit tests with mocked contracts cover the routing and validation paths.
ae03a7b: feat(sdk): constructor option
timeoutMsoverrides the request timeout defaultAdds an additive
timeoutMsoption to theAugustSDKconstructor (via the sharedIAugustBaseconfig) that overrides the default request timeout used by every August fetcher helper. The compiled-in default (90 s) is preserved when the option is omitted; per-callIFetchAugustOptions.timeoutMsstill wins over the SDK-level default.const sdk = new AugustSDK({ appName: 'acme-trader', providers: { 1: '...' }, keys: { august: process.env.AUGUST_KEY }, timeoutMs: 20_000, // shorten the default deadline to 20s for this instance });Also exports two helpers for advanced use:
setSdkRequestTimeout(ms | null)β apply / clear the override directly.getSdkRequestTimeout()β read the active default (override or compiled-in).
Notes:
This is process-global state. If you instantiate multiple
AugustSDKobjects in the same process with different timeouts, the last constructor call wins.Lowering the default for the entire package was deliberately skipped β that change is behaviorally observable for current integrators and belongs on a major bump.
e3d589e: feat(audit-followup): tx-flow audit fixes β Solana bigint amounts, cross-chain destination validation, quote staleness, Stellar account error
Additive correctness improvements identified during the deposit / withdraw / redeem audit. No new exported types are renamed or removed.
Solana (adapters/solana)handleSolanaDeposit/handleSolanaRedeemnow acceptbigintfordepositAmount/redeemShares, in addition to the existingnumberform. Whenbigintis passed it is treated as the raw on-chain unit and used directly β nouiAmountToRawBnround-trip through a JS float. Recommended for money flows so the value the wallet signs cannot drift from the value the UI displayed. Thenumberform is still supported for back-compat.The SDK wrapper methods
augustSdk.solana.vaultDepositandvaultRedeemwiden theirdepositAmount/redeemSharesparameter tonumber | bigintaccordingly.Both handlers reject
0n(and0) viaAugustValidationError.
Cross-chain (evm/methods/crossChainVault)buildCrossChainVaultTxnow rejects requests wheredestinationChainIdoruserChainId(onDEPOSIT) is neither the configuredhubChainIdnor present inconfig.layerZeroEids.spokes. Previously the unknown chain ID silently fell back to the hub EID, routing user funds to a chain they did not pick. Behavior unchanged when the chain ID is omitted / equals the hub / is a configured spoke.quoteCrossChainDeposit/quoteCrossChainRedeemnow populatequotedAtandexpiresAton the returnedIQuoteCrossChainResult. The UI should callisQuoteStale(quote)before submit and re-quote when it returnstrueβ LayerZero fees drift between quote and submit.New exports from
evm/types/crossChain:CROSS_CHAIN_QUOTE_TTL_MS(30 000 ms default validity window).isQuoteStale(quote, now?)helper.
Stellar (adapters/stellar/soroban)buildSorobanTxnow wrapsserver.getAccountfailures: when the account does not exist or is unfunded, the SDK throws anAugustValidationErrorwith copy that names the actual fix ("send at least 1 XLM to activate"). Detected via bothinstanceof NotFoundError(forward-compat) and the current"Account not found: <addr>"message the rpc server actually throws. Other RPC errors propagate unchanged.
Known limitations (deferred)The Solana
depositinstruction's IDL does not yet accept amin_shares_outargument, so client-side slippage protection cannot be enforced on-chain for Solana vaults. ATODO(slippage)comment marks the call site invault.actions.ts; on-chain enforcement requires a program update.
Patch Changes
a18ea6d: chore(benchmarks): per-iteration RPC/API request counting
Adds
benchmarks/request-counter.js, aglobalThis.fetchwrapper that buckets requests asrpc(Alchemy, Helius, QuickNode, etc.) vsapi(everything else, with a per-host breakdown). The harness now resets the counter before each measured iteration and surfacesmeanRpc,meanApi,meanRequests, and ahostBreakdownon every result.Console + markdown reporters render the new columns when counts are present and append a "Total requests across all measured iterations" section so AUGUST-5835-style perf claims (in-flight dedup, whitelist cache,
parallelLimitfix) can be measured directly instead of estimated from the diff.Counting is on by default. Set
BENCHMARK_ALCHEMY_REQUEST_COUNT=0to skip the global fetch patch (e.g. in environments where another tool already wrapsfetch). No behavior change to the SDK itself β this is a benchmark-tooling-only change.0f92c9c: refactor(vaults/date-utils): lift duplicate
TIMESTAMP_MANIPULATION_WINDOW = 300to module scopecomputeClaimableDateandisClaimableNoweach re-declared the sameconst TIMESTAMP_MANIPULATION_WINDOW = 300inside their function bodies. Lifted to a single module-level constant mirroringTimelockedVault.sol's 5-minute window. Pure refactor β identical observable behavior.Coverage was thin (no existing tests for
date-utils.ts); addstests/vaults/date-utils.test.tscoveringcomputeClaimableDate,isClaimableNow,formatDateKey,isValidClaimableDate, andgetDaysInMonth(8 tests, including UTC-day rollover and leap-February).0f92c9c: perf(adapters/evm): parallelize receipt-token + whitelisted-assets fetch in
getEvmVaultV2After the initial vault-contract
Promise.allresolves,getEvmVaultV2previously fetched the receipt-token metadata batch (5 RPCs) and the whitelisted-assets list (1 RPC) sequentially, even though both depend only onvaultContractCallsand have no data dependency on each other. They now run inside a shared outerPromise.all, so the wall time per V2 vault read is bounded by the slower of the two batches instead of their sum.No change to the merged
combinedCalls/combinedFunctionsshape, so downstreambuildFormattedVaultsees identical inputs. Static regression test (tests/adapters/evm-vault-v2-parallel-fetch.test.ts) guards the wrapping pattern.0f92c9c: docs(adapters/evm): TSDoc for
vaultAllowance,vaultDeposit,vaultRequestRedeem,depositNative, andvaultRedeemThe EVM adapter's public write methods shipped without TSDoc blocks, which CLAUDE.md section 1 requires for every exported symbol on the published surface. Integrators saw "(no description)" in their IDE and had to read
modules/vaults/write.actions.tsto learn the parameter shape and return semantics. Each method now has a one-sentence summary,@param/@returns/@throwsnotes, and an@example. A static presence test (tests/adapters/evm-write-tsdoc.test.ts) guards against regression.No behavior change.
0f92c9c: refactor(vaults/utils): extract local
IEvmAssetMetadatatypebuildFormattedVaultdeclared the same{ address: IAddress; symbol: string; decimals: number }shape twice as inline types (once fordepositAssets[], once forreceipt). Lifted to a single file-local@internaltypeIEvmAssetMetadata. Not exported β kept internal so the public surface doesn't grow. Pure refactor.0f92c9c: perf(core/web3): in-flight request dedup for
getDecimalsandgetSymbolgetDecimalsandgetSymbolalready cache results in the sharedlru-cache, but concurrent identical calls (e.g. a fresh page-load with multiple components asking for the same token's decimals before any cache write lands) each fired their own RPC. The price-fetcher path already used an in-flightMap<key, Promise>to coalesce these βPRICE_REQUESTSincore/fetcher.ts:250β and this change applies the same pattern togetDecimals(DECIMALS_REQUESTS) andgetSymbol(SYMBOL_REQUESTS).Behavior on a cold cache: the first caller initiates the RPC; subsequent callers within the same tick share that promise instead of starting their own. On error, the in-flight entry is cleared in a
finallyso the next caller can retry. Cache-hit and Solana-address fast paths are unchanged, so no observable difference for callers that aren't concurrent.Adds
tests/utils/getdecimals-getsymbol-dedup.test.tswith three cases (coalescing, no-false-coalescing across addresses, getSymbol parity).0f92c9c: perf(core/web3): in-flight request dedup for
getReceiptTokenAddressgetReceiptTokenAddressalready caches results in the sharedlru-cache, but concurrent identical reads (multiple components or vault paths resolving the same vault's receipt-token address before the first cache write lands) each fired their ownlpTokenAddress()RPC. This change adds aRECEIPT_TOKEN_REQUESTSin-flightMap<string, Promise>so simultaneous identical reads share a single promise β same pattern as the existingDECIMALS_REQUESTS,SYMBOL_REQUESTS, andWHITELISTED_ASSETS_REQUESTSmaps. The in-flight entry is cleared in afinallyso the next caller can retry after a failure.Cache-hit and missing-arg fast paths are unchanged.
Adds
tests/utils/getreceipttokenaddress-dedup.test.ts(coalescing + no false-coalescing across addresses).0f92c9c: perf(vaults/getters): lift duplicate
getReceiptTokenAddresscall in the V2 position-read pathInside the
version === 'evm-2'branch of the position loop inmodules/vaults/getters.ts,getReceiptTokenAddress(provider, vault)was awaited twice for the same vault in back-to-back lines β once to derive decimals, once again to construct the receipt contract for the balance read. The second call was a cache hit (so cheap in RPC terms) but still incurred a function call, a cache lookup, and a Promise hop per iteration. Both call sites now reuse a singlereceiptAddresslocal.Pure lift with no behavior change β same value returned in both spots either way, and the wallet-balance branch only runs when the first await would also have run.
ae03a7b: fix(adapters): Solana / Stellar adapters now throw typed errors for input validation
Replaces every
throw new Error(...)in the Solana and Stellar adapter paths that represents an input-validation failure withAugustValidationError, and the Stellar submit / Soroban downstream failures withAugustSDKError/AugustTimeoutError. Consumers can now narrow:catch (err) { if (err instanceof AugustValidationError) { ... } }β¦on non-EVM paths, just like EVM. Error messages are unchanged, so existing substring assertions and Sentry message-based grouping continue to work; the class-based bucket gains signal.
Affected files:
adapters/stellar/actions.tsβvalidateContractAddress,validateAccountAddressadapters/stellar/soroban.tsβtoBigIntAmount, simulation / assembly failures (nowAugustSDKError)adapters/stellar/submit.tsβ submission failures (AugustSDKError), poll-timeout (AugustTimeoutError)adapters/stellar/getters.tsβgetStellarUserPosition/convertToSharesaddress validatorsadapters/stellar/utils.tsβassertNotStellar(nowINVALID_CHAIN)adapters/solana/vault.actions.tsβ input-validation failures insidehandleSolanaDeposit/handleSolanaRedeemadapters/solana/utils.tsβ wallet / program-id / vault-version validation anduiAmountToRawBnprecision checks
bb0873f: fix(perf-pr-review): address review findings on the perf-optimizations PR
Bundle of small fixes responding to the code review of
AUGUST-5835-perf-optimizations. No public-API change.CACHE.hasvsCACHE.gettruthy check β flipped 4 sites incore/helpers/web3.ts(getDecimals,getSymbol,getReceiptTokenAddress,getWhitelistedAssets) fromif (CACHE.get(key))toif (CACHE.has(key)). Tokens withdecimals === 0, empty-string symbols, or empty whitelist arrays were silently re-fetching on every sequential call because the cached value was falsy. Resolves and supersedestodo/29.getWhitelistedAssetstyped error β replacedthrow new Error(...)withAugustValidationError('INVALID_INPUT', ...). The function stays@internal; the change keeps Sentry's error-grouping intact (rawErrorcollapsed to the generic bucket).generatePermitSignatureLogger β theconsole.error('Could not fetch DOMAIN_SEPARATORβ¦')that the Solana sweep had skipped is nowLogger.log.error('generatePermitSignature', error, { message: β¦ }), with the original throw preserved.Dead
namewrite β movedlet nameinto the cache-miss discovery block (const name = β¦). The assignment on the cache-hit path was never read;signTypedDatausesmatchingDomaindirectly.runWithConcurrencycorrectness note β one-line comment explaining whynextIndex++is safe across workers (JS single-threaded; increment finishes before anyawait).Parallel-fetch test upgrade β
tests/adapters/evm-vault-v2-parallel-fetch.test.tsis rewritten from a regex-on-source assertion to a behavior test that mocksContract/getDecimals/getSymbol/getWhitelistedAssetswith controlled delays and asserts wall time falls in the parallel range (1.5Γβ2.5Γ RPC_DELAY), not the serial range (3Γ RPC_DELAY).New regression test β
tests/utils/cache-falsy-value-hit.test.tsprovesgetDecimalsreturning0is cached and the second call doesn't re-fetch.
0f92c9c: perf(vaults/utils): cache matched permit domain per (chainId, token)
generatePermitSignaturepreviously, on every invocation, fetched the token'sname()(RPC), built 4 candidate EIP-2612 domain configurations, hashed each withTypedDataEncoder.hashDomain, and β only if all 4 failed β fell back to fetchingversion()(another RPC). For integrators generating multiple permits against the same token in a session, every signature reran the full discovery.The matched
TypedDataDomainis now cached in the SDK's sharedlru-cachekeyedpermit-domain-<chainId>-<token>for 1 hour. The liveDOMAIN_SEPARATOR()is still fetched on every call and compared against the cached domain's hash; on mismatch (e.g. an upgraded token contract) the cache entry is invalidated and the original discovery loop runs. On a cache hit thename()RPC, the 4-iteration hashing loop, and the rareversion()fallback are all skipped.The function also pairs
nonces()withDOMAIN_SEPARATOR()in a singlePromise.all(they were previously sequential), shaving a round trip on the cache-miss path.Adds
tests/vaults/permit-domain-cache.test.tscovering the discovery path and the cached fast-path.0f92c9c: refactor(adapters/solana): route console.* through Logger
Replaces all 50 raw
console.log/console.warn/console.errorcalls inadapters/solana/{vault.actions,utils}.tswith the equivalentLogger.log.{info,warn,error}calls. Output is now sanitized via the analytics pipeline and gated byLogger.setDevMode()/Logger.setStructuredLogger()rather than being printed unconditionally to stdout. Level mapping is preserved (console.logβinfo,console.warnβwarn,console.errorβerror). No behavior change for callers that have not configured a logger; consumers that have already enabled dev mode or plugged in a structured logger will now receive Solana adapter events on the same channel as the rest of the SDK. A static test (tests/adapters/solana-logger-hygiene.test.ts) guards against regression.a18ea6d: fix(adapters/solana): propagate the underlying error from
getVaultMintsinstead of swallowing itSolanaUtils.getVaultMintspreviously caught any failure insideprogram.account.vaultState.fetch(vaultStatePda)β Anchor discriminator mismatch, account-not-found, RPC error β logged it, and returned{ depositMint: '', shareMint: '', vaultVersion: undefined }. DownstreamhandleSolanaDeposit/handleSolanaRedeemchecked the empty mints and threw the generic"Failed to read vault mints from on-chain state", which carried zero diagnostic signal. Operators triaging a failed deposit on a specific vault (e.g. Sentora xBTC on the Upshift portfolio page) had nothing actionable in the user-visible error.getVaultMintsnow throws anAugustSDKError(code: 'UNKNOWN') whosemessageincludes the underlying cause and whosecontextcarriesvaultProgramIdandvaultAddress. The original error is set as.cause. Successful reads still cache as before; the existing read-sidegetVaultStateReadOnlypath is unchanged.The outer catch in
handleSolanaDepositalready re-wraps SDK errors withcause, so the user-visible message becomes"Solana deposit failed: Failed to read vault mints from on-chain state: <real cause>"β pointing at whether the IDL is wrong, the PDA doesn't exist, or the RPC failed.Adds
tests/vaults/solana-vault-mints-error-propagation.test.tscovering account-not-found and discriminator-mismatch causes, asserting the typed-error shape and that the cause string flows through.0f92c9c: fix(vaults/fetcher): honor
parallelLimitin batch + comprehensive vault fetchersfetchVaultsBatchandfetchVaultsComprehensivepreviously accepted aparallelLimitoption but renamed it to_parallelLimitand ran every task in a batch concurrently viaPromise.allβ the option was a no-op. The defaultgetVaultscall site (modules/vaults/main.ts) passesparallelLimit: 8expecting it to take effect, so RPC fan-out for a typical batch of 15 vaults was running 15-wide instead of the intended 8-wide.Both fetchers now route their per-batch work through an internal
runWithConcurrencyhelper that pulls tasks from a queue with a hard in-flight cap. The defaultparallelLimitisbatchSize, so any caller that did not specifyparallelLimitsees identical pre-fix concurrency (no regression). Callers that did specify it β including the SDK's owngetVaultsβ now get the cap they asked for.Adds
tests/vaults/fetcher-parallel-limit.test.tscovering: the cap, the default-preserves-prior-behavior path, and that every task still completes whenparallelLimit < batchSize.0f92c9c: perf(core/vaults): pre-compute lowercase
VAULT_SYMBOLSlookup mapgetVaultSymbol's hardcoded-fallback path usedObject.entries(VAULT_SYMBOLS).find(([k]) => k.toLowerCase() === address.toLowerCase())β an O(n) scan over the table on every cache-miss / non-canonical-case lookup. The canonical-case fast path (VAULT_SYMBOLS[address]) is preserved; the case-insensitive fallback now reads from a module-levelVAULT_SYMBOLS_LOWERCASEmap built once viaObject.fromEntries, making it O(1).The lookup precedence (backend metadata β hardcoded fallback β on-chain
getSymbol) is unchanged. The hardcoded list is@deprecatedper its existing TSDoc β backend remains canonical.Adds
tests/utils/get-vault-symbol-lowercase.test.tscovering canonical-case, lowercase, and unknown-address paths.0f92c9c: perf(core/web3): cache
getWhitelistedAssetslist per (chain, whitelist contract)V2 vault reads (
getEvmVaultV2) callgetWhitelistedAssetson the vault's whitelist contract on every invocation, and the returned list immediately fans out into per-assetgetDecimals+getSymbolreads insidebuildFormattedVault. The list itself rarely changes, so a new internal helpergetWhitelistedAssets(incore/helpers/web3.ts) wraps the contract call with anlru-cacheentry keyedwhitelisted-assets-<providerScope>-<whitelistAddress>and a 5-minute TTL. Concurrent identical reads share an in-flight promise β same pattern asgetDecimals/getSymbol.getEvmVaultV2now delegates to that helper instead of building the contract inline; the merge step that flattenscontractCalls.getWhitelistedAssetsinto the formatted vault is unchanged, so callers see the same shape.Adds
tests/utils/get-whitelisted-assets-cache.test.ts(in-flight coalescing, sequential cache-hit, no false-coalescing across addresses).
6.0.0
Major Changes
00c6ba9:
registerUserForPointsnow authenticates via a wallet signature instead of an admin API key. The function gains four required parameters βchainId,signature,nonce,expiryβ and no longer readsoptions.augustKey. Callers must obtain a personal_sign (EIP-191) signature over a canonical message containing the lowercased user address, lowercased referrer (or"none"), chain id, nonce, and expiry; the backend reconstructs the same message and verifies the signature against the claimed wallet (EOA recovery first, then EIP-1271 for smart-contract wallets such as Safe).chainIdmust be one of the chains Upshift supports (see backendSUPPORTED_REGISTRATION_CHAINS); unsupported chains return 422. The class methodAugustVaults#registerUserForPointsand the top-levelSdk#registerUserForPointsaddchainId,signature,nonce,expiryas required positional arguments afterreferrerAddress. See the TSDoc onregisterUserForPointsfor the exact message template and a worked example.
Patch Changes
0422e61: patch an issue with version ts. This patches a broken import in v 5.1.0 and 5.1.1
5.1.1
Patch Changes
Re-publish of 5.1.0 with a clean build. The 5.1.0 tarball on npm was shipped from a stale
lib/directory and was missing the Solana share-price + position fixes described in the 5.1.0 changelog below βlib/adapters/solana/getters.jsstill read onlydeployedAumfortotalAssets. Anyone on@augustdigital/sdk@5.1.0should bump to5.1.1.Added a
prepublishOnlyscript (pnpm clean && pnpm build) so subsequent publishes refuse to ship a stalelib/and force a fresh transpile. The 5.1.0 mishap was caused by a manualpnpm publishrun without a precedingpnpm build; the new hook makes that impossible by construction.
5.1.0
Minor Changes
9dbc693: fix(solana): use
local_aum + deployed_aumfor vault total assets; add BigInt-safe share-balance helper; stop dropping Solana fromgetVaults/getVaultPositionsBump rationale (minor, not patch): this release is bug-fix-driven but adds two purely additive public-surface elements β
SolanaAdapter.fetchUserShareBalanceRaw()and the dedicatedIAugustBase.solana = { rpcUrl, network }config entry point. Per the additive-public-API rule a minor bump is required even though no existing API breaks.Root causes
getSolanaVaultread onlyvaultState.deployedAumfortotalAssets, but the on-chainVaultState::total_assets()islocal_aum + deployed_aum. The displayed share price dropped below 1.0 the instant the operator deployed any portion of the vault, even with zero PnL (jitoSOL showed0.7370against a 1:1 share supply).getVaultPositionsSolana branch passeduiAmount(a JS number) intotoNormalizedBnwith no decimals argument. It defaulted to 18 and produced awalletBalance.rawoff by10**(18 β mintDecimals), breaking redemption sizing and max-action math even though the displayednormalizedlooked plausible.The provider-availability filter (
vaultsPerAvailableProviders) had an explicit Stellar pass-through but no Solana one β Solana vaults were silently dropped from both the vault list and position list on any SDK instance whoseprovidersmap didn't register chainId-1.The IDL (
vault-idl.ts/.json) andISolanaVaultStatewere missinglocal_aum,aum_increase_limit,aum_decrease_limit, andvault_versionβ fields that exist in the RustVaultStatestruct (seeprograms/august-vault/src/state/vault.rs). Because the missing fields sat afterdeployed_aum, the earlier fields still deserialized correctly but every field after the drift (pda_bump,paused,padding) read from the wrong bytes.pausedhappening to read0x00is why this didn't blow up in production sooner.
Changes
adapters/solana/getters.ts: sumlocalAum + deployedAumfortotalAssets. Falls back to backend TVL when on-chain is unavailable.adapters/solana/utils.ts: newfetchUserShareBalanceRaw({ publicKey, shareMint })returning{ amount: string; decimals: number | null }from a singlegetParsedTokenAccountsByOwner.adapters/solana/index.ts: expose the helper onSolanaAdapterwith TSDoc and a worst-case RPC note.adapters/solana/types.ts: extendISolanaVaultStatewithlocalAum,aumIncreaseLimit,aumDecreaseLimit, and the (re-positioned)vaultVersion.adapters/solana/idl/vault-idl.{ts,json}: re-syncVaultStatefield order with the Rust source.main.ts: constructSolanaAdapterfrom eitherproviders[-1]or the dedicatedsolana: { rpcUrl, network }config, so partner SDK instances can opt into Solana without polluting their EVM providers map.modules/vaults/main.ts: passchain_type === 'solana'through the provider filter whenthis.solanaServiceis available β mirrors the existing Stellar clause.modules/vaults/getters.ts: Solana branch now reads via the raw helper, uses the mint's true decimals, drops theas anyonvaultState, and returnsvault: v.addressinstead of the outer parameter (mirrors the Stellar branch).modules/vaults/types.ts:ISolanaService.fetchUserShareBalanceRawis required (only impl is the in-packageSolanaAdapter, which now always provides it).
No behaviour change for EVM or Stellar paths.
Verification
Borsh layout sanity-checked against
programs/august-vault/src/state/vault.rs:36-50and against the live jitoSOL vault state at2tmMcVv2Ene7wFGebPivhwYhAZyjaJoibMz1GYVaXsB1: 455-byte account decodes cleanly with the new field order βlocal_aum=564_529_610,deployed_aum=1_582_093_475,aum_increase_limit=20,aum_decrease_limit=20,pda_bump=[254],vault_version=[0],paused=false, padding all-zero.local_aum + deployed_aumequals the share-mint supply at parity. Every byte accounted for.Benchmark entry added at
benchmarks/suites/sdk-methods.js:fetchUserShareBalanceRaw() [cold, no account]. Gated onBENCHMARK_SOLANA_RPC_URLso the existing EVM-only CI run isn't affected; set the env var to opt in. Uses the jitoSOL share mint with the system-program key as wallet β deterministic "no account" path that measuresgetParsedTokenAccountsByOwnerround-trip plus the short-circuit return, which is the hot path on the vault grid for users without a position.
5.0.0
Major Changes
8881c9b: Integrator experience: require
appName, add a runtime version-nudge.Breaking β required
appName.appNameis now a required field on theAugustSDKconstructor (andIAugustBase). Pass a stable kebab-case slug identifying your application β e.g.new AugustSDK({ appName: 'acme-trader', ... }). Despite the friendly name the value is identifier-shaped: 3β64 chars,[a-zA-Z0-9._-]only (it's used as a Sentry tag and HTTP header). Use a slug like'acme-trader', not a display name like'Acme Trader'. The SDK throws synchronously from the constructor when the value is missing, empty, or out of the allowed shape.Why: the SDK now tags outbound analytics events with
app.name, so the August Digital team can attribute error spikes to the right consuming application and reach out about breaking changes / critical bugs. See the "App Name" section inpackages/sdk/README.md.Migration: add
appName: '<your-slug>'to your existingnew AugustSDK({ ... })call. No other changes required.Additive β version-nudge on construction. On non-production builds the SDK now performs one best-effort npm-registry check per session and prints a
console.warnbanner when a newer@augustdigital/sdkis available. The check never runs inNODE_ENV=production, can be silenced withAUGUST_SDK_DISABLE_VERSION_CHECK=1, or programmatically withnew AugustSDK({ versionCheck: { enabled: false }, ... }). Never blocks construction; failures are silent. New exports:runVersionCheck,IVersionCheckConfig,compareSemver.
Minor Changes
c24003b: feat: production-grade hardening
Security & errors
New typed error hierarchy:
AugustSDKError,AugustAuthError,AugustNetworkError,AugustTimeoutError,AugustValidationError,AugustRateLimitError,AugustServerError, plusisAugustSDKErrortype guard. All extendErrorso existinginstanceof Errorconsumers are unaffected.Secret sanitization in error messages, logger, and Slack adapter via
sanitizeString/sanitizeError/sanitizeForLogging.URL injection hardening:
buildAugustUrlrejects unknown server keys, absolute URLs, and protocol-relative paths; origin check enforces same-origin.fetchAugustWithKey(undefined, β¦)now throwsAugustAuthError(AUTH_MISSING_KEY)instead of returning a synthetic{status: 500}response β callers usingif (res.status === 200)previously misclassified missing-auth as a 500 server error; they now receive a proper typed error.verifyAugustKeyshort-circuits empty keys soinit()behavior is unchanged.overrideflag onIFetchAugustOptionsis@deprecatedwith a one-time runtime warning; will be removed in the next major.HTTP errors are now typed by status: 401 β
AugustAuthError, 429 βAugustRateLimitError, elseAugustServerError.Response.headers.get('x-correlation-id')(was bracket-accessed; alwaysundefined).
Transport
Per-request
signal: AbortSignalandtimeoutMs: numberonIFetchAugustOptions. Combined with the default timeout viaAbortSignal.any(Node 22+) with a manual relay + cleanup fallback. Distinguishes caller-cancel from timeout via an internaltimedOutflag.
Observability
New
ILoggerinterface andLogger.setStructuredLogger()alongside the existing Sentry-compatibleSDKLogger. Pino-friendly: pass a context object as the first arg.
Performance
Parallelized
getVaultloans + allocations (Promise.allSettled, preserves original control flow).Removed redundant
fetchTokenizedVaultcalls ingetVaultLoans/getVaultSubaccountLoans.createProvider(rpcUrl, chainId?)enables ethers'staticNetwork(skips theeth_chainIdround-trip).getInfuraProviderroutes throughcreateProvider(was rebuilding per call).decimals/symbol/receipt-tokencaches are chain-scoped viaproviderScope.
Bundle
Buffer polyfill extracted to
polyfills.ts; guarded against clobbering a consumer-setBuffer.sideEffects: ["./lib/polyfills.js"]lets bundlers tree-shake the rest of the SDK.Source maps excluded from the npm tarball.
Bug fixes
fetchAugustWithBearerno longer crashes whenoptionsis undefined (options?.everywhere).AbortSignalfallback path now removes itsabortlistener on completion (no more leak across long-lived caller signals).Slack adapter's webhook fetch has a 5s timeout.
sanitizeErrorpreserves typed-error subclasses by cloning via prototype + own properties instead of calling the constructor (which would have misaligned positional args likeAugustAuthError(code, message, opts)).AugustSDKErrorand subclasses ship atoJSON()soJSON.stringify(err)no longer returns"{}".code,correlationId,status,timeoutMs,retryAfterMs, andcauseare all included.
No public API breaks. All additions are opt-in. The only behavior change is
fetchAugustWithKey(undefined, β¦)throwing instead of returning a fake 500 β the thrown value is still anErrorinstance.8881c9b: feat(sdk): expose
getVaultRedemptionHistoryon theAugustVaultsmodule and the top-levelAugustSDKclass. Wraps the existing module-level getter with the standard option-plumbing (RPC resolution fromchainId,augustKey/subgraphKey/headersfrom the SDK instance), validates the vault input, and returns the same historical redemption records the underlying getter produces. Stellar vaults continue to return[]until on-chain indexing lands for that adapter.
Patch Changes
7027223: fix: vault read paths no longer hang or surface ethers'
network is not available yetwhen the configured RPC is unreachable or rate-limitedThree related changes that together resolve
august vault tvl <addr> --chain <id>failures (crypticNETWORK_ERRORon a healthy RPC, infinite "JsonRpcProvider failed to detect network" retry loop on a 403/401 RPC):providerScope(cache-key builder used bygetDecimals,getReceiptTokenAddress, β¦) now tolerates ethers v6's lazy-network state. Readingprovider._networkis a getter that throwsnetwork is not available yetuntil the first successful request resolves the chain id; the throw was bubbling out of every cached vault read on freshly constructed providers.AugustVaults.getVaultTvlnow threadschainIdinto the getter options, and the EVM branch ofgetVaultTvl(packages/sdk/src.ts/modules/vaults/getters.ts) forwards it tocreateProvider. This sets ethers'staticNetwork, skipping theeth_chainIdround-trip and, more importantly, preventing the indefinite network-detection retry loop when the RPC returns 4xx errors.createProvidernow throws a clear, remediable error when called with a missing or emptyrpcUrl, instead of silently constructing aJsonRpcProviderpointed athttp://localhost:8545.
f0741e2: fix: HyperEVM RPC compatibility for
getWithdrawalRequestsWithStatusc14c10b: chore: remove unused
namefield fromAugustSDK. The field was declared but never assigned and never read βappName(onAugustBase) is the single source of truth for the app identifier.0cb921a: fix: cap
fetchTokenizedVaultscache at 10 minutes and avoid stale-get evictionfetchTokenizedVaults(bulk list) was callingCACHE.set(key, value)with no TTL override, falling back to the 24-hour global default β so vault config changes made on the backend (fee rates, fee waivers, etc.) could take up to 24h to surface to bulk-list consumers. The cache lookup also calledCACHE.get(key)twice in a row; because the globalCACHEis configured withallowStale: true, the first.get()on a stale entry returns it and evicts it, leaving the second.get()undefined. Switched togetSafeCache(which uses.has()and so never triggers stale-get eviction) and set an explicit 10-minute TTL to matchfetchTokenizedVault(single).
4.27.0
Minor Changes
78231b6: feat: add RWA instant redemption β new
AugustVaults.rwaRedeemAsset()andpreviewRwaRedemption()methods, plus aninstant_redeem_configfield onIVaultreturned fromgetVault/getVaults. The SDK automatically routes redemption calls to the correctRwaRedeemSubaccountfor each vault.
Patch Changes
5766173: fix:
getWithdrawalRequestsWithStatusnow requires achainIdargument so cross-chain queries return correct results.8872391: feat: add helpers for OFT (LayerZero Omnichain Fungible Token) flows.
4.25.0
Minor Changes
a267145: feat: add a Stellar SDK adapter β Soroban RPC support, transaction building and submission, and end-to-end localnet test coverage.
455b625: feat: add
getWithdrawalRequestsWithStatusfor tracking the status of withdrawal requests.ad5ea73: chore: remove SUI points from vault responses.
7e5aa22: feat: add Stellar vault support (backend-only) including a Stellar adapter, routing, and a shared vault builder.
Patch Changes
8f1bcee: chore: refactor Solana vault adapter getters into a shared
buildBackendVaultutility (no public API change).c721801: fix: include PnL data in LayerZero (LZ) vault responses.
e12e957: fix: prevent silent data loss in
getWithdrawalRequestsWithStatuswhen responses span multiple pages.d6e7f96: feat: add
fetchTokenizedVaultSubaccountLoansfor retrieving subaccount loan data on tokenized vaults.bba0483: feat: add
show_cap_filledto the tokenized vault response so callers can render cap-filled UI states.fd90233: feat: add a
getVaultPendingRedemptionsmethod onAugustVaults.
4.24.6
Patch Changes
bf55850: feat: add earnAUSD support over LayerZero.
301e84e: fix: resolve a circular dependency in the Solana adapter imports that caused
AugustBaseto be undefined in CommonJS builds.e0a1135: fix: forward
vaultAddresstogetVaultStatefromgetVaultPositionsso PDA derivation no longer returns the wrong address.40d8d3f: fix: read the share mint from on-chain vault state (instead of PDA derivation) so multi-vault Solana programs are supported correctly.
ebefff4: fix: ensure the tokenized vault API call always issues its query.
4.14.0
Minor Changes
0364b53: feat: add new vault API methods.
New Methods:
getVaultAnnualizedApyβ fetch annualized APY metrics for vaults (cUSDO, tETH, wstETH, rsETH).getVaultSummaryβ fetch a summary of a vault (name, type, chain, recent returns).getVaultWithdrawalsβ fetch a withdrawal summary and the pending withdrawal queue.
New Types:
IVaultAnnualizedApyIVaultSummaryIVaultWithdrawals
Deprecation Notice:
IVaultAnnualizedApy.hgETH30dLiquidAPYβ useliquidAPY30Dayinstead (removal: 2026-01-01).IVaultAnnualizedApy.hgETH7dLiquidAPYβ useliquidAPY7Dayinstead (removal: 2026-01-01).
Documentation:
Vault method documentation added to
docs/02-vaults.md.
4.13.0
Minor Changes
01f6203: feat: add support for the Katana chain.
Patch Changes
e58170f: fix: improve observability when Goldsky subgraph requests fail.
d417f0b: feat: add subgraph configuration for the superMON, earnMON, and k3EUROP vaults.
fe74f64: fix: update the query parameters used by the tokenized vault endpoints; deprecate
historical_snapshotson the vault response β usegetVaultHistoricalTimeseriesinstead.
4.6.1
Patch Changes
79c3917: feat: add
historical_apyto the tokenized vault response.b01879f: feat: add a deposit-with-permit function so callers can deposit using EIP-2612 signatures.
5506682: perf: reduce RPC calls during vault fetching.
c7b052e: perf: remove the deposit cap query from the initial vault fetch β it's loaded on demand instead.
3.15.1
Patch Changes
1ef7bfb: adding coingecko key to staking
04c7782: add error response to debank res
Updated dependencies [1ef7bfb]
Updated dependencies [04c7782]
@augustdigital/services@3.15.1
@augustdigital/vaults@3.15.1
@augustdigital/pools@3.15.1
@augustdigital/types@3.15.1
@augustdigital/utils@3.15.1
@augustdigital/abis@3.15.1
3.3.0
Minor Changes
a86b316: update
c5c2570: update hash in events
c9b3c1a: update
705637a: update fetch user history
b6e3aba: update version
Patch Changes
Updated dependencies [a86b316]
Updated dependencies [c5c2570]
Updated dependencies [c9b3c1a]
Updated dependencies [705637a]
Updated dependencies [b6e3aba]
@augustdigital/pools@3.3.0
@augustdigital/types@3.3.0
@augustdigital/utils@3.3.0
@augustdigital/abis@3.3.0
@augustdigital/vaults@3.3.0
3.1.0
Minor Changes
81ab166: add isFeeWaived to pools
25bc103: update user history
2c4618a: remove console
Patch Changes
Updated dependencies [81ab166]
Updated dependencies [25bc103]
Updated dependencies [2c4618a]
@augustdigital/pools@3.1.0
@augustdigital/types@3.1.0
@augustdigital/utils@3.1.0
@augustdigital/abis@3.1.0
@augustdigital/sdk@3.1.0
0.0.3
Patch Changes
d72f854: (v0.0.3) testing github workflows
2f95c56: v0.0.3 edited readme and testing automated npm publish github workflow
c388be5: (v0.0.2) changeset working appropriately
Updated dependencies [d72f854]
Updated dependencies [2f95c56]
Updated dependencies [c388be5]
@augustdigital/pools@0.0.3
@augustdigital/types@0.0.3
@augustdigital/utils@0.0.3
@augustdigital/abis@0.0.3
Last updated