Repo context. accensa-contracts holds the on-chain half of Accensa: ReceiptAnchor
(Merkle batch anchoring so an agent can verify it was charged correctly without trusting
the seller's API) and RefundVault (policy-bounded refunds without the merchant becoming
a custodian). Both are deployed on testnet. soroban-sdk 27.0.4, MIT. Read README.md,
docs/SECURITY_MODEL.md and DEPLOYMENTS.md before starting.
Problem
ReceiptAnchor exposes initialize, anchor_batch, get_batch, verify_receipt,
get_batch_count, extend_batch_ttl and prune_batches. There is no upgrade, and
soroban_sdk's env.deployer().update_current_contract_wasm() is never called.
That means the deployed WASM is final. Every correctness issue already filed against this
contract — the unbounded proof loop (#96), the missing domain separation (#147), the
prune_batches budget exhaustion (#149) — is unfixable on the live testnet deployment. The only
remedy is to deploy a new contract at a new address and ask every integrator to re-point, which
also orphans every batch already anchored: verify_receipt on the old address keeps working,
but the new one starts at batch 1 with no history.
For a contract whose value proposition is long-lived auditability, "we redeploy and lose the
history" is not an acceptable recovery story.
What to do
This needs a design decision before code. Immutability is a legitimate choice for an anchoring
contract — it is arguably why an auditor should trust it — so the point of this issue is to
make the choice deliberately and write it down.
- Write an ADR (follow
docs/ADR-001-merkle-structure.md for format) arguing for either a
permanent admin-gated upgrade, a time-locked upgrade, an upgrade that can be permanently
renounced, or deliberate immutability.
- If the ADR lands on upgradeable, implement it: admin-gated
upgrade(new_wasm_hash: BytesN<32>)
with require_auth, an UpgradeEvent, and a test that exercises an actual upgrade through
env.deployer().
- If the ADR lands on immutable, say so prominently in
README.md and docs/SECURITY_MODEL.md,
and state what the migration story is instead.
Note on scope
#126 covers RefundVault state migration. This issue is ReceiptAnchor and should reach a
consistent answer with it — coordinate before starting.
Acceptance criteria
- An ADR in
docs/ states the decision and its reasoning.
- The code matches the ADR, with tests.
README.md tells an integrator which guarantee they are getting.
Problem
ReceiptAnchorexposesinitialize,anchor_batch,get_batch,verify_receipt,get_batch_count,extend_batch_ttlandprune_batches. There is noupgrade, andsoroban_sdk'senv.deployer().update_current_contract_wasm()is never called.That means the deployed WASM is final. Every correctness issue already filed against this
contract — the unbounded proof loop (#96), the missing domain separation (#147), the
prune_batchesbudget exhaustion (#149) — is unfixable on the live testnet deployment. The onlyremedy is to deploy a new contract at a new address and ask every integrator to re-point, which
also orphans every batch already anchored:
verify_receipton the old address keeps working,but the new one starts at batch 1 with no history.
For a contract whose value proposition is long-lived auditability, "we redeploy and lose the
history" is not an acceptable recovery story.
What to do
This needs a design decision before code. Immutability is a legitimate choice for an anchoring
contract — it is arguably why an auditor should trust it — so the point of this issue is to
make the choice deliberately and write it down.
docs/ADR-001-merkle-structure.mdfor format) arguing for either apermanent admin-gated
upgrade, a time-locked upgrade, an upgrade that can be permanentlyrenounced, or deliberate immutability.
upgrade(new_wasm_hash: BytesN<32>)with
require_auth, anUpgradeEvent, and a test that exercises an actual upgrade throughenv.deployer().README.mdanddocs/SECURITY_MODEL.md,and state what the migration story is instead.
Note on scope
#126 covers
RefundVaultstate migration. This issue isReceiptAnchorand should reach aconsistent answer with it — coordinate before starting.
Acceptance criteria
docs/states the decision and its reasoning.README.mdtells an integrator which guarantee they are getting.