Skip to content

saline_sdk

Saline SDK: Official Python library for interacting with the Saline blockchain.

This package provides comprehensive tools and interfaces for developers to interact with the Saline blockchain network, including account management, transaction construction, and RPC communication.

Basic usage: from saline_sdk import Saline

# Initialize with node URL
saline = Saline(node_url="http://localhost:26657")

# Create a new account
mnemonic = saline.create_account()

# Or load an existing account
saline.load_account("your twelve word mnemonic phrase goes here")

saline_sdk.rpc.query_responses

Dataclasses for structured RPC query responses, using bindings.py types for intents.

ParsedIntentInfo Objects

python
@dataclass
class ParsedIntentInfo()

Holds information about a single intent fetched from the node.

addresses

Raw address list

raw_intent_data

Keep raw data for debugging

error

Parsing error message

ParsedAllIntentsResponse Objects

python
@dataclass
class ParsedAllIntentsResponse()

Wrapper for the result of get_all_intents.

ParsedWalletInfo Objects

python
@dataclass
class ParsedWalletInfo()

Structure holding parsed info from get_wallet_info.

balances

Assuming token -> amount mapping

raw_wallet_data

Keep raw data for debugging/completeness

error

Parsing error message

contains_binding_type

python
def contains_binding_type(node: Optional[Union[bindings.Intent,
                                               bindings.Expr]],
                          target_type: type) -> bool

(Optimized) Recursively check if an intent/expression tree contains a node of target_type.

parse_dict_to_binding_intent

python
def parse_dict_to_binding_intent(
        raw_intent_data: Any) -> Optional[bindings.Intent]

Attempts to parse a raw dictionary/list structure into an Intent object from bindings.py using its from_json methods.

Handles potential nesting in the raw data. Returns None if parsing fails or input is invalid.

saline_sdk.rpc.testnet.faucet

Testnet faucet utilities.

This module provides utilities for interacting with the Saline testnet faucet to obtain test tokens.

top_up

python
async def top_up(account: Any,
                 client: Client,
                 use_dynamic_amounts: bool = True,
                 wait_seconds: int = 3) -> Dict[str, int]

Requests tokens from the testnet faucet for the given account. Waits briefly, then returns the updated balances.

This function fetches the faucet's intent to determine dynamic token amounts (if requested) and then creates/submits a transaction signed by the target account to trigger the faucet transfer. After submission, it waits for wait_seconds and queries the account's new balances.

Arguments:

  • account - The Account or Subaccount object that will receive tokens and sign the request.
  • client - An initialized Client instance.
  • use_dynamic_amounts - Whether to use the amounts defined in the faucet intent (True) or use hardcoded amounts (False).
  • wait_seconds - Seconds to wait after submitting the transaction before querying balances.

Returns:

A dictionary representing the account's balances (token -> amount) after the faucet request. Returns an empty dictionary if balance retrieval fails.

Raises:

  • RPCError - If querying the faucet, parsing its intent (for dynamic amounts), or submitting the transaction fails.
  • ValueError - If the input account object is invalid.
  • KeyError - If an invalid token name is used (relevant for dynamic amounts).

saline_sdk.rpc.testnet

Testnet utilities for Saline SDK.

This module provides utilities for interacting with the Saline testnet.

saline_sdk.rpc.client

RPC client for interacting with Saline nodes.

This module provides a unified client for submitting transactions and querying the Saline network.

IMPORTANT: Saline nodes and Tendermint RPC endpoints have specific behaviors:

  1. Transaction Broadcasting:

    • broadcast_tx_commit and broadcast_tx_sync will return errors like "Failed decode: Error in $: not enough input" even for valid transactions if decoded incorrectly.
    • broadcast_tx_async is more permissive and will accept transactions, returning a transaction hash even if the transaction cannot be decoded.
  2. Transaction Format:

    • Transactions must be properly serialized as JSON and base64 encoded.
    • POST requests with parameters in the body are more reliable than GET requests with URL parameters.
  3. Error Handling:

    • Error responses often include hex-encoded error messages which need to be decoded for human readability.

Note on method naming conventions:

  • Transaction broadcasting methods use descriptive names (tx_fire, tx_broadcast, tx_commit) that match the behavior rather than the RPC endpoint names

Client Objects

python
class Client()

Unified client for interacting with Saline nodes.

