Repository navigation
feat: fee network-switch reset, muxed accounts, gas resource breakdown, IPFS failover (#956 #957 #958 #959) - #986
Merged
k-deejah merged 1 commit intoOct 15, 2026
Conversation
…n, IPFS failover - FeeEstimator (Sorokit#958): clear cached fees and refetch immediately on network switch, drop stale in-flight responses, surge pricing alert (base fee > 300 stroops), 1.2x/1.5x/2.0x speed multiplier toggles. - utils (Sorokit#956): validate 69-char muxed M-addresses via StrKey decoding, add decodeMuxedAccount, lossless BigInt formatTokenAmount; toXLM uses it. - GasOptimizer (Sorokit#959): collapsible Resource Breakdown (CPU, memory, ledger read/write with per-resource fees), plain-English contract panic diagnostics, NaN-safe zero-fee/zero-limit handling. - ipfs (Sorokit#957): Cloudflare/ipfs.io/Pinata/dweb.link failover, CIDv0/CIDv1 parsing with sub-paths, 8s AbortController timeout per gateway; NFT images advance to the next gateway after an 8s stall. Closes Sorokit#956 Closes Sorokit#957 Closes Sorokit#958 Closes Sorokit#959
|
@Abidoyesimze Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
| } | ||
|
|
||
| // Drop a query string or fragment; neither is part of the content path. | ||
| rest = rest.replace(/[?#].*$/, "").replace(/^\/+/, ""); |
| rest = rest.replace(/[?#].*$/, "").replace(/^\/+/, ""); | ||
| const slash = rest.indexOf("/"); | ||
| const rawCid = slash === -1 ? rest : rest.slice(0, slash); | ||
| const path = slash === -1 ? "" : rest.slice(slash + 1).replace(/\/+$/, ""); |
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.
Closes #956
Closes #957
Closes #958
Closes #959
This PR covers four related issues. Each section below says what changed, why, and how it is tested.
#958: FeeEstimator: network switch, surge alert, speed multipliers
Problem: after a network switch, the previous network's fees stayed on screen until the next poll (up to 30s). Surge pricing wasn't explained. Users had no way to pay more for faster inclusion.
Changes
useFeeDatanow readsnetworkfromuseSorokit()and builds a key from the name and passphrase. When the key changes, the shared fee cache is cleared and a new estimate is fetched right away. The skeleton shows instead of stale values.SURGE_FEE_THRESHOLD(300 stroops, 3× the minimum), arole="alert"banner appears. It shows the ratio and explains that ledgers are full and transactions are competing on fee. The compact variant shows a "Surge pricing" badge.aria-pressed) show a priority fee based on the recommended fee. Clicking the active button clears it. A new optionalonMultiplierChange(multiplier, fee)callback reports the choice.500 × 1.2gives exactly 600. With plain float math it comes out as 600.0000000000001 and rounds up to 601.Tests (
FeeEstimator.test.tsx): a network switch clears fees and refetches; a stale old-network response is ignored; no refetch when the network values are unchanged; surge banner shown above 300 and not at exactly 300; compact surge badge; multiplier select, switch, clear and callback; multiplier rounding.#956: utils: muxed accounts and lossless stroop formatting
Problem:
validateStellarAddressrejected valid 69-character muxed (M…) accounts, and converting stroops withNumber(stroops) / 1e7loses precision above 2^53.Changes
validateStellarAddressaccepts bothG…(56 chars) andM…(69 chars, SEP-23) addresses. Both go through full StrKey decoding: base32, version byte, payload length and CRC16-XMODEM checksum. I refactored the decoding into shareddecodeStrKey/encodeStrKeyhelpers.StrKey.isValidMed25519PublicKeyin js-stellar-base.decodeMuxedAccount(address)returns{ baseAddress, id }. The ID is a decimal string, because 64-bit IDs don't fit in a JS number. There is also anisMuxedAccounthelper.formatTokenAmount(amount, decimals = 7)does the conversion with BigInt and string formatting. It always gives exactly 7 decimals, handles negatives and i128-size amounts, and returnsnullfor non-integer input.toXLMnow uses it, while keeping its parseInt-style leading-digit parsing and its"0.0000000"fallback for invalid input.Tests (
utils.test.ts): the SEP-23 test vectors (ID 0 and ID 2^63); a corrupted checksum, mutated payload, wrong length or case, and a G payload with an M prefix are all rejected; the decoded base address round-trips; stroop edge cases (0, 1, just above 2^53, max int64, i128, negatives); invalid input; formatting round-trips back to the original stroops.#959: GasOptimizer: resource breakdown and panic diagnostics
Problem: cost was shown as one lump sum, contract panics appeared as raw diagnostic output, and the zero-limit and zero-fee cases weren't tested.
Changes
aria-expanded). It lists CPU instructions, memory, ledger read bytes and ledger write bytes, each with its own fee, plus a total in stroops and XLM.estimate.resources(a new optionalSorobanResourceUsagefield onGasEstimate) when the client provides simulation data. Otherwise it uses the configured CPU and memory limits and labels them as such.RESOURCE_FEE_RATES: 25 stroops per 10k instructions, 1,786 per KB read, 11,800 per KB written. These are approximate Mainnet values and validators can change them. Memory has no separate fee.src/lib/diagnostics.tswithparseContractPanic():panicked at '…') and the host error (Error(WasmVm, InvalidAction),Error(Contract, #3), …) and turns them into plain English.nulland are shown as before.role="alert"explanation. The raw diagnostics are kept in a collapsed<details>.NaN.Tests (
GasOptimizer.test.tsx): the breakdown with simulated resources (per-resource amounts and costs checked); the fallback to configured limits; empty resource limits give zeros, not NaN;computeResourceCostswith missing, zero, negative and non-finite values; rounding; zero-fee and empty-fee transactions; panic and custom contract error codes rendered in plain English; XDR panic extraction; known host error mapping; non-contract errors left unchanged.#957: ipfs: gateway failover, CIDv1 sub-paths, 8s timeout
Problem: one gateway failing (429/504) broke NFT media,
ipfs://bafy…/metadata.jsonwasn't parsed properly, and stalled requests could hang forever.Changes
IPFS_GATEWAYSis now ipfs.io → Cloudflare → Pinata → dweb.link. ipfs.io stays first because Cloudflare retired its public gateway in 2024 and now redirects.parseIpfsUri/isValidCid:Qm…) and CIDv1 (base32b…, base36k…) with nested file paths.ipfs://ipfs/prefix and existing gateway URLs.fetchIpfsResource(url, { timeoutMs, signal }): each gateway attempt gets its ownAbortControllerwith an 8s (IPFS_REQUEST_TIMEOUT_MS) timeout. A non-2xx response, network error or timeout moves on to the next gateway, and an abort from the caller stops the whole chain.NFTGalleryimages move to the next gateway if they haven't loaded after 8s, and changing the image URL cancels the stalled browser request.useIsVisible), becauseloading="lazy"images don't start loading until scrolled to.Tests (new
ipfs.test.ts, plusNFTGallery.test.tsx): CID validation; CIDv1 sub-path parsing and resolution; gateway order and clamping; failover on 429/504 and on network errors; abort after exactly 8s (fake timers) then fallback; every gateway stalling; a caller abort stopping the chain. In the gallery: an 8s stall moves to the next gateway, and a loaded image isn't timed out. I updated the existing gallery gateway test for the added Pinata step.Testing notes
I couldn't run the full suite locally because my machine ran out of disk space during
npm install. The pure logic (StrKey and muxed decoding against the SEP-23 vectors, BigInt formatting, CID parsing, gateway failover and timeout, panic parsing) was run directly in Node and matches the test expectations. Lint, typecheck, build and the full vitest suite are left to CI on this PR.