fn get(env: soroban_sdk::Env, id: soroban_sdk::BytesN<32>) -> Subscription
fn pause(env: soroban_sdk::Env, id: soroban_sdk::BytesN<32>)
fn cancel(env: soroban_sdk::Env, id: soroban_sdk::BytesN<32>)
Trigger the next charge.
v0.1 auth model (audit-002 F4): the buyer must sign every charge.
buyer.require_auth() is called below. An off-chain scheduler can
submit the transaction, but the buyer must produce a fresh signature
each time — via smart-wallet session, WalletConnect, or equivalent.
v0.2 will replace this with a pre-auth allowance primitive.
fn charge(env: soroban_sdk::Env, id: soroban_sdk::BytesN<32>) -> u64
Buyer authorizes a new subscription. Returns a deterministic 32-byte id. Both buyer and contract authentication are required at the host level (require_auth invocations).
fn create(
env: soroban_sdk::Env,
buyer: soroban_sdk::Address,
merchant: soroban_sdk::Address,
token: soroban_sdk::Address,
amount: i128,
period_seconds: u64,
max_periods: u32,
expires_at: u64,
nonce: soroban_sdk::BytesN<32>,
) -> soroban_sdk::BytesN<32>
fn resume(env: soroban_sdk::Env, id: soroban_sdk::BytesN<32>)
v0.2 autonomous charge — NO buyer signature at charge time.
Closes the audit-002 F4 pre-auth gap. Instead of buyer.require_auth
transfer (which forces a fresh buyer signature every period), this
pulls amount from the buyer's standing SEP-41 allowance via
transfer_from, with this contract as the spender. The buyer signs
ONCE, off-band: token.approve(buyer, <this contract>, cap, expiry).
Thereafter any party (an off-chain scheduler/relayer that pays the tx
fee, never custodies funds) can submit autocharge(id) each period.Bounds are enforced on two independent layers:
transfer_from fails and the
buyer must re-approve — a hard, on-chain spending ceiling.Non-custodial: funds move buyer -> merchant directly; the contract only holds the spender role, never the balance.
fn autocharge(env: soroban_sdk::Env, id: soroban_sdk::BytesN<32>) -> u64
Mark a subscription as Expired if its terminal conditions hold (expires_at passed OR max_periods reached). Anyone can call; idempotent. Returns true if state was changed, false otherwise. This exists because charge() cannot persist a status change while also panicking — Soroban panics revert state.
fn mark_expired(env: soroban_sdk::Env, id: soroban_sdk::BytesN<32>) -> bool