Provides HTTP RPC connectivity to Saline nodes with functionality for:

  • Transaction broadcasting
  • Block and transaction querying
  • Balance querying
  • Intent querying and parsing
  • Wallet information retrieval
  • Aggregate balance queries

Methods are provided in both asynchronous and synchronous versions:

  • Asynchronous methods (default) have no suffix
  • Synchronous wrappers have the _sync suffix

Transaction broadcasting methods use descriptive names:

  • tx_fire: Fire-and-forget transaction (broadcast_tx_async RPC)
  • tx_broadcast: Submit and check transaction (broadcast_tx_sync RPC)
  • tx_commit: Submit and wait for block commit (broadcast_tx_commit RPC)

__init__

python
def __init__(http_url: str = "http://localhost:26657", debug: bool = False)

Initialize the client.

Arguments:

  • http_url - Base URL for HTTP RPC endpoints
  • debug - Enable debug logging

tx_fire

python
async def tx_fire(tx_bytes: str) -> Dict[str, Any]

Fire a transaction and return immediately (using broadcast_tx_async RPC).

Fire and forget - doesn't wait for any validation.

Arguments:

  • tx_bytes - Base64-encoded transaction bytes

Returns:

Transaction receipt with hash

tx_broadcast

python
async def tx_broadcast(tx_bytes: str) -> Dict[str, Any]

Broadcast a transaction and wait for validation (using broadcast_tx_sync RPC).

Submit and check - waits for the transaction to be validated but not committed.

Arguments:

  • tx_bytes - Base64-encoded transaction bytes

Returns:

Transaction receipt with validation results

tx_commit

python
async def tx_commit(tx_bytes: str) -> Dict[str, Any]

Broadcast a transaction and wait for it to be committed (using broadcast_tx_commit RPC).

Submit and wait - waits for the transaction to be committed.

Arguments:

  • tx_bytes - Base64-encoded transaction bytes

Returns:

Transaction receipt with commit results

get_block

python
async def get_block(height: Optional[int] = None) -> Dict[str, Any]

Get block at specified height or latest if not specified.

get_current_block

python
async def get_current_block() -> Dict[str, Any]

Get the current block.

get_transactions

python
async def get_transactions(
        height: Optional[int] = None) -> List[Dict[str, Any]]

Get transactions from a block at specified height or latest if not specified.

get_tx

python
async def get_tx(tx_hash: str) -> Dict[str, Any]

Get transaction by hash.

get_status

python
async def get_status() -> Dict[str, Any]

Get node status asynchronously.

Returns:

Node status information

abci_query_async

python
async def abci_query_async(path: str,
                           data: str,
                           height: int = 0,
                           prove: bool = False) -> Dict[str, Any]

Make a direct ABCI query asynchronously.

Arguments:

  • path - Query path (e.g., "/store/balance", "/store/intent")
  • data - Query data (hex-encoded)
  • height - Block height (0 for latest)
  • prove - Whether to include proofs

Returns:

Query result

get_balance_async

python
async def get_balance_async(address: str,
                            token: str = "USDC") -> Optional[float]

Get the balance of a specific token for an address asynchronously.

Arguments:

  • address - Account address to query
  • token - Token symbol (e.g., "USDC", "ETH")

Returns:

Balance amount or None if not found

get_all_balances_async

python
async def get_all_balances_async(address: str) -> Dict[str, float]

Get balances for all tokens for an address asynchronously.

Arguments:

  • address - Account address to query

Returns:

Dictionary mapping token symbols to balances

get_wallet_info_async

python
async def get_wallet_info_async(address: str) -> ParsedWalletInfo

Get wallet information for an address asynchronously.

This method retrieves comprehensive information about a wallet, including:

  • All token balances
  • The wallet's intent (parsed into an SDK Intent object)

Arguments:

  • address - Address to get wallet info for

Returns:

ParsedWalletInfo dataclass containing parsed balances and intent.

get_all_intents

python
async def get_all_intents() -> ParsedAllIntentsResponse

Get all intents in the system asynchronously.

This method queries the node for all registered intents and parses them into specialized Intent objects from the SDK. It handles various intent types including All, Any, Restriction, Finite, Temporary and Signature intents.

Returns:

ParsedAllIntentsResponse object containing a dictionary of ParsedIntentInfo objects.

saline_sdk.rpc.error

RPC error handling for Saline SDK.

RPCError Objects

