All notable changes to ReceiptAnchor and RefundVault are recorded here.
The two contracts are versioned together and share a tag. Versioning follows the
policy in docs/RELEASING.md: while the project is pre-1.0,
breaking changes bump the minor version, and they are called out as such.
- Build was broken on
mainafter the yield-strategy merge (#200). TheYieldStrategytrait used#[contractimpl], which cannot generate a client on a bare trait; it is now#[contractclient(name = "YieldStrategyClient")].deploy_to_yieldalso transferred tokens to the strategy without notifying it (strategy_client.deposit), so the strategy never recorded the principal and later withdrawals failed.yield_tests.rsadditionally used event APIs that do not exist in this SDK. No deployed contract is affected — this restores a compiling, green test suite.
- Property-based fuzz suites in
contracts/*/src/fuzz_test.rsnow generate random operation sequences and assert invariants after every step: pruning stays a contiguous prefix with a monotonicPrunedUpTocursor, Merkle verification rejects every wrong proof shape (wrong leaf/sibling/length/batch and reversed level order), vault float always equalsdeposits - refunds - withdrawalsand never goes negative, apayment_refcan never be refunded twice, paused operations never mutate state, and TTL extension never shortens a TTL while missing records always error. Budgets are tunable viaFUZZ_CASES/FUZZ_SEQ_LENwith longer#[ignore]d local profiles.
0.2.0 — 2026-08-14
Everything below has been merged and tested on main. It is not what is deployed
on testnet — see Deployment status.
- Event topics changed and any indexer written against
0.1.0matches nothing.0.1.0published events by hand as("anchored", batch_id)and("refunded", payment_ref). Both contracts now derive their events with#[contractevent], which emits the topicsanchor_event,prune_event,deposit_event,refund_event, andwithdraw_event. The README advertised the old topics for three weeks after the code had changed; that is fixed, and the shapes are now pinned as a contract indocs/EVENTS.mdwith an Event Stability Policy inCONTRIBUTING.mdso it cannot drift again silently.
ReceiptAnchor:
extend_batch_ttl(batch_id)— public and unauthenticated, so anyone can stop an anchored batch being archived.prune_batches(before_ledger)— merchant-authorised, walking forward from a persistedPrunedUpTocursor and stopping at the first batch not old enough, so the pruned range stays a contiguous prefix and no batch is ever removed from the middle.get_batch_count()— exposes the batch count; a maximum batch size is now enforced onanchor_batch.AnchorEventandPruneEvent.
RefundVault:
pause()/unpause()under merchant auth. Deposit, refund and withdraw all reject while paused.extend_refund_ttl(payment_ref)— public and unauthenticated, same rationale as above.DepositEvent,RefundEventandWithdrawEvent, so the vault is indexable rather than poll-only.
Both:
contractmeta!embeddingname,version,repoand the build'sGIT_SHAvia abuild.rs, so a deployed contract can be traced to its exact source commit.deploy.shnow records wasmsha256sumalongside the contract IDs.
soroban-sdk27.0.0 → 27.0.4.- TTL constants set to roughly 30 days of ledgers, with a threshold so a bump is not written on every call. Archival and restore implications are documented.
refundnow validatesamount > 0.
RefundVaultstorage.set()calls corrected.- README test counts and event-topic names no longer contradict the code.
docs/EVENTS.md— the indexer-facing event contract.docs/storage-audit.md— rewritten from a single line of escaped text into an audit of all 13DataKeyvariants, with storage class, justification, TTL strategy and projected rent.docs/ADR-002— design notes on the x402uptoscheme for Stellar. Status DRAFT: the construction has not been validated against the upstream spec, a running contract, or Soroban's authorization semantics, and §6 lists what must be confirmed first.docs/RELEASING.md,TROUBLESHOOTING.md, and a SEP-41 section indocs/SECURITY_MODEL.mdrecording whyRefundVaultlets a missing-trustline transfer panic at the token rather than paying the budget cost of a pre-check.
- 25 → 58 tests:
receipt-anchor24,refund-vault29, and 5 cross-contract integration tests that replaced a placeholder asserting nothing. The integration tests cover receipt correspondence, double-refund against a valid proof, refund of a payment inside a pruned batch, TTL archival across both contracts, and the pause interaction. verify_receiptremains pinned to conformance vectors shared with the TypeScript SDK, so off-chain and on-chain verification are proven to agree.
The testnet deployment has deliberately not been updated to 0.2.0. The
contracts live at:
| Contract | Contract ID | Version deployed |
|---|---|---|
ReceiptAnchor |
CBHRJU7CF4XIFRNDITFHNQHABKBMFM2FYFHLGWN3JGSFYYCDSMDAWPRV |
0.1.0 |
RefundVault |
CCMBM44EJUGD52G4LSMGHSXMAH2KSAQZX7VOYY4TTBF5BK4D7M4IHRQA |
0.1.0 |
Soroban deployment mints a new contract ID. Redeploying would invalidate every
published address — including the ones the public receipt verifier at
https://accensa-dashboard.vercel.app/verify reads live, and every contract link
in this repository and in accensa-app. So 0.2.0 is a source release: the
tag, the notes and the reproducible build are the artifact. A redeployment is a
coordinated change across both repositories and is tracked separately in
#59, which also covers
pubnet.
Practical consequence: the new functions above and the new event topics exist in
the source and in the tagged build, not at those two addresses. Anything
reading the live contracts should keep treating them as 0.1.0.
0.1.0 — 2026-07-14
First testnet deployment. ReceiptAnchor with anchor_batch, get_batch,
verify_receipt and initialize; RefundVault with deposit, refund,
withdraw, get_refund, set_refund_window and initialize. Contract IDs and
the transactions that created them are recorded in
DEPLOYMENTS.md.