Tags: trustwallet/wallet-core
Tags
feat(solana): add off-chain message signing and structured messages (#… …4879) * feat(solana): sign messages as Solana off-chain messages MessageSigningInput and MessageVerifyingInput gain a MessageType: `raw`, the unwrapped UTF-8 bytes this coin has always signed, and `offchain_v0`, the Solana Off-Chain Message Signing standard, header version 0 — plus the 32-byte application domain that header carries, which is what stops a signature over one application's messages verifying against another's. The message itself moves into a `message_payload` oneof. `message` keeps its field number and type, so nothing changes on the wire and C++, Java and Swift keep their generated `message` accessors. The second variant is a StructuredMessage — a bare header line, ordered "label: value" lines and a closing statement — which this library renders so that every platform produces the same bytes from the same fields. The envelope and the body are independent choices: either message type can carry either payload. Two guards are not incidental. The renderer refuses a control character or a Unicode line separator anywhere in a rendered line, because a value carrying a newline forges further labeled lines in the message a user is about to approve, under a signature that is perfectly genuine. And the body length is checked before the u16 length field is written, so a body over 64 KiB cannot wrap it into a plausible-looking value. OffchainMessageSigner becomes SolanaMessageSigner. It never implemented the off-chain standard — it signed raw bytes, as its own doc comment said — and the name is needed for the type that does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(solana): cross-check the off-chain encoding against the Identity fixtures The six fixtures are copied verbatim from the Identity service (internal/domain/signing/solana/testdata in backend-identity), which rebuilds these exact bytes server-side and verifies the signature against them. They are the contract between the two implementations: signing each one here must reproduce its envelope, its sha256 content digest and its signature, so a drift on either side fails in CI rather than reaching production as an unexplainable signature mismatch. Around that: the rendered body pinned per message type, the header asserted field by field rather than round-tripped through our own encoder, nine forged-line cases, the 1147-byte body cap and the u16 wrap, a missing or wrong-length application domain, another signer's envelope, a different application domain, and raw signing a structured body. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Change message field number in Solana.proto Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * feat(solana): choose the off-chain message format, and close review findings MessageSigningInput and MessageVerifyingInput gain a MessageFormat, so the format byte in the off-chain header is the caller's choice: `utf8`, what a body of labeled lines needs, and `restricted_ascii`, printable ASCII only and the one format a hardware wallet renders instead of blind-signing. The enum's numbering is not the standard's — the standard writes ASCII as 0 and UTF-8 as 1, and `MessageFormat_utf8` sits at 0 here so that an input naming no format keeps signing the bytes it signed before the field existed. One `From` impl is the only place the two numberings meet. Restricted ASCII is checked against the body rather than trusted: a byte outside 0x20..=0x7e is refused, naming the character, because the format byte is a claim about those bytes and a wallet that believes it would render something else. A newline is outside that range, so a StructuredMessage of more than one line cannot be signed as restricted ASCII, which is a refusal and not a silent mislabel. The format is never derived from the body the way solana_sdk derives it: editing "hello" to "héllo" would otherwise move a byte that is inside the signature. Three findings from the review of this branch: `message_preimage_hashes` no longer requires the private key it cannot have. External signing is the flow the method exists for, so MessageSigningInput gains a `public_key`, which is enough to name the signer the off-chain header states; `MessageType_raw` needs neither key, and asking for an envelope with no key at all now says which field to set instead of reporting an invalid private key. `MessageType_raw` refuses an application domain or a format instead of dropping it. Raw is the proto3 default, so an input that sets a header field and forgets the type was being signed without it — a signature that looks fine and fails at whatever rebuilds the envelope, indistinguishable from a wrong key. And the layout is documented for what it is: the off-chain message signing proposal's 85-byte preamble, not `solana_sdk`'s shipped 20-byte one, which carries no application domain and no signer list. These signatures do not verify with `solana verify-offchain-signature` and a Ledger cannot produce them; what they interoperate with is a service that rebuilds this layout. Field 6 of MessageVerifyingInput is held reserved. It was `string message` for part of this branch's review, and an encoder generated from that revision would put a string where a later field is read. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(solana): don't read a private key a raw pre-image never needed `message_preimage_hashes` parsed `private_key` before it knew which message type it was building, so a raw pre-image with an absent or malformed key returned Error_invalid_private_key. Before the off-chain types existed the method never read the key at all — 60ef068 shipped it returning the message bytes and nothing else, with no error path — so this rejected inputs that released versions accept. External signing, which is the flow the method exists for, is exactly the caller with no key to offer. The key is now read only for MessageType_offchain_v0, the one type that states a signer inside the signed bytes. Raw signs the body and nothing else, so it goes back to ignoring whatever is in the field. Found auditing 63b34db against master for backward compatibility, and pinned by a test that asserts both an absent and a malformed key still produce a raw pre-image. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(ci): let bc-risk-router comment on a pull request scan-and-flag has failed on every pull_request run since #4854 gave it contents: read + issues: write. Commenting on a pull request through POST /issues/{n}/comments needs pull-requests: write — issues: write covers real issues only — so the API answers 403 "Resource not accessible by integration" and the step dies. The run log shows the token it was handed: Contents: read, Issues: write, Metadata: read. check-binary-sizes in rust.yml posts its comment on the same event with pull-requests: write, which is the only difference between the two. Adds that one permission, leaving the rest of #4854's per-job hardening alone. verify-bc-check-comment still only reads. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(solana): clarify message signing requirements in comments --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
ci: update pinned rustup installer checksum (#4864) The sha256 pinned in #4837 no longer matches the script served by https://sh.rustup.rs — rustup rotated it upstream, so every Docker build since 4061646 has failed at the checksum step: expected 6c30b75a75b28a96fd913a037c8581b580080b6ee9b8169a3c0feb1af7fe8caf actual 7d0ea0f8eba7fa1ebfe998091cd7ec4501e33ec5ca6b884eb4d894d7da5170af Nothing in the repo caused this; the first failing commit only touched Sonar config. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
fix: update key retrieval methods to return nullable types on failure (… …#4849) * fix: update key retrieval methods to return nullable types on failure * fix: update HD wallet key retrieval methods to return nullable types on failure * fix: ensure extended key retrieval methods return non-optional types
fix(thorchain): prevent uncaught exception crossing C ABI in swap bui… …lder (#4840) * fix(thorchain): prevent uncaught exception crossing C ABI in swap builder Malformed numeric amount fields (non-numeric or overflowing from_amount, to_amount_limit, or stream interval/quantity) made uint256_t()/std::stoull() throw; the exception escaped the extern "C" TWTHORChainSwapBuildSwap boundary and called std::terminate — a remotely-triggerable DoS (CWE-248). - Validate numeric amount fields in SwapBuilder::build(), returning an error code instead of parsing malformed input - Remove noexcept from buildMemo so a stoull throw can no longer terminate before the FFI catch runs - Wrap the TWTHORChainSwapBuildSwap FFI entry in try/catch as a backstop - Add C++ unit + FFI regression tests for malformed/overflow amounts Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(thorchain): enhance validation for from_amount to prevent leading zeros and overflow --------- Co-authored-by: PandaXadnaP <251992235+PandaXadnaP@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
feat: add native token name support to CoinInfo structure and related… … functions (#4831) * feat: add native token name support to CoinInfo structure and related functions * test: add unit tests for native token name behavior in iOS, Android, WASM
[sc-144760] [sc-144909]: Fix Stellar and NEAR handling wrong input pa… …rameters (#4812) * fix(stellar): Validate memo_hash and memo_return_hash sizes to 32 bytes * fix(stellar): Improve memo hash validation and error handling * fix(stellar): Refactor error handling and result types for memo validation * fix(stellar): Fix C++ unit tests * fix(stellar): Fix serialization in TransactionCompilerTests * fix(stellar+near): Enhance error handling for transaction data and signature preimage * fix(stellar): Improve error handling for invalid public key type in Signer * fix(stellar): Add tests for invalid memo handling in AnySigner * fix(near): Refactor serialization functions to return SigningResult for better error handling
PreviousNext