Skip to main content

Supply

Liquidity is held in pools. Supply a listed stablecoin to receive a non-transferable receipt; burn that receipt to withdraw the pool's current mix of assets. Withdrawals are not blocked by pause, although token transfer restrictions or insufficient reserves after a loss can still make them fail.

Hub and spokes​

PoolIDWhat it holds
Hub0The stablecoins listed as hub assets; hub suppliers receive DLRS
Spoke>= 1One additional stablecoin and an internal DLRS-side reserve funded with hub assets; suppliers receive spoke receipt shares

An asset belongs to one pool at a time. Governance lists assets and records their decimals for accounting. The supported token-decimal range is 6 through 18.

Supplying to the hub​

A hub deposit mints DLRS one for one in normalized 6-decimal units. For example, if USDC and USDS are listed hub assets:

Supply 1,000 USDC → 1,000 DLRS minted
Supply 500 USDS → 500 DLRS minted

DLRS represents the hub basket rather than the token originally supplied. DLRS from a USDC deposit and DLRS from a USDS deposit work the same way.

(uint256 amountIn, uint256 receipts) = dollarStore.deposit(
0, USDC, 1_000e6, msg.sender, block.timestamp + 300
);
// amountIn == 1_000e6 native USDC; receipts == 1_000e6 raw DLRS.

Approve the DollarStore proxy to spend the offered token before depositing. amount is a native token budget; any portion smaller than one normalized unit stays in the caller's wallet.

Who owns the receipt​

The caller pays, but receiver owns the DLRS or spoke shares. Pass your own address for your own position, or the user's address when depositing through an integration. The zero address and DollarStore itself are invalid receivers.

Receipts cannot be transferred, and only their owner can call withdraw. Choose a receiver that can make that call. Anyone can deposit for a receiver without asking it, so an integration's receipt balance can include deposits made by others.

Withdrawing from the hub​

withdraw burns an exact amount of your DLRS and pays a basket of hub assets, split by the hub's current reserve weights. You do not select a single output token.

Illustrative hub reserve mix: 60% USDC, 40% USDS
Burn 1,000 DLRS → Receive 600 USDC + 400 USDS
Native payout: [600e6, 400e18]

To finish entirely in one token, withdraw first, then swap the other assets. That swap follows the normal liquidity and queue rules.

Previewing and setting minimums​

previewWithdraw(poolId, receiptAmount) returns the asset list and native amounts that the withdrawal would pay at the current state. Use its returned asset order to build minAmountsOut:

(address[] memory assets, uint256[] memory quoted) =
dollarStore.previewWithdraw(0, 1_000e6);

uint256[] memory minimums = new uint256[](quoted.length);
for (uint256 i; i < quoted.length; ++i) {
minimums[i] = quoted[i] * 99 / 100; // Accept up to 1% less of each token.
}

(, uint256[] memory paid) = dollarStore.withdraw(
0, 1_000e6, minimums, block.timestamp + 300
);
// paid[i] is in the native decimals of assets[i].

An empty minimums array accepts the proportional payout without per-token minimums. Otherwise, its length must match the preview's asset list. A new hub asset adds an entry, so an older minimums array will revert on length rather than apply to the wrong tokens.

The preview checks the calculation, not the caller's receipt balance or token transfer permissions. The mix can change before execution. Minimums let you refuse an unacceptable mix; they do not change the basket the contract calculates.

Supplying to a spoke​

A spoke has two sides, and a liquidity provider can fund either:

  • The spoke asset enters that spoke's reserve.
  • A hub asset enters hub reserves and increases that spoke's internal DLRS-side reserve.

Both mint receipt shares in the selected spoke, proportional to its value before the deposit. Shares are non-transferable balances tracked per pool, rather than ERC-20 tokens. A hub asset deposited into a spoke mints spoke shares, not wallet DLRS.

Use the same deposit function with the spoke's pool ID. Its receiver owns the shares and later calls withdraw to burn them for a proportional slice of both sides: the spoke asset, plus hub assets representing the spoke's DLRS-side allocation. The hub portion follows the hub's current basket, regardless of which hub token funded the spoke. The receipt does not preserve the mix you deposited.

For a spoke exit, the preview lists the spoke asset first, then every hub asset in listing order. Build minimums from previewWithdraw, not getPoolAssets(spokePoolId), which lists only the spoke asset. Spokes explains the changing asset mix and issuer exposure.

Deposit limits​

Deposits are subject to global, pool and asset pauses, fresh oracle prices within the configured peg tolerance, and the selected pool's launch cap. A winding-down spoke accepts no new deposits.

Caps are checked on deposits. The hub cap limits wallet DLRS supply; a spoke cap limits its spoke reserve plus its DLRS-side reserve. Funding a spoke with a hub token uses the spoke's cap, so aggregate hub reserves can exceed the hub's own cap. A cap of 0 means uncapped.

Units​

ValueUnits
Deposit amount, returned amountIn, withdrawal amounts and minimumsNative decimals of the relevant token
Hub receiptAmountRaw DLRS, with 6 decimals
Spoke receiptAmountReceipt-share count; it can stop matching deposited value after a loss
Reserves, DLRS-side reserves, caps, floors and queue accountingNormalized 6-decimal units

For a token with decimals decimals, its scaling factor is 10**(decimals - 6). units = nativeAmount / scalingFactor; only units * scalingFactor is pulled. Do not add native USDC and native USDS amounts directly: their decimal scales differ.

Receipt accounting​

DLRS is an ERC-20 with 6 decimals, minted and burned only by DollarStore. transfer, transferFrom and approve revert with NonTransferable().

During ordinary operations, the accounting identity is:

DLRS total supply + sum of all spokes' DLRS-side reserves = total hub reserves

For example, 1,000 wallet DLRS plus a spoke's 500-unit hub allocation corresponds to 1,500 units of hub reserves. Queue escrow is separate and never counted as a reserve. A governor reserve write-down after an actual token balance loss can break this equality; it does not burn existing wallet DLRS.

An exit is not pausable, but every token it pays must transfer successfully. Assets paying zero are normally tested with a zero-value transfer; governance can exempt an asset from that probe. See Security for issuer restrictions and loss handling, and Addresses for deployment information.