From e94dc67b3187ebfbaa630e43805e2f4be306803a Mon Sep 17 00:00:00 2001 From: natsoni Date: Thu, 13 Mar 2025 15:46:11 +0100 Subject: [PATCH 1/3] Update tapscript multisig minimum size --- frontend/src/app/shared/script.utils.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/shared/script.utils.ts b/frontend/src/app/shared/script.utils.ts index 62a7a5845..df50a4070 100644 --- a/frontend/src/app/shared/script.utils.ts +++ b/frontend/src/app/shared/script.utils.ts @@ -310,8 +310,10 @@ export function parseTapscriptMultisig(script: string): undefined | { m: number, } const ops = script.split(' '); - // At minimum, one pubkey group (3 tokens) + m push + final opcode = 5 tokens - if (ops.length < 5) return; + // At minimum, 2 pubkey group (3 tokens) + m push + final opcode = 8 tokens + if (ops.length < 8) { + return; + } const finalOp = ops.pop(); if (finalOp !== 'OP_NUMEQUAL' && finalOp !== 'OP_GREATERTHANOREQUAL') { From 188096e651f745ef8a09d4091d1eb727282a50c4 Mon Sep 17 00:00:00 2001 From: natsoni Date: Thu, 13 Mar 2025 16:38:53 +0100 Subject: [PATCH 2/3] Add opcodes that can be used for tapscript multisig --- frontend/src/app/shared/script.utils.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/shared/script.utils.ts b/frontend/src/app/shared/script.utils.ts index df50a4070..f0c4701db 100644 --- a/frontend/src/app/shared/script.utils.ts +++ b/frontend/src/app/shared/script.utils.ts @@ -316,7 +316,7 @@ export function parseTapscriptMultisig(script: string): undefined | { m: number, } const finalOp = ops.pop(); - if (finalOp !== 'OP_NUMEQUAL' && finalOp !== 'OP_GREATERTHANOREQUAL') { + if (!['OP_NUMEQUAL', 'OP_NUMEQUALVERIFY', 'OP_GREATERTHANOREQUAL', 'OP_GREATERTHAN', 'OP_EQUAL', 'OP_EQUALVERIFY'].includes(finalOp)) { return; } @@ -331,6 +331,10 @@ export function parseTapscriptMultisig(script: string): undefined | { m: number, return; } + if (finalOp === 'OP_GREATERTHAN') { + m += 1; + } + if (ops.length % 3 !== 0) { return; } From 322e81d3edcbea536274ea72110188e4f333bc40 Mon Sep 17 00:00:00 2001 From: natsoni Date: Fri, 14 Mar 2025 14:59:15 +0100 Subject: [PATCH 3/3] Parse tapscript unanimous n-of-n multisig --- frontend/src/app/shared/script.utils.ts | 52 +++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/frontend/src/app/shared/script.utils.ts b/frontend/src/app/shared/script.utils.ts index f0c4701db..8453bdd63 100644 --- a/frontend/src/app/shared/script.utils.ts +++ b/frontend/src/app/shared/script.utils.ts @@ -256,6 +256,11 @@ export function detectScriptTemplate(type: ScriptType, script_asm: string, witne return ScriptTemplates.multisig(tapscriptMultisig.m, tapscriptMultisig.n); } + const tapscriptUnanimousMultisig = parseTapscriptUnanimousMultisig(script_asm); + if (tapscriptUnanimousMultisig) { + return ScriptTemplates.multisig(tapscriptUnanimousMultisig, tapscriptUnanimousMultisig); + } + return; } @@ -366,6 +371,53 @@ export function parseTapscriptMultisig(script: string): undefined | { m: number, return { m, n }; } +export function parseTapscriptUnanimousMultisig(script: string): undefined | number { + if (!script) { + return; + } + + const ops = script.split(' '); + // At minimum, 2 pubkey group (3 tokens) = 6 tokens + if (ops.length < 6) { + return; + } + + if (ops.length % 3 !== 0) { + return; + } + + const n = ops.length / 3; + + for (let i = 0; i < n; i++) { + const pushOp = ops.shift(); + const pubkey = ops.shift(); + const sigOp = ops.shift(); + + if (pushOp !== 'OP_PUSHBYTES_32') { + return; + } + if (!/^[0-9a-fA-F]{64}$/.test(pubkey)) { + return; + } + if (i < n - 1) { + if (sigOp !== 'OP_CHECKSIGVERIFY') { + return; + } + } else { + // Last opcode can be either CHECKSIG or CHECKSIGVERIFY + if (!(sigOp === 'OP_CHECKSIGVERIFY' || sigOp === 'OP_CHECKSIG')) { + return; + } + } + } + + if (ops.length) { + return; + } + + return n; +} + export function getVarIntLength(n: number): number { if (n < 0xfd) { return 1;