Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 20 additions & 13 deletions packages/runar-rs/src/sdk/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -880,21 +880,28 @@ impl RunarContract {
tx_change_amount: i64| -> Result<(String, String, String), String> {
let (op_sig, preimage) = compute_op_push_tx_with_code_sep(tx, input_idx, subscript, sats, code_sep_idx)?;

// Only sign Sig params for extra inputs, not the primary
if input_idx > 0 {
// In stateful contracts, user checkSig is AFTER OP_CODESEPARATOR — trim.
let mut sig_subscript = subscript.to_string();
if code_sep_idx >= 0 {
let trim_pos = ((code_sep_idx as usize) + 1) * 2;
if trim_pos <= sig_subscript.len() {
sig_subscript = sig_subscript[trim_pos..].to_string();
}
}
for &idx in sig_indices {
let real_sig = signer.sign(tx, input_idx, &sig_subscript, sats, None)?;
resolved_args[idx] = SdkValue::Bytes(real_sig);
// Sign Sig params for ALL inputs. Stateful contracts that mix
// OP_PUSH_TX preimage verification with user `check_sig` calls
// require a real signature at the primary covenant input
// (input_idx == 0) too — leaving the placeholder zero bytes
// there fails on-chain `check_sig` and the relay rejects the
// transaction. The BIP-143 sighash for input 0 is identical
// to the OP_PUSH_TX sighash for that input (same tx, same
// input_idx, same trimmed subscript), so both checks in the
// unlock context see consistent message bytes.
//
// In stateful contracts, user checkSig is AFTER OP_CODESEPARATOR — trim.
let mut sig_subscript = subscript.to_string();
if code_sep_idx >= 0 {
let trim_pos = ((code_sep_idx as usize) + 1) * 2;
if trim_pos <= sig_subscript.len() {
sig_subscript = sig_subscript[trim_pos..].to_string();
}
}
for &idx in sig_indices {
let real_sig = signer.sign(tx, input_idx, &sig_subscript, sats, None)?;
resolved_args[idx] = SdkValue::Bytes(real_sig);
}

// Resolve ByteString params (auto-compute allPrevouts from tx)
if !prevouts_indices.is_empty() {
Expand Down
Loading