spUSDT
Custom price feed for Spark Savings USDT (spUSDT).
Custom price feed for Spark Savings USDT (spUSDT). spUSDT is an ERC-4626 vault share that accrues value as savings yield accumulates. The price is derived from the vault's current share-to-asset conversion rate multiplied by the NAV's USDT/USD price.
Source: spUSDT_CustomPriceFeed.sol
Approach
spUSDT.convertToAssets(1 spUSDT) × USDT/USD (from the NAV's primary feed)
Spark shipped this savings family twice — pin the vault by address, never by symbol(). A dead earlier generation answers the same symbol() at a different address with totalSupply == 0. An empty ERC-4626 answers convertToAssets at the 1:1 default instead of reverting, so wiring the dead one prices plausibly and wrongly. Note that spETH is 18-decimal in both generations, so decimals alone does not disambiguate it — only the address does.
Registered at heartbeat 90000, not the 86400 its USDC-based siblings use. USDT/USD is itself registered at 86400, and a derived feed's updatedAt is its base feed's timestamp — so a tighter gate cannot prevent a stale price, only manufacture a stale verdict while the base is fresh. That is the failure sUSDS shipped at 82800, which priced $0 for ~23s a day on 97% of days. Keep this at or above USDT's own heartbeat.
Price calculation
decimals = spUSDT.decimals() // vault share decimals
rate = spUSDT.convertToAssets(10^decimals) // USDT per 1 spUSDT
price = rate × USDT_USD / 10^assetDecimalsconvertToAssets()
IERC4626(spUSDT)
USDT backing per 1 spUSDT share at the current accrued rate
USDT_USD
NAV base — getPriceDataNoDivergence(USDT) (8 dec)
the NAV's primary USDT/USD price
The divisor is 10^assetDecimals (the underlying's decimals), not the share decimals — they differ whenever a vault uses a decimals offset. Result carries the feed's 8 decimals.
Constructor
vault_
The spUSDT vault address (also used to read vault decimals)
nav_
NAVCalculator (proxy) — supplies the base asset's USD price via getPriceDataNoDivergence
baseAsset_
The registered base asset whose USD price is read (USDT); must equal the vault's asset() — reverts BaseAssetMismatch otherwise
Staleness
The price is stale if the NAV reports the base asset (USDT) stale — all its feeds stale. The base leg's updatedAt comes from the NAV's selected USDT feed. The convertToAssets rate has no heartbeat — it is a live view on the ERC-4626 vault.
Chains
Deployed on Ethereum mainnet only.
Last updated