This document provides comprehensive API documentation for all Gathera smart contracts, including function signatures, parameters, return values, usage examples, and gas costs.
- Overview
- Ticket Contract API
- Escrow Contract API
- Multi-Signature Wallet Contract API
- Integration Layer API
- Error Handling
- Gas Cost Analysis
- Usage Examples
The Gathera platform consists of three main smart contracts:
- SoulboundTicketContract: Manages non-transferable event tickets
- EscrowContract: Handles secure fund escrow with dispute resolution
- MultisigWalletContract: Provides multi-signature wallet functionality
All contracts are built on the Stellar Soroban platform using Rust and compile to WebAssembly.
[TBD] (To be populated after deployment)
Issues a new soulbound ticket to a recipient.
pub fn issue_ticket(
env: Env,
event_id: Symbol,
recipient: Address,
metadata: String,
) -> Result<Symbol, TicketError>Parameters:
env(Env): The contract environmentevent_id(Symbol): Unique identifier for the eventrecipient(Address): Stellar address of the ticket recipientmetadata(String): Additional ticket metadata (JSON format)
Returns:
Result<Symbol, TicketError>:Ok(Symbol): Unique ticket identifierErr(TicketError): Error if ticket issuance fails
Gas Cost: ~15,000 gas units
Example:
use soroban_sdk::{Symbol, Address, String, Env};
let env = Env::default();
let event_id = Symbol::new(&env, "conf2024");
let recipient = Address::from_string(&env, "GD...");
let metadata = String::from_str(&env, r#"{"type": "VIP", "seat": "A1"}"#);
let ticket_id = SoulboundTicketContract::issue_ticket(
env,
event_id,
recipient,
metadata
)?;Verifies if a given address owns a specific ticket.
pub fn verify_ownership(
env: Env,
ticket_id: Symbol,
claimed_owner: Address,
) -> boolParameters:
env(Env): The contract environmentticket_id(Symbol): Unique identifier for the ticketclaimed_owner(Address): Address claiming ownership
Returns:
bool: True if the claimed_owner owns the ticket, false otherwise
Gas Cost: ~5,000 gas units
Example:
let is_owner = SoulboundTicketContract::verify_ownership(
env,
ticket_id,
claimed_address
);Retrieves ticket information.
pub fn get_ticket(env: Env, ticket_id: Symbol) -> Result<Ticket, TicketError>Parameters:
env(Env): The contract environmentticket_id(Symbol): Unique identifier for the ticket
Returns:
Result<Ticket, TicketError>:Ok(Ticket): Ticket data structureErr(TicketError): Error if ticket not found
Gas Cost: ~8,000 gas units
Example:
let ticket = SoulboundTicketContract::get_ticket(env, ticket_id)?;
println!("Ticket owner: {}", ticket.owner);
println!("Issued at: {}", ticket.issued_at);pub struct Ticket {
pub ticket_id: Symbol,
pub event_id: Symbol,
pub owner: Address,
pub issued_at: u64,
pub metadata: String,
}pub enum TicketError {
TicketAlreadyExists = 1,
TicketNotFound = 2,
Unauthorized = 3,
InvalidEventId = 4,
NotTransferable = 5,
EventEnded = 6,
MaxTicketsReached = 7,
NotImplemented = 255,
}[TBD] (To be populated after deployment)
Creates a new escrow arrangement.
pub fn create_escrow(
env: Env,
beneficiary: Address,
amount: u128,
expires_at: u64,
terms: String,
required_confirmations: u32,
) -> Result<Symbol, EscrowError>Parameters:
env(Env): The contract environmentbeneficiary(Address): Address of the beneficiaryamount(u128): Amount to escrow (in stroops)expires_at(u64): Expiration timestamp (Unix timestamp)terms(String): Escrow terms and conditionsrequired_confirmations(u32): Number of confirmations needed for release
Returns:
Result<Symbol, EscrowError>:Ok(Symbol): Unique escrow identifierErr(EscrowError): Error if escrow creation fails
Gas Cost: ~25,000 gas units
Example:
let beneficiary = Address::from_string(&env, "GD...");
let amount = 100_000_0000; // 100 XLM in stroops
let expires_at = 1704067200; // January 1, 2024
let terms = String::from_str(&env, "Payment for event ticket");
let required_confirmations = 2;
let escrow_id = EscrowContract::create_escrow(
env,
beneficiary,
amount,
expires_at,
terms,
required_confirmations
)?;Funds an existing escrow with tokens.
pub fn fund_escrow(env: Env, escrow_id: Symbol) -> Result<bool, EscrowError>Parameters:
env(Env): The contract environmentescrow_id(Symbol): Unique identifier for the escrow
Returns:
Result<bool, EscrowError>:Ok(bool): True if funding was successfulErr(EscrowError): Error if funding fails
Gas Cost: ~10,000 gas units + token transfer cost
Example:
let success = EscrowContract::fund_escrow(env, escrow_id)?;Releases funds from escrow to the beneficiary.
pub fn release_funds(env: Env, escrow_id: Symbol) -> Result<bool, EscrowError>Parameters:
env(Env): The contract environmentescrow_id(Symbol): Unique identifier for the escrow
Returns:
Result<bool, EscrowError>:Ok(bool): True if release was successfulErr(EscrowError): Error if release fails
Gas Cost: ~15,000 gas units + token transfer cost
Example:
let success = EscrowContract::release_funds(env, escrow_id)?;Creates a dispute for an escrow.
pub fn create_dispute(
env: Env,
escrow_id: Symbol,
reason: String,
) -> Result<Symbol, EscrowError>Parameters:
env(Env): The contract environmentescrow_id(Symbol): Unique identifier for the escrowreason(String): Dispute reason description
Returns:
Result<Symbol, EscrowError>:Ok(Symbol): Unique dispute identifierErr(EscrowError): Error if dispute creation fails
Gas Cost: ~12,000 gas units
Example:
let reason = String::from_str(&env, "Service not delivered as agreed");
let dispute_id = EscrowContract::create_dispute(env, escrow_id, reason)?;Resolves a dispute with specified resolution.
pub fn resolve_dispute(
env: Env,
dispute_id: Symbol,
resolution: String,
) -> Result<bool, EscrowError>Parameters:
env(Env): The contract environmentdispute_id(Symbol): Unique identifier for the disputeresolution(String): Dispute resolution details
Returns:
Result<bool, EscrowError>:Ok(bool): True if resolution was successfulErr(EscrowError): Error if resolution fails
Gas Cost: ~18,000 gas units
Example:
let resolution = String::from_str(&env, "Partial refund to beneficiary");
let success = EscrowContract::resolve_dispute(env, dispute_id, resolution)?;Retrieves escrow information.
pub fn get_escrow(env: Env, escrow_id: Symbol) -> Result<Escrow, EscrowError>Parameters:
env(Env): The contract environmentescrow_id(Symbol): Unique identifier for the escrow
Returns:
Result<Escrow, EscrowError>:Ok(Escrow): Escrow data structureErr(EscrowError): Error if escrow not found
Gas Cost: ~8,000 gas units
Example:
let escrow = EscrowContract::get_escrow(env, escrow_id)?;
println!("Escrow amount: {}", escrow.amount);
println!("Status: {:?}", escrow.status);pub struct Escrow {
pub escrow_id: Symbol,
pub depositor: Address,
pub beneficiary: Address,
pub amount: u128,
pub status: EscrowStatus,
pub created_at: u64,
pub expires_at: u64,
pub terms: String,
pub required_confirmations: u32,
pub confirmations: Vec<Address>,
}pub enum EscrowStatus {
Pending = 0,
Funded = 1,
Completed = 2,
Disputed = 3,
Refunded = 4,
Expired = 5,
}pub struct Dispute {
pub dispute_id: Symbol,
pub escrow_id: Symbol,
pub initiator: Address,
pub reason: String,
pub resolved: bool,
pub resolution: Option<String>,
}pub enum EscrowError {
EscrowAlreadyExists = 1,
EscrowNotFound = 2,
Unauthorized = 3,
InsufficientFunds = 4,
InvalidTerms = 5,
AlreadyCompleted = 6,
DisputeExists = 7,
InvalidResolution = 8,
EscrowExpired = 9,
NotImplemented = 255,
}[TBD] (To be populated after deployment)
Initializes the multi-signature wallet with owners and settings.
pub fn initialize(
env: Env,
owners: Vec<Address>,
threshold: u32,
timelock: u64,
max_amount: u128,
) -> Result<bool, MultisigError>Parameters:
env(Env): The contract environmentowners(Vec): List of initial wallet ownersthreshold(u32): Number of signatures required (1 ≤ threshold ≤ owners.len())timelock(u64): Time-lock period in secondsmax_amount(u128): Maximum transaction amount
Returns:
Result<bool, MultisigError>:Ok(bool): True if initialization was successfulErr(MultisigError): Error if initialization fails
Gas Cost: ~30,000 gas units
Example:
let mut owners = Vec::new(&env);
owners.push_back(Address::from_string(&env, "GD..."));
owners.push_back(Address::from_string(&env, "GD..."));
owners.push_back(Address::from_string(&env, "GD..."));
let threshold = 2;
let timelock = 3600; // 1 hour
let max_amount = 1_000_000_000; // 1000 XLM
let success = MultisigWalletContract::initialize(
env,
owners,
threshold,
timelock,
max_amount
)?;Submits a new transaction for approval.
pub fn submit_transaction(
env: Env,
destination: Address,
amount: u128,
data: String,
expires_at: u64,
) -> Result<Symbol, MultisigError>Parameters:
env(Env): The contract environmentdestination(Address): Recipient addressamount(u128): Amount to transfer (in stroops)data(String): Transaction data/payloadexpires_at(u64): Expiration timestamp
Returns:
Result<Symbol, MultisigError>:Ok(Symbol): Unique transaction identifierErr(MultisigError): Error if submission fails
Gas Cost: ~20,000 gas units
Example:
let destination = Address::from_string(&env, "GD...");
let amount = 50_000_000; // 5 XLM
let data = String::from_str(&env, "Payment for event services");
let expires_at = 1704067200 + 86400; // 24 hours from now
let tx_id = MultisigWalletContract::submit_transaction(
env,
destination,
amount,
data,
expires_at
)?;Approves a pending transaction.
pub fn approve_transaction(
env: Env,
transaction_id: Symbol,
) -> Result<bool, MultisigError>Parameters:
env(Env): The contract environmenttransaction_id(Symbol): Unique identifier for the transaction
Returns:
Result<bool, MultisigError>:Ok(bool): True if approval was successfulErr(MultisigError): Error if approval fails
Gas Cost: ~10,000 gas units
Example:
let success = MultisigWalletContract::approve_transaction(env, tx_id)?;Executes an approved transaction.
pub fn execute_transaction(
env: Env,
transaction_id: Symbol,
) -> Result<bool, MultisigError>Parameters:
env(Env): The contract environmenttransaction_id(Symbol): Unique identifier for the transaction
Returns:
Result<bool, MultisigError>:Ok(bool): True if execution was successfulErr(MultisigError): Error if execution fails
Gas Cost: ~15,000 gas units + token transfer cost
Example:
let success = MultisigWalletContract::execute_transaction(env, tx_id)?;Adds a new owner to the wallet (requires governing transaction).
pub fn add_owner(
env: Env,
new_owner: Address,
transaction_id: Symbol,
) -> Result<bool, MultisigError>Parameters:
env(Env): The contract environmentnew_owner(Address): Address of the new ownertransaction_id(Symbol): Governing transaction ID
Returns:
Result<bool, MultisigError>:Ok(bool): True if owner addition was successfulErr(MultisigError): Error if addition fails
Gas Cost: ~12,000 gas units
Example:
let new_owner = Address::from_string(&env, "GD...");
let success = MultisigWalletContract::add_owner(env, new_owner, gov_tx_id)?;Removes an owner from the wallet (requires governing transaction).
pub fn remove_owner(
env: Env,
owner_to_remove: Address,
transaction_id: Symbol,
) -> Result<bool, MultisigError>Parameters:
env(Env): The contract environmentowner_to_remove(Address): Address of the owner to removetransaction_id(Symbol): Governing transaction ID
Returns:
Result<bool, MultisigError>:Ok(bool): True if owner removal was successfulErr(MultisigError): Error if removal fails
Gas Cost: ~12,000 gas units
Example:
let owner_to_remove = Address::from_string(&env, "GD...");
let success = MultisigWalletContract::remove_owner(env, owner_to_remove, gov_tx_id)?;Changes the signature threshold (requires governing transaction).
pub fn change_threshold(
env: Env,
new_threshold: u32,
transaction_id: Symbol,
) -> Result<bool, MultisigError>Parameters:
env(Env): The contract environmentnew_threshold(u32): New threshold valuetransaction_id(Symbol): Governing transaction ID
Returns:
Result<bool, MultisigError>:Ok(bool): True if threshold change was successfulErr(MultisigError): Error if change fails
Gas Cost: ~10,000 gas units
Example:
let new_threshold = 3;
let success = MultisigWalletContract::change_threshold(env, new_threshold, gov_tx_id)?;Retrieves transaction information.
pub fn get_transaction(
env: Env,
transaction_id: Symbol,
) -> Result<Transaction, MultisigError>Parameters:
env(Env): The contract environmenttransaction_id(Symbol): Unique identifier for the transaction
Returns:
Result<Transaction, MultisigError>:Ok(Transaction): Transaction data structureErr(MultisigError): Error if transaction not found
Gas Cost: ~8,000 gas units
Example:
let transaction = MultisigWalletContract::get_transaction(env, tx_id)?;
println!("Amount: {}", transaction.amount);
println!("Status: {:?}", transaction.status);Retrieves current wallet configuration.
pub fn get_config(env: Env) -> MultisigConfigParameters:
env(Env): The contract environment
Returns:
MultisigConfig: Current wallet configuration
Gas Cost: ~5,000 gas units
Example:
let config = MultisigWalletContract::get_config(env);
println!("Threshold: {}", config.threshold);
println!("Owners: {:?}", config.owners);pub struct Transaction {
pub transaction_id: Symbol,
pub destination: Address,
pub amount: u128,
pub data: String,
pub status: TransactionStatus,
pub created_at: u64,
pub expires_at: u64,
pub required_confirmations: u32,
pub confirmations: Vec<Address>,
pub creator: Address,
}pub enum TransactionStatus {
Pending = 0,
Approved = 1,
Rejected = 2,
Executed = 3,
Expired = 4,
}pub struct MultisigConfig {
pub owners: Vec<Address>,
pub threshold: u32,
pub timelock: u64,
pub max_transaction_amount: u128,
}pub enum MultisigError {
TransactionAlreadyExists = 1,
TransactionNotFound = 2,
Unauthorized = 3,
InsufficientSignatures = 4,
InvalidOwner = 5,
ThresholdNotMet = 6,
AlreadyExecuted = 7,
InvalidTransaction = 8,
WalletLocked = 9,
DuplicateSignature = 10,
NotImplemented = 255,
}Creates a complete event ticketing setup with escrow integration.
pub fn create_event_with_escrow(
&self,
event_id: Symbol,
organizer: Address,
ticket_price: u128,
max_tickets: u32,
escrow_terms: String,
) -> Result<Symbol, WorkflowError>Parameters:
event_id(Symbol): Unique identifier for the eventorganizer(Address): Event organizer addressticket_price(u128): Price per ticketmax_tickets(u32): Maximum number of ticketsescrow_terms(String): Escrow terms and conditions
Returns:
Result<Symbol, WorkflowError>:Ok(Symbol): Workflow transaction identifierErr(WorkflowError): Error if workflow fails
Gas Cost: ~50,000 gas units
Processes a ticket purchase with escrow integration.
pub fn process_ticket_purchase(
&self,
event_id: Symbol,
buyer: Address,
payment_amount: u128,
) -> Result<Symbol, WorkflowError>Parameters:
event_id(Symbol): Unique identifier for the eventbuyer(Address): Buyer addresspayment_amount(u128): Payment amount
Returns:
Result<Symbol, WorkflowError>:Ok(Symbol): Transaction identifierErr(WorkflowError): Error if purchase fails
Gas Cost: ~35,000 gas units
Retrieves all contract addresses.
pub fn get_addresses(&self) -> (Address, Address, Address)Returns:
(Address, Address, Address): Tuple of (ticket, escrow, multisig) addresses
Gas Cost: ~3,000 gas units
All contracts use comprehensive error handling with specific error codes:
- Authorization Errors: Verify caller permissions
- Validation Errors: Check input parameters
- State Errors: Verify contract state
- Business Logic Errors: Enforce business rules
- Check error codes for specific failure reasons
- Use appropriate retry strategies for temporary failures
- Implement proper error logging and monitoring
| Function | Min Cost | Max Cost | Notes |
|---|---|---|---|
issue_ticket |
15,000 | 25,000 | Depends on metadata size |
verify_ownership |
5,000 | 8,000 | Simple lookup |
get_ticket |
8,000 | 12,000 | Data retrieval |
create_escrow |
25,000 | 40,000 | Depends on terms length |
fund_escrow |
10,000 | 15,000 | + token transfer |
release_funds |
15,000 | 25,000 | + token transfer |
create_dispute |
12,000 | 18,000 | Depends on reason length |
resolve_dispute |
18,000 | 30,000 | Complex logic |
initialize |
30,000 | 45,000 | Depends on owner count |
submit_transaction |
20,000 | 30,000 | Depends on data size |
approve_transaction |
10,000 | 15,000 | Simple approval |
execute_transaction |
15,000 | 25,000 | + token transfer |
- Batch Operations: Combine multiple operations when possible
- Metadata Optimization: Keep metadata strings concise
- Storage Patterns: Optimize data storage layouts
- Event Logging: Use events instead of storage when possible
use soroban_sdk::{Symbol, Address, String, Env, Vec};
fn setup_complete_event(env: Env) -> Result<(), Box<dyn std::error::Error>> {
// 1. Initialize multisig wallet
let mut owners = Vec::new(&env);
owners.push_back(Address::from_string(&env, "GD...organizer1"));
owners.push_back(Address::from_string(&env, "GD...organizer2"));
MultisigWalletContract::initialize(
env.clone(),
owners,
2, // threshold
3600, // 1 hour timelock
1_000_000_000 // 1000 XLM max
)?;
// 2. Create event with escrow
let workflow = EventTicketingWorkflow::new(env.clone());
let event_id = Symbol::new(&env, "tech_conf_2024");
let organizer = Address::from_string(&env, "GD...organizer");
let ticket_price = 100_000_000; // 10 XLM
let max_tickets = 500;
let escrow_terms = String::from_str(&env, "Refundable until event start");
workflow.create_event_with_escrow(
event_id,
organizer,
ticket_price,
max_tickets,
escrow_terms
)?;
// 3. Issue tickets to initial participants
let participants = vec![
"GD...user1",
"GD...user2",
"GD...user3"
];
for (i, participant) in participants.iter().enumerate() {
let ticket_id = SoulboundTicketContract::issue_ticket(
env.clone(),
event_id,
Address::from_string(&env, participant),
String::from_str(&env, &format!("Ticket #{}", i + 1))
)?;
println!("Issued ticket {} to {}", ticket_id, participant);
}
Ok(())
}fn purchase_ticket_with_escrow(
env: Env,
event_id: Symbol,
buyer: Address,
payment_amount: u128
) -> Result<Symbol, Box<dyn std::error::Error>> {
// 1. Create escrow for payment
let escrow_id = EscrowContract::create_escrow(
env.clone(),
buyer, // beneficiary (will be refunded if purchase fails)
payment_amount,
1704067200, // expiration
String::from_str(&env, "Ticket purchase escrow"),
1 // single confirmation needed
)?;
// 2. Fund the escrow
EscrowContract::fund_escrow(env.clone(), escrow_id)?;
// 3. Process ticket purchase through workflow
let workflow = EventTicketingWorkflow::new(env.clone());
let tx_id = workflow.process_ticket_purchase(
event_id,
buyer,
payment_amount
)?;
// 4. If successful, release funds to organizer
EscrowContract::release_funds(env, escrow_id)?;
Ok(tx_id)
}fn execute_multisig_payment(
env: Env,
destination: Address,
amount: u128,
owners: Vec<Address>
) -> Result<Symbol, Box<dyn std::error::Error>> {
// 1. Submit transaction
let tx_id = MultisigWalletContract::submit_transaction(
env.clone(),
destination,
amount,
String::from_str(&env, "Event payment"),
1704067200 + 86400 // expires in 24 hours
)?;
// 2. Collect approvals from required owners
let threshold = 2; // Assuming threshold is 2
let mut approvals = 0;
for owner in owners {
if approvals >= threshold {
break;
}
// In a real implementation, each owner would call this separately
let approved = MultisigWalletContract::approve_transaction(
env.clone(),
tx_id
)?;
if approved {
approvals += 1;
}
}
// 3. Execute the transaction if threshold met
if approvals >= threshold {
MultisigWalletContract::execute_transaction(env, tx_id)?;
println!("Transaction executed successfully");
} else {
println!("Insufficient approvals for transaction");
}
Ok(tx_id)
}- Input Validation: Always validate user inputs
- Access Control: Implement proper authorization checks
- Reentrancy Protection: Guard against reentrancy attacks
- Integer Overflow: Use safe arithmetic operations
- Event Logging: Emit events for important state changes
- Gas Efficiency: Optimize for low gas consumption
- Storage Patterns: Minimize storage operations
- Batch Operations: Combine multiple operations when possible
- Caching: Cache frequently accessed data
- Unit Tests: Test individual functions
- Integration Tests: Test contract interactions
- Property Tests: Test edge cases and invariants
- Gas Tests: Verify gas consumption limits
This API documentation is maintained by the Gathera development team. For the most up-to-date information, please check the official repository.