You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR #30 adds support for ConditionMultisigClosure to ReadArkadeScript by replacing the hardcoded MultisigClosure-only decoder with a scriptlib.DecodeClosure() switch covering all closure types. We should add an e2e integration test exercising the ConditionMultisigClosure path end-to-end with introspector.
Background
Before PR #30, pkg/arkade/script.go had a hardcoded MultisigClosure decoder and would reject any VTXO using a different closure type with "spendingtapscript is not a MultisigClosure". PR #30 replaced that with a scriptlib.DecodeClosure() switch, adding handling for:
A ConditionMultisigClosure tapscript leaf is structured as:
<condition_subscript> OP_VERIFY <multisig_script>
The condition is an arbitrary subscript that must evaluate to true before the multisig is checked. The witness must satisfy both the condition and the multisig. Pubkeys are extracted from the embedded MultisigClosure.
Real-world use: This is the VHTLC claim closure in Fulmine. The ClaimClosure is a ConditionMultisigClosure where the condition is a preimage check:
A receiver claims the VTXO by providing the preimage in the witness, satisfying the condition, alongside their multisig signature.
What needs to be tested
An integration test (suggested location: test/condition_multisig_test.go, parallel to test/tx_test.go) that:
Constructs a ConditionMultisigClosure tapscript — e.g., a preimage condition (OP_SHA256 <hash> OP_EQUALVERIFY) combined with a multisig over Bob and the introspector key
Builds a VTXO tapscript tree that includes this closure (via createVtxoScriptWithArkadeScript or equivalent)
Funds a VTXO to that tapscript via alice.SendOffChain
Constructs an offchain tx spending via the ConditionMultisigClosure leaf, providing the preimage in the witness
Submits to introspector via introspectorClient.SubmitTx or introspectorClient.SubmitIntent
Verifies introspector decodes the ConditionMultisigClosure, extracts the owner pubkey from c.PubKeys, finds the tweaked key, and produces a valid signature
Verifies the signed tx is accepted by arkd
(Bonus) Verifies introspector rejects the tx if the wrong preimage is provided (condition fails), or if the preimage is omitted entirely
arkade-os/arkd/pkg/ark-lib/script/closure.go — ConditionMultisigClosure definition and DecodeClosure switch order
fulmine/pkg/vhtlc/ — real-world ConditionMultisigClosure usage as claim closure (good reference for preimage condition construction)
Key distinctions from other closure types
MultisigClosure
ConditionMultisigClosure
ConditionCSVMultisigClosure
Condition
None
Arbitrary (e.g. preimage)
Arbitrary + CSV timelock
Witness
Signatures only
Preimage + signatures
Preimage + signatures (after CSV)
Pubkey source
c.PubKeys
c.PubKeys (via embedded MultisigClosure)
c.PubKeys (via embedded CSVMultisigClosure)
Use case in Ark
Collaborative exit
VHTLC claim
VHTLC unilateral claim
The key subtlety: introspector's ReadArkadeScript only checks that its own tweaked pubkey appears in c.PubKeys. It does not evaluate the condition subscript — that is left to Bitcoin script execution. The test should confirm the introspector correctly signs without needing to evaluate the preimage itself.
Why this matters
ConditionMultisigClosure is the mechanism behind VHTLC claims — the core of Fulmine's Lightning bridge. If introspector silently fails to sign a ConditionMultisigClosure leaf (e.g. due to a future refactor of DecodeClosure), any VHTLC that includes the introspector in its claim multisig loses its ability to settle. This test ensures that regression cannot happen silently.
PR #30 adds support for
ConditionMultisigClosuretoReadArkadeScriptby replacing the hardcodedMultisigClosure-only decoder with ascriptlib.DecodeClosure()switch covering all closure types. We should add an e2e integration test exercising theConditionMultisigClosurepath end-to-end with introspector.Background
Before PR #30,
pkg/arkade/script.gohad a hardcodedMultisigClosuredecoder and would reject any VTXO using a different closure type with"spendingtapscript is not a MultisigClosure". PR #30 replaced that with ascriptlib.DecodeClosure()switch, adding handling for:MultisigClosure(collaborative spend)CSVMultisigClosure(unilateral exit — tracked in issue Unilateral exit integration test #31)CLTVMultisigClosure(absolute timelock — tracked in issue CLTVMultisig integration test #32)ConditionMultisigClosure← this issueConditionCSVMultisigClosureWhat is ConditionMultisigClosure?
A
ConditionMultisigClosuretapscript leaf is structured as:The condition is an arbitrary subscript that must evaluate to true before the multisig is checked. The witness must satisfy both the condition and the multisig. Pubkeys are extracted from the embedded
MultisigClosure.Real-world use: This is the VHTLC claim closure in Fulmine. The
ClaimClosureis aConditionMultisigClosurewhere the condition is a preimage check:A receiver claims the VTXO by providing the preimage in the witness, satisfying the condition, alongside their multisig signature.
What needs to be tested
An integration test (suggested location:
test/condition_multisig_test.go, parallel totest/tx_test.go) that:ConditionMultisigClosuretapscript — e.g., a preimage condition (OP_SHA256 <hash> OP_EQUALVERIFY) combined with a multisig over Bob and the introspector keycreateVtxoScriptWithArkadeScriptor equivalent)alice.SendOffChainConditionMultisigClosureleaf, providing the preimage in the witnessintrospectorClient.SubmitTxorintrospectorClient.SubmitIntentConditionMultisigClosure, extracts the owner pubkey fromc.PubKeys, finds the tweaked key, and produces a valid signatureRelevant code paths
pkg/arkade/script.go—ReadArkadeScript/ConditionMultisigClosurebranch (PR Support every type of tapscript closure #30, line ~70)pkg/arkade/script_test.go+testdata/read_arkade_script.json— unit-level decode test data (reference for valid/invalid fixtures)test/tx_test.go—TestOffchain: reference for full e2e test structure (setup, VTXO creation, introspector client, tx submission)test/utils_test.go—createVtxoScriptWithArkadeScript,setupIntrospectorClient,setupBobWallet, regtest helpersarkade-os/arkd/pkg/ark-lib/script/closure.go—ConditionMultisigClosuredefinition andDecodeClosureswitch orderfulmine/pkg/vhtlc/— real-worldConditionMultisigClosureusage as claim closure (good reference for preimage condition construction)Key distinctions from other closure types
c.PubKeysc.PubKeys(via embedded MultisigClosure)c.PubKeys(via embedded CSVMultisigClosure)The key subtlety: introspector's
ReadArkadeScriptonly checks that its own tweaked pubkey appears inc.PubKeys. It does not evaluate the condition subscript — that is left to Bitcoin script execution. The test should confirm the introspector correctly signs without needing to evaluate the preimage itself.Why this matters
ConditionMultisigClosureis the mechanism behind VHTLC claims — the core of Fulmine's Lightning bridge. If introspector silently fails to sign aConditionMultisigClosureleaf (e.g. due to a future refactor ofDecodeClosure), any VHTLC that includes the introspector in its claim multisig loses its ability to settle. This test ensures that regression cannot happen silently.Related
ConditionMultisigClosuresupport toReadArkadeScriptCSVMultisigClosure(unilateral exit)CLTVMultisigClosureConditionMultisigClosureas claim closure