Label: complexity: high
Points: 200
Description
Without comprehensive replay protection, signed payment transactions could be resubmitted. This issue adds a global transaction ID registry — every state-changing function accepts an optional tx_id: BytesN<32> that is stored on-chain after first use, rejecting any duplicate submission.
Technical Context
Involves lib.rs. Store used transaction IDs in persistent key ("txid", tx_id) as bool. Add check_and_mark_txid(env, tx_id: Option<BytesN<32>>) helper called at the start of pay(), release(), refund(). If tx_id already exists in storage, panic with "duplicate transaction".
Acceptance Criteria
Label: complexity: high
Points: 200
Description
Without comprehensive replay protection, signed payment transactions could be resubmitted. This issue adds a global transaction ID registry — every state-changing function accepts an optional
tx_id: BytesN<32>that is stored on-chain after first use, rejecting any duplicate submission.Technical Context
Involves
lib.rs. Store used transaction IDs in persistent key("txid", tx_id)asbool. Addcheck_and_mark_txid(env, tx_id: Option<BytesN<32>>)helper called at the start ofpay(),release(),refund(). Iftx_idalready exists in storage, panic with"duplicate transaction".Acceptance Criteria
pay(),release(),refund()accept optionaltx_idparametertx_idsucceeds and marks it as usedtx_idpanics with"duplicate transaction"tx_id = Noneskips replay check (backward compatible)tx_idtwice and verifies second call panicscargo clippypasses with zero warnings