Files
wallet/Cargo.toml
T
grenadeandClaude Opus 5.5 7ddab3ebda
ci / gate (push) Failing after 1m22s
feat(near): wallet-near, shared with the sponsor, with NEP-366 delegate actions
The sponsor (#81) relays each wallet's NEAR legs as meta-transactions, so
it encodes, decodes and verifies the same bytes the wallet signs. Rather
than a second implementation in the observer, the NEP-649 key and the
transaction encoder move out of wallet-data into wallet-near: no I/O, no
dependency on wallet-core, a raw 64-byte seed in and its own error type.

New in it is delegate.rs:
- DelegateAction signs over SHA-256 of NEP-461's prefix (2^30 + 366)
  and its borsh, as nearcore 2.13's classic Delegate action (tag 8)
  wants.
- SignedDelegate::decode is the sponsor's side. It accepts only the
  shapes the wallet sends (function calls and transfers, from an
  ML-DSA-65 key) and refuses anything else, trailing bytes included.
- verify checks the signature under the empty context.
- A relayer wraps the result as Action::Delegate.

An ML-DSA-65 delegate action, relayed, was proven on mainnet once,
outside the repo: 2SVwJsa1seKQHvAJ2JCzaBvAq8cLfJSPJtppxkr9ahK4.

Refs #81, #74

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NUx7SPonBnB3ofU4mH41WT
2026-10-09 13:31:41 +03:00

92 lines
4.2 KiB
TOML

[workspace]
resolver = "3"
members = ["crates/*"]
[workspace.package]
version = "0.3.0"
edition = "2024"
rust-version = "1.88"
license = "GPL-3.0-or-later"
authors = ["Rob Thijssen <rob@lair.cafe>"]
repository = "https://git.lair.cafe/blackbeard/wallet"
[workspace.dependencies]
wallet-entities = { path = "crates/wallet-entities", version = "=0.3.0" }
wallet-core = { path = "crates/wallet-core", version = "=0.3.0" }
wallet-data = { path = "crates/wallet-data", version = "=0.3.0" }
wallet-near = { path = "crates/wallet-near", version = "=0.3.0" }
anyhow = "1"
async-trait = "0.1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "2"
tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "time"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
# Types in `wallet-entities` are exported to the webview as TypeScript so the
# UI and the Rust side never disagree about a field. See .cargo/config.toml.
ts-rs = { version = "10", features = ["serde-compat", "no-serde-warnings"] }
toml = "0.8"
zeroize = { version = "1", features = ["derive"] }
# Quantus's post-quantum primitives. The dilithium crate is the FIPS 204
# implementation the chain verifies against; hdwallet is the BIP32/39/44
# derivation for lattice keys; poseidon is the account-id hash.
qp-rusty-crystals-dilithium = { version = "4.1.1", default-features = false, features = ["ml-dsa-65", "ml-dsa-87"] }
qp-rusty-crystals-hdwallet = { version = "4.1.1", features = ["ml-dsa-65", "ml-dsa-87"] }
qp-poseidon-core = "3.1.0"
# SS58: blake2b-512 checksum and base58. Nothing else from sp-core is needed.
blake2 = { version = "0.10", default-features = false }
bs58 = "0.5"
# NEAR RPC carries transactions and view arguments as base64.
base64 = "0.22"
# NEAR (#74): NEP-649 is SLIP-10 over HMAC-SHA512; a transaction hash is
# SHA-256; an ML-DSA-65 key's on-chain handle is SHA3-256.
hmac = "0.12"
sha2 = "0.10"
sha3 = "0.10"
getrandom = "0.3"
# The quantus-cli keystore format: Argon2id (frozen m=19456,t=2,p=1) into
# AES-256-GCM. The versions are pinned to what the CLI itself uses.
argon2 = { version = "0.5", features = ["std"] }
aes-gcm = "0.10"
chrono = { version = "0.4", default-features = false, features = ["clock", "serde", "std"] }
directories = "6"
tempfile = "3"
# Mnemonics: the same bip39 the hdwallet crate pins, so validation and seed
# stretching cannot disagree about a phrase. The checkphrase crate is
# Quantus's human-readable address checksum; its wordlist is vendored.
bip39 = { version = "=2.2.2", features = ["zeroize"] }
qp-human-checkphrase = "2.2.1"
# subxt 0.44 is the version quantus-cli signs mainnet transactions with; its
# extension resolver skips extensions whose type is empty, which is how the
# chain's two custom extensions (Reversible, WormholeProofRecorder) are
# tolerated without a custom config. 0.51 will add a builder for them.
subxt = "0.44"
parity-scale-codec = { version = "3", features = ["derive"] }
hex = "0.4"
# `isolation`: the IPC isolation pattern (crates/wallet-app/isolation/index.html).
tauri = { version = "2", features = ["isolation"] }
tauri-build = { version = "2", features = ["isolation"] }
# Native file dialogs, for importing a quantus-cli wallet file. The only
# plugin so far; each one is a capability entry with a reason.
tauri-plugin-dialog = "2"
# Copying an address to the clipboard from the receive screen. Write only.
tauri-plugin-clipboard-manager = "2"
# History comes from blackbeard.observer over HTTPS; rustls, no system TLS, JSON only.
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] }
# The local history cache, so an account's past is readable with the network down.
rusqlite = { version = "0.40", features = ["bundled"] }
# Opening the explorer in the system browser. URLs only, allow-listed in the capability.
tauri-plugin-opener = "2"
# Updates for the AppImage, NSIS and dmg installs: minisign-verified manifests
# published with every release. dnf owns updates for the rpm, which opts out.
tauri-plugin-updater = "2"
# Relaunch after an accepted update; nothing else from it is granted.
tauri-plugin-process = "2"
[profile.release]
lto = "thin"
codegen-units = 1
strip = "debuginfo"