Repository navigation
Sun-lit redesign: new logo, neumorphism, global illumination - #1324
Closed
takemiyamakoto wants to merge 48 commits into
Closed
takemiyamakoto wants to merge 48 commits into
takemiyamakoto wants to merge 48 commits into
Conversation
Two Polkaswap screens broke on iPhone with the 4.2.0 redesign (#1305): - The token picker stretched its search field over most of the sheet and left the list a strip at the bottom. SearchTextField took its size from BackgroundedContentControl's empty contentView, a zero height, and #1305 replaced its fixed height with a 44 pt minimum, so the sheet's stack view stretched the field. The field now reports its own height and hugs it, and the list and its empty state share a container so the hidden empty view no longer fights the list's height. - Preview pushed the confirmation inside the new swap tab, where the tab bar and the raised Polkaswap button covered Confirm and the header sat under the status bar. The confirmation now hides the tab bar and keeps its header and button inside the safe area. Both tests fail on the previous code: the search field measured 653 pt in an iPhone-sized sheet, and a tap on Confirm reached a tab button. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On 4.2.0 a swap quote could take minutes to appear. Since #1305 every quote request carried its own ID and only the newest request's reply was shown, while every SORA block (about 6 s) cancelled the pending request, hid the shown quote and asked again. Any reply slower than a block was therefore thrown away, block after block, until one happened to be fast enough. Quotes also queued in the app-wide operation queue behind unrelated work, waited 0.8 s after each keystroke, and replaced block subscriptions kept refreshing because the subscription service cancels them as requests, which leaves them running on the node. - A reply is shown when it answers the question on screen (pair, amount, direction, market) and nothing newer is shown, so a refresh no longer invalidates the reply already on its way. Replies to an old amount and older replies are still dropped. - A block refresh keeps the shown quote, sends nothing while a reply is awaited, and a failed refresh keeps the quote instead of clearing the inputs behind an alert. - Quotes go straight to the SORA socket with a 10 s timeout; fees and pair checks use the swap screen's own operation queue. - Typing waits 0.3 s instead of 0.8 s. - Updates from replaced block subscriptions are ignored. In the simulator, against the production SORA nodes, the time from keystroke to quote fell from about 1.8 s to 0.7 s. The new presenter test fails on the previous code: the awaited reply is discarded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026.11.5 went to TestFlight and App Review on 4 November 2026, so it joins the consumed builds and becomes a supported in-place upgrade predecessor in the usability gate. The startup capture keeps accepting it under its own name, every release tool now pins 2026.11.6, and the build-number check's test treats 2026.11.5 as the latest consumed build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Apple approved 4.2.0 with build 2026.11.5 (Pending Developer Release on 7 November 2026), which closes 4.2.0 to new uploads, so the Polkaswap fixes ship as 4.2.1 (2026.11.6). The Release target, the archive, identity, signed-artifact and build-number checks, the usability gate and fastlane now expect 4.2.1. The startup capture still expects 4.2.0 for every earlier build and 4.2.1 only for 2026.11.6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The self-test parsed the check's output with a literal "Release 4.2.0" and used 4.2.0 in its version-drift cases, so it stopped recognising a passing repository once the release moved to 4.2.1. It now reads the version and build from the check's output and uses them in every case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On the owner's word, 4.2.0 (2026.11.5) was removed from review, its version record renumbered to 4.2.1 with build 2026.11.6, and submitted on 7 November 2026 at 10:06 UTC. It is Waiting for Review with a manual release. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
verify-native-source.py accepted SOURCE_PACKAGES_DIR from its callers but never read it, so a moved tag or an edited package checkout passed the check. It now compares every pinned checkout's HEAD with its revision and refuses local changes, using git --no-optional-locks so the check never writes. verify-pods.py and config/pods-source-pins.json record digests of the 11 pods compiled into the app or its tests and of the rswift and swiftformat executables that Xcode runs. The rswift digest equals the upstream 6.1.0 release binary. Recorded from the reviewed 4.2.1 install. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
createPublicKeySoft copied SR25519_KEYPAIR_SIZE (96) bytes out of a 32-byte stack buffer, reading stack memory into the key and always failing. Nothing calls it today; it now copies the 32-byte public key and a test checks it against the soft-derived key pair. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tonkeeper/ton-api-swift 0.1.7 has no licence file. Packages/TonAPI holds the same client generated here by Apple's swift-openapi-generator 0.3.1 (Apache-2.0) from the MIT-licensed opentonapi specification, with provenance in its README. Client.swift is byte-identical to ton-api-swift's; Types.swift is byte-identical after postprocess.py drops Action._type, as ton-api-swift did, so a new tonapi action kind cannot fail a history page. scripts/deps/regenerate-tonapi.sh rebuilds the pinned generator and fails if the committed sources differ from fresh output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner, 2026-11-07: fix the key-exposure audit findings, and "don't use any closed source libraries. make everything you need here in this repo, open source". Closed and non-open-source code: - Delete the closed Kotlin/Native sorawallet framework, loaded at every launch. Its only use, Polkaswap strategic-bonus APY, is now Swift (PolkaswapAPYWorker, PolkaswapPoolApyMapper) against pi.soramitsu.io; the framework's SubQuery endpoint answers 503. - Remove WalletConnect (reown-swift, WalletConnect Community License) with its prebuilt yttrium binary and five Reown-only packages. A one-time clean-up deletes only com.walletconnect.sdk generic passwords and WalletConnect defaults. Keep the Chainlink ABI code under its web3swift and MEWwalletKit licences. - Build against the in-repo TonAPI package instead of ton-api-swift. Key exposure: - The emergency recovery export becomes a password-encrypted file (scrypt plus XSalsa20-Poly1305, 8+ characters, verified before sharing) and never shows a secret; scripts/recovery/decrypt-emergency-material.py opens it. - Forget wallet (now PIN-gated) and logout erase the Keychain secrets of removed wallets that were backed up, after their rows are gone. Orphaned keys and never-backed-up wallets' keys stay recoverable through the encrypted export. - PIN lockout with backoff persisted in the Keychain, constant-time compare, biometric enrollment checks that trust an existing install's first unlock, a 5-minute monotonic background re-lock, and PIN or biometrics before every fund-moving or staking submission. - JSON exports need 8+ characters; secret files get complete protection, their own directories and removal after sharing; Inbox copies and old leftovers are removed. - Remote SVGs are filtered before SVGKit; seed and key share sheets exclude Copy; secrets hide while the screen is captured and screenshots warn; keyboard extensions are refused. - TON Connect never signs a ton_proof for a site its manifest does not come from, and gets a veto-only kill switch. - Xcode now runs the checkout and pod verification before any build tool. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026.11.6 is in App Review and counts as consumed; 2026.11.7 replaces it in review with the closed-source removal and the key-exposure fixes. Release tools, gates and their tests now pin 4.2.1 (2026.11.7), as cc8e3ec and 1092c5e did for 2026.11.6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…26.11.7) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Packages/FearlessWalletConnect speaks WalletConnect v2 in the wallet role on Apple's system frameworks only (Foundation, CryptoKit, Security, Combine). It replaces Reown's reown-swift, which is under the WalletConnect Community License and is not open source. - X25519 key agreement, HKDF-SHA256 session keys, SHA-256 topics, and ChaCha20-Poly1305 type 0 envelopes in padded base64 (type 1 is read, never opened). - The relay's EdDSA did:key sign-in JWT, valid for 24 hours. - The relay over URLSessionWebSocketTask: subscribe, batch subscribe, publish, unsubscribe, the batch message fetch, acknowledging each delivery, keep-alive pings and reconnecting with back-off. - Pairing, proposals, approval and refusal, settlement, requests checked against the session's namespaces, answers, ping, disconnection and expiry, with each Sign method's relay tag and lifetime. - Verify: ES256 attestations from the relay, or the trusted service's answer by message hash. - A strict JSON reader that keeps numbers exact and refuses duplicate keys. - Its record in the app group's user defaults and its keys in one keychain item, and the import of what WalletConnectSwiftV2 (Fearless up to 4.1.0) and Reown 1.8.0 (4.2.x) saved, left in place for a downgrade. Tests run on macOS with swift test: RFC 7748 and WalletConnect relay-auth vectors, the wallet role against an in-memory relay that follows the live relay's delivery rules, and both earlier storage layouts. Two checks use the WalletConnect SDK installed outside the repository, never as a dependency: scripts/walletconnect/reference-vectors.mjs for a differential cryptography check, and reference-dapp.mjs as a dApp on the live relay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner, 2026-11-08, asked "Bring WalletConnect back on the new 4.2.1 head with this client?": "Bring it back". e0dda28 removed WalletConnect because reown-swift is not open source. This restores the WalletConnect part of that commit on Packages/FearlessWalletConnect and keeps everything else in it: the key-exposure fixes, the removal of sorawallet and ton-api-swift, and the source and pod verification phase. - The WalletConnect service, screens, coordinators, models and tests come back as they were in 4.2.1 (2026.11.6), on FearlessWalletConnect instead of WalletConnectSign. Reown's socket engine, socket factory and crypto provider stay deleted. - Forgetting a wallet and logging out disconnect its WalletConnect sessions again, after the new secret erasure. - RetiredWalletConnectDataCleanup is removed. It deleted the com.walletconnect.sdk Keychain items and WalletConnect defaults that the client imports, so sessions paired in 3.0.5 to 4.2.1 (2026.11.6) carry over again. Devices that already ran 2026.11.7 lost them; their dApps pair again. - RLPBigInt.swift and SignTypedData.swift (MEWwalletKit, MIT) return to WalletConnect/eip_mew with that licence and a NOTICE entry; the regex helper the ABI move dropped is String+Match.swift there. - The release audits again require WalletConnect.projectId (FL_WALLET_CONNECT_PROJECT_ID) and check that the WalletConnect service uses the entitled app group. - No package is added: the resolved graph stays at 40 external packages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/walletconnect-protocol.md describes Packages/FearlessWalletConnect: its files, the wire format, its storage, the import of what earlier SDKs saved, and how to rerun its checks, including the real-storage upgrade check from a Reown 1.8.0 build. It notes that 4.2.1 build 2026.11.7 deleted those records once per install, so a device that ran that build has nothing to carry over and its dApps pair again. The binary provenance record says the wallet now speaks WalletConnect with its own client on Apple's system frameworks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WalletConnect pairing codes use the `wc:` scheme (EIP-1328), but the QR matcher accepted `ws:` instead, so a scanned pairing code was reported as an invalid QR code. `WalletQRService` now matches `wc:` codes itself, from the camera and from gallery images, and no longer reports a `ws:` node address as a pairing code (the shared decoder still does; its result is refused). A new connection is only useful for signing, so `connect(uri:)` opens it together with signing: while `WalletConnectSigningPolicy` is off, a scanned code shows a localized "not available in this version" message and nothing is paired. This change also adds, in every bundled localization, the strings the reworked WalletConnect request flow uses in the following changes. Tests cover pairing codes and node addresses from the camera, the gallery and the scanner, connecting with signing off and on, malformed codes, and the new message in every shipped localization. The scanner tests now use `wc:` codes. Ported onto the in-repo client (Packages/FearlessWalletConnect): the service pairs through the client, or through an injected pairer in tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 805b624e2cadaa59856d89ea719e56ba9230e7b6)
…ation Every request is now prepared before its confirmation opens, and the confirmation and the signer use the same prepared values: - The request must name an account the session approved for the request's chain. The signing key is that account's, not a match picked by address from all wallets. - EVM transactions get their nonce, gas limit and gas price before the confirmation opens. The confirmation shows the network first, then the recipient (the token recipient or spender for ERC-20 transfers and approvals), the amount and the most the network can charge, and exactly those values are signed; nothing is quoted again after Confirm. Chain ids are parsed as the decimal values the app stores, a transaction for another chain is declined, and so is a request without a recipient. - EIP-712 typed data must carry the request's chain id when its domain names one, and permits show their spender and amount. The legacy array format, which no domain binds to a network, is declined. - Substrate transactions must carry the chain's genesis hash, spec version and transaction version. The call is decoded and must encode back to exactly the dApp's bytes; transfers show their recipient and amount, the fee is quoted for that exact extrinsic, and the tip is signed as sent. - Substrate messages are signed inside the `<Bytes>…</Bytes>` envelope that polkadot-js uses. - Personal-sign and typed-data signatures use the 27/28 recovery id that JSON-RPC callers and `ecrecover` expect. Declined requests show a localized reason and get an error response, and the request sheet no longer prepares the request again on every balance update. `WalletConnectSigningPolicy.production` stays off. Tests cover account binding, the quoted and exactly signed transaction for a decimal chain id, chain-id, address and quantity checks, ERC-20 decoding, the EIP-712 specification's example digest, permits, the `<Bytes>` envelope and its signature, Substrate genesis, runtime and call checks against the bundled Polkadot runtime, the signed payload, a runtime change before signing, and the confirmation rows for every method. Ported onto the in-repo client: the new files import FearlessWalletConnect, and the project changes were applied to this line's project file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 59c74e0bf33f93f29593006dc1219cb4b39e2b08)
…sts behind the lock - Signing now waits for the PIN or biometrics, asked from the confirmation after the user taps Sign. Closing the PIN screen signs nothing and leaves the request open to sign or reject; without a PIN nothing is signed, and a PIN screen that goes away without an answer counts as not confirmed. - The PIN screen that locks the app after inactivity now records that the app is locked. While it is shown, WalletConnect requests and notices wait in their queue, and a request already on screen is hidden until the app is unlocked. - A request the SDK delivers again while it is queued or on screen is shown only once. Tests cover signing with and without the user's confirmation, the PIN screen from the confirmation with its success and cancel paths, the missing-PIN case, requests waiting behind the lock and appearing after it, one request at a time, a repeated request shown once, the request window hidden while locked, and the lock ending with its PIN screen. Applied unchanged on the 4.2.1 line: the lock marker sits after the head's unlock-PIN guard in FearlessApplication.dropSession(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit cc3e7ee3a6275c65e84f58f077de2781bcd66ebe)
…s scams The SDK reports what WalletConnect Verify knows about the app behind each proposal and request, but the service dropped it. It now reaches the screens: - The proposal shows a Verification row below the app: verified domain, domain not verified, or domain mismatch. - The request sheet shows the same status under the app's name; a domain mismatch replaces the generic warning with one saying the app may not be the website it claims to be. The confirmation lists it as its last row. - A proposal or request from an app Verify flags as a known scam is declined before anything opens, and the user is told which app was blocked and that nothing was connected or signed. This applies while signing is off too. The notice presenter now serves both the signing-unavailable and the blocked-app notices. The domain-mismatch status is shortened for the rows, with its explanation as a separate warning, in every bundled localization. Tests cover how every Verify result maps to what is shown, declined and never shown scam proposals, scam requests declined before any confirmation with signing on and off, verified requests opening with their status, the blocked-app notice, the confirmation row, and the texts in every shipped localization. Ported onto the in-repo client: the client's sessionProposal and sessionRequest events carry the VerifyContext its Verify client produced, and a scam-flagged proposal is refused through the client (or an injected rejecter in tests). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 1b9a737d14a75b715d8f3d722c7a682b8dd9dc18)
…submission PIN Owner's decision for 4.2.1 (2026.11.8), relayed from the key-exposure session: "we need some wallet connect support of course", choosing "Connect and sign": pair from wc: codes and links, sign EVM, Polkadot and TON requests, ask for the PIN or Face ID before each signature, show the real requesting site, and let a remote kill switch turn signing off. - WalletConnectSigningPolicy.production is on. The ported WC-SIGN checks stay in front of every key: the account the session approved, the network, the decoded call that must encode back to the dApp's bytes, the quoted fee, the <Bytes> envelope, and scam-flagged apps declined. - Every signature asks through SubmissionAuthorizer, the step every fund-moving and staking submission takes, with its PIN lockout and biometric rules. Without a PIN nothing is signed. - Remote vetoes, absent means enabled and only an explicit false pauses: evm_dapp_signing_enabled and polkadot_dapp_signing_enabled for WalletConnect, ton_dapp_signing_enabled for TON Connect transactions and ton_proof sign-ins, the Android key names; never dapp_enabled. A paused request is declined before anything opens and the user is told nothing was signed. The confirmation checks again before and after the PIN. - The requesting site is shown as WalletConnect Verify reports it: on a domain mismatch the website row names the site the request came from, and a site Verify could not check is labelled "Domain not verified" with a warning. - wc: links and fearless://wc?uri= links pair (Info.plist registers wc). A link that opens the app waits until WalletConnect starts after the unlock; a failed link gets a notice. A wc: link without a key only brings the wallet forward. - New strings in every bundled localization. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scripts/walletconnect/reference-dapp-sign.mjs runs the WalletConnect SDK most dApps ship as a dApp on the live relay. It asks for personal_sign, eth_signTypedData_v4 and polkadot_signMessage, and checks every signature with code that is not Fearless's: ox recovers the EVM signer and @noble/curves verifies the Polkadot ed25519 signature over the <Bytes> envelope (and that it does not cover the bare message). The SDK and those libraries stay outside the repository. WalletConnectLiveSigningTests (skipped unless FEARLESS_WC_SIGN_LIVE=1) is the wallet: it pairs from the dApp's link, approves an EVM and a Polkadot account, and answers each request with the app's own request preparation and signer, as the confirmation does after the PIN. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/walletconnect-protocol.md now says how the app pairs (wc: codes and links, fearless://wc?uri=), what it signs and checks before the confirmation, how the requesting site is shown, the PIN step, the per-network remote vetoes, and the live signing check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The client's request and proposal ids are Int64 (Reown's were RPCID and String), and its JSONRPCError is FearlessWalletConnect.JSONRPCError, qualified because SSFUtils has a type of the same name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The live signing check found that the polkadot_signMessage and polkadot_signTransaction answers carried a random 64-bit id. dApps read the answer in JavaScript, where an integer beyond 2^53 becomes a BigInt that plain JSON.stringify cannot write. The id is now between 1 and 2^53 - 1. The reference dApp scripts' in-memory storage writes such values too, and the live signing test fails, instead of skipping, when the dApp never writes its result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SwiftFormat's unusedArguments rule; no change in behavior. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…quests Security review of c82dd63, findings 3, 4 and 6 (client side): - pair(uri:) refuses a link whose topic is a live session's, or a pairing's with another key (ClientError.topicInUse): its key would replace theirs. Opening the same pending link again changes nothing. - respond(topic:requestId:response:) answers only a request the dApp still waits for (ClientError.requestNotFound otherwise); isPending(topic:requestId:) tells the app, expiry included, before the sweep runs. - disconnectAll() ends every session and pairing for logout, and keeps going when one fails. Package tests: 52 run, 0 failures, 2 env-gated skips. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Independent review of c82dd63: 1. HIGH, app lock: the idle and background lock puts its PIN on the app's own window (SceneWindowFinder.mainWindow), never on the key request window that hides while locked, so no flow ending can dismiss it. A request sheet hidden with its window is not rejected; the main window takes key status back. 2. MEDIUM, blind signing: undecoded call data gets a warning, the contract, the selector and the raw data; transfer, transferFrom, approve, increaseAllowance (maximum = unlimited) and setApprovalForAll are decoded strictly, with a warning for trailing bytes. Typed data shows permits' spender, amount and deadline (DAI allowed: true = unlimited) and every signed field of anything else, with a warning. Polkadot calls other than transfers show the call and its arguments, Utility.batch* and Proxy.* inner calls numbered, with a warning. 3. MEDIUM, forget wallet: every session that granted one of the wallet's accounts ends (any namespace and chain, by account id); logout ends every session and pairing. 5. LOW: typed data whose domain carries an undeclared chainId is declined; a domain without one gets a warning; the hash comment is fixed. 6. LOW: expired or ended requests and proposals leave the queue or close with a notice; the confirmation checks the request is still pending before the PIN and before signing; a transaction already sent still shows its hash. 7. LOW: at most 10 flows wait (more are declined at once), at most 3 links wait for the unlock, and requests are keyed by topic and id. 8. LOW: Polkadot chains match only the exact 32-character CAIP-13 reference. (4 and the client half of 3 and 6 are in the previous commit.) Focused hosted tests: 361 run, 0 failures, 2 env-gated skips; the lock, gate and lifecycle classes 5 times over: 240 runs, 0 failures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-review of 4619160, problem C: disconnectAll() forgot one topic, then waited for that peer, before the next. It now forgets every session and pairing locally in one write first (loading the record when the client has not started, and removing earlier SDKs' records of them), then tells every peer at once, best effort. Nothing comes back on a later start. Package tests: 54 run, 0 failures, 2 env-gated skips. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-review of 4619160: A. HIGH: permits are read only when the primary type is defined exactly as EIP-2612, DAI or Permit2 define it (compared as the EIP-712 type string), and only from declared fields, so undeclared keys such as allowed:false or expiry:0 can't change what is shown. The token and name come from the domain only when EIP712Domain declares them. Every signed field is listed under the permit too. Undeclared keys get a warning that they are not signed. A value whose shape differs from its declared type is declined. B. MEDIUM: nothing is cut. Typed data over 500 fields or 10 levels, and a Substrate call carrying over 100 calls or past 60,000 characters or 24 levels, is declined before the confirmation opens. Substrate calls get a summary of every call they carry, by call and account with counts and totals: fund-moving and rarer calls first, then larger amounts. Lists of numbers (bytes) show on one line. C. LOW: logout reaches WalletConnect's record even before it was set up. D. LOW: at most 5 requests per session, 5 proposals and 20 flows in all. E. LOW: transfer, transferFrom and approve on a contract that isn't a known token show "Amount or item ID". Focused hosted tests: 383 run, 0 failures, 2 env-gated skips; lock, gate and lifecycle classes 5 times over: 255 runs, 0 failures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tocol notes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Third review of c1201eb, F: the ABI encoder that hashes typed data reads a number string as decimal, then as unprefixed hex, then as signed, and encodes negatives in two's complement, so "-1" or -1 for a uint256 signed as 2^256-1, "ff" as 255 and "1e18" as 0x1e18, while the screen showed the text as written. A malformed address was also hashed as other bytes. Before anything is hashed or shown, every value of an atomic declared type, in the domain and at any depth of the message, is now parsed strictly and written back in one canonical form (WalletConnectTypedDataValues): - uintN/intN: decimal without leading zeros, 0x hex, or a JSON integer, within the bit width; negatives only for intN; shown and hashed as decimal. - address: 0x and 40 hex digits. bool: a JSON bool, or 1 and 0. - bytes: even-length 0x hex. bytesN: at most N bytes, right-padded as hashed. - string: a JSON string. Fixed-size arrays must have their size. Anything else is declined. The hash reads only the canonical data, so the signature covers exactly what the confirmation shows. A hex domain chainId is now read as its number and bound to that network. Focused hosted tests: 390 run, 0 failures, 2 env-gated skips. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026.11.7 is in App Review and counts as consumed; 2026.11.8 replaces it with WalletConnect back through the in-repo client: wc: pairing and EVM and Polkadot signing behind the PIN, remote vetoes and the requesting site, after three independent security review passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Apply shared native lighting, raised surfaces, inset controls, approved brand assets, and informative wallet motion. Preserve accessible layouts and keep sheet rims static across recovery and signing contexts. Add regressions for motion policy, sync state, localized layouts, transaction states, and generated asset integrity.
The Profile authorization fixture called the data source's cellForRowAt directly on every open(). That dequeues outside a table request, and a second open() raises "Attempted to dequeue multiple cells for the same index path". The raised exception unwinds through the async test, which aborts the test host. The sun-lit row spacing exposed this: with tighter footers, scrolling no longer recycled the rows between the two opens. Scroll each row into place and read it with cellForRow(at:), the same way UIKit asks for it. Test code only; the app's data source is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner, 8 November 2026: "on pages like this, we are not constrained to this little circle. make the wings logo span most of the width of the screen". PIN, welcome, onboarding start, About and the launch screens now show the approved mark at full span: the badge's own wing, joint and disc paths without the circle, at about 90% of the screen width and no taller than the circle was. The generator embeds the master path text unchanged, so the wings stay byte-identical. FWWingsView adds the sun's glow and drops it under reduced effects and high contrast. The wallet's hero keeps the round sun because its sync arc needs the circle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Screens from the final build showed two flaws. The PIN page's scroll view cut the glow in a straight line above the wings, so the glow now fades within the room every page keeps above the mark. The About list still had the system's black cells and a black header fade under the lit page; it now shows the page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in the owner-verified PIN keypad sizing from TestFlight 2026.11.9: 72 pt keys, comfortable spacing and vertical centering. The release line's metrics decide the keypad's sizes; the sun-lit paint and the wide wings sit on top. Both sides' PIN tests are kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A dismissed authorization releases Profile a run-loop turn after UIKit ends the transition, so a tap on the very next poll could be ignored and fail the test. The fixture now waits for that release before tapping. A release that never comes still fails, so the test still guards against a stuck Change PIN. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nvzhu
previously approved these changes
Nov 8, 2026
This was referenced Nov 10, 2026
Contributor
Author
|
Folded into #1326, which brings every open iOS PR into master in one change, so one code-owner approval covers it. This PR's branch is kept. |
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.
Summary
Redesigns the iOS app around the approved winged-sun logo, with neumorphic surfaces, one light across every screen, and animations that report real state. Owner request, 8 November 2026.
This is UI only. Key generation, storage, signing, seed handling, networking, remote config and chain logic are unchanged.
scripts/brand/generate-ios-brand-assets.mjs, 100 outputs checked against a manifest).fearless/Common/DesignSystem/Sunlitholds the shared light, raised surfaces, inset controls, the tab well and the sheet rim. Screens use it instead of raw colours.Related Issue
No tracked issue.
Merge after #1315. This branch contains
hotfix/4.2.0-polkaswap-usabilityat23ecb96e6, so until #1315 lands the diff against master includes it. The redesign alone is 239 files, +5,788 / -2,540.Target Branch
developmasterand is a release or hotfix PRThe head is named
release/*becausevalidateonly letsrelease/*andhotfix/*into master. It does not change the app version.Type of Change
Screenshots / Videos
Before and after screens are in the workspace at
build/mobile-redesign-20261108/:wide-wings-final-screens.png,ios-final-b16/andios-final-b17/. The commit, results and binary hashes are inFINAL-RECEIPT.jsonthere.Test Plan
Application and behavioral tests ran locally on
488fd4be7. The final headd3b3d5166adds only whitespace in one test file and explicitly records two generated TON documentation placeholders in the TODO baseline; app sources and test non-whitespace content are unchanged. On 10 November the retained summaries, logs, simulator binaries and screenshots were rechecked against their SHA-256 receipts (19/19 match).fearlessTests, iOS 27.0 simulatorAccountEvent.extrafrom the pinned TonAPI schema. Generated sources remain byte-identical; the audit still rejects new debt and crashing placeholders.Not verified: physical devices, a signed release build, and the full suite on iOS 18 (targeted classes only).
Risks & Rollout
hotfix/4.2.0-polkaswap-usability. This ships in the next version.