Short, practical snippets for common shipment contract calls. Copy the call shape and adapt it to your needs.
use soroban_sdk::{testutils::Address as _, Address, BytesN, Env, Symbol, Vec};
use shipment::{NavinShipment, NavinShipmentClient};
let env = Env::default();
let contract_id = env.register(NavinShipment, ());
let client = NavinShipmentClient::new(&env, &contract_id);
let admin = Address::generate(&env);
let company = Address::generate(&env);
let carrier = Address::generate(&env);
let receiver = Address::generate(&env);Set the admin and token contract address:
let token_contract = Address::generate(&env);
client.initialize(&admin, &token_contract);let data_hash = BytesN::from_array(&env, &[1u8; 32]);
let deadline = env.ledger().timestamp() + 3600; // 1 hour from now
let shipment_id = client.create_shipment(
&company, // sender (Company)
&receiver, // recipient
&carrier, // assigned carrier
&data_hash, // SHA-256 hash of shipment data
&Vec::new(&env), // payment milestones (empty for no milestones)
&deadline, // deadline timestamp
);let shipment = client.get_shipment(&shipment_id);
println!("Status: {:?}", shipment.status);
println!("Escrow: {}", shipment.escrow_amount);Only the sender (Company) can cancel if the shipment is still in Created state:
let data_hash = BytesN::from_array(&env, &[1u8; 32]);
client.cancel_shipment(&company, &shipment_id, &data_hash);Move a shipment through its lifecycle (Created → InTransit → Delivered):
let data_hash = BytesN::from_array(&env, &[1u8; 32]);
// Mark as in transit (carrier updates status)
client.update_status(
&carrier,
&shipment_id,
&ShipmentStatus::InTransit,
&data_hash,
);
// Confirm delivery (receiver confirms arrival)
client.confirm_delivery(&receiver, &shipment_id, &data_hash);The company deposits funds before shipment begins:
let amount = 1000i128; // Must be > 0
client.deposit_escrow(&company, &shipment_id, &amount);After delivery, the receiver (or admin) releases funds to the carrier:
client.release_escrow(&receiver, &shipment_id);If the shipment is cancelled, the company can get funds back:
client.refund_escrow(&company, &shipment_id);Admin grants Company role to an address:
client.add_company(&admin, &company);Admin grants Carrier role to an address:
client.add_carrier(&admin, &carrier);Admin revokes Company role:
client.remove_company(&admin, &company);Admin temporarily suspends a carrier (escrow frozen):
client.suspend_carrier(&admin, &carrier);Admin restores a suspended carrier:
client.reactivate_carrier(&admin, &carrier);Total number of shipments created:
let count = client.get_shipment_counter().unwrap();
println!("Total shipments: {}", count);Retrieve overall contract health and configuration:
let status = client.get_contract_status().unwrap();
println!("Paused: {}", status.is_paused);
println!("Total shipments: {}", status.shipment_count);How many active shipments a company has:
let active = client.get_active_shipment_count(&company).unwrap();
println!("Active shipments: {}", active);All contract calls that return Result<T, NavinError> can fail. Handle errors gracefully:
match client.try_deposit_escrow(&company, &shipment_id, &0) {
Ok(()) => println!("Deposited"),
Err(e) => println!("Deposit failed: {:?}", e),
}Common errors:
InvalidAmount: Zero or negative amountShipmentNotFound: Shipment ID doesn't existInvalidStatus: Operation not allowed in current statusUnauthorized: Caller lacks permissionEscrowLocked: Escrow already has funds