Skip to content

A-1217833856533186: external connections - #257

Open
owlsua wants to merge 23 commits into
mainfrom
A-1217833856533186
Open

A-1217833856533186: external connections#257
owlsua wants to merge 23 commits into
mainfrom
A-1217833856533186

Conversation

@owlsua

@owlsua owlsua commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

💬 Description

Restore external connections, transactions are now built from the wallet's own UTXO set instead of letting the SDK refetch it, which fixes a second transaction sent before the first one confirms being rejected by the node as an orphan.

More

  • All ML flows (transfer, NFT, delegation create/stake/withdraw, fill order) call buildTransaction with opts.withUTXO; order filling extracted into a useFillOrder hook
  • Spent outpoints are recorded for unconfirmed transactions, so their UTXOs are excluded from the next build
  • Delegation withdraw accepts the full delegation balance, the fee is paid from the withdrawn amount, not the wallet
  • A failing exchange rates API no longer logs the account out
  • Montserrat ships with the extension, external styles and fonts removed from the CSP
  • UI fixes
  • Branch work included: external dApp API re-enabled, connection page rebuilt with SiteBadge / PermissionItem / BitcoinDataNotice, connections section in settings

📷 Screenshots

📋 Checklist:

  • I have named my branch as A-[id of Asana task]
  • I have set the title of my PR as A-[id of Asana task]: [short description]
  • My changes passed successfully by prettier check
  • My changes passed successfully by lint check
  • My changes kept the previous test coverage rate
  • I have added enough tests for my new feature/bugfix
  • I have set at least one person to review this PR
  • I have set myself as the assignee of this PR
  • I have set at least one label to this PR

owlsua added 14 commits August 28, 2026 15:27
Replace the SDK sugar methods (transfer, transferNft, delegationCreate,
delegationStake, delegationWithdraw, fillOrder) with direct
buildTransaction calls that pass opts.withUTXO, since only
buildTransaction accepts the option.

The SDK otherwise refetches spendable UTXOs from the indexer on every
build and knows nothing about the UTXOs the wallet already filtered out.
Passing our own list also drops one request per fee recalculation.

Order filling is extracted into a useFillOrder hook, shared by
OrderDetails and ManualSwap.
MintlayerProvider already filters out UTXOs listed in
usedUtxosOutpoints of pending transactions, but only the legacy
MLTransaction helpers ever wrote that field. Transactions signed
through the SDK path left it undefined, so the filter was a no-op and a
second transaction sent before the first one confirmed reused its
inputs, which the node rejects as an orphan.
The withdraw branch only returned early when the amount exceeded the
balance, then fell through to the shared check that adds the network
fee to the amount. Withdrawing the whole balance always failed there
with "Insufficient funds".

Nothing is paid from the wallet on a delegation withdrawal: the only
input is the delegation account input, so the fee comes out of the
withdrawn amount itself.
In the compact variant the compact size was applied only to the inner
circle, so the wrapper kept its default 72px and did not fit the 76px
card. The overflow was cut and the circle landed on the rounded corner.
The declared height never applied: the base button sets
min-height: max-content, which won over it, so each button was sized by
its content and the outlined one was taller by its border. Dropping the
vertical padding keeps the intrinsic height below the fixed one.
A failing exchange rate request logged the account out and sent it back
to the start screen, even with the Mintlayer nodes reachable. Only the
chain tip request decides now; the rate is logged and ignored.
Addresses are persisted as JSON and read back on session restore, which
turns the Uint8Array pubkey into a plain object that Buffer.from
rejects. Use the same toHexString helper the Mintlayer keys already go
through; it handles both shapes.
The font stylesheet was pulled from Google Fonts by a render-blocking
link in the HTML shell, so nothing was painted until that request came
back. On a cold cache, or a slow network, that is a blank screen for as
long as the request takes: a 6s stall moved first contentful paint from
0.4s to 6.4s.

Montserrat now ships as two subsetted variable woff2 files, one upright
and one italic, 116KB together and covering every weight in use. The
remote links are gone and the CSP no longer allows external styles or
fonts.
Uncomment the connect, signTransaction, signChallenge and delegation
handlers in the background script, so websites can talk to the wallet
again.

The popup read the pending request through a state variable that is
still null on the first pass; it now uses the value handed to the
handler.
Add a SiteBadge component and put it on the challenge, bitcoin and
external transaction screens, so it is visible which origin asked for
the signature. Requests without an origin are marked as unknown.
Split the page into PermissionItem and BitcoinDataNotice components,
show the requesting site through SiteBadge and move the styles from a
global stylesheet to CSS modules.
List the sites that have a stored session and let them be revoked from
the settings page.
@owlsua owlsua self-assigned this Aug 28, 2026
@owlsua owlsua added the enhancement New feature or request label Aug 28, 2026
@owlsua
owlsua requested a review from anyxem August 29, 2026 10:18
owlsua added 8 commits August 30, 2026 15:28
Swap Assets refused to look for orders until an amount was typed: the
button stayed disabled and the submit handler returned early. The amount
only narrows the result, so it is optional now, and an empty field lists
every order for the pair.

The filter reads the threshold explicitly instead of relying on
Number('') being 0.
The preview summarised a transaction into one line and hid the rest.
Only the first output that was not a change address was displayed, so a
second recipient never appeared, and a transaction that pays only our own
addresses crashed on an undefined output. Sending 10 coins with a 2 coin
fee read as "Amount: 10".

TransactionBreakdown now lists every input and output with its address,
marks the ones the wallet owns and sums what actually leaves it, fee
included. Fields it has no layout for are printed as they come, so
nothing is dropped silently.

The type of an operation is resolved once, by priority, instead of
raising independent flags: a delegation withdrawal used to draw a
"mint with lock" panel next to the right one, because it produces a
LockThenTransfer output. A transaction that matches nothing is now
called unrecognized instead of being shown as a transfer, and the
internal preview gets the error boundary the external one already had.
The sections were grey boxes with 20px padding and bold black labels,
which read as a stack of unrelated cards and did not sit next to the new
breakdown. They are rows of one list now: hairline separators, small
uppercase labels, one type scale. Labels lose their trailing colon,
which an uppercase label does not need.

The action line finally shows its accent colour: it pointed at
--color-primary, a variable this project never defines.
The class is declared in a CSS module, so its name is hashed at build
time, but the button passed the plain string. It matched nothing and the
button kept its default width. Renamed to camelCase like the rest of the
module.
The amount field masks input with the bitcoin expression, which caps the
fraction at eight digits. ML has eleven, so the last three could not be
entered at all.

The number of decimals is an argument now: bitcoin keeps eight, every ML
amount takes eleven, and a token field takes the decimals that token was
issued with, instead of the eight it inherited.
"24H PERCENT" wrapped: the uppercase label with wide letter-spacing did
not fit the column. The label no longer wraps and the side padding gives
it the room.
Same fix as the ML form: the plain string never matched the hashed name
of a CSS module class, so the button kept its default width.
The content area had a fixed height of 70%, so a long preview ran past
it while the space below stayed empty. The screens are flex columns now:
header and buttons keep their size, the content between them takes what
is left.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant