This document covers the full public interface of the SplitChain Soroban smart contract and the frontend helper utilities.
- Contract Overview
- Data Types
- Contract Methods
- Error Conditions
- Frontend Helpers
- Environment Variables
- Language: Rust (
#![no_std]) - Platform: Soroban (Stellar)
- Storage: Instance storage (all group and balance data)
- Auth:
require_auth()enforced on all state-mutating functions - Amounts: All monetary values are in stroops (
i128). 1 XLM = 10,000,000 stroops.
Stored per group. Contains the list of member addresses.
pub struct GroupData {
pub members: Vec<Address>,
}pub enum DataKey {
Group(Symbol), // group_id → GroupData
Balance(Symbol), // group_id → Map<Address, i128>
ExpenseCount(Symbol), // group_id → u32
}Map<Address, i128> — maps each member address to their net balance.
| Value | Meaning |
|---|---|
Positive (> 0) |
This member is owed money by the group |
Negative (< 0) |
This member owes money to the group |
Zero (0) |
This member is fully settled |
Creates a new expense group with a fixed set of members.
pub fn create_group(env: Env, group_id: Symbol, members: Vec<Address>)Parameters
| Parameter | Type | Description |
|---|---|---|
group_id |
Symbol |
Unique identifier for the group (e.g. "trip2025") |
members |
Vec<Address> |
List of Stellar addresses in the group |
Behavior
- Panics if a group with the same
group_idalready exists - Initializes all member balances to
0 - Initializes expense counter to
0
Auth: None required (anyone can create a group)
Example (Soroban CLI)
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
--source alice \
-- create_group \
--group_id trip2025 \
--members '["GABC...","GDEF...","GHIJ..."]'Records a new expense paid by one member, split equally among all group members.
pub fn add_expense(
env: Env,
group_id: Symbol,
payer: Address,
amount: i128,
description: Symbol,
)Parameters
| Parameter | Type | Description |
|---|---|---|
group_id |
Symbol |
The group to record the expense in |
payer |
Address |
The member who paid |
amount |
i128 |
Total amount paid, in stroops |
description |
Symbol |
Short label (e.g. "dinner", "rent") |
Balance Update Logic
For a group of N members where payer paid amount:
share = amount / N (integer division)
payer balance += amount - share (credited for everyone else's share)
other balances -= share (debited their portion)
Auth: payer must sign the transaction
Example
Alice pays 300,000,000 stroops (30 XLM) for dinner in a 3-person group:
soroban contract invoke \
--id <CONTRACT_ID> \
--network testnet \
--source alice \
-- add_expense \
--group_id trip2025 \
--payer GABC... \
--amount 300000000 \
--description dinnerResult: Alice +200,000,000, Bob -100,000,000, Carol -100,000,000
Records a settlement payment from one member to another, adjusting their balances.
pub fn settle(
env: Env,
group_id: Symbol,
from: Address,
to: Address,
amount: i128,
)Parameters
| Parameter | Type | Description |
|---|---|---|
group_id |
Symbol |
The group context |
from |
Address |
The member paying (the debtor) |
to |
Address |
The member receiving (the creditor) |
amount |
i128 |
Amount being settled, in stroops |
Behavior
- Panics if
fromwould over-settle (i.e.from_balance + amount > 0) - Adjusts
frombalance by+amount(reduces debt) - Adjusts
tobalance by-amount(reduces credit)
Auth: from must sign the transaction
Note: This method records the settlement in contract state. The actual XLM transfer should be executed as a separate Stellar payment operation in the same transaction envelope.
Returns the current net balance for every member in a group.
pub fn get_balances(env: Env, group_id: Symbol) -> Map<Address, i128>Returns: Map<Address, i128> — net balance per member in stroops
Auth: None (read-only)
Returns the list of member addresses for a group.
pub fn get_members(env: Env, group_id: Symbol) -> Vec<Address>Returns: Vec<Address>
Auth: None (read-only)
Returns the total number of expenses recorded for a group.
pub fn expense_count(env: Env, group_id: Symbol) -> u32Returns: u32
Auth: None (read-only)
| Condition | Trigger | Behavior |
|---|---|---|
| Group already exists | create_group called with duplicate group_id |
panic!("group already exists") |
| Group not found | Any method called with unknown group_id |
expect("group not found") panics |
| Empty group | add_expense on a group with 0 members |
panic!("group has no members") |
| Over-settlement | settle amount exceeds debtor's balance |
panic!("settling more than owed") |
| Unauthorized | State-mutating call without valid auth | Soroban auth failure |
Located in frontend/splitchain-ui/src/lib/contract.ts.
export const NETWORK_PASSPHRASE = StellarSdk.Networks.TESTNET;
export const RPC_URL = "https://soroban-testnet.stellar.org";
export const CONTRACT_ID = import.meta.env.VITE_CONTRACT_ID ?? "";Returns a configured Soroban RPC server instance.
export function getRpc(): StellarSdk.rpc.ServerConverts an XLM amount to stroops for use in contract calls.
export const toStroops = (xlm: number) => BigInt(Math.round(xlm * 10_000_000));Converts stroops back to XLM for display.
export const fromStroops = (stroops: bigint) => Number(stroops) / 10_000_000;| Variable | Required | Description |
|---|---|---|
VITE_CONTRACT_ID |
Yes | Deployed SplitChain contract address (starts with C) |
VITE_NETWORK |
No | testnet (default) or mainnet |
Copy .env.example to .env and fill in your values before running the frontend.