Skip to main content

nautilus_derive/signing/
mod.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Derive self-custodial action signing.
17//!
18//! Derive signs every state-changing request with an EIP-712 typed-data
19//! signature over secp256k1. V3 domains use Ethereum chain 1 or Sepolia chain
20//! 11155111, with the same Trade module on both networks. The pipeline is:
21//!
22//! ```text
23//! action_hash = keccak256(abi.encode(
24//!     [bytes32, uint, uint, address, bytes32, uint, address, address],
25//!     [ACTION_TYPEHASH, subaccount_id, nonce, module_address,
26//!      keccak256(module_data_abi_encoded), signature_expiry_sec, owner, signer],
27//! ))
28//! typed_data_hash = keccak256(0x1901 || DOMAIN_SEPARATOR || action_hash)
29//! signature = secp256k1_sign(typed_data_hash, signer_key)
30//! ```
31//!
32//! Per-action `module_data` ABI encodings live under [`modules`]. REST and
33//! WebSocket session authentication use the simpler `eth_sign(timestamp_ms)`
34//! pattern in [`auth`]. Per-`(wallet, subaccount)` nonce allocation lives in
35//! [`nonce`].
36//!
37//! The byte-equivalence oracle is
38//! `test_data/common/signing_trade_action_vectors.json`, generated by
39//! `scripts/oracle-py/derive/generate_oracle.py` from the upstream Python SDK at a
40//! revision and source hashes pinned in the fixture metadata, replayed against
41//! this implementation in [`eip712`] tests. The generator uses derive-py 0.1.4
42//! and independently checks the domain and Action typehash formulas. Attribution is
43//! recorded in `licenses/THIRD_PARTY_LICENSES.md`.
44//!
45//! Protocol constants (`DOMAIN_SEPARATOR`, `ACTION_TYPEHASH`, Trade module address)
46//! are sourced from <https://docs.derive.xyz/authentication/action-signing>.
47//! Financial inputs allow at most 12 fractional digits, but the canonical trade
48//! ABI still scales them by 1e18. Nonces are nanoseconds encoded as strings;
49//! login timestamps are milliseconds and signature expiry is seconds.
50
51pub mod auth;
52pub mod context;
53pub mod eip712;
54pub mod encoding;
55pub mod modules;
56pub mod nonce;