python
class RPCError(Exception)

RPC-related error.

saline_sdk.rpc

RPC client for interacting with Saline nodes.

This package provides utilities for interacting with Saline nodes via RPC.

saline_sdk.crypto.bls

BLS signature implementation for Saline SDK.

This module provides BLS signature functionality using the BLS12-381 curve, following the IETF BLS signature standard draft v4 (basic scheme).

This implementation matches the implementation in Saline exactly:

  • Uses raw message bytes for signing (no pre-hashing)
  • Uses BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_ as domain parameter
  • Follows the same serialization format

BLS Objects

python
class BLS()

BLS signature implementation using the basic scheme.

sk_to_pk

python
@staticmethod
def sk_to_pk(sk: Union[bytes, PrivateKey]) -> bytes

Convert private key to public key bytes.

Arguments:

  • sk - Private key (bytes or PrivateKey object)

Returns:

  • bytes - Public key in compressed form

Raises:

  • ValueError - If conversion fails

sign

python
@staticmethod
def sign(sk: Union[bytes, PrivateKey],
         message: bytes,
         dst: Optional[bytes] = None) -> G2Element

Sign a message using BLS signature scheme.

Arguments:

  • sk - Private key (bytes or PrivateKey object)
  • message - Message to sign (raw bytes, NOT pre-hashed)
  • dst - Domain separation tag (default: SALINE_DOMAIN)

Returns:

Signature in compressed form

Raises:

  • ValueError - If signing fails

Notes:

This matches the implementation exactly:

  • Signs raw message bytes directly (no pre-hashing)
  • Uses BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_ domain parameter

verify

python
@staticmethod
def verify(pk_bytes: bytes, message: bytes, signature_bytes: bytes) -> bool

Verify a message signature using a public key.

Arguments:

  • pk_bytes - Public key bytes to verify with
  • message - Message that was signed
  • signature_bytes - Signature to verify

Returns:

True if signature is valid, False otherwise

aggregate_signatures

python
@staticmethod
def aggregate_signatures(signatures: list[bytes]) -> bytes

Aggregate multiple BLS signatures.

Arguments:

  • signatures - List of signatures in compressed form

Returns:

Aggregated signature in compressed form

Raises:

  • ValueError - If aggregation fails

verify_aggregate

python
@staticmethod
def verify_aggregate(signature: bytes, messages: list[bytes],
                     public_keys: list[bytes]) -> bool

Verify an aggregate signature.

Arguments:

  • signature - Aggregate signature in compressed form
  • messages - List of original messages (raw bytes, NOT pre-hashed)
  • public_keys - List of public keys in compressed form

Returns:

True if aggregate signature is valid

Notes:

BasicSchemeMPL.aggregate_verify() internally uses the domain parameter "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_" which matches Saline's.

saline_sdk.crypto.key_derivation

debug_print

python
def debug_print(*args, **kwargs)

Helper function for debug printing

hkdf_extract

python
def hkdf_extract(salt: bytes, ikm: bytes) -> bytes

HKDF-Extract (RFC5869) using SHA-256.

hkdf_expand

python
def hkdf_expand(prk: bytes, info: bytes, length: int = 32) -> bytes

HKDF-Expand (RFC5869) using SHA-256.

derive_master_SK

python
def derive_master_SK(seed: bytes) -> bytes

Derive master secret key from seed.

parent_SK_to_lamport_PK

python
def parent_SK_to_lamport_PK(parent_SK: bytes, index: int) -> bytes

Generate compressed Lamport public key from parent SK.

derive_child_SK

python
def derive_child_SK(parent_SK: bytes, index: int) -> bytes

Derive a child secret key from a parent secret key and index. parent_SK is in big-endian format (I2OSP).

derive_key_from_path

python
def derive_key_from_path(seed: bytes, path: str = "m/0") -> bytes

Derive a key from a seed and path. Path format: "m/0" for first child of master key.

saline_sdk.crypto

Saline SDK Crypto Module

This module provides cryptographic functionality for the Saline SDK, including:

  • BLS key derivation (EIP-2333)
  • BLS signatures
  • Signature verification
  • Signature aggregation
  • Public key operations

saline_sdk.transaction.tx

Transaction handling module for the Saline SDK.

This module provides functions for creating, signing, and encoding transactions for submission to the Saline network.

prepareSimpleTx

python
def prepareSimpleTx(signer: Union[Account, Subaccount],
                    tx: Transaction) -> str

Prepare a simple transaction by signing it with a generated nonce.

This is a convenience function that generates a nonce, signs the transaction, and encodes it in a single step.

Arguments:

  • signer - Account or Subaccount to sign with
  • tx - Transaction object to sign

Returns:

Base64 encoded transaction ready for submission

encodeSignedTx

python
def encodeSignedTx(signed: Signed) -> str

Encode a signed transaction for network submission.

Arguments:

  • signed - Signed transaction object

Returns:

Base64 encoded transaction string

sign

python
def sign(account: Union[Account, Subaccount], nonce: str,
         tx: Transaction) -> Signed

Sign a transaction with the given account and nonce.

Arguments:

  • account - Account or Subaccount to sign with
  • nonce - Unique nonce for this signature
  • tx - Transaction object to sign

Returns:

Signed transaction object

Raises:

  • AttributeError - If the account does not support signing

tx_is_accepted

python
def tx_is_accepted(result)

Determine if a Tendermint transaction was accepted.

A transaction is considered accepted if both 'check_tx' and 'deliver_tx' phases have a 'code' of 0, indicating success.

check_tx -> pre-flight - transaction is rejectd deliver_tx -> state changed - Transaction is recorded with failure status

Arguments:

  • result dict - The transaction result dictionary containing 'check_tx' and 'deliver_tx' entries.

Returns:

  • bool - True if both phases succeeded; False otherwise.

python
def print_tx_errors(result, label="Transaction")

Print error details from a Tendermint transaction result.

This function checks the 'check_tx' and 'deliver_tx' phases of a transaction result. If either phase has a non-zero 'code', it prints the phase, error code, and attempts to decode the 'data' field from Base64 to provide a human-readable error message.

Arguments:

  • result dict - The transaction result dictionary containing 'check_tx' and 'deliver_tx' entries.
  • label str - A label to identify the transaction in the output. Defaults to "Transaction".

Returns:

None

saline_sdk.transaction.instructions

Transaction instructions module for the Saline SDK.

This module provides helper functions for creating various transaction instructions that can be used when building transactions for the Saline network.

transfer

python
def transfer(sender: str, recipient: str, token: str,
             amount: Union[int, float]) -> TransferFunds

Create a transfer instruction for sending tokens.

Arguments:

  • sender - Sender's public key
  • recipient - Recipient's public key
  • token - Token identifier (e.g., "USDC", "BTC", "ETH")
  • amount - Amount to transfer (as integer for atomic units or float for decimal representation)

Returns:

TransferFunds instruction

Example:

transfer("sender_public_key", "recipient_public_key", "USDC", 100)

swap

python
def swap(sender: str, recipient: str, give_token: str,
         give_amount: Union[int, float], take_token: str,
         take_amount: Union[int, float]) -> List[TransferFunds]

Create a pair of instructions for a token swap.

Arguments:

  • sender - Sender's public key
  • recipient - Recipient's public key
  • give_token - Token to give (e.g., "USDC")
  • give_amount - Amount to give
  • take_token - Token to take (e.g., "BTC")
  • take_amount - Amount to take

Returns:

List of two transfer instructions that make up the swap

Example:

swap("alice_pk", "bob_pk", "USDC", 100, "BTC", 0.001)

set_intent

python
def set_intent(signer_pk: str,
               condition_type: str = "ConditionTag_Signature") -> List

Create an intent mask entry for authorizations.

Arguments:

  • signer_pk - Signer public key
  • condition_type - Condition tag type, defaults to signature-based authorization

Returns:

Intent mask entry for use in transactions

Example:

set_intent("signer_public_key")

saline_sdk.transaction.serialisation

Transaction encoding for Saline SDK.

This module handles transaction serialization for both network transmission and signature generation, specifically designed to match Saline's implementation's expectations.

serialize_for_network

python
def serialize_for_network(tx: dict) -> bytes

Serialize transaction for network submission.

Saline requires a hexadecimal encoding with fields in a specific order:

  1. Sort all nested dictionaries for deterministic output
  2. Convert to JSON with field ordering preserved
  3. Encode as hex (base16)

Arguments:

  • tx - Transaction dictionary

Returns:

Hex-encoded transaction bytes

decode_network_tx

python
def decode_network_tx(data: bytes) -> Dict[str, Any]

Decode a transaction received from the network.

Arguments:

  • data - The encoded transaction bytes

Returns:

Decoded transaction dictionary

Raises:

  • ValueError - If data is invalid

encode_base64

python
def encode_base64(data: bytes) -> str

Encode binary data as base64 string.

Arguments:

  • data - Binary data to encode

Returns:

Base64 encoded string

decode_base64

python
def decode_base64(data: str) -> bytes

Decode base64 string to binary data.

Arguments:

  • data - Base64 encoded string

Returns:

Decoded binary data

Raises:

  • ValueError - If input is not valid base64

saline_sdk.transaction.bindings

saline_sdk.transaction.bindings_docstrings

Documentation for the autogenerated bindings.py module.

This module contains documentation for the classes and functions defined in the autogenerated bindings.py file. These docstrings can be used by documentation generators to provide proper documentation for the bindings.py module without modifying the autogenerated file itself.

saline_sdk.transaction

saline_sdk.account

Account management for Saline SDK.

This module provides comprehensive account management for the Saline protocol, including both individual subaccounts (key pairs) and multi-account management.

Subaccount Objects

python
class Subaccount()

Individual Saline subaccount representing a single key pair. Handles cryptographic operations and always derived from an Account.

__init__

python
def __init__(private_key_bytes: bytes,
             public_key_bytes: Optional[bytes] = None,
             path: Optional[str] = None,
             label: Optional[str] = None)

Initialize a subaccount with private key bytes.

Arguments:

  • private_key_bytes - The private key in bytes
  • public_key_bytes - Optional public key bytes (will be derived if not provided)
  • path - Optional derivation path
  • label - Optional subaccount label

public_key

python
@property
def public_key() -> str

Get the public key as hex string.

sign

python
def sign(message: bytes) -> bytes

Sign a message with this subaccount's private key.

__str__

python
def __str__() -> str

String representation of the subaccount.

Account Objects

python
class Account()

High-level account management.

Acts as a container for subaccounts and provides a user-friendly interface for managing keys and performing wallet operations.

create

python
@classmethod
def create(cls) -> 'Account'

Create a new account with a random mnemonic.

from_mnemonic

python
@classmethod
def from_mnemonic(cls,
                  mnemonic: str,
                  base_path: str = "m/12381/997") -> 'Account'

Create an account from a mnemonic phrase.

Arguments:

  • mnemonic - 24-word mnemonic phrase
  • base_path - Optional base path for derivation (default: m/12381/997)

Returns:

Account instance

Raises:

  • ValueError - If the mnemonic is invalid or the base_path is invalid

__init__

python
def __init__()

Initialize an empty account.

create_subaccount

python
def create_subaccount(label: str, path: Optional[str] = None) -> Subaccount

Create a new subaccount.

Arguments:

  • label - Subaccount label
  • path - Optional derivation path (default: m/12381/997/0/0/{next_index})

Returns:

Created subaccount

Raises:

  • ValueError - If account not initialized or name exists

get_subaccount

python
def get_subaccount(label: str) -> Subaccount

Get a subaccount by label.

Arguments:

  • label - Subaccount label

Returns:

Subaccount instance

Raises:

  • KeyError - If subaccount not found

list_subaccounts

python
def list_subaccounts() -> Dict[str, str]

Get a list of all subaccounts.

Returns:

Dict mapping subaccount names to public keys

set_default_subaccount

python
def set_default_subaccount(label: str) -> None

Set the default subaccount.

Arguments:

  • label - Subaccount label

Raises:

  • KeyError - If subaccount not found

transfer

python
def transfer(to: str,
             amount: Union[int, float],
             currency: str = "USDC",
             from_subaccount: Optional[str] = None) -> bytes

Create a transfer transaction.

Arguments:

  • to - Recipient address (public key)
  • amount - Amount to transfer
  • currency - Currency to transfer (default: USDC)
  • from_subaccount - Source subaccount name (uses default if None)

Returns:

Signed transaction

Raises:

  • ValueError - If no source subaccount specified or found

__getitem__

python
def __getitem__(name: str) -> Subaccount

Dict-like access to subaccounts.

__contains__

python
def __contains__(name: str) -> bool

Check if subaccount exists.

__iter__

python
def __iter__()

Iterate over subaccount names.

__len__

python
def __len__() -> int

Number of subaccounts.

__str__

python
def __str__() -> str

String representation.