[0.2.7] - 2026-07-31
A faucet button in the wallet's KOR row. A signet wallet holding no KOR is stuck: Kontor charges gas in KOR, an account with none has its operation dropped before execution, and buying KOR would itself cost gas. The pre-flights added in 0.2.5 report that deadlock accurately and leave the user with nowhere to go. This release ships the way out — the Portal's signet faucet, reachable from the wallet screen on web and mobile, next to the balance it fixes.
Added
useKontorFaucet()andclient.requestKontorFaucet()— ask the signet faucet for KOR. The hook is a small state machine (available,status,result,error,request(),reset()) whoserequest()never rejects, so a button'sonPressneeds no try/catch; the client method is the same call for the CLI and for scripts. It credits the connected wallet's taproot key (getAddresses().xOnlyPubkey— the faucet credits a key, not an address) and resolves with the faucet's commit + reveal txids. The KOR lands when the reveal confirms, about a block later, so neither one refreshes balances — the host does that when it dismisses its success UI.availableis the render condition, not a disabled state: it is false off Kontor signet (mainnet has no faucet, and a greyed-out button there would advertise free coins that don't exist) and false for a wallet exposing no taproot key. The client method refuses the same cases before making a request.- Endpoint defaults to
${baseUrl}/api/kontor-faucet— horizon.market's proxy in front of the Portal faucet, which is where a browser has to go anyway (the Portal sets no CORS headers of its own). Override with the newkontorFaucetUrlclient option / provider prop to hit{portal}/api/faucetdirectly from Node or React Native. - No
@kontor/sdkbehind any of it. It is a plainfetch, so it works in a web bundle built to keep the Kontor WebAssembly out and on a React Native build with no@kontor/sdk-nativelinked — the very builds where every other Kontor call fails, and where funding an account is what you'd want to do about it. The main entry exports the bare wire callrequestKontorFaucet(for a caller holding a recipient key and nothing else) alongsideKONTOR_FAUCET_AMOUNT_KOR;/reactexports the hook,KONTOR_FAUCET_AMOUNT_KORand theKontorFaucetResulttype.
renderTokenActiononWalletBalances(web + native) — where that button goes. The headline token rows (XCP / KOR / ZELD) ship a fixed set of controls — Deposit / Withdraw / Sell — so a host with one more to add had to choose between forking the component and putting its button somewhere else on the page, away from the balance it acts on. The prop is called once per headline token with that row's line and its return value is rendered at the start of the action group, ahead of the SDK's own buttons; returnnullfor the rows you don't extend. Both the horizon.market wallet page and the example mobile app now passline.symbol === "KOR" ? <KorFaucetAction /> : nulland nothing else.- The row shape is exported as
WalletTokenLine(symbol,amount,error,asset,sellAsset) so the callback can be typed and can branch on the same balance the row prints — including telling "the wallet holds none" from "the read failed", whichamount: nullpluserroralready keep apart. - Same prop, same position, same type name on both entries, so a host that renders both platforms writes the branch once.
- The row shape is exported as
- The example mobile app ships the faucet (
apps/native): a droplet button in the KOR row opening a confirm → requesting → txids modal, with the signet-explorer links and the same two Usermaven events the web wallet page reports (wallet_faucet_opened/wallet_faucet_completed), so the funnel is one chart across web and mobile.