Quickstart

This guide will help you get started with the Saline SDK quickly.

Basic Usage

Initialize the SDK Client

To interact with the Saline network, you need to initialize an RPC client:

from saline_sdk.rpc.client import Client

# Initialize the client with your node connection
rpc_url = "https://node0.try-saline.com"
client = Client(http_url=rpc_url)

# Check connection (optional but recommended)
try:
    status = client.get_status() # Synchronous call
    print(f"Connected to Saline node network: {status['node_info']['network']}!")
except Exception as e:
    print(f"Failed to connect or get status: {e}")

Working with Accounts

Accounts manage your keys and identities.

from saline_sdk.account import Account

# Create a new root account (holds the mnemonic)
root_account = Account.create()
print(f"Save this mnemonic safely: {root_account.mnemonic}")

# Or load an existing account from mnemonic
# root_account = Account.from_mnemonic("your twelve word mnemonic phrase goes here")

# Create subaccounts (derived wallets)
subaccount = root_account.create_subaccount("my_subaccount")
print(f"Subaccount public key: {subaccount.public_key}")

Checking Balances

Use the client to query balances for a specific public key. Requires an async context.

import asyncio
from saline_sdk.rpc.client import Client
from saline_sdk.account import Account

# Assume client and subaccount are initialized as shown above
# rpc_url = "http://localhost:26657"
# client = Client(http_url=rpc_url)
# root_account = Account.create()
# subaccount = root_account.create_subaccount(label="my_subaccount")

async def check_balances(client: Client, address: str):
    print(f"Checking balances for {address[:10]}...")
    try:
        # get_wallet_info_async is an async function
        wallet_info = await client.get_wallet_info_async(address)
        balances = wallet_info.get('balances', []) if wallet_info else []
        print(f"Balances: {balances}")
    except Exception as e:
        print(f"Could not retrieve balances: {e}")

# Example usage within an async main function
async def main():
    rpc_url = "https://node0.try-saline.com"
    client = Client(http_url=rpc_url)
    root_account = Account.create()
    subaccount = root_account.create_subaccount(label="my_subaccount")
    # Need to fund the account first to see balances, e.g., via faucet
    await check_balances(client, subaccount.public_key)

if __name__ == "__main__":
    # Run the async function
    asyncio.run(main())

Creating and Signing Transactions

Transactions are built using instructions from saline_sdk.transaction.bindings. prepareSimpleTx helps sign transactions easily for single-signer scenarios.

import asyncio
from saline_sdk.rpc.client import Client
from saline_sdk.account import Account
from saline_sdk.transaction.bindings import Transaction, TransferFunds, NonEmpty
# prepareSimpleTx is sufficient for basic signing
from saline_sdk.transaction.tx import prepareSimpleTx
import json # For printing results

# Assume client and subaccount are initialized
# rpc_url = "http://localhost:26657"
# client = Client(http_url=rpc_url)
# root_account = Account.create()
# subaccount = root_account.create_subaccount(label="sender")

async def create_and_send_tx(client: Client, sender_account: Account):
    # Create a transaction with a transfer instruction
    transfer_instruction = TransferFunds(
        source=sender_account.public_key, # The sender's public key
        target="destination_public_key...", # Replace with actual destination PK
        funds={"USDC": 100} # Dictionary of token strings to amounts
    )
    tx = Transaction(instructions=NonEmpty.from_list([transfer_instruction]))

    # Sign the transaction using the subaccount's key
    # prepareSimpleTx handles nonce and signature generation
    print("Signing transaction...")
    signed_tx = prepareSimpleTx(sender_account, tx)

    # Send the signed transaction using the client
    print("Submitting transaction...")
    try:
        # tx_commit handles the signed transaction object directly
        tx_result = await client.tx_commit(signed_tx)
        print(f"Transaction submitted! Result: {json.dumps(tx_result)}")
        return tx_result.get('hash') # Return hash for status check
    except Exception as e:
        print(f"Transaction failed: {e}")
        return None

# Example usage (requires funding the sender account first)
async def main():
    rpc_url = "https://node0.try-saline.com"
    client = Client(http_url=rpc_url)
    root_account = Account.create()
    sender = root_account.create_subaccount(label="sender")
    # --- Add funding logic here (e.g., using faucet top_up) ---
    tx_hash = await create_and_send_tx(client, sender)
    # ... can use tx_hash later ...

if __name__ == "__main__":
    asyncio.run(main())

Checking Transaction Status

Use the hash returned by tx_commit to query the transaction’s status.

import asyncio
from saline_sdk.rpc.client import Client
import json

# Assume client is initialized and you have a tx_hash
# rpc_url = "http://localhost:26657"
# client = Client(http_url=rpc_url)
# tx_hash = "ABCDEF1234..." # Replace with actual hash

async def check_tx_status(client: Client, tx_hash: str | None):
    if not tx_hash:
        print("No transaction hash provided.")
        return

    print(f"Checking status for tx {tx_hash[:10]}...")
    try:
        # get_tx_async is async
        tx_info = await client.get_tx_async(tx_hash)
        if tx_info:
            print(f"Transaction Info: {json.dumps(tx_info)}")
            if tx_info.get('error'):
                print(f"Transaction Status: FAILED ({tx_info.get('error')})")
            else:
                print("Transaction Status: SUCCESS (likely)")
        else:
            # This might mean pending or hash is incorrect/not found
            print(f"Transaction not found or still pending.")
    except Exception as e:
        print(f"Error checking transaction status: {e}")

# Example Usage
async def main():
    rpc_url = "https://node0.try-saline.com"
    client = Client(http_url=rpc_url)
    example_tx_hash = "PASTE_A_REAL_TX_HASH_HERE" # Get this from a previous tx_commit result
    await check_tx_status(client, example_tx_hash)

if __name__ == "__main__":
    asyncio.run(main())

Asynchronous Operations

The Saline SDK is primarily asynchronous. Most interactions with the Client that involve network requests (like tx_commit, get_wallet_info_async, get_tx_async, get_all_intents) are async functions and should be await`ed. These typically need to be called from within an `async def function, which is then executed using asyncio.run().

Synchronous methods like client.get_status() do not require await.

Using the Testnet Faucet

The SDK includes utilities for obtaining tokens from the testnet faucet.

import asyncio
from saline_sdk.account import Account
from saline_sdk.rpc.client import Client
from saline_sdk.rpc.testnet.faucet import top_up

RPC_URL = "https://node0.try-saline.com"

async def get_testnet_tokens():
    # Create account and client
    root_account = Account.create()
    alice = root_account.create_subaccount(label="alice")
    bob = root_account.create_subaccount(label="bob")
    client = Client(http_url=RPC_URL)

    # Check connection
    try:
        status = client.get_status()
        print(f"Connected: {status['node_info']['network']} (Block: {status['sync_info']['latest_block_height']})")
    except Exception as e:
        print(f"ERROR: Connection failed: {e}")
        return

    # Request default tokens for Alice
    print(f"Requesting faucet tokens for Alice ({alice.public_key[:10]}...)")
    try:
        # top_up is async
        await top_up(
            account=alice,  # Pass Subaccount directly
            client=client
            # use_dynamic_amounts=True is default
        )
        print("Faucet request submitted for Alice.")
        # Wait briefly for faucet tx to potentially process
        await asyncio.sleep(3)
        alice_info = await client.get_wallet_info_async(alice.public_key)
        print(f"Alice balances: {alice_info.get('balances', []) if alice_info else 'Error/None'}")
    except Exception as e:
        print(f"Faucet top-up failed for Alice: {e}")

    # Request specific token amounts for Bob
    print(f"\nRequesting specific faucet tokens for Bob ({bob.public_key[:10]}...)")
    try:
        await top_up(
            account=bob,
            client=client,
            tokens={"BTC": 0.5, "ETH": 5}, # Specify desired tokens
            use_dynamic_amounts=False      # Required when specifying tokens
        )
        print("Faucet request submitted for Bob.")
        await asyncio.sleep(3)
        bob_info = await client.get_wallet_info_async(bob.public_key)
        print(f"Bob balances: {bob_info.get('balances', []) if bob_info else 'Error/None'}")
    except Exception as e:
         print(f"Faucet top-up failed for Bob: {e}")

# Run the async function
if __name__ == "__main__":
    asyncio.run(get_testnet_tokens())