FAQ
General
What is DollarStore?
DollarStore is open-source smart contract software for exchanging listed stablecoins at 1:1 in normalized units, with no protocol fee or price curve. Available liquidity determines how much fills immediately.
What's the catch?
Time and liquidity. A swap can fill against opposite-side users and reserves, but a queued remainder waits until liquidity arrives. Queueing is not a guarantee of a fill or a completion time. For a full immediate fill or a revert, use an all-or-nothing endpoint.
Why use this instead of Uniswap?
DollarStore may suit a stablecoin route where the fixed protocol rate matters more than immediate execution. An AMM's price curve and fee schedule work differently. Compare actual fillability for the assets, amount and deployment you intend to use.
Which stablecoins are supported?
Governance selects the hub assets and spoke listings. Read getPoolAssets(0) for the hub and use
poolCount, getPoolAssets(poolId), isAssetListed and assetPoolId to inspect other pools.
Token names in these docs are examples, rather than a fixed launch list.
What are hub and spoke pools?
The hub, pool 0, holds the hub stablecoins and issues DLRS to hub suppliers. Each spoke,
pool 1 or above, pairs one additional stablecoin with an internal DLRS-side allocation of hub
liquidity. Its LPs receive separate non-transferable receipt shares.
The ordinary swap endpoints support hub-to-hub, hub-to-spoke and spoke-to-hub routes. A dedicated
swapSpokeToSpoke endpoint combines two legs through an ordered list of hub assets in one
all-or-nothing transaction. See Spokes.
Is there a token?
DLRS is the hub's non-transferable accounting receipt, minted by hub deposits. It is not a governance token or a tradeable asset. Spoke LPs instead hold non-transferable per-pool receipt-share balances.
Using the protocol
How do I swap one stablecoin for another?
- Check the deployment, listed assets and route, then approve the DollarStore proxy to spend your offer token.
- Call
swapOrQueue(offerAsset, wantAsset, amount, minAmountOut, deadline)to fill now and queue any remainder under your address. - Track its returned native input, native output, native queued input and queue position ID.
amount is in offer-token decimals and minAmountOut is in wanted-token decimals. There is no tip
argument. To avoid queueing, use
swapExactInput(offerAsset, wantAsset, amount, minAmountOut, recipient, deadline).
What happens if there is no liquidity?
swapOrQueuewith an output floor of0can queue the input, provided the remainder passes queue limits and other checks.- A full native output minimum makes
swapOrQueuerevert unless the whole order fills now. swapExactInputrequires a full fill by construction and never queues, regardless of its minimum.
For scaling factors from assetScalingFactor, the full native output is
floor(amount / S_offer) * S_want.
Can I require that part of my swap settles now, without queueing the rest?
A partial minimum on swapOrQueue requires that much now and queues the rest. To leave unused input
in your wallet, quote first and submit only the desired fill through swapExactInput. Simulate that
smaller call, since the quote assumes transfers succeed and state may change. See
Time vs slippage.
Who receives my swap output?
swapOrQueue pays its caller, who also owns any queued position and its future payouts.
swapExactInput and swapSpokeToSpoke pay an explicit recipient. It can be the calling integration
or an end user, but cannot be the zero address or DollarStore itself. Routers should use the
all-or-nothing endpoints when they do not intend to manage a queue position.
How long will I wait in queue?
There is no fixed wait. Opposite swaps can peer-match positions, later same-direction swaps settle
older positions before using reserves, and deposits into a spoke can settle its affected lines.
A deposit into the hub does not itself process queues. Anyone can call processQueue when route
liquidity and the inflow checks allow.
Can I cancel my queue position?
Only its owner can call cancelQueue(positionId). A successful cancellation returns the remaining
escrow in the original offer token, including while paused or after the pool is removed.
If an active position's refund fails, it is parked with escrow unchanged. A failed refund of an
already parked position reverts with EscrowTransferFailed, leaving it available to retry when
token transfers can succeed. There is no fallback conversion into DLRS or spoke shares.
What if my position is partially filled?
You receive each fill in the wanted token. The active remainder keeps its place in line. Cancelling returns the remaining offered token when the refund can succeed.
What is a parked position?
A queued position whose owner could not receive a fill or refund is removed from active FIFO so it does not block later positions. Its offered tokens stay escrowed. It no longer fills automatically; the owner must cancel once the offered-token transfer can succeed.
isQueuePositionParked identifies it, and getUserQueuePositions includes both active and parked
positions. See Parked positions.
Can queue escrow shrink after a loss?
Yes. An actual token balance loss can impair escrow separately from reserves. While the asset's pool
is paused, the guardian can apply haircutEscrow proportionally to its active and parked escrow,
including positions left after pool removal. A market depeg alone does not rewrite the token amount.
See When tokens are lost.
DLRS
What is DLRS?
A non-transferable hub receipt with 6 decimals. A hub deposit of 1,000 normalized dollars mints
1,000 DLRS. Burning it through withdraw returns a reserve-weighted basket of hub assets rather
than a chosen token.
Can I transfer or trade DLRS?
No. transfer, transferFrom and approve revert with NonTransferable().
What can I do with DLRS?
The owner calls withdraw(0, receiptAmount, minAmountsOut, deadline) to burn it for the current hub
basket. Use previewWithdraw to see the ordered native payouts and build minimums. To finish with
only one token, withdraw and then swap the others. See Supply.
How is DLRS accounted for?
During ordinary operations:
DLRS total supply + all spokes' DLRS-side reserves = total hub reserves
Spoke funding increases hub reserves and a spoke's allocation without minting wallet DLRS. Queue
escrow is excluded. A governor syncReserves write-down after an actual token balance loss can
reduce recorded reserves without reducing wallet DLRS supply, so the equality is not unconditional
after a loss.
Can someone else deposit or withdraw for me?
Anyone can pay for a deposit and name you as its receiver. You own the resulting DLRS or spoke
shares; the depositor does not. Only the receipt owner can withdraw, and receipts cannot be moved to
another owner. An integration should choose a receiver that can call withdraw and account for
deposits that third parties may make for it.
Do pause controls block withdrawals?
No. Withdrawals and queue cancellations bypass protocol and pool pause controls. A withdrawal still
needs sufficient reserves and successful transfers of its basket. Zero-payout asset entries are
normally tested with a zero-value transfer unless governance exempted that asset, so an issuer
restriction can still block an exit. previewWithdraw does not test these transfers.
For integrators
How do aggregators integrate DollarStore?
- Calculate the full native wanted-token output from the input and the two scaling factors.
- Call
getSwapQuote(offerAsset, wantAsset, amount)and compare it with that full output. - Simulate the intended
swapExactInputcall with its actual caller and recipient, then execute if suitable. It returns native(amountIn, amountOut)and never queues.
For spoke-to-spoke trades, select the hub assets in via and simulate swapSpokeToSpoke directly.
Its route order affects execution. See How swaps resolve.
Does swapExactInput ever partially fill?
No. It either fills the full normalized input or reverts with InsufficientLiquidity. A separate
minimum-output check uses native output units. The reported fill in a reverted error describes
that attempted execution, not a promise that a smaller retry will fill.
Why does getSwapQuote return 0 when there are reserves?
Older same-direction positions may use the available reserves first. The quote includes reserves left after simulating up to eight older positions; if that line remains, those reserves are not available to the new swap. Opposite-queue escrow is counted first, so a same-direction queue does not automatically make the quote zero.
The view also returns zero for unsupported routes or failed route, pause or offer-price checks. It accepts no caller or recipient and assumes transfers succeed. A failed queued-owner payout can change the real fill, and a recipient restriction can revert the final transfer.
What units does minAmountOut use?
Native decimals of wantAsset, in both swapOrQueue and swapExactInput. For example, a
1,000-USDS floor is 1_000e18 for an 18-decimal USDS token, while a 1,000-USDC floor is 1_000e6
for 6-decimal USDC. The minimum is compared without rounding it to normalized units.
Reserves, queue views, queue events and minimum queued order sizes still use normalized 6-decimal accounting. Spoke receipt amounts are share counts. See Units.
What's the gas cost?
It depends on the route and queue work. The eight-position inline limit applies to same-direction
reserve settlement per pass; opposite peer matching can touch more positions, and spoke deposits
or composed swaps can visit several lines. processQueue has a caller-selected bound, with parked
positions counted as visits. Measure the intended call against the deployment you use.
Technical
What chains is the protocol on?
See Addresses for networks, release status and deployment addresses. These
docs describe the deployed v1.0.0 interface; check a deployment's version() and release details
before using these signatures against a live address.
Is the contract upgradeable?
Yes. DollarStore uses a UUPS proxy with a dedicated upgrader role separate from governor.
Role holders and timelock configuration depend on the deployment. The implementation uses ERC-7201
namespaced storage. See Security for governance and upgrade details.
Has it been audited?
Published reports and the revisions they cover are listed under Audits. Check the report scope against the release you use; a report for an earlier revision does not automatically cover every function in this interface. The software remains experimental.