df-papertrade-core 0.0.11-beta

Papertrade SDK for Rust on df-hyperliquid-core: intents, relayer, live account, session keys, signed writes, deposits and exact venue math. Wasm-ready.
Documentation
//! The account's own wallet, for what a session key may not sign: registration, withdrawals,
//! staking and deposit sends. Every signature is recovered against the account's owner before
//! it is posted.

use std::future::Future;

use df_hyperliquid_core::account::{LocalKey, Signature};
use df_hyperliquid_core::utils::Address;

/// What a signature is for, so a confirmation can show it.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Purpose {
    /// Lets a session key trade for the wallet for 30 days. It can never withdraw, stake or
    /// claim.
    RegisterSessionKey,
    /// USDC from the venue to the wallet's own HyperCore spot account.
    Withdraw,
    Stake,
    Unstake,
    /// Distributed USDC rewards into the venue balance.
    Claim,
    /// A deposit's first send: USDC from the perp balance to spot.
    DepositToSpot,
    /// A deposit's send to the wallet's deposit address.
    Deposit,
}

/// One signature asked of the wallet.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SignRequest {
    pub purpose: Purpose,
    /// The EIP-712 typed data, as `eth_signTypedData_v4` takes it.
    pub json: String,
    /// The EIP-712 hash of `json`, the bytes signed, for signers that sign digests.
    pub digest: [u8; 32],
}

/// Why the wallet did not sign.
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum WalletError {
    #[error("declined in the wallet")]
    Declined,
    /// The wallet is on a different chain than the one signed for.
    #[error("the wallet is on chain {got}, and this is signed on {want}")]
    WrongChain { got: u64, want: u64 },
    #[error("the wallet could not sign: {0}")]
    Failed(String),
}

/// The account's own wallet. No `Send` bound, so it works in single-threaded browser wasm.
pub trait Wallet {
    fn address(&self) -> Address;

    fn sign(&self, request: &SignRequest) -> impl Future<Output = Result<Signature, WalletError>>;
}

/// An in-memory key used as the wallet, for tests and native tools.
pub struct LocalWallet(pub LocalKey);

impl std::fmt::Debug for LocalWallet {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_tuple("LocalWallet").field(&self.0.address()).finish()
    }
}

impl Wallet for LocalWallet {
    fn address(&self) -> Address {
        self.0.address()
    }

    fn sign(&self, request: &SignRequest) -> impl Future<Output = Result<Signature, WalletError>> {
        std::future::ready(self.0.sign_digest(&request.digest).map_err(|e| WalletError::Failed(e.to_string())))
    }
}

#[cfg(test)]
#[path = "tests/wallet.rs"]
mod tests;