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
@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
@dataclass
class ParsedAllIntentsResponse()
Wrapper for the result of get_all_intents.
ParsedWalletInfo Objects
@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
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
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
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:
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.
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.
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
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__
def __init__(http_url: str = "http://localhost:26657", debug: bool = False)
Initialize the client.
Arguments:
http_url
- Base URL for HTTP RPC endpointsdebug
- Enable debug logging
tx_fire
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
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
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
async def get_block(height: Optional[int] = None) -> Dict[str, Any]
Get block at specified height or latest if not specified.
get_current_block
async def get_current_block() -> Dict[str, Any]
Get the current block.
get_transactions
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
async def get_tx(tx_hash: str) -> Dict[str, Any]
Get transaction by hash.
get_status
async def get_status() -> Dict[str, Any]
Get node status asynchronously.
Returns:
Node status information
abci_query_async
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
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 querytoken
- Token symbol (e.g., "USDC", "ETH")
Returns:
Balance amount or None if not found
get_all_balances_async
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
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
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
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
class BLS()
BLS signature implementation using the basic scheme.
sk_to_pk
@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
@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
@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 withmessage
- Message that was signedsignature_bytes
- Signature to verify
Returns:
True if signature is valid, False otherwise
aggregate_signatures
@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
@staticmethod
def verify_aggregate(signature: bytes, messages: list[bytes],
public_keys: list[bytes]) -> bool
Verify an aggregate signature.
Arguments:
signature
- Aggregate signature in compressed formmessages
- 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
def debug_print(*args, **kwargs)
Helper function for debug printing
hkdf_extract
def hkdf_extract(salt: bytes, ikm: bytes) -> bytes
HKDF-Extract (RFC5869) using SHA-256.
hkdf_expand
def hkdf_expand(prk: bytes, info: bytes, length: int = 32) -> bytes
HKDF-Expand (RFC5869) using SHA-256.
derive_master_SK
def derive_master_SK(seed: bytes) -> bytes
Derive master secret key from seed.
parent_SK_to_lamport_PK
def parent_SK_to_lamport_PK(parent_SK: bytes, index: int) -> bytes
Generate compressed Lamport public key from parent SK.
derive_child_SK
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
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
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 withtx
- Transaction object to sign
Returns:
Base64 encoded transaction ready for submission
encodeSignedTx
def encodeSignedTx(signed: Signed) -> str
Encode a signed transaction for network submission.
Arguments:
signed
- Signed transaction object
Returns:
Base64 encoded transaction string
sign
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 withnonce
- Unique nonce for this signaturetx
- Transaction object to sign
Returns:
Signed transaction object
Raises:
AttributeError
- If the account does not support signing
tx_is_accepted
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.
print_tx_errors
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
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 keyrecipient
- Recipient's public keytoken
- 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
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 keyrecipient
- Recipient's public keygive_token
- Token to give (e.g., "USDC")give_amount
- Amount to givetake_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
def set_intent(signer_pk: str,
condition_type: str = "ConditionTag_Signature") -> List
Create an intent mask entry for authorizations.
Arguments:
signer_pk
- Signer public keycondition_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
def serialize_for_network(tx: dict) -> bytes
Serialize transaction for network submission.
Saline requires a hexadecimal encoding with fields in a specific order:
- Sort all nested dictionaries for deterministic output
- Convert to JSON with field ordering preserved
- Encode as hex (base16)
Arguments:
tx
- Transaction dictionary
Returns:
Hex-encoded transaction bytes
decode_network_tx
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
def encode_base64(data: bytes) -> str
Encode binary data as base64 string.
Arguments:
data
- Binary data to encode
Returns:
Base64 encoded string
decode_base64
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
class Subaccount()
Individual Saline subaccount representing a single key pair. Handles cryptographic operations and always derived from an Account.
__init__
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 bytespublic_key_bytes
- Optional public key bytes (will be derived if not provided)path
- Optional derivation pathlabel
- Optional subaccount label
public_key
@property
def public_key() -> str
Get the public key as hex string.
sign
def sign(message: bytes) -> bytes
Sign a message with this subaccount's private key.
__str__
def __str__() -> str
String representation of the subaccount.
Account Objects
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
@classmethod
def create(cls) -> 'Account'
Create a new account with a random mnemonic.
from_mnemonic
@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 phrasebase_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__
def __init__()
Initialize an empty account.
create_subaccount
def create_subaccount(label: str, path: Optional[str] = None) -> Subaccount
Create a new subaccount.
Arguments:
label
- Subaccount labelpath
- 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
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
def list_subaccounts() -> Dict[str, str]
Get a list of all subaccounts.
Returns:
Dict mapping subaccount names to public keys
set_default_subaccount
def set_default_subaccount(label: str) -> None
Set the default subaccount.
Arguments:
label
- Subaccount label
Raises:
KeyError
- If subaccount not found
transfer
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 transfercurrency
- 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__
def __getitem__(name: str) -> Subaccount
Dict-like access to subaccounts.
__contains__
def __contains__(name: str) -> bool
Check if subaccount exists.
__iter__
def __iter__()
Iterate over subaccount names.
__len__
def __len__() -> int
Number of subaccounts.
__str__
def __str__() -> str
String representation.