Repository navigation
v0.4.1
Added
-
The waiting standard.
waitingView(elapsedMs, kind, steps?)in@noirwire/shared/presentationsays what to show as time passes: nothing beforeWAITING_DELAY_MS(300 ms), then a quiet signal, then a calm "still working" line afterSTILL_WORKING_AFTER_MS(4 s for content, a check or a review; 8 s for an action), and which step of multi-step work is current. A pure function of elapsed time: each platform owns its clock.importWaitingViewandimportFailedTextdo the same for an import, withIMPORT_LAST_STEP_AFTER_MS(6 s). -
waitingCopy, and the import's progress words (onboardingCopy.import.progress, with the phone's lead and failure inmobileOnboardingCopy.import.progress). -
Quiet retries for reads:
withRetries,readWithRetries,READ_RETRY,isTransientin@noirwire/shared/application. Three tries, 400 ms and then 800 ms apart, on a request that never got through, ran out of time or came back 429 or 5xx. Wrapped: the balance refresh, live prices, price history, tracker multipliers, the lending rate and position, import lookups,checkRecipient, and preparing a review (a trade's price, a send's cost, whether a holding is open, the relayer's price and keys). Nothing that signs or submits is retried, and a refusal never is. -
mobileSettingsCopyandmobileWalletCopy: the phone's Settings, Unlock and Reset words, as variants.unlockProblemTextandisWrongPasswordin@noirwire/shared/presentation. -
walletCopy.reset.notRemoved,walletCopy.crossTab.noticeandwalletCopy.crossTab.refused, which the web app kept for itself. -
decimalAmountin@noirwire/shared/domain: a period or a comma as the decimal separator, and null for text that could be read two ways. -
signAsClientandunsignedTransactionin@noirwire/shared/testing, for a test's stand-in chain client to sign through the real signing guard. The testing layer may now importinfrastructure/for that. -
The phone's layout tokens in
@noirwire/shared/design:mobileRadius,layout,size,MIN_TARGET,opacity,overlayColor,fonts,motion, andspace[8]. -
failureAccountin@noirwire/shared/presentation: a failure in its own account, which is what it is counted under. -
lookFurtherForPortfolios(mnemonic, scheme, activity)in@noirwire/shared/infrastructure, andlookFurtherViewwithonboardingCopy.import.lookFurther("Missing a portfolio? Look further"): a second scan a person can ask for from an import's result. It carries on from where the first stopped (SchemeActivity.scannedThrough) and gives up only afterEXTENDED_DISCOVERY_GAP(100) unused addresses in a row. -
canCreatePortfolioandunusedPortfoliosInARowin@noirwire/shared/application, and the constantsDISCOVERY_GAP(20),EXTENDED_DISCOVERY_GAPandMAX_UNUSED_PORTFOLIOS_IN_A_ROW(10) in@noirwire/shared/domain. -
createPacerin@noirwire/shared/application, a rate pacer with an injectable clock, andpaceImportWithandIMPORT_REQUESTS_PER_SECOND(8) in@noirwire/shared/infrastructure.withRetriestakesjitterandrandom. -
MAX_ACTIVITY_ENTRIES(500) in@noirwire/shared/domain,olderNotKepton the Activity list view, and its words for both platforms. -
focusRingand thefocustoken in@noirwire/shared/design;findStockandphraseWordsin@noirwire/shared/infrastructure;canonicalSymbolon the catalog;tooPreciseandsmallestAmountin@noirwire/shared/domain;portfolioNameTakenin@noirwire/shared/application;privacySectionHelpin@noirwire/shared/presentation;LOCK_SIGNAL_KEYin@noirwire/shared/wallet.
Changed
lock()locks the wallet everywhere it is open: it announces the lock through the vault, undernoirwire.wallet.lock(a counter, nothing about the wallet), and every other tab or running copy locks on hearing it. A reset does the same when the record would not be removed. An idle lock stays with the tab that went idle.changePasswordrefuses the password it already has: "That is already your password."- Every button variant, the icon button, the input and the chip carry a keyboard focus ring in a colour named outright (
focusRing). - Every counted noun goes through
plural: "1 asset", "1 result", "Order placed". sendCopy.invalidAmountandmobileSendCopy.invalidAmount: "Enter a finite amount greater than zero." and "Enter an amount greater than zero." are now "Enter an amount, like 12.50."- An amount typed with more decimals than its asset has, which includes one below its smallest unit, is refused in a send, when moving money in, in Earn and in a trade: "That amount has too many decimals. The smallest amount is 0.000001 USDC."
parseRecoveryPhrasereads a phrase as people paste one (numbered lists, commas, line breaks, tabs, capitals) and says exactly what is wrong: how many words there were, which word is not a recovery phrase word and where it stands, or that the words do not form a phrase. It answersproblembesideerror.stockBySymboland the catalog'sassetfind a tracker whatever the capitals:nvdaxis NVDAx.createPortfoliorefuses a name another portfolio already has, archived ones included, withduplicateName.fundingAmountViewtakestouchedand shows no error under an amount field nobody has typed in.createPortfoliorefuses withunusedPortfolios("You have several portfolios that were never used. Use one of those first. An archived one can be restored.") once the wallet ends in ten portfolios in a row that never held or did anything, archived ones included.- An import asks about each candidate address in one request instead of two, paces all its requests to eight a second across both sets of addresses, and adds jitter to its pauses after a refusal.
- The wallet's record keeps its 500 most recent activity entries. The oldest are dropped as new ones are written.
Failure and waiting messages say what happened, what it means for the money and what to do next, and no longer say how the app asked. This changes what the web says too.
| String | Was | Is |
|---|---|---|
onboardingCopy.import.networkFailed |
Could not reach the network to check balances. Try again. | We couldn't finish importing your wallet. Nothing was saved in this browser. Try again. |
onboardingCopy.import.checking |
Checking balances and recovering portfolios onchain... | Finding your portfolios... |
onboardingCopy.password.encryptFailed |
Could not encrypt the wallet. Try again. | We couldn't encrypt your wallet, so nothing was saved. Try again. |
mobileOnboardingCopy.import.networkFailed |
Could not reach the network to check this phrase. Try again. | We couldn't finish importing your wallet. Nothing was saved on this phone. Try again. |
mobileOnboardingCopy.import.offline |
You're offline. Importing needs the network to find what this phrase holds. | You're offline. Nothing was saved on this phone. Go back online to import your wallet. |
appCopy.networkGate.wrongNetwork(n) |
This app is built for n, but its network connection serves a different chain. Nothing can be sent until that is fixed. | NoirWire is not connected to n as it should be. Your money has not moved, and nothing can be sent until this is fixed. Try again later. |
appCopy.networkGate.unreachable |
The network could not be reached, so balances cannot be shown safely. | We can't show your balances right now. Your money has not moved. Try again. |
mobileAppCopy.network.checking |
Checking the network... | Getting things ready... |
errorsCopy.chain.noQuote |
Jupiter has no price for this order right now. | There is no price for this order right now. Nothing was traded. Try again in a moment. |
errorsCopy.chain.wrongNetwork |
The network connection serves a different chain than this app is built for. Nothing was signed or sent. | NoirWire is not connected to Solana as it should be, so this was stopped. Nothing was signed or sent. Try again later. |
errorsCopy.funding.failed |
Funding failed. | We couldn't move this money. Nothing was moved. Try again. |
errorsCopy.funding.privateNotStarted |
The private transfer could not be started. | The private transfer could not be started. Nothing left your funding wallet. Try again. |
errorsCopy.send.notCompleted |
Transfer could not be completed. Check the balance and recipient. | This send can't be made. Nothing was sent. Check the amount and the recipient's address. |
errorsCopy.send.failed |
Transfer failed. | We couldn't complete this send. Nothing was sent. Try again. |
errorsCopy.trade.noPrice |
Could not get a price for this trade. | We couldn't get a price for this trade. Nothing was traded. Try again. |
errorsCopy.earn.failed |
The transaction did not complete. | This did not go through. Nothing was moved. Try again. |
sendCopy.sending |
Sending onchain... | Sending... |
fundingCopy.unknown |
...was sent, and the answer never came back. It may still arrive... | ...was sent, but we could not confirm that it arrived. It may still arrive... |
tradeCopy.costCheckFailed |
Could not check the network cost of this order. Get a new price. | We couldn't work out the network cost of this order. Nothing was charged. Get a new price. |
pieCopy.order.costCheckFailed |
Could not check the network cost of these orders. Try again. | We couldn't work out the network cost of these orders. Nothing was charged. Try again. |
mobilePortfolioCopy.home.refreshFailed, .detail.refreshFailed |
Could not refresh. Pull down to try again. | We couldn't update your balances. What you see may be out of date. Pull down to try again. |
mobileFundingCopy.page.readFailed |
Could not refresh. Pull down to try again. | We couldn't update your balance. What you see may be out of date. Pull down to try again. |
failureMessageno longer passes on a failure's own account when that only says how a request failed ("fetch failed", "429 Too Many Requests", "Jupiter returned 502."): the person is told the plain words for what the action was doing. Analytics still band the failure by its own account (failureAccount).typedAmount, and with it the send, funding and Earn drafts, reads an amount throughdecimalAmount: "12,5" is 12.5 on both apps, and "1e3", "0x10" and grouped digits are no longer amounts.
Kept as they are, because they are honest and needed: "Network cost" and "Relay fee" as fee lines, "Solana" where the chain matters, "offline", and the privacy notes that name who can see what (NoirWire's server, the network provider, Jupiter, MagicBlock).
Fixed
-
An import's pace was taken before a request had one of its three slots, so requests that queued behind slow answers all started together when those came back. The turn is now taken inside the slot, right before the request is sent.
-
Locking the wallet in one tab left it unlocked and usable in the others.
-
Changing the password to the same password reported "Password changed".
-
A funded portfolio could be lost to a restore. An import stops looking after 20 unused addresses in a row, and creation allowed any number of empty portfolios: twenty empty ones and then a funded one put the funded one out of reach. Creation is now held to a limit safely under the scan's gap, a test holds the two constants to that, and a further scan can be asked for.
-
An import could fail on a provider that allows about ten requests a second: both sets of addresses started together and sent a burst, and pauses that lined up used up the retries. Requests now share one pace, and a failed attempt carries on from the last completed step when it is tried again instead of starting over.
-
The activity list grew without limit inside the encrypted record, so every write and unlock grew with it, and web storage could in time refuse a write.
-
An action that landed can no longer be reported as failed.
sendandfundDirectlyansweredfailedwhen the balance read after a landed transaction threw, which invited paying again. Now, once the chain or the venue has confirmed, the answer isconfirmed: the read after it is asked again quietly, and if it still cannot be had the answer carriessettlement: "balancesEstimated"(balancesUnread(result)in@noirwire/shared/application), which a screen shows as done, "Balances will update shortly." The same holds for Earn deposits and withdrawals, a trade whose account was just opened, opening a pie's holdings, and a private transfer the service accepted. An unknown outcome stays unknown, and a reservation that cannot be ended never changes what an action answers.sendResultView,earnResultViewandfundingOutcomeViewtakebalancesUnread. With that guaranteed, a failure before anything was sent says so: "Nothing was sent", "Nothing was moved". -
A password change left
indeterminateno longer holds every later change until the app restarts: it is forgotten when the wallet is reset, and settled when the record read back is another one.