-
Notifications
You must be signed in to change notification settings - Fork 70
feat: implemented nep-413 offchain messages signing #507
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Gmin2 This is a great progress!
Were you able to test all the signing flows end-to-end? Which Operating System do you have? (I will also do it on my side, but I'd like you to check it first unless you don't have Ledger device or system keychain)
@race-of-sloths invite
src/commands/mod.rs
Outdated
#[strum_discriminants(strum(message = "message - Sign an arbitrary message (NEP-413)"))] | ||
/// Sign an arbitrary message (NEP-413) | ||
Message(self::message::MessageCommand), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move it up - between "transaction" and "config"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in 9fb58cd
pub struct SignNep413 { | ||
#[interactive_clap(long)] | ||
/// A 32-byte nonce as a base64-encoded string: | ||
nonce: crate::types::base64_bytes::Base64Bytes, | ||
#[interactive_clap(long)] | ||
/// The recipient of the message (e.g. "alice.near" or "myapp.com"): | ||
recipient: String, | ||
#[interactive_clap(long)] | ||
/// Which account to sign the message with: | ||
signer_account_id: crate::types::account_id::AccountId, | ||
#[interactive_clap(subcommand)] | ||
message_type: self::message_type::MessageType, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the proposed design in #497 was following the general style of named arguments used everywhere else in the CLI and this implementation uses --long
parameters, which are generally only used for optional parameters.
- Let's use named args (you'll have to split it into intermediate structs)
- Let's move
signer_account_id
after the message (you will only be able to do that after you introduce the intermediate structs from step (1)) and name itsign-as
to align with how it is named when you sign a transaction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, here is the proposal in #497 that I liked:
near message sign-nep413
<"utf8" | "base64"> "<MESSAGE>" \
nonce "<BASE64_NONCE>" recipient "<RECIPIENT>" \
sign-as "<SIGNER_ACCOUNT_ID>" \
sign-with-keychain
This is the implemented:
near message sign-nep413 \
--nonce "$BASE64_NONCE" \
--recipient "myapp.com" \
--signer-account-id "your_account.near" \
utf8 "Hello, NEAR" \
sign-with-plaintext-private-key "$SECRET_KEY"
- The message is the most important thing and it is the first we want to prompt
- nonce and recipient are not optional, so they should have no
--
- The signer account must be followed by the signing options and should be named "sign-as" to match the other CLI commands
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
refactored in 9fb58cd
let nonce_bytes = scope.nonce.as_bytes(); | ||
if nonce_bytes.len() != 32 { | ||
return Err(color_eyre::eyre::eyre!( | ||
"Invalid nonce length: expected 32 bytes, got {}", | ||
nonce_bytes.len() | ||
)); | ||
} | ||
let mut nonce = [0u8; 32]; | ||
nonce.copy_from_slice(nonce_bytes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in 9fb58cd
@Gmin2 Thank you for your contribution! Your pull request is now a part of the Race of Sloths! Current status: executed
Your contribution is much appreciated with a final score of 13! @frol received 25 Sloth Points for reviewing and scoring this pull request. Congratulations @Gmin2! Your PR was highly scored and you completed another monthly streak! To keep your monthly streak make another pull request next month and get 8+ score for it What is the Race of SlothsRace of Sloths is a friendly competition where you can participate in challenges and compete with other open-source contributors within your normal workflow For contributors:
For maintainers:
Feel free to check our website for additional details! Bot commands
|
hey tested all of it just not tested the ledger one , i am on ubuntu |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds support for NEP-413 offchain message signing via a new message sign-nep413
CLI command.
- Introduces a
Nonce32
type for handling 32-byte nonces encoded as base64 - Implements the
sign_nep413_payload
function with Borsh serialization and hash prefixing - Adds interactive CLI flows for signing messages with seed phrases, private keys, keychains, Ledger devices, and access key files
Reviewed Changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 1 comment.
Show a summary per file
File | Description |
---|---|
src/types/nonce32_bytes.rs | Adds Nonce32 for base64-encoded 32-byte nonces |
src/types/mod.rs | Exposes nonce32_bytes module |
src/commands/mod.rs | Registers the top-level message subcommand |
src/commands/message/mod.rs | Defines MessageCommand and MessageActions with sign-nep413 |
src/commands/message/sign_nep413/mod.rs | Implements NEP413Payload , SignedMessage , and sign_nep413_payload |
src/commands/message/sign_nep413/nonce/mod.rs | Adds interactive step to collect a Nonce32 |
src/commands/message/sign_nep413/recipient/mod.rs | Adds interactive step to collect the message recipient |
src/commands/message/sign_nep413/message_type/mod.rs | Defines MessageType enum for UTF-8 or base64 input |
src/commands/message/sign_nep413/message_type/utf8.rs | Handles plain UTF-8 message input |
src/commands/message/sign_nep413/message_type/base64.rs | Handles base64 message input |
src/commands/message/sign_nep413/signer/mod.rs | Adds SignAs step to choose signer account |
src/commands/message/sign_nep413/signature_options/mod.rs | Defines SignWith enum for signing methods |
src/commands/message/sign_nep413/signature_options/sign_with_seed_phrase.rs | Implements signing via seed phrase |
src/commands/message/sign_nep413/signature_options/sign_with_private_key.rs | Implements signing via plaintext private key |
src/commands/message/sign_nep413/signature_options/sign_with_access_key_file.rs | Implements signing via access key file |
src/commands/message/sign_nep413/signature_options/sign_with_keychain.rs | Implements signing via OS keychain |
src/commands/message/sign_nep413/signature_options/sign_with_legacy_keychain.rs | Implements signing via legacy keychain |
src/commands/message/sign_nep413/signature_options/sign_with_ledger.rs | Implements signing via Ledger Nano device |
src/commands/account/mod.rs | Makes export_account public for keychain integration |
Cargo.toml | Adds borsh dependency for payload serialization |
Comments suppressed due to low confidence (9)
src/types/nonce32_bytes.rs:1
- Consider adding unit tests for
Nonce32::from_str
andDisplay
to verify correct base64 parsing/formatting and error conditions.
#[derive(Debug, Clone, Default)]
src/commands/message/sign_nep413/signature_options/sign_with_seed_phrase.rs:34
- Missing import for
serde_json
. Adduse serde_json;
(or the specific functions) at the top to avoid compile errors.
println!("{}", serde_json::to_string_pretty(&signed_message)?);
src/commands/message/sign_nep413/signature_options/sign_with_private_key.rs:26
- Missing import for
serde_json
. Adduse serde_json;
at the top to fix the unresolved name.
println!("{}", serde_json::to_string_pretty(&signed_message)?);
src/commands/message/sign_nep413/signature_options/sign_with_legacy_keychain.rs:40
- Missing import for
serde_json
. Adduse serde_json;
to ensureto_string_pretty
is in scope.
println!("{}", serde_json::to_string_pretty(&signed_message)?);
src/commands/message/sign_nep413/signature_options/sign_with_keychain.rs:31
- Missing import for
serde_json
. Adduse serde_json;
so the JSON serialization call compiles.
println!("{}", serde_json::to_string_pretty(&signed_message)?);
src/commands/message/sign_nep413/signature_options/sign_with_access_key_file.rs:36
- Missing import for
serde_json
. Adduse serde_json;
at the top to resolve this symbol.
println!("{}", serde_json::to_string_pretty(&signed_message)?);
src/commands/message/sign_nep413/signature_options/sign_with_ledger.rs:54
- Missing import for
serde_json
. Includeuse serde_json;
to fix the unresolved call.
println!("{}", serde_json::to_string_pretty(&signed_message)?);
src/commands/message/sign_nep413/signature_options/sign_with_seed_phrase.rs:7
- [nitpick] The seed phrase is sensitive and will be echoed in the terminal. Consider marking this input as secret (e.g., hidden/password input) to avoid exposing it on-screen.
master_seed_phrase: String,
src/commands/message/sign_nep413/signature_options/sign_with_private_key.rs:6
- [nitpick] The private key will be entered in plaintext. Consider hiding the input (password style) to prevent it from being displayed in the terminal.
pub private_key: crate::types::secret_key::SecretKey,
.to_bytes(), | ||
)); | ||
|
||
std::thread::sleep(std::time::Duration::from_secs(1)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Sleeping for a fixed duration may slow interactive use and is brittle. Consider polling or using an event to detect when the Ledger app is ready instead of an arbitrary sleep.
std::thread::sleep(std::time::Duration::from_secs(1)); | |
wait_for_ledger_ready(std::time::Duration::from_secs(10))?; |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@race-of-sloths score 13
## 🤖 New release * `near-cli-rs`: 0.21.0 -> 0.22.0 (⚠ API breaking changes) ### ⚠ `near-cli-rs` breaking changes ```text --- failure enum_no_repr_variant_discriminant_changed: enum variant had its discriminant change value --- Description: The enum's variant had its discriminant value change. This breaks downstream code that used its value via a numeric cast like `as isize`. ref: https://doc.rust-lang.org/reference/items/enumerations.html#assigning-discriminant-values impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.41.0/src/lints/enum_no_repr_variant_discriminant_changed.ron Failed in: variant TopLevelCommandDiscriminants::Config 5 -> 6 in /tmp/.tmphokuMN/near-cli-rs/src/commands/mod.rs:50 variant TopLevelCommandDiscriminants::Extensions 6 -> 7 in /tmp/.tmphokuMN/near-cli-rs/src/commands/mod.rs:54 variant TopLevelCommandDiscriminants::Config 5 -> 6 in /tmp/.tmphokuMN/near-cli-rs/src/commands/mod.rs:50 variant TopLevelCommandDiscriminants::Extensions 6 -> 7 in /tmp/.tmphokuMN/near-cli-rs/src/commands/mod.rs:54 --- failure enum_variant_added: enum variant added on exhaustive enum --- Description: A publicly-visible enum without #[non_exhaustive] has a new variant. ref: https://doc.rust-lang.org/cargo/reference/semver.html#enum-variant-new impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.41.0/src/lints/enum_variant_added.ron Failed in: variant CliTopLevelCommand:Message in /tmp/.tmphokuMN/near-cli-rs/src/commands/mod.rs:15 variant TopLevelCommandDiscriminants:Message in /tmp/.tmphokuMN/near-cli-rs/src/commands/mod.rs:45 variant TopLevelCommandDiscriminants:Message in /tmp/.tmphokuMN/near-cli-rs/src/commands/mod.rs:45 ``` <details><summary><i><b>Changelog</b></i></summary><p> <blockquote> ## [0.22.0](v0.21.0...v0.22.0) - 2025-07-21 ### Added - New "message sign-nep413" command - NEP-413 offchain messages signing ([#507](#507)) ### Fixed - Gracefully handle (Started, NotStarted) transaction status ([#510](#510)) ### Other - Removed dj8yfo from CODEOWNERS </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/).
Fixes #497