Skip to content

Support dotusd mint and redemption - #7614

Merged
wliyongfeng merged 5 commits into
mainfrom
dotusd-mint
Oct 14, 2026
Merged

wliyongfeng merged 5 commits into
mainfrom
dotusd-mint

Conversation

@wliyongfeng

Copy link
Copy Markdown
Member

No description provided.

Minting is what the page is for and had no UI at all. Adds a labelled Mint
button to the account panel, beside the transfer icon, and a popup that picks
an approved external asset, takes an amount, and shows what it yields and what
the fee takes out of it.

psm.mint takes its two asset arguments as XCM locations. The page holds them in
papi's decoded shape, which polkadot-js cannot encode, so they are rebuilt from
the asset id rather than converted: rebuilding has one possible output per id,
where a converter that met an unfamiliar junction would produce a different but
still valid location. The stored location is checked to be a local asset first,
and anything else disables the button instead of guessing.

The quote mirrors the pallet's maths, ceiling rounding on the fee included, so
the amount shown is the amount that gets minted. max_fee is floored at the
pair's own fee, since the chain rejects the call when the fee is above it and a
hardcoded value would block minting the day governance raised the fee past it.

The balances are subscriptions and follow a mint by themselves, but the PSM
snapshot is read once, so it is refreshable now and the debt and cap panels
catch up after a mint rather than on the next reload.
It was rendered from inside the Origin field, so it landed wherever that field
happened to sit — below "Pay with" in the mint popup. The reminder is about the
extension that will sign the transaction, so it belongs above every field: it
now renders from the popup shell, which is what every signer popup goes
through.

The five places that rendered it themselves are dropped so it cannot appear
twice, which leaves the three page level uses on the overview panels and the
asset hub header alone; those render the dismissible variant rather than the
banner and were never in a popup.
papi's watchValue defaults to finalized, and finality on Asset Hub trails the
best block by however far the relay chain is behind. Subscribing both ways at
once, best sat 15 blocks — around 90 seconds — ahead of finalized.

That lag lands exactly when someone has just transferred or minted and is
watching this number, which is why the balance appeared to update long after
the transaction did. Best blocks put it in the block that included their
transaction. A reorg would show a stale value briefly and then correct itself.
The way back out of dotUSD: an approved external asset comes back for the
dotUSD that goes in. Adds a Redeem button beside Mint in the account panel and
a popup that takes a dotUSD amount, shows the balance that caps it, and reports
what the payout asset would return and what the fee takes.

The fee is charged in dotUSD, out of what is being redeemed — the opposite way
round from minting — and redemptions keep working while minting is disabled,
which is what the middle circuit breaker state is for, so only AllDisabled
stops them.

What actually limits a redemption is the pair's outstanding debt, not the
reserve's token balance. The pallet compares against the tracked debt under an
error named InsufficientReserve, and only checks the reserve itself
defensively, where debt <= reserve holds by construction; so the debt is the
bound the popup validates.

Both directions need the same location building, amount parsing, max fee and
asset selection, so those moved out of mintUtils into psmUtils and a
swapPopupFields module, leaving each direction with its own maths and rules.
psmUtils now carries the raw redemption fee alongside the minting one, since
max_fee is compared against the exact Permill.
The "You will receive" and fee rows of both swap popups only showed an "≈" when
ValueDisplay's own abbreviation happened to add one, so a redemption fee of
0.0001 dotUSD rendered as a bare "0" — reading as no fee at all — while the same
row at 0.00255 showed "≈ 0".

The rows now decide for themselves: isRoundedAmount asks whether showing the
amount at three decimals drops part of it, and the row marks it when it does.
ValueDisplay keeps rendering the number and its full-value tooltip, with its own
mark switched off so the two cannot both appear.
@wliyongfeng
wliyongfeng merged commit 1a56395 into main Oct 14, 2026
1 check passed
@wliyongfeng
wliyongfeng deleted the dotusd-mint branch October 14, 2026 08:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant