Summary
The Rust SDK's call-tx builder writes nLockTime = 0 unconditionally. There is no way for callers to override this via CallOptions. Contracts that assert against extractLocktime(txPreimage) therefore cannot work as designed:
- An auction
close() method that requires extractLocktime(txPreimage) >= deadline always fails for any non-zero deadline, because the signed transaction's nLockTime is 0.
- The same applies to any time-locked contract (escrow refund after timeout, vesting release, etc.).
The TypeScript SDK has the same gap in packages/runar-sdk/src/contract.ts.
Reproduction
The reference test test_auction_close in integration/rust/tests/auction.rs works around this by hardcoding deadline = 0:
SdkValue::Int(0), // deadline=0 so extractLocktime(txPreimage) >= deadline passes with nLocktime=0
The workaround proves the limitation is known. With any realistic non-zero deadline (e.g. currentBlock + 8), close() fails ARC validation because the script's deadline assertion returns false.
Affected files
packages/runar-rs/src/sdk/types.rs — CallOptions struct has no locktime field.
packages/runar-rs/src/sdk/contract.rs and packages/runar-rs/src/sdk/calling.rs — call-tx build sites write to_little_endian_32(0) for the locktime bytes.
Proposed fix
Add an optional locktime: Option<u32> field to CallOptions. Default None → SDK still writes 0 → existing callers see identical behavior. Callers can pass Some(n) for time-locked methods.
This is purely additive and back-compatible.
Evidence
A patched SDK has been validated against BSV mainnet: transactions with a caller-supplied non-zero nLockTime mine successfully through ARC; the same transactions with hardcoded nLockTime = 0 are rejected with Script evaluated without error but finished with a false/empty top stack element (the deadline assertion failing).
PR with fix + regression tests is opened alongside this issue.
Summary
The Rust SDK's call-tx builder writes
nLockTime = 0unconditionally. There is no way for callers to override this viaCallOptions. Contracts that assert againstextractLocktime(txPreimage)therefore cannot work as designed:close()method that requiresextractLocktime(txPreimage) >= deadlinealways fails for any non-zerodeadline, because the signed transaction'snLockTimeis0.The TypeScript SDK has the same gap in
packages/runar-sdk/src/contract.ts.Reproduction
The reference test
test_auction_closeinintegration/rust/tests/auction.rsworks around this by hardcodingdeadline = 0:The workaround proves the limitation is known. With any realistic non-zero deadline (e.g.
currentBlock + 8),close()fails ARC validation because the script's deadline assertion returns false.Affected files
packages/runar-rs/src/sdk/types.rs—CallOptionsstruct has nolocktimefield.packages/runar-rs/src/sdk/contract.rsandpackages/runar-rs/src/sdk/calling.rs— call-tx build sites writeto_little_endian_32(0)for the locktime bytes.Proposed fix
Add an optional
locktime: Option<u32>field toCallOptions. DefaultNone→ SDK still writes0→ existing callers see identical behavior. Callers can passSome(n)for time-locked methods.This is purely additive and back-compatible.
Evidence
A patched SDK has been validated against BSV mainnet: transactions with a caller-supplied non-zero
nLockTimemine successfully through ARC; the same transactions with hardcodednLockTime = 0are rejected withScript evaluated without error but finished with a false/empty top stack element(the deadline assertion failing).PR with fix + regression tests is opened alongside this issue.