Repository navigation
Conversation
The dapp no longer assembles a transaction. For each of the seven actions a person can take on a lending offer it hands the wallet the deployed manifest, the .simf sources of every covenant involved, the instance the factory published, the state the indexer reports, and the parameters the person chose. The wallet compiles the sources, resolves what the manifest computes for itself, builds the transaction, shows what it will do and broadcasts it. Landed here: - One wallet facade between the application and any provider, connected to the humid extension through the injected AppKit adapter. - Creating a borrower account and creating an offer, from the protocol's own deployed document rather than from code written against it. - Accepting, cancelling, claiming the principal, liquidating, repaying and collecting the lender settlement, all through one shared request builder and one shared hook, so each modal and each demo page differ only in the action they name. - What a contract action can be funded from is read from the chain, because the wallet does not serve it. - The deployed lending document is carried beside the contracts it describes, with the two references that named a namespace unable to hold them corrected. - The indexer's compose build generates the contract artifacts it depends on. - Tests over the request builder, the shared action hook and the seam itself.
…action The dapp acted through one wallet. It acts through four now - the HUMID extension, a Jade device, a recovery phrase held in the page for demos, and SideSwap over its relay - and every screen sees the same value whichever is connected. Adding a wallet is writing one adapter; it is never another path from a screen to a connector. Selection. connect takes the wallet the person pressed and whatever that wallet needs to start - a phrase, an address kind, a resume flag - availability is reported per wallet rather than as one flag, and signerType is the connected wallet's own answer. Nothing selected refuses by name rather than answering from whichever adapter happened to be built first, and a wallet already connected or coming back from a held approval is selected without anyone pressing anything. The account. Descriptor derivation stopped assuming a bare descriptor: the chain library is asked rather than the string guessed at, so a connector's already confidential descriptor is read as it stands and only a bare one is wrapped. scriptPubkey is a real script on all four wallets. What an adapter publishes has the account's own blinding key taken out first - anything holding it could unblind every output the account owns - and a descriptor whose key cannot be taken out is refused rather than passed on. The chain. The cached wollet, its IndexedDB namespace, the cross-tab lock, the 60s reread with its throttle and focus handlers, the reconciliation of a just-broadcast transaction and the asset-contract stage that lets a device show asset names rather than hashes all moved out of the old provider and behind the facade. It gives back the Rust memory it takes. syncWallet rereads the chain before the balances are asked for, which is what the six builders that call it before choosing inputs have always meant by it. A reread nobody asked for reaches the screens rather than sitting in the session. Performing. Each wallet that signs in the page performs an action by following the document's own input rule - an input is either one the wallet finds itself, named by asset and amount, or one located in the deployment's state by its type - and hands the result to the builder that already implements that action. All eight actions, creating the borrower account included, which every other one presupposes. The seven builders moved beside the protocol they build for, because a wallet and a screen both call them now. What the screens are told. The confirmed balance is what has confirmed, because only that can fund an action; the receive address is the wallet's own; a device waiting for its PIN reads as locked and gets its unlock screen back; a wallet being approved elsewhere says which request and offers the link and a cancel. The picker offers four cards, each disabled only for a reason true of this browser or this build. The seam test still guards the seam. Modules that became adapters left its superseded list, each departure stated, and it now notices a screen reaching for a wallet however the import is spelled. Two adversarial reviews over five rounds broke seventeen things with executable tests, every one of them fixed here. Forty-five stubs of this code fail the suite that used to stay green under them. Typecheck, lint, format, build and 143 tests pass at zero warnings. Creating a borrower account is proven against Liquid testnet by transaction 61d9833f at block 2590033. The other seven actions on a signing wallet await a recorded manual run.
The wallet now funds a contract action from every output it holds in the asset, the blinded ones included: it unblinds its own money and hands the signing module the secrets. This page was still counting only what the chain shows in the open at the account's first address, which on a network that hides by default is a small part of the account and reads to the person as an account holding almost nothing. So the count is now two reads that do not overlap. The wallet answers for what it holds, which is the only way a blinded amount can be counted at all. The chain read is left with the one output the wallet's own list leaves out, an unblinded output at the first address, which the chain library treats as external and omits while the wallet's action funding reads it separately and spends it. They are added by outpoint, so an output both reads return is counted once. getUtxos was already a capability every adapter serves and the facade did not publish; it does now, and nothing above the facade names a wallet to get it. The vendored connector is re-copied from humid at 7ef0dab, byte for byte as VENDOR.md requires. One behavioural line in it: the wallet's answer to an action is now a stated shape rather than "no dapp-facing shape exists yet". The manifest correction was re-checked against the same commit and is still needed, for the reason recorded beside it. Not verified: no typecheck, lint, suite or end-to-end run has been made against any of this.
lukachi
force-pushed
the
humid/wallet-protocol-actions
branch
from
September 18, 2026 11:17
7c5ca63 to
3ef16ac
Compare
Every action after an offer is created reads the deployment it created, and six of them declare no create_instance, so the wallet works nothing out for them: the deployment is exactly what this page sends. It sent the ten values the indexer records and left the covenant script hashes out, on the reasoning that the wallet would compute them from the document. It does not, for an action that creates nothing, and so each of those actions failed when the wallet came to compile a covenant from a field that was not there. The deployment now carries every compile-time field. The five vault and script hashes and the lending covenant's script hash are derived here through the same derivation the offer was created with, and CURRENT_DEBT through the same computation that builds the lending covenant's storage leaf. ZERO_HASH is sent as well: the document gives it a default, but the wallet fills defaults only for an action's own parameters, and none of the actions that spend a finalized vault declares it. The tests hold the derived hashes to the values the in-page path computes for the same offer, the debt to a multiply-then-floor division, the lending script hash to the offer's terms, and every action to the fields it reads beyond the recorded ten. They run the real chain library, handed its wasm bytes. Run against Liquid testnet through the HUMID wallet on 2026-09-22, alongside accepting, cancelling and claiming the principal: RepayLoan f1ff2237 at block 2628663, ClaimLenderVault f214edbc at 2628664, LiquidateOffer 906ae9fb at 2628700. Typecheck, lint, format and 154 tests pass.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The dapp used to build its own transactions against one wallet. It now hands the protocol's own deployed document to whichever of four wallets is connected, and every screen sees the same value whichever that is.
Before: screens named connectors directly —
providers/wallet/andproviders/humid/were parallel paths to a wallet, and adding one meant adding another path. Transaction building lived here, written against the protocol rather than reading it. The chain session (cached wollet, IndexedDB, cross-tab lock, periodic reread) sat inside the wallet provider. Only the extension could perform a protocol action.Now:
providers/walletFacade/is the only thing a screen talks to, with four adapters behind it — the HUMID extension, a Jade device, a recovery phrase held in the page for demos, and SideSwap over its relay. For each action the dapp hands over the deployed manifest, the.simfsources of every covenant involved, the factory instance, the indexer's state and the person's parameters. The extension compiles those and builds the transaction itself; a wallet that signs in the page follows the document's own input rule and calls the shared builder. All eight actions work on every wallet. The chain session moved behind the facade, and adding a wallet is now writing one adapter.web/src/test/theSeam.test.tswalks the import graph from the entry point and fails if anything above the facade names a wallet directly, or if the application can reach a superseded module. Nothing was deleted; the pre-facade wiring stays on disk and unreachable.Trying it out
1. Install the HUMID extension
Download
humid-extension-1.1.0-rc.0.zipfrom humid 1.1.0-rc.0 and unzip it. In Chrome:chrome://extensions→ enable Developer mode → Load unpacked → select the unzipped folder. Create or import a wallet in the extension and switch it to Liquid testnet.2. Start the indexer API
From the repo root — the web app reads offers from it and will not list anything without it:
cp .env.example .env docker compose up --build # api on :80003. Configure and run the web app
Worth setting in
web/.env:VITE_REOWN_PROJECT_IDVITE_DEMO_MODE=trueVITE_SIDESWAP_WS_URLVITE_DEBUG_MNEMONIC4. Fund the account
Send testnet L-BTC to the address the wallet shows. Then send it to itself once, unblinded — a contract action can only be funded from unblinded outputs at the signing address, so a normally-funded account shows a balance the protocol cannot spend. This is a property of the wallet, not of this change.
5. Connect and act
The picker shows four cards, each disabled only for a reason true of your browser or build:
VITE_NETWORKset toliquidorliquidtestnet(regtesthas no chain)navigator.serialis missingVITE_DEMO_MODE=trueVITE_SIDESWAP_WS_URLsetThen: create a borrower account, create an offer, and from a second account accept it — followed by repay, or let the term lapse and liquidate.
Verified on chain
Liquid testnet, against the deployed protocol.
e0154712…2e089324…cddc64df…114c0bee…1afe98ad…b2bbcddd…793d73d7…Creating a borrower account on a wallet that signs in the page is proven by
61d9833fat block 2590033. The other seven on a signing wallet await a recorded manual run — the table above is the extension path.Gates:
tsc -b,eslint,prettier --check,vite buildand 143 tests, all clean. Two adversarial reviews over five rounds broke seventeen things with executable tests; every one is fixed here.Two known limitations
Neither is introduced here; both are properties of the wallet, recorded rather than worked around.