crypto — Wallets and signing¶
This module implements key generation, message signing, and external signer support for the O2 Exchange SDK.
See also
The O2 Exchange uses a specific on-chain signing format documented at https://docs.o2.app. The SDK handles this format automatically.
Signer protocol¶
- class o2_sdk.crypto.Signer[source]¶
Protocol for objects that can sign messages for the O2 Exchange.
Both
WalletandEvmWalletsatisfy this protocol. For external signing (hardware wallets, AWS KMS, HSMs), useExternalSignerorExternalEvmSigner, or implement this protocol directly.
Wallet classes¶
- class o2_sdk.crypto.Wallet[source]¶
A Fuel-native wallet. Satisfies the
Signerprotocol.- personal_sign(message)[source]¶
Sign using Fuel’s
personalSignformat.Uses
fuel_personal_sign_digest()for message framing andfuel_compact_sign()for signing.
- class o2_sdk.crypto.EvmWallet[source]¶
An EVM-compatible wallet with B256 zero-padded address. Satisfies the
Signerprotocol.- personal_sign(message)[source]¶
Sign using Ethereum’s
personal_signformat.Uses
evm_personal_sign_digest()for message framing andfuel_compact_sign()for signing.
Wallet generation and loading¶
- o2_sdk.crypto.generate_wallet()[source]¶
Generate a new Fuel-native wallet with a random private key.
- o2_sdk.crypto.generate_evm_wallet()[source]¶
Generate a new EVM-compatible wallet with a random private key.
- o2_sdk.crypto.load_wallet(private_key_hex)[source]¶
Load a Fuel-native wallet from a hex-encoded private key.
- o2_sdk.crypto.load_evm_wallet(private_key_hex)[source]¶
Load an EVM-compatible wallet from a hex-encoded private key.
- o2_sdk.crypto.generate_keypair()[source]¶
Generate a secp256k1 keypair and derive the Fuel B256 address.
This is a low-level function; prefer
generate_wallet()for most use cases.
- o2_sdk.crypto.generate_evm_keypair()[source]¶
Generate a secp256k1 keypair with EVM address derivation.
This is a low-level function; prefer
generate_evm_wallet()for most use cases.
Digest helpers¶
These functions compute the message digest for each signing scheme without
performing the actual ECDSA signing. They are the single source of truth
for message framing and are used internally by all personal_sign
methods (Wallet, EvmWallet, ExternalSigner,
ExternalEvmSigner) and the module-level convenience functions.
- o2_sdk.crypto.fuel_personal_sign_digest(message)[source]¶
Compute the Fuel
personalSigndigest.Constructs:
SHA-256(b"\x19Fuel Signed Message:\n" + str(len(message)) + message)
and returns the 32-byte digest.
Signing functions¶
- o2_sdk.crypto.fuel_compact_sign(private_key_bytes, digest)[source]¶
Sign a 32-byte digest and return a 64-byte Fuel compact signature.
The Fuel compact signature format embeds the recovery ID in the MSB of byte 32 (first byte of
s):s[0] = (recovery_id << 7) | (s[0] & 0x7F)
The result is
r(32 bytes) + s(32 bytes) = 64 bytes.
- o2_sdk.crypto.personal_sign(private_key_bytes, message_bytes)[source]¶
Sign a message using Fuel’s
personalSignformat.Used for session creation and withdrawals with Fuel-native wallets. Delegates to
fuel_personal_sign_digest()for framing andfuel_compact_sign()for signing.
- o2_sdk.crypto.raw_sign(private_key_bytes, message_bytes)[source]¶
Sign a message using raw SHA-256 (no prefix).
Used for session actions (orders, cancels, settlements).
Format:
fuel_compact_sign(key, sha256(msg))
- o2_sdk.crypto.evm_personal_sign(private_key_bytes, message_bytes)[source]¶
Sign using Ethereum’s
personal_signprefix + keccak-256.Used for session creation and withdrawals with EVM wallets. Delegates to
evm_personal_sign_digest()for framing andfuel_compact_sign()for signing.
External signer support¶
For production deployments where private keys are managed by hardware wallets, AWS KMS, Google Cloud KMS, HashiCorp Vault, or other secure enclaves, use the external signer classes.
- o2_sdk.crypto.SignDigestFn¶
Type alias for external signing callbacks.
SignDigestFn = Callable[[bytes], bytes]
The callback receives a 32-byte digest and must return a 64-byte Fuel compact signature. Use
to_fuel_compact_signature()to convert from standard(r, s, recovery_id)components.
- o2_sdk.crypto.to_fuel_compact_signature(r, s, recovery_id)[source]¶
Convert standard
(r, s, recovery_id)components to a 64-byte Fuel compact signature.This is a helper for implementing
SignDigestFncallbacks when your external signing service returns standard secp256k1 components.- Parameters:
- Returns:
64-byte Fuel compact signature.
- Return type:
- Raises:
ValueError – If
rorsis not 32 bytes, orrecovery_idis not 0 or 1.
def my_kms_sign(digest: bytes) -> bytes: r, s, v = kms_client.sign(digest) return to_fuel_compact_signature(r, s, v)
- class o2_sdk.crypto.ExternalSigner(b256_address, sign_digest)[source]¶
A Fuel-native signer backed by an external signing function.
The SDK uses
fuel_personal_sign_digest()internally for message framing; your callback only needs to sign a raw 32-byte digest.- Parameters:
b256_address (str) – The Fuel B256 address for this signer.
sign_digest (
SignDigestFn) – A callback that signs a 32-byte digest and returns a 64-byte Fuel compact signature.
from o2_sdk import ExternalSigner, to_fuel_compact_signature def kms_sign(digest: bytes) -> bytes: r, s, v = my_kms.sign(key_id="...", digest=digest) return to_fuel_compact_signature(r, s, v) signer = ExternalSigner( b256_address="0x1234...abcd", sign_digest=kms_sign, ) session = await client.create_session(owner=signer, markets=["fFUEL/fUSDC"])
- class o2_sdk.crypto.ExternalEvmSigner(b256_address, evm_address, sign_digest)[source]¶
An EVM signer backed by an external signing function.
Same as
ExternalSignerbut usesevm_personal_sign_digest()for Ethereumpersonal_signmessage framing (prefix + keccak-256 hashing).- Parameters:
b256_address (str) – The Fuel B256 address (EVM address zero-padded).
evm_address (str) – The Ethereum address.
sign_digest (
SignDigestFn) – A callback that signs a 32-byte digest.
from o2_sdk import ExternalEvmSigner, to_fuel_compact_signature signer = ExternalEvmSigner( b256_address="0x000000000000000000000000abcd...1234", evm_address="0xabcd...1234", sign_digest=kms_sign, )