Contract 4312612c5cc1dc46623efc553910096c2c2af9cd83b324cbd6068071ea28fcaf

← Back to Index 📥 Download WASM

Meta

cliver 26.0.0#60f7458e7ecffddf2f2d91dc6d0d2db4fab03ecc
rssdkver 26.0.0#e1bf74ba6c3ddb591593f5eb5dfb85458ff714c1
rsver 1.95.0

Instances

  • CD2RFNOLMIKZN4EETDCGULGMD4ANS56IIUDIBLOE24P4JRZM2GCVFV2U

Interface

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:

  • this contract: status / period elapsed / max_periods / expiry.
  • the SAC: the allowance cap AND its expiration ledger. When the allowance is exhausted or expires, 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

Bind an integrity attester (ed25519 public key) to a subscription. The merchant sets it; thereafter autocharge_attested is the only autonomous path that settles, and it requires a fresh signature from this key.

fn set_attester(
    env: soroban_sdk::Env,
    id: soroban_sdk::BytesN<32>,
    attester: soroban_sdk::BytesN<32>,
)

Deploy-time, immutable platform fee config. fee_bps (basis points, 297 = 2.97%, max 1000 = 10%) is taken out of every autonomous charge (autocharge / autocharge_attested) and routed to platform; the merchant receives amount - fee. fee_bps = 0 means no fee leg (the rail runs free). Set atomically at deploy so there is no front-running window on a public network — the fee recipient and rate are bound to the contract instance.

fn __constructor(env: soroban_sdk::Env, platform: soroban_sdk::Address, fee_bps: u32)

v0.3 attested autonomous charge — the integrity gate, on-chain.

Autonomous debit that REFUSES to settle without a fresh, valid integrity attestation. The off-chain attester (which actually determines whether the requesting agent is compromised) signs id || not_after with the ed25519 key bound via set_attester. This contract verifies that signature on the host, checks freshness against ledger time, and only then pulls the charge.

What this guarantees on-chain: no settlement without a fresh signed attestation bound to THIS subscription (no cross-sub replay; expiry enforced). What it does NOT do: detect compromise itself — that is the attester's job. The contract makes the attestation inescapable, not optional. x402/AP2 settle on authorization alone; this refuses.

Fail-closed: no attester set → AttesterNotSet; expired → AttestationExpired; bad signature → ed25519_verify traps (reverts).

fn autocharge_attested(
    env: soroban_sdk::Env,
    id: soroban_sdk::BytesN<32>,
    not_after: u64,
    signature: soroban_sdk::BytesN<64>,
) -> u64

Imports

WebAssembly Text (WAT) ▶