Skip to content

feat(wallet)!: apply FRC-0102 envelope to sign/verify by default#7216

Open
0xDevNinja wants to merge 1 commit into
ChainSafe:mainfrom
0xDevNinja:0xdevninja/issue-6442-frc0102-wallet
Open

feat(wallet)!: apply FRC-0102 envelope to sign/verify by default#7216
0xDevNinja wants to merge 1 commit into
ChainSafe:mainfrom
0xDevNinja:0xdevninja/issue-6442-frc0102-wallet

Conversation

@0xDevNinja

@0xDevNinja 0xDevNinja commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary of changes

Reopens the work from #6967, which was closed for inactivity. Rebased on current main and the two outstanding review comments are addressed.

Changes introduced in this pull request:

  • forest-wallet sign and forest-wallet verify now apply the FRC-0102 signing envelope (0x19 || "Filecoin Signed Message:\n" || ascii(len(msg)) || msg) to the message by default.
  • A --raw flag on both sides reproduces the previous raw-bytes behaviour.
  • Fixes the sign/verify payload-shape mismatch in remote mode (wallet_sign now takes Vec<u8> and passes the payload through unchanged, so both paths operate on the same bytes).

Reference issue to close (if applicable)

Closes #6442

Other information and links

Follow-up from the review on #6967 (thanks @akaladarshi for the guidance there). Addressed both remaining comments:

  • Removed the now-unused Filsnap entry from .config/forest.dic (interoperating is still referenced in a doc comment, kept).
  • Collapsed the near-identical wrap_frc0102 unit tests into parametrized #[rstest] cases (envelope-shape cases and the length-boundary cases).

Change checklist

  • I have performed a self-review of my own code,
  • I have made corresponding changes to the documentation. All new code adheres to the team's documentation standards,
  • I have added tests that prove my fix is effective or that my feature works (if possible),
  • I have made sure the CHANGELOG is up-to-date. All user-facing changes should be reflected in this document.

Summary by CodeRabbit

  • New Features
    • forest-wallet sign and forest-wallet verify now apply the FRC-0102 signing envelope to messages by default.
    • Use the new --raw flag on either command to preserve the previous raw-bytes message behavior.
    • Message/signature inputs and outputs remain hex-based, with signatures returned as hex.
  • Chores
    • Updated the onboarded dictionary word list.

@0xDevNinja 0xDevNinja requested a review from a team as a code owner June 22, 2026 10:17
@0xDevNinja 0xDevNinja requested review from LesnyRumcajs and hanabi1224 and removed request for a team June 22, 2026 10:17
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0184b347-cdf1-44b0-8ade-96e36eed0fcd

📥 Commits

Reviewing files that changed from the base of the PR and between 2f54633 and 04acdf6.

📒 Files selected for processing (3)
  • .config/forest.dic
  • CHANGELOG.md
  • src/wallet/subcommands/wallet_cmd.rs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • filecoin-project/lotus (manual)
✅ Files skipped from review due to trivial changes (2)
  • .config/forest.dic
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/wallet/subcommands/wallet_cmd.rs

Walkthrough

Adds FRC-0102 signing envelope support to forest-wallet sign and forest-wallet verify. Both commands now wrap messages by default, with --raw preserving prior raw-bytes behavior. wallet_sign now accepts raw message bytes directly.

Changes

FRC-0102 Envelope in forest-wallet

Layer / File(s) Summary
Envelope helper and byte signing
src/wallet/subcommands/wallet_cmd.rs
Adds FRC_0102_FILECOIN_PREFIX, rewrites wrap_frc0102 to build `prefix
Sign and verify command flow
src/wallet/subcommands/wallet_cmd.rs
Adds --raw to sign and verify, and updates command handling to hex-decode inputs, optionally apply wrap_frc0102, and pass bytes to signing or verification.
Tests, changelog, and dictionary
src/wallet/subcommands/wallet_cmd.rs, CHANGELOG.md, .config/forest.dic
Adds rstest coverage for envelope edge cases and a wrapped-bytes secp256k1 roundtrip test, updates the changelog, and adds interoperating to the dictionary.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • hanabi1224
  • LesnyRumcajs
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly states the wallet signing change and default FRC-0102 behavior.
Linked Issues check ✅ Passed The PR implements the FRC-0102 envelope, adds tests, and updates docs as required by #6442.
Out of Scope Changes check ✅ Passed The changes stay focused on wallet signing/verification, tests, docs, and minor repo housekeeping.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/wallet/subcommands/wallet_cmd.rs (2)

810-813: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Avoid direct slicing in tests; use .get() to prevent panic-style failures.

Line 810 through Line 813 use direct range slicing. Switching to .get() keeps failures explicit and follows the repository Rust safety rule.

Suggested patch
-    use super::{SignatureType, resolve_method_num, resolve_target_address, wrap_frc0102};
+    use super::{
+        FRC_0102_FILECOIN_PREFIX, SignatureType, resolve_method_num, resolve_target_address,
+        wrap_frc0102,
+    };
@@
-        assert_eq!(&wrapped[..26], b"\x19Filecoin Signed Message:\n");
-        assert_eq!(&wrapped[26..26 + digits.len()], digits.as_bytes());
-        assert_eq!(&wrapped[26 + digits.len()..], msg.as_slice());
+        let prefix_len = FRC_0102_FILECOIN_PREFIX.len();
+        assert_eq!(
+            wrapped
+                .get(..prefix_len)
+                .expect("wrapped message shorter than FRC-0102 prefix"),
+            FRC_0102_FILECOIN_PREFIX
+        );
+        let digits_end = prefix_len + digits.len();
+        assert_eq!(
+            wrapped
+                .get(prefix_len..digits_end)
+                .expect("wrapped message missing encoded length"),
+            digits.as_bytes()
+        );
+        assert_eq!(
+            wrapped
+                .get(digits_end..)
+                .expect("wrapped message missing payload"),
+            msg.as_slice()
+        );

As per coding guidelines, **/*.rs: "Use .get() instead of direct indexing [index] to avoid panics".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/wallet/subcommands/wallet_cmd.rs` around lines 810 - 813, Replace the
direct range slicing operations on the wrapped variable with the safer `.get()`
method to avoid panic-style failures. In the test assertions (lines checking
wrapped[..26], wrapped[26..26 + digits.len()], and wrapped[26 +
digits.len()..]), convert each direct slice access to use `.get()` with
appropriate range parameters, and handle the Result type by unwrapping or
matching on the returned Option to maintain the assertion logic while following
the repository's Rust safety guidelines.

Source: Coding guidelines


169-177: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Add operation context to local signing errors.

Line 171 and Line 173 propagate errors without local operation context, which makes CLI failures harder to diagnose.

Suggested patch
     async fn wallet_sign(&self, address: Address, message: Vec<u8>) -> anyhow::Result<Signature> {
         if let Some(keystore) = &self.local {
-            let key = crate::key_management::try_find_key(&address, keystore)?;
+            let key = crate::key_management::try_find_key(&address, keystore)
+                .with_context(|| format!("failed to find local key for address {address}"))?;
 
             Ok(crate::key_management::sign(
                 *key.key_info.key_type(),
                 key.key_info.private_key(),
                 &message,
-            )?)
+            )
+            .with_context(|| format!("failed to sign message with address {address}"))?)
         } else {
             Ok(WalletSign::call(&self.remote, (address, message)).await?)
         }
     }

As per coding guidelines, **/*.rs: "Use anyhow::Result<T> for most operations and add context with .context() when errors occur".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/wallet/subcommands/wallet_cmd.rs` around lines 169 - 177, The wallet_sign
function propagates errors from try_find_key and crate::key_management::sign
without providing operational context, making CLI failures difficult to
diagnose. Add error context using the .context() method to both the try_find_key
call (which finds the key by address) and the sign call (which performs the
actual signing operation) with descriptive messages that explain what operation
was being attempted when the error occurred.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/wallet/subcommands/wallet_cmd.rs`:
- Around line 810-813: Replace the direct range slicing operations on the
wrapped variable with the safer `.get()` method to avoid panic-style failures.
In the test assertions (lines checking wrapped[..26], wrapped[26..26 +
digits.len()], and wrapped[26 + digits.len()..]), convert each direct slice
access to use `.get()` with appropriate range parameters, and handle the Result
type by unwrapping or matching on the returned Option to maintain the assertion
logic while following the repository's Rust safety guidelines.
- Around line 169-177: The wallet_sign function propagates errors from
try_find_key and crate::key_management::sign without providing operational
context, making CLI failures difficult to diagnose. Add error context using the
.context() method to both the try_find_key call (which finds the key by address)
and the sign call (which performs the actual signing operation) with descriptive
messages that explain what operation was being attempted when the error
occurred.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e3acfb8d-f708-4316-81f0-e9990ea3d88a

📥 Commits

Reviewing files that changed from the base of the PR and between 9aa6f70 and 0874419.

📒 Files selected for processing (3)
  • .config/forest.dic
  • CHANGELOG.md
  • src/wallet/subcommands/wallet_cmd.rs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • filecoin-project/lotus (manual)

@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 65.38462% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.01%. Comparing base (1062edb) to head (2f54633).
⚠️ Report is 12 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/wallet/subcommands/wallet_cmd.rs 65.38% 9 Missing ⚠️
Additional details and impacted files
Files with missing lines Coverage Δ
src/wallet/subcommands/wallet_cmd.rs 29.15% <65.38%> (+2.60%) ⬆️

... and 11 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1062edb...2f54633. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@0xDevNinja 0xDevNinja force-pushed the 0xdevninja/issue-6442-frc0102-wallet branch from 0874419 to 2f54633 Compare June 24, 2026 08:12
Comment thread CHANGELOG.md Outdated

- [#7164](https://github.com/ChainSafe/forest/issues/7164): JSON-RPC authentication is now performed once per connection (e.g. at the WebSocket upgrade) instead of on every request, matching Lotus. Note that token expiry is no longer re-checked for the lifetime of an established connection.

- [#6442](https://github.com/ChainSafe/forest/issues/6442): `forest-wallet sign` and `forest-wallet verify` now apply the FRC-0102 signing envelope to the message by default. Pass `--raw` on both sides to reproduce the previous raw-bytes behaviour.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move that to the current release train

@LesnyRumcajs

Copy link
Copy Markdown
Member

LGTM, just please update the changelog.

`forest-wallet sign` and `forest-wallet verify` now wrap the decoded
message with the FRC-0102 Filecoin signing envelope
(`\x19Filecoin Signed Message:\n<len>`) before handing it to the signer
/ verifier. This aligns Forest with the Ledger Filecoin app, Filsnap,
iso-filecoin and Lotus (filecoin-project/lotus#13388), so signatures
produced by any of these wallets over the same bytes now round-trip.

A new `--raw` flag restores the prior raw-bytes behaviour on both
commands. `--raw` is also the correct choice when signing on-chain
Filecoin messages, which must not be wrapped.

The envelope is applied client-side only; the Forest and Lotus
`WalletSign` / `WalletVerify` RPCs treat their input as opaque bytes,
so a single wrap here is correct against today's daemons.

BREAKING CHANGE: signatures produced by the default invocation are not
verifiable by pre-FRC-0102 Forest or Lotus releases without `--raw` on
the verifier side.

Refs ChainSafe#6442
@0xDevNinja 0xDevNinja force-pushed the 0xdevninja/issue-6442-frc0102-wallet branch from 2f54633 to 04acdf6 Compare June 26, 2026 06:57
@0xDevNinja

Copy link
Copy Markdown
Contributor Author

Done — moved the entry up to the unreleased train. Thanks for the review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement FRC-102 in forest-wallet for consistency across Filecoin wallets

2 participants