From 157d32d2fe50929b787b2f803aaaa38e1f58a6e9 Mon Sep 17 00:00:00 2001 From: michael1011 Date: Sun, 28 Jan 2024 01:45:42 +0100 Subject: [PATCH 1/3] fix: type in file name --- lib/liquid/index.ts | 2 +- lib/liquid/swap/Claim.ts | 2 +- .../swap/{TaprooUtils.ts => TaprootUtils.ts} | 0 package-lock.json | 176 +++++++++--------- package.json | 6 +- test/integration/Utils.ts | 2 +- .../liquid/swapTree/SwapTreeClaim.spec.ts | 2 +- ...prooUtils.spec.ts => TaprootUtils.spec.ts} | 2 +- ...spec.ts.snap => TaprootUtils.spec.ts.snap} | 0 9 files changed, 96 insertions(+), 96 deletions(-) rename lib/liquid/swap/{TaprooUtils.ts => TaprootUtils.ts} (100%) rename test/unit/liquid/swap/{TaprooUtils.spec.ts => TaprootUtils.spec.ts} (98%) rename test/unit/liquid/swap/__snapshots__/{TaprooUtils.spec.ts.snap => TaprootUtils.spec.ts.snap} (100%) diff --git a/lib/liquid/index.ts b/lib/liquid/index.ts index ee86cd9..073cf89 100644 --- a/lib/liquid/index.ts +++ b/lib/liquid/index.ts @@ -4,7 +4,7 @@ import { LiquidClaimDetails, LiquidRefundDetails } from './consts/Types'; import { init } from './init'; import { constructClaimTransaction } from './swap/Claim'; import { constructRefundTransaction } from './swap/Refund'; -import * as TaprootUtils from './swap/TaprooUtils'; +import * as TaprootUtils from './swap/TaprootUtils'; export { Networks, diff --git a/lib/liquid/swap/Claim.ts b/lib/liquid/swap/Claim.ts index 762fe74..536da35 100644 --- a/lib/liquid/swap/Claim.ts +++ b/lib/liquid/swap/Claim.ts @@ -27,7 +27,7 @@ import { getOutputValue } from '../Utils'; import Networks from '../consts/Networks'; import { LiquidClaimDetails } from '../consts/Types'; import { ecpair, secp } from '../init'; -import { createControlBlock, tapLeafHash, toHashTree } from './TaprooUtils'; +import { createControlBlock, tapLeafHash, toHashTree } from './TaprootUtils'; const dummyTaprootSignature = Buffer.alloc(64); diff --git a/lib/liquid/swap/TaprooUtils.ts b/lib/liquid/swap/TaprootUtils.ts similarity index 100% rename from lib/liquid/swap/TaprooUtils.ts rename to lib/liquid/swap/TaprootUtils.ts diff --git a/package-lock.json b/package-lock.json index d58a01a..b3cf765 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,10 +24,10 @@ "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@typechain/ethers-v6": "^0.5.1", "@types/jest": "^29.5.11", - "@types/node": "^20.11.5", + "@types/node": "^20.11.8", "@types/ws": "^8.5.10", - "@typescript-eslint/eslint-plugin": "^6.19.0", - "@typescript-eslint/parser": "^6.19.0", + "@typescript-eslint/eslint-plugin": "^6.19.1", + "@typescript-eslint/parser": "^6.19.1", "bip174": "^2.1.1", "cross-os": "^1.5.0", "eslint": "^8.56.0", @@ -1553,9 +1553,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz", - "integrity": "sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==", + "version": "20.11.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.8.tgz", + "integrity": "sha512-i7omyekpPTNdv4Jb/Rgqg0RU8YqLcNsI12quKSDkRXNfx7Wxdm6HhK1awT3xTgEkgxPn3bvnSpiEAc7a7Lpyow==", "dependencies": { "undici-types": "~5.26.4" } @@ -1612,16 +1612,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.0.tgz", - "integrity": "sha512-DUCUkQNklCQYnrBSSikjVChdc84/vMPDQSgJTHBZ64G9bA9w0Crc0rd2diujKbTdp6w2J47qkeHQLoi0rpLCdg==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.1.tgz", + "integrity": "sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.19.0", - "@typescript-eslint/type-utils": "6.19.0", - "@typescript-eslint/utils": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0", + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/type-utils": "6.19.1", + "@typescript-eslint/utils": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1647,13 +1647,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.0.tgz", - "integrity": "sha512-dO1XMhV2ehBI6QN8Ufi7I10wmUovmLU0Oru3n5LVlM2JuzB4M+dVphCPLkVpKvGij2j/pHBWuJ9piuXx+BhzxQ==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz", + "integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0" + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1664,9 +1664,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.0.tgz", - "integrity": "sha512-lFviGV/vYhOy3m8BJ/nAKoAyNhInTdXpftonhWle66XHAtT1ouBlkjL496b5H5hb8dWXHwtypTqgtb/DEa+j5A==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz", + "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1677,13 +1677,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.0.tgz", - "integrity": "sha512-o/zefXIbbLBZ8YJ51NlkSAt2BamrK6XOmuxSR3hynMIzzyMY33KuJ9vuMdFSXW+H0tVvdF9qBPTHA91HDb4BIQ==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz", + "integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1705,17 +1705,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.0.tgz", - "integrity": "sha512-QR41YXySiuN++/dC9UArYOg4X86OAYP83OWTewpVx5ct1IZhjjgTLocj7QNxGhWoTqknsgpl7L+hGygCO+sdYw==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.1.tgz", + "integrity": "sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.19.0", - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/typescript-estree": "6.19.0", + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/typescript-estree": "6.19.1", "semver": "^7.5.4" }, "engines": { @@ -1730,12 +1730,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.0.tgz", - "integrity": "sha512-hZaUCORLgubBvtGpp1JEFEazcuEdfxta9j4iUwdSAr7mEsYYAp3EAUyCZk3VEEqGj6W+AV4uWyrDGtrlawAsgQ==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz", + "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", + "@typescript-eslint/types": "6.19.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1786,15 +1786,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.0.tgz", - "integrity": "sha512-1DyBLG5SH7PYCd00QlroiW60YJ4rWMuUGa/JBV0iZuqi4l4IK3twKPq5ZkEebmGqRjXWVgsUzfd3+nZveewgow==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.1.tgz", + "integrity": "sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.19.0", - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/typescript-estree": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0", + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", "debug": "^4.3.4" }, "engines": { @@ -1814,13 +1814,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.0.tgz", - "integrity": "sha512-dO1XMhV2ehBI6QN8Ufi7I10wmUovmLU0Oru3n5LVlM2JuzB4M+dVphCPLkVpKvGij2j/pHBWuJ9piuXx+BhzxQ==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz", + "integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0" + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1831,9 +1831,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.0.tgz", - "integrity": "sha512-lFviGV/vYhOy3m8BJ/nAKoAyNhInTdXpftonhWle66XHAtT1ouBlkjL496b5H5hb8dWXHwtypTqgtb/DEa+j5A==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz", + "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1844,13 +1844,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.0.tgz", - "integrity": "sha512-o/zefXIbbLBZ8YJ51NlkSAt2BamrK6XOmuxSR3hynMIzzyMY33KuJ9vuMdFSXW+H0tVvdF9qBPTHA91HDb4BIQ==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz", + "integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1872,12 +1872,12 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.0.tgz", - "integrity": "sha512-hZaUCORLgubBvtGpp1JEFEazcuEdfxta9j4iUwdSAr7mEsYYAp3EAUyCZk3VEEqGj6W+AV4uWyrDGtrlawAsgQ==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz", + "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", + "@typescript-eslint/types": "6.19.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1945,13 +1945,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.0.tgz", - "integrity": "sha512-mcvS6WSWbjiSxKCwBcXtOM5pRkPQ6kcDds/juxcy/727IQr3xMEcwr/YLHW2A2+Fp5ql6khjbKBzOyjuPqGi/w==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.1.tgz", + "integrity": "sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.19.0", - "@typescript-eslint/utils": "6.19.0", + "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/utils": "6.19.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1972,13 +1972,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.0.tgz", - "integrity": "sha512-dO1XMhV2ehBI6QN8Ufi7I10wmUovmLU0Oru3n5LVlM2JuzB4M+dVphCPLkVpKvGij2j/pHBWuJ9piuXx+BhzxQ==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz", + "integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0" + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1989,9 +1989,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.0.tgz", - "integrity": "sha512-lFviGV/vYhOy3m8BJ/nAKoAyNhInTdXpftonhWle66XHAtT1ouBlkjL496b5H5hb8dWXHwtypTqgtb/DEa+j5A==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz", + "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2002,13 +2002,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.0.tgz", - "integrity": "sha512-o/zefXIbbLBZ8YJ51NlkSAt2BamrK6XOmuxSR3hynMIzzyMY33KuJ9vuMdFSXW+H0tVvdF9qBPTHA91HDb4BIQ==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz", + "integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/visitor-keys": "6.19.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2030,17 +2030,17 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.0.tgz", - "integrity": "sha512-QR41YXySiuN++/dC9UArYOg4X86OAYP83OWTewpVx5ct1IZhjjgTLocj7QNxGhWoTqknsgpl7L+hGygCO+sdYw==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.1.tgz", + "integrity": "sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.19.0", - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/typescript-estree": "6.19.0", + "@typescript-eslint/scope-manager": "6.19.1", + "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/typescript-estree": "6.19.1", "semver": "^7.5.4" }, "engines": { @@ -2055,12 +2055,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.0.tgz", - "integrity": "sha512-hZaUCORLgubBvtGpp1JEFEazcuEdfxta9j4iUwdSAr7mEsYYAp3EAUyCZk3VEEqGj6W+AV4uWyrDGtrlawAsgQ==", + "version": "6.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz", + "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", + "@typescript-eslint/types": "6.19.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { diff --git a/package.json b/package.json index 7ad5f20..f1d71b9 100644 --- a/package.json +++ b/package.json @@ -64,10 +64,10 @@ "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@typechain/ethers-v6": "^0.5.1", "@types/jest": "^29.5.11", - "@types/node": "^20.11.5", + "@types/node": "^20.11.8", "@types/ws": "^8.5.10", - "@typescript-eslint/eslint-plugin": "^6.19.0", - "@typescript-eslint/parser": "^6.19.0", + "@typescript-eslint/eslint-plugin": "^6.19.1", + "@typescript-eslint/parser": "^6.19.1", "bip174": "^2.1.1", "cross-os": "^1.5.0", "eslint": "^8.56.0", diff --git a/test/integration/Utils.ts b/test/integration/Utils.ts index 82d61d1..ee50af9 100644 --- a/test/integration/Utils.ts +++ b/test/integration/Utils.ts @@ -30,7 +30,7 @@ import { constructClaimTransaction as liquidConstructClaimTransaction, constructRefundTransaction as liquidConstructRefundTransaction, } from '../../lib/liquid'; -import { tweakMusig as liquidTweakMusig } from '../../lib/liquid/swap/TaprooUtils'; +import { tweakMusig as liquidTweakMusig } from '../../lib/liquid/swap/TaprootUtils'; import Musig from '../../lib/musig/Musig'; import { outputFunctionForType, diff --git a/test/integration/liquid/swapTree/SwapTreeClaim.spec.ts b/test/integration/liquid/swapTree/SwapTreeClaim.spec.ts index 9feebaf..19a62bb 100644 --- a/test/integration/liquid/swapTree/SwapTreeClaim.spec.ts +++ b/test/integration/liquid/swapTree/SwapTreeClaim.spec.ts @@ -7,7 +7,7 @@ import { constructClaimTransaction, init, } from '../../../../lib/liquid'; -import { hashForWitnessV1 } from '../../../../lib/liquid/swap/TaprooUtils'; +import { hashForWitnessV1 } from '../../../../lib/liquid/swap/TaprootUtils'; import reverseSwapTree from '../../../../lib/swap/ReverseSwapTree'; import swapTree from '../../../../lib/swap/SwapTree'; import { ECPair, slip77 } from '../../../unit/Utils'; diff --git a/test/unit/liquid/swap/TaprooUtils.spec.ts b/test/unit/liquid/swap/TaprootUtils.spec.ts similarity index 98% rename from test/unit/liquid/swap/TaprooUtils.spec.ts rename to test/unit/liquid/swap/TaprootUtils.spec.ts index feb78f5..6100c9f 100644 --- a/test/unit/liquid/swap/TaprooUtils.spec.ts +++ b/test/unit/liquid/swap/TaprootUtils.spec.ts @@ -16,7 +16,7 @@ import { tapTweakHash, toHashTree, tweakMusig, -} from '../../../../lib/liquid/swap/TaprooUtils'; +} from '../../../../lib/liquid/swap/TaprootUtils'; import Musig from '../../../../lib/musig/Musig'; import { createLeaf } from '../../../../lib/swap/TaprootUtils'; import { ECPair } from '../../Utils'; diff --git a/test/unit/liquid/swap/__snapshots__/TaprooUtils.spec.ts.snap b/test/unit/liquid/swap/__snapshots__/TaprootUtils.spec.ts.snap similarity index 100% rename from test/unit/liquid/swap/__snapshots__/TaprooUtils.spec.ts.snap rename to test/unit/liquid/swap/__snapshots__/TaprootUtils.spec.ts.snap From b4111ad5a2cdda6da3afece145e723e9232e6146 Mon Sep 17 00:00:00 2001 From: michael1011 Date: Sun, 28 Jan 2024 16:35:30 +0100 Subject: [PATCH 2/3] feat: Liquid claim covenant --- lib/liquid/TreeSort.ts | 64 +++ lib/liquid/Utils.ts | 31 ++ lib/liquid/consts/Ops.ts | 6 + lib/liquid/consts/Types.ts | 12 +- lib/liquid/index.ts | 11 + lib/liquid/swap/Claim.ts | 56 ++- lib/liquid/swap/ReverseSwapTree.ts | 118 +++++ lib/liquid/swap/TaprootUtils.ts | 5 +- lib/swap/Claim.ts | 9 +- lib/swap/PreimageDetector.ts | 5 +- package-lock.json | 8 +- package.json | 2 +- test/integration/Utils.ts | 33 +- .../ReverseSwapTreeCovenantClaim.spec.ts | 455 ++++++++++++++++++ .../liquid/utils/ElementsClient.ts | 13 +- test/integration/utils/ChainClient.ts | 28 +- test/unit/liquid/TreeSort.spec.ts | 96 ++++ test/unit/liquid/Utils.spec.ts | 58 +++ .../unit/liquid/swap/PreimageDetector.spec.ts | 21 +- test/unit/liquid/swap/ReverseSwapTree.spec.ts | 50 ++ 20 files changed, 1019 insertions(+), 62 deletions(-) create mode 100644 lib/liquid/TreeSort.ts create mode 100644 lib/liquid/consts/Ops.ts create mode 100644 lib/liquid/swap/ReverseSwapTree.ts create mode 100644 test/integration/liquid/reverseSwapTree/ReverseSwapTreeCovenantClaim.spec.ts create mode 100644 test/unit/liquid/TreeSort.spec.ts create mode 100644 test/unit/liquid/Utils.spec.ts create mode 100644 test/unit/liquid/swap/ReverseSwapTree.spec.ts diff --git a/lib/liquid/TreeSort.ts b/lib/liquid/TreeSort.ts new file mode 100644 index 0000000..9f9b231 --- /dev/null +++ b/lib/liquid/TreeSort.ts @@ -0,0 +1,64 @@ +import { Tapleaf } from '../consts/Types'; +import { LiquidSwapTree } from './consts/Types'; + +type ProbabilityNode = { probability: number; value: T }; + +type TreeNode = Tree | T; +type Tree = [TreeNode, TreeNode]; + +const subSortTree = (nodes: ProbabilityNode[]): TreeNode => { + if (nodes.length === 1) { + return nodes[0].value; + } else if (nodes.length === 2) { + return [nodes[0].value, nodes[1].value]; + } + + const sum = nodes.reduce((sum, node) => sum + node.probability, 0); + + let mid = 0; + let midSum = 0; + + while (midSum < sum / 2) { + midSum += nodes[mid].probability; + mid++; + } + + return [subSortTree(nodes.slice(0, mid)), subSortTree(nodes.slice(mid))]; +}; + +export const sortTree = (nodes: ProbabilityNode[]): TreeNode => + subSortTree(nodes.sort((a, b) => b.probability - a.probability)); + +export const assignTreeProbabilities = ( + tree: Omit, +): ProbabilityNode[] => { + if (tree.covenantClaimLeaf) { + return [ + { + probability: 51, + value: tree.covenantClaimLeaf, + }, + { + probability: 25, + value: tree.claimLeaf, + }, + { + probability: 24, + value: tree.refundLeaf, + }, + ]; + } + + return [ + { + probability: 51, + value: tree.claimLeaf, + }, + { + probability: 49, + value: tree.refundLeaf, + }, + ]; +}; + +export { Tree, TreeNode, ProbabilityNode }; diff --git a/lib/liquid/Utils.ts b/lib/liquid/Utils.ts index c2514b5..75ef542 100644 --- a/lib/liquid/Utils.ts +++ b/lib/liquid/Utils.ts @@ -1,3 +1,5 @@ +import ops from '@boltz/bitcoin-ops'; +import { crypto, script } from 'bitcoinjs-lib'; import { TxOutput, confidential } from 'liquidjs-lib'; import { confidentialLiquid } from './init'; @@ -17,3 +19,32 @@ export const getOutputValue = ( ) : confidential.confidentialValueToSatoshi(output.value); }; + +const getScriptIntrospectionWitnessScript = (outputScript: Buffer) => + outputScript.subarray(2, 40); + +export const getScriptIntrospectionValues = ( + outputScript: Buffer, +): { version: number; script: Buffer } => { + const dec = script.decompile(outputScript)!; + + switch (dec[0]) { + case ops.OP_1: + return { + version: 1, + script: getScriptIntrospectionWitnessScript(outputScript), + }; + + case ops.OP_0: + return { + version: 0, + script: getScriptIntrospectionWitnessScript(outputScript), + }; + + default: + return { + version: -1, + script: crypto.sha256(outputScript), + }; + } +}; diff --git a/lib/liquid/consts/Ops.ts b/lib/liquid/consts/Ops.ts new file mode 100644 index 0000000..c0ec34e --- /dev/null +++ b/lib/liquid/consts/Ops.ts @@ -0,0 +1,6 @@ +// Reference: https://github.com/ElementsProject/elements/blob/master/doc/tapscript_opcodes.md#new-opcodes-for-additional-functionality +export default { + OP_INSPECTOUTPUTSCRIPTPUBKEY: 0xd1, + OP_INSPECTOUTPUTASSET: 0xce, + OP_INSPECTOUTPUTVALUE: 0xcf, +}; diff --git a/lib/liquid/consts/Types.ts b/lib/liquid/consts/Types.ts index 5825597..ec2ccf9 100644 --- a/lib/liquid/consts/Types.ts +++ b/lib/liquid/consts/Types.ts @@ -1,12 +1,18 @@ +import { BIP32Interface } from 'bip32'; +import { ECPairInterface } from 'ecpair'; import { Transaction, TxOutput } from 'liquidjs-lib'; -import { RefundDetails } from '../../consts/Types'; +import { RefundDetails, SwapTree, Tapleaf } from '../../consts/Types'; -export type LiquidRefundDetails = Omit & +export type LiquidSwapTree = SwapTree & { covenantClaimLeaf?: Tapleaf }; + +export type LiquidRefundDetails = Omit & TxOutput & { legacyTx?: Transaction; + swapTree?: LiquidSwapTree; blindingPrivateKey?: Buffer; }; -export type LiquidClaimDetails = LiquidRefundDetails & { +export type LiquidClaimDetails = Omit & { preimage: Buffer; + keys?: ECPairInterface | BIP32Interface; }; diff --git a/lib/liquid/index.ts b/lib/liquid/index.ts index 073cf89..08cf158 100644 --- a/lib/liquid/index.ts +++ b/lib/liquid/index.ts @@ -1,18 +1,29 @@ import { getOutputValue } from './Utils'; +import * as Utils from './Utils'; import Networks from './consts/Networks'; +import ops from './consts/Ops'; import { LiquidClaimDetails, LiquidRefundDetails } from './consts/Types'; import { init } from './init'; import { constructClaimTransaction } from './swap/Claim'; import { constructRefundTransaction } from './swap/Refund'; +import reverseSwapTree, { + Feature, + FeatureOption, +} from './swap/ReverseSwapTree'; import * as TaprootUtils from './swap/TaprootUtils'; export { + ops, + Utils, + Feature, Networks, TaprootUtils, + FeatureOption, LiquidClaimDetails, LiquidRefundDetails, init, getOutputValue, + reverseSwapTree, constructClaimTransaction, constructRefundTransaction, }; diff --git a/lib/liquid/swap/Claim.ts b/lib/liquid/swap/Claim.ts index 536da35..93e0d11 100644 --- a/lib/liquid/swap/Claim.ts +++ b/lib/liquid/swap/Claim.ts @@ -21,7 +21,7 @@ import { reverseBuffer, varuint } from 'liquidjs-lib/src/bufferutils'; import { Network } from 'liquidjs-lib/src/networks'; import { getHexString } from '../../Utils'; import { OutputType } from '../../consts/Enums'; -import { validateInputs } from '../../swap/Claim'; +import { isRelevantTaprootOutput, validateInputs } from '../../swap/Claim'; import { scriptBuffersToScript } from '../../swap/SwapUtils'; import { getOutputValue } from '../Utils'; import Networks from '../consts/Networks'; @@ -36,6 +36,29 @@ const getSighashType = (type: OutputType) => ? Transaction.SIGHASH_DEFAULT : Transaction.SIGHASH_ALL; +const validateLiquidInputs = ( + utxos: LiquidClaimDetails[], + isRefund: boolean, +) => { + validateInputs(utxos); + + const taprootInputs = utxos.filter(isRelevantTaprootOutput); + + if (isRefund && taprootInputs.some((utxo) => utxo.keys === undefined)) { + throw 'not all Taproot refund inputs have keys'; + } + + if ( + taprootInputs.some( + (utxo) => + utxo.keys === undefined && + utxo.swapTree!.covenantClaimLeaf === undefined, + ) + ) { + throw 'not all Taproot signature claims have keys'; + } +}; + /** * Claim swaps * @@ -58,7 +81,7 @@ export const constructClaimTransaction = ( timeoutBlockHeight?: number, isRefund = false, ): Transaction => { - validateInputs(utxos); + validateLiquidInputs(utxos, isRefund); if ( utxos.some( @@ -133,10 +156,10 @@ export const constructClaimTransaction = ( }, ]); - const addFeeOutput = () => { + const addFeeOutput = (isUnblinded = false) => { updater.addOutputs([ { - amount: fee, + amount: isUnblinded ? fee - 1 : fee, asset: network.assetHash, }, ]); @@ -149,7 +172,8 @@ export const constructClaimTransaction = ( pset.addOutput( new CreatorOutput( network.assetHash, - 0, + // TODO: figure out flakiness with blinding 0 amount outputs + 1, Buffer.of(ops.OP_RETURN), ecpair.makeRandom().publicKey, 0, @@ -157,7 +181,7 @@ export const constructClaimTransaction = ( ); } - addFeeOutput(); + addFeeOutput(blindingKey === undefined); blindPset(pset, utxos); } else { @@ -170,7 +194,7 @@ export const constructClaimTransaction = ( for (const [i, utxo] of utxos.entries()) { if (utxo.type === OutputType.Taproot) { - if (utxo.cooperative) { + if (utxo.cooperative || (!isRefund && utxo.keys === undefined)) { signatures.push(dummyTaprootSignature); continue; } @@ -178,7 +202,7 @@ export const constructClaimTransaction = ( const leafHash = tapLeafHash( isRefund ? utxo.swapTree!.refundLeaf : utxo.swapTree!.claimLeaf, ); - const signature = utxo.keys.signSchnorr( + const signature = utxo.keys!.signSchnorr( pset.getInputPreimage( i, getSighashType(utxo.type), @@ -194,7 +218,7 @@ export const constructClaimTransaction = ( tapScriptSigs: [ { signature: signature, - pubkey: toXOnly(utxo.keys.publicKey), + pubkey: toXOnly(utxo.keys!.publicKey), leafHash, }, ], @@ -203,7 +227,7 @@ export const constructClaimTransaction = ( ); } else { const signature = script.signature.encode( - utxo.keys.sign(pset.getInputPreimage(i, getSighashType(utxo.type))), + utxo.keys!.sign(pset.getInputPreimage(i, getSighashType(utxo.type))), getSighashType(utxo.type), ); signatures.push(signature); @@ -212,7 +236,7 @@ export const constructClaimTransaction = ( i, { partialSig: { - pubkey: utxo.keys.publicKey, + pubkey: utxo.keys!.publicKey, signature, }, }, @@ -253,13 +277,19 @@ export const constructClaimTransaction = ( dummyTaprootSignature, ]); } else { + const isCovenantClaim = utxo.keys === undefined; + const tapleaf = isRefund ? utxo.swapTree!.refundLeaf - : utxo.swapTree!.claimLeaf; + : isCovenantClaim + ? utxo.swapTree!.covenantClaimLeaf! + : utxo.swapTree!.claimLeaf; const witness = isRefund ? [signatures[i]] - : [signatures[i], utxo.preimage]; + : isCovenantClaim + ? [utxo.preimage] + : [signatures[i], utxo.preimage]; finals.finalScriptWitness = witnessStackToScriptWitness( witness.concat([ diff --git a/lib/liquid/swap/ReverseSwapTree.ts b/lib/liquid/swap/ReverseSwapTree.ts new file mode 100644 index 0000000..5e4ed5c --- /dev/null +++ b/lib/liquid/swap/ReverseSwapTree.ts @@ -0,0 +1,118 @@ +import ops from '@boltz/bitcoin-ops'; +import { crypto, script } from 'bitcoinjs-lib'; +import { reverseBuffer } from 'liquidjs-lib/src/bufferutils'; +import { getHexBuffer } from '../../Utils'; +import { Tapleaf } from '../../consts/Types'; +import bitcoinReverseSwapTree from '../../swap/ReverseSwapTree'; +import { leafVersionLiquid } from '../../swap/TaprootUtils'; +import { assignTreeProbabilities, sortTree } from '../TreeSort'; +import { getScriptIntrospectionValues } from '../Utils'; +import liquidOps from '../consts/Ops'; +import { LiquidSwapTree } from '../consts/Types'; + +enum Feature { + ClaimCovenant, +} + +type ClaimCovenant = { + assetHash: string; + outputScript: Buffer; + expectedAmount: number; +}; + +type FeatureOption = { type: Feature } & ClaimCovenant; + +const claimCovenantOutputIndex = script.number.encode(0); + +const createClaimCovenantLeaf = ( + preimageHash: Buffer, + assetHash: string, + outputScript: Buffer, + expectedAmount: number, +): Tapleaf => { + const userOutput = getScriptIntrospectionValues(outputScript); + + const amountBuffer = Buffer.alloc(8); + amountBuffer.writeBigUint64LE(BigInt(expectedAmount)); + + return { + version: leafVersionLiquid, + output: script.compile([ + ops.OP_SIZE, + script.number.encode(32), + ops.OP_EQUALVERIFY, + ops.OP_HASH160, + crypto.ripemd160(preimageHash), + ops.OP_EQUALVERIFY, + + claimCovenantOutputIndex, + liquidOps.OP_INSPECTOUTPUTSCRIPTPUBKEY, + script.number.encode(userOutput.version), + ops.OP_EQUALVERIFY, + userOutput.script, + ops.OP_EQUALVERIFY, + + claimCovenantOutputIndex, + liquidOps.OP_INSPECTOUTPUTASSET, + ops.OP_DROP, + reverseBuffer(getHexBuffer(assetHash)), + ops.OP_EQUALVERIFY, + + claimCovenantOutputIndex, + liquidOps.OP_INSPECTOUTPUTVALUE, + ops.OP_DROP, + amountBuffer, + ops.OP_EQUAL, + ]), + }; +}; + +const reverseSwapTree = ( + preimageHash: Buffer, + claimPublicKey: Buffer, + refundPublicKey: Buffer, + timeoutBlockHeight: number, + features?: FeatureOption[], +): LiquidSwapTree => { + const tree: LiquidSwapTree = bitcoinReverseSwapTree( + true, + preimageHash, + claimPublicKey, + refundPublicKey, + timeoutBlockHeight, + ); + + if (features === undefined) { + return tree; + } + + if ( + new Set(features.map((feature) => feature.type)).size !== features.length + ) { + throw 'duplicate feature'; + } + + for (const feature of features) { + switch (feature.type) { + case Feature.ClaimCovenant: + tree.covenantClaimLeaf = createClaimCovenantLeaf( + preimageHash, + feature.assetHash, + feature.outputScript, + feature.expectedAmount, + ); + break; + + default: + throw `unknown feature: ${feature.type}`; + } + } + + return { + ...tree, + tree: sortTree(assignTreeProbabilities(tree)), + }; +}; + +export default reverseSwapTree; +export { Feature, FeatureOption }; diff --git a/lib/liquid/swap/TaprootUtils.ts b/lib/liquid/swap/TaprootUtils.ts index 7c5e4e2..a265079 100644 --- a/lib/liquid/swap/TaprootUtils.ts +++ b/lib/liquid/swap/TaprootUtils.ts @@ -1,6 +1,6 @@ import { toXOnly } from 'bitcoinjs-lib/src/psbt/bip371'; import { Taptree, isTapleaf } from 'bitcoinjs-lib/src/types'; -import { Transaction } from 'liquidjs-lib'; +import { Transaction, TxOutput } from 'liquidjs-lib'; import { HashTree, TaprootLeaf, @@ -13,7 +13,6 @@ import { Network } from 'liquidjs-lib/src/networks'; import { getHexString } from '../../Utils'; import { Tapleaf } from '../../consts/Types'; import Musig from '../../musig/Musig'; -import { LiquidRefundDetails } from '../consts/Types'; import { secp } from '../init'; const convertLeaf = (leaf: Tapleaf) => ({ @@ -23,7 +22,7 @@ const convertLeaf = (leaf: Tapleaf) => ({ export const hashForWitnessV1 = ( network: Network, - details: LiquidRefundDetails[], + details: TxOutput[], tx: Transaction, index: number, leafHash?: Buffer, diff --git a/lib/swap/Claim.ts b/lib/swap/Claim.ts index ef06a14..3f1cf5f 100644 --- a/lib/swap/Claim.ts +++ b/lib/swap/Claim.ts @@ -14,10 +14,13 @@ import { createControlBlock, hashForWitnessV1 } from './TaprootUtils'; const dummyTaprootSignature = Buffer.alloc(64); -const isRelevantTaprootOutput = (utxo: Omit) => - utxo.type === OutputType.Taproot && utxo.cooperative !== true; +export const isRelevantTaprootOutput = ( + utxo: Omit, +) => utxo.type === OutputType.Taproot && utxo.cooperative !== true; -export const validateInputs = (utxos: Omit[]) => { +export const validateInputs = ( + utxos: Omit[], +) => { if ( utxos .filter((utxo) => utxo.type !== OutputType.Taproot) diff --git a/lib/swap/PreimageDetector.ts b/lib/swap/PreimageDetector.ts index b37720a..ba269bc 100644 --- a/lib/swap/PreimageDetector.ts +++ b/lib/swap/PreimageDetector.ts @@ -11,8 +11,9 @@ export const detectPreimage = ( // Get the preimage for P2TR, P2WSH and nested P2SH-P2WSH if (input.witness.length !== 0) { - // The second element of the witness is the preimage - return input.witness[1]; + // The second element of the witness is the preimage for claims with signature + // The first element in case of claims with covenant + return input.witness[0].length === 32 ? input.witness[0] : input.witness[1]; } else { // Get the preimage of legacy P2SH const scriptBuffers = script.decompile(input.script) as (Buffer | number)[]; diff --git a/package-lock.json b/package-lock.json index b3cf765..7efd87f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@typechain/ethers-v6": "^0.5.1", "@types/jest": "^29.5.11", - "@types/node": "^20.11.8", + "@types/node": "^20.11.9", "@types/ws": "^8.5.10", "@typescript-eslint/eslint-plugin": "^6.19.1", "@typescript-eslint/parser": "^6.19.1", @@ -1553,9 +1553,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.8.tgz", - "integrity": "sha512-i7omyekpPTNdv4Jb/Rgqg0RU8YqLcNsI12quKSDkRXNfx7Wxdm6HhK1awT3xTgEkgxPn3bvnSpiEAc7a7Lpyow==", + "version": "20.11.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.9.tgz", + "integrity": "sha512-CQXNuMoS/VcoAMISe5pm4JnEd1Br5jildbQEToEMQvutmv+EaQr90ry9raiudgpyDuqFiV9e4rnjSfLNq12M5w==", "dependencies": { "undici-types": "~5.26.4" } diff --git a/package.json b/package.json index f1d71b9..c9939da 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@typechain/ethers-v6": "^0.5.1", "@types/jest": "^29.5.11", - "@types/node": "^20.11.8", + "@types/node": "^20.11.9", "@types/ws": "^8.5.10", "@typescript-eslint/eslint-plugin": "^6.19.1", "@typescript-eslint/parser": "^6.19.1", diff --git a/test/integration/Utils.ts b/test/integration/Utils.ts index ee50af9..4de3f13 100644 --- a/test/integration/Utils.ts +++ b/test/integration/Utils.ts @@ -72,16 +72,9 @@ const sendFundsToOutput = async < let blindingPrivateKey: Buffer | undefined; if (confidential) { - const slip = slip77.derive(outputScript); - blindingPrivateKey = slip.privateKey; - - const dec = liquidAddress.fromBech32(swapAddress); - swapAddress = liquidAddress.toBlech32( - Buffer.concat([Buffer.from([dec.version, dec.data.length]), dec.data]), - slip.publicKey!, - LiquidNetworks.liquidRegtest.blech32, - outputType === OutputType.Bech32 ? 0 : 1, - ); + const enc = blindWitnessAddress(swapAddress, outputType); + swapAddress = enc.address; + blindingPrivateKey = enc.blindingKey.privateKey; } const chainClient = isBitcoin ? bitcoinClient : elementsClient; @@ -121,6 +114,24 @@ export const destinationOutput = p2wpkhOutput( crypto.hash160(generateKeys().publicKey!), ); +export const blindWitnessAddress = ( + address: string, + outputType: OutputType, +) => { + const slip = slip77.derive(liquidAddress.toOutputScript(address)); + const dec = liquidAddress.fromBech32(address); + + return { + blindingKey: slip, + address: liquidAddress.toBlech32( + Buffer.concat([Buffer.from([dec.version, dec.data.length]), dec.data]), + slip.publicKey!, + LiquidNetworks.liquidRegtest.blech32, + outputType === OutputType.Bech32 ? 0 : 1, + ), + }; +}; + export const claimSwap = async ( claimDetails: (ClaimDetails | LiquidClaimDetails)[], outputBlindingKey?: Buffer, @@ -153,7 +164,7 @@ export const claimSwap = async ( }; export const refundSwap = async ( - refundDetails: (RefundDetails | LiquidRefundDetails)[], + refundDetails: (RefundDetails | Omit)[], blockHeight: number, outputBlindingKey?: Buffer, ): Promise => { diff --git a/test/integration/liquid/reverseSwapTree/ReverseSwapTreeCovenantClaim.spec.ts b/test/integration/liquid/reverseSwapTree/ReverseSwapTreeCovenantClaim.spec.ts new file mode 100644 index 0000000..98c4538 --- /dev/null +++ b/test/integration/liquid/reverseSwapTree/ReverseSwapTreeCovenantClaim.spec.ts @@ -0,0 +1,455 @@ +import zkp from '@vulpemventures/secp256k1-zkp'; +import { crypto } from 'bitcoinjs-lib'; +import { randomBytes } from 'crypto'; +import { Transaction, address, networks } from 'liquidjs-lib'; +import { OutputType } from '../../../../lib/consts/Enums'; +import { + LiquidClaimDetails, + constructClaimTransaction, + constructRefundTransaction, + init, +} from '../../../../lib/liquid'; +import { secp } from '../../../../lib/liquid/init'; +import liquidReverseSwapTree, { + Feature, +} from '../../../../lib/liquid/swap/ReverseSwapTree'; +import { + hashForWitnessV1, + tweakMusig, +} from '../../../../lib/liquid/swap/TaprootUtils'; +import Musig from '../../../../lib/musig/Musig'; +import { p2trOutput, p2wshOutput } from '../../../../lib/swap/Scripts'; +import { detectSwap } from '../../../../lib/swap/SwapDetector'; +import { ECPair } from '../../../unit/Utils'; +import { + blindWitnessAddress, + elementsClient, + init as utilsInit, +} from '../../Utils'; +import { AddressType } from '../../utils/ChainClient'; + +describe.each` + shouldBlind + ${false} + ${true} +`( + 'ReverseSwapTree Covenant claim path with blinded input $shouldBlind', + ({ shouldBlind }) => { + beforeAll(async () => { + init(await zkp()); + await Promise.all([utilsInit(), elementsClient.init()]); + }); + + afterEach(async () => { + await elementsClient.generate(1); + }); + + const createOutput = async ( + preimage?: Buffer, + outputAddress?: string, + timeoutBlockHeight?: number, + ) => { + preimage = preimage || randomBytes(32); + timeoutBlockHeight = + timeoutBlockHeight || + (await elementsClient.getBlockchainInfo()).blocks + 21; + + const preimageHash = crypto.sha256(preimage); + const ourKeys = ECPair.makeRandom(); + const theirKeys = ECPair.makeRandom(); + + const expectedOutput = address.toOutputScript( + outputAddress || (await elementsClient.getNewAddress()), + networks.regtest, + ); + const expectedAmount = 10_000; + + const tree = liquidReverseSwapTree( + preimageHash, + ourKeys.publicKey, + theirKeys.publicKey, + timeoutBlockHeight, + [ + { + expectedAmount, + outputScript: expectedOutput, + type: Feature.ClaimCovenant, + assetHash: networks.regtest.assetHash, + }, + ], + ); + const musig = new Musig(secp, ourKeys, randomBytes(32), [ + ourKeys.publicKey, + theirKeys.publicKey, + ]); + const tweakedKey = tweakMusig(musig, tree.tree); + + let swapAddress = address.fromOutputScript( + p2trOutput(tweakedKey), + networks.regtest, + ); + let blindingPrivateKey: Buffer | undefined = undefined; + + if (shouldBlind) { + const enc = blindWitnessAddress(swapAddress, OutputType.Taproot); + swapAddress = enc.address; + blindingPrivateKey = enc.blindingKey.privateKey; + } + + const feeBuffer = 210; + const tx = Transaction.fromHex( + await elementsClient.getRawTransaction( + await elementsClient.sendToAddress( + swapAddress, + expectedAmount + feeBuffer, + ), + ), + ); + + const output = detectSwap(tweakedKey, tx)!; + + return { + tree, + musig, + output, + ourKeys, + preimage, + feeBuffer, + theirKeys, + expectedAmount, + expectedOutput, + timeoutBlockHeight, + blindingPrivateKey, + lockupTx: tx, + utxos: [ + { + ...output, + preimage, + swapTree: tree, + blindingPrivateKey, + txHash: tx.getHash(), + internalKey: musig.getAggregatedPublicKey(), + }, + ] as LiquidClaimDetails[], + }; + }; + + test('should claim via key path', async () => { + const { utxos, musig, feeBuffer, theirKeys, expectedOutput } = + await createOutput(undefined, undefined, undefined); + utxos[0].cooperative = true; + + const claimTx = constructClaimTransaction( + utxos, + expectedOutput, + feeBuffer, + true, + networks.regtest, + ); + + const theirNonce = secp.musig.nonceGen( + randomBytes(32), + theirKeys.publicKey, + ); + musig.aggregateNonces([[theirKeys.publicKey, theirNonce.pubNonce]]); + musig.initializeSession( + hashForWitnessV1(networks.regtest, utxos, claimTx, 0), + ); + musig.signPartial(); + musig.addPartial( + theirKeys.publicKey, + secp.musig.partialSign( + theirNonce.secNonce, + theirKeys.privateKey!, + musig['pubkeyAgg'].keyaggCache, + musig['session']!, + ), + ); + + claimTx.setWitness(0, [musig.aggregatePartials()]); + + await elementsClient.sendRawTransaction(claimTx.toHex()); + }); + + test('should claim via signature script path', async () => { + const { utxos, feeBuffer, expectedOutput, ourKeys } = + await createOutput(); + utxos[0].keys = ourKeys; + utxos[0].cooperative = false; + + const claimTx = constructClaimTransaction( + utxos, + expectedOutput, + feeBuffer, + true, + networks.regtest, + ); + + await elementsClient.sendRawTransaction(claimTx.toHex()); + }); + + test('should refund via signature script path', async () => { + const { + utxos, + timeoutBlockHeight, + feeBuffer, + expectedOutput, + theirKeys, + } = await createOutput( + undefined, + undefined, + (await elementsClient.getBlockchainInfo()).blocks - 1, + ); + + const claimTx = constructRefundTransaction( + [ + { + ...utxos[0], + keys: theirKeys, + cooperative: false, + }, + ], + expectedOutput, + timeoutBlockHeight, + feeBuffer, + true, + networks.regtest, + ); + + await elementsClient.sendRawTransaction(claimTx.toHex()); + }); + + test.each` + addressType + ${'p2tr'} + ${AddressType.Bech32} + ${'p2wsh'} + ${AddressType.P2shegwit} + ${AddressType.Legacy} + `( + 'should claim via covenant script path to $addressType address', + async ({ addressType }) => { + let outputAddress: string; + + switch (addressType) { + case 'p2tr': + outputAddress = address.fromOutputScript( + p2trOutput(ECPair.makeRandom().publicKey), + networks.regtest, + ); + break; + + case 'p2wsh': + outputAddress = address.fromOutputScript( + p2wshOutput(randomBytes(32)), + networks.regtest, + ); + break; + + default: + outputAddress = await elementsClient.getNewAddress(addressType); + break; + } + + const { + tree, + musig, + output, + preimage, + lockupTx, + feeBuffer, + expectedOutput, + blindingPrivateKey, + } = await createOutput(undefined, outputAddress, undefined); + + const claimTx = constructClaimTransaction( + [ + { + ...output, + preimage, + blindingPrivateKey, + swapTree: tree, + cooperative: false, + txHash: lockupTx.getHash(), + internalKey: musig.getAggregatedPublicKey(), + }, + ], + expectedOutput, + feeBuffer, + true, + networks.regtest, + ); + await elementsClient.sendRawTransaction(claimTx.toHex()); + }, + ); + + test.each` + length + ${31} + ${33} + `( + 'should not claim with invalid preimage hash length $length', + async ({ length }) => { + const { + tree, + musig, + output, + preimage, + lockupTx, + feeBuffer, + expectedOutput, + blindingPrivateKey, + } = await createOutput(randomBytes(length)); + + const claimTx = constructClaimTransaction( + [ + { + ...output, + preimage, + blindingPrivateKey, + swapTree: tree, + cooperative: false, + txHash: lockupTx.getHash(), + internalKey: musig.getAggregatedPublicKey(), + }, + ], + expectedOutput, + feeBuffer, + true, + networks.regtest, + ); + await expect( + elementsClient.sendRawTransaction(claimTx.toHex()), + ).rejects.toEqual({ + code: -26, + message: + 'non-mandatory-script-verify-flag (Script failed an OP_EQUALVERIFY operation)', + }); + }, + ); + + test('should not claim with invalid preimage', async () => { + const { + tree, + musig, + output, + lockupTx, + feeBuffer, + expectedOutput, + blindingPrivateKey, + } = await createOutput(); + + const claimTx = constructClaimTransaction( + [ + { + ...output, + blindingPrivateKey, + swapTree: tree, + cooperative: false, + txHash: lockupTx.getHash(), + preimage: randomBytes(32), + internalKey: musig.getAggregatedPublicKey(), + }, + ], + expectedOutput, + feeBuffer, + true, + networks.regtest, + ); + await expect( + elementsClient.sendRawTransaction(claimTx.toHex()), + ).rejects.toEqual({ + code: -26, + message: + 'non-mandatory-script-verify-flag (Script failed an OP_EQUALVERIFY operation)', + }); + }); + + test('should not claim to invalid address', async () => { + const { + tree, + musig, + output, + preimage, + lockupTx, + feeBuffer, + blindingPrivateKey, + } = await createOutput(); + + const claimTx = constructClaimTransaction( + [ + { + ...output, + preimage, + blindingPrivateKey, + swapTree: tree, + cooperative: false, + txHash: lockupTx.getHash(), + internalKey: musig.getAggregatedPublicKey(), + }, + ], + address.toOutputScript( + await elementsClient.getNewAddress(), + networks.regtest, + ), + feeBuffer, + true, + networks.regtest, + ); + await expect( + elementsClient.sendRawTransaction(claimTx.toHex()), + ).rejects.toEqual({ + code: -26, + message: + 'non-mandatory-script-verify-flag (Script failed an OP_EQUALVERIFY operation)', + }); + }); + + test.each` + delta + ${2} + ${1} + ${-1} + ${-2} + `( + 'should not claim with $delta delta to expected amount', + async ({ delta }) => { + const { + tree, + musig, + output, + preimage, + lockupTx, + feeBuffer, + expectedOutput, + blindingPrivateKey, + } = await createOutput(); + + const claimTx = constructClaimTransaction( + [ + { + ...output, + preimage, + blindingPrivateKey, + swapTree: tree, + cooperative: false, + txHash: lockupTx.getHash(), + internalKey: musig.getAggregatedPublicKey(), + }, + ], + expectedOutput, + feeBuffer - delta, + true, + networks.regtest, + ); + await expect( + elementsClient.sendRawTransaction(claimTx.toHex()), + ).rejects.toEqual({ + code: -26, + message: + 'non-mandatory-script-verify-flag (Script evaluated without error but finished with a false/empty top stack element)', + }); + }, + ); + }, +); diff --git a/test/integration/liquid/utils/ElementsClient.ts b/test/integration/liquid/utils/ElementsClient.ts index 4b237c2..2c5b3ca 100644 --- a/test/integration/liquid/utils/ElementsClient.ts +++ b/test/integration/liquid/utils/ElementsClient.ts @@ -1,13 +1,20 @@ -import ChainClient from '../../utils/ChainClient'; +import ChainClient, { AddressType } from '../../utils/ChainClient'; + +enum LiquidAddressType { + Blech32 = 'blech32', +} class ElementsClient extends ChainClient { public dumpBlindingKey = (address: string): Promise => { return this.client.request('dumpblindingkey', [address]); }; - public getNewAddress = (): Promise => { - return this.client.request('getnewaddress', ['', 'blech32']); + public getNewAddress = ( + type: AddressType | LiquidAddressType = LiquidAddressType.Blech32, + ): Promise => { + return this.client.request('getnewaddress', ['', type]); }; } export default ElementsClient; +export { LiquidAddressType }; diff --git a/test/integration/utils/ChainClient.ts b/test/integration/utils/ChainClient.ts index aa00f78..116ef47 100644 --- a/test/integration/utils/ChainClient.ts +++ b/test/integration/utils/ChainClient.ts @@ -1,6 +1,12 @@ -import { OutputType } from '../../../lib/Boltz'; import RpcClient from './RpcClient'; +enum AddressType { + Legacy = 'legacy', + P2shegwit = 'p2sh-segwit', + Bech32 = 'bech32', + Taproot = 'bech32m', +} + type ChainConfig = { host: string; port: number; @@ -95,11 +101,8 @@ class ChainClient { } }; - public getNewAddress = (type = OutputType.Bech32): Promise => { - return this.client.request('getnewaddress', [ - '', - this.getAddressType(type), - ]); + public getNewAddress = (type = AddressType.Bech32): Promise => { + return this.client.request('getnewaddress', ['', type]); }; public sendToAddress = (address: string, amount: number): Promise => { @@ -115,18 +118,7 @@ class ChainClient { this.miningAddress, ]); }; - - private getAddressType = (type: OutputType): string => { - switch (type) { - case OutputType.Bech32: - return 'bech32'; - case OutputType.Compatibility: - return 'p2sh-segwit'; - default: - return 'legacy'; - } - }; } export default ChainClient; -export { ChainConfig }; +export { ChainConfig, AddressType }; diff --git a/test/unit/liquid/TreeSort.spec.ts b/test/unit/liquid/TreeSort.spec.ts new file mode 100644 index 0000000..a31264f --- /dev/null +++ b/test/unit/liquid/TreeSort.spec.ts @@ -0,0 +1,96 @@ +import { + assignTreeProbabilities, + sortTree, +} from '../../../lib/liquid/TreeSort'; +import { LiquidSwapTree } from '../../../lib/liquid/consts/Types'; +import { createLeaf } from '../../../lib/swap/TaprootUtils'; + +describe('TreeSort', () => { + test.each` + tree | result + ${[[100, 1]]} | ${1} + ${[[51, 1], [49, 2]]} | ${[1, 2]} + ${[[10, 1], [20, 2], [70, 3]]} | ${[3, [2, 1]]} + ${[[10, 1], [20, 2], [30, 3], [40, 4]]} | ${[[4, 3], [2, 1]]} + ${[[10, 1], [20, 2], [30, 3], [40, 4]]} | ${[[4, 3], [2, 1]]} + ${[[5, 1], [5, 2], [10, 3], [25, 4], [50, 5]]} | ${[5, [4, [3, [1, 2]]]]} + ${[[12, 1], [12, 2], [12, 3], [12, 4], [50, 5]]} | ${[5, [[1, 2], [3, 4]]]} + `('should sort generic tree', ({ tree, result }) => { + expect( + sortTree( + (tree as [number, any][]).map(([probability, value]) => ({ + probability, + value, + })), + ), + ).toEqual(result); + }); + + test('should sort tree', () => { + const tree: Omit = { + claimLeaf: createLeaf(true, [1]), + refundLeaf: createLeaf(true, [2]), + }; + const sortedTree = sortTree(assignTreeProbabilities(tree)); + + expect(sortedTree).toHaveLength(2); + expect(sortedTree[0]).toEqual(tree.claimLeaf); + expect(sortedTree[1]).toEqual(tree.refundLeaf); + }); + + test('should sort tree with claim covenant', () => { + const tree: Omit = { + claimLeaf: createLeaf(true, [1]), + refundLeaf: createLeaf(true, [2]), + covenantClaimLeaf: createLeaf(true, [3]), + }; + const sortedTree = sortTree(assignTreeProbabilities(tree)); + + expect(sortedTree).toHaveLength(2); + expect(sortedTree[0]).toEqual(tree.covenantClaimLeaf); + expect(sortedTree[1]).toHaveLength(2); + expect(sortedTree[1][0]).toEqual(tree.claimLeaf); + expect(sortedTree[1][1]).toEqual(tree.refundLeaf); + }); + + test('should assign tree probabilities', () => { + const tree: Omit = { + claimLeaf: createLeaf(true, [1]), + refundLeaf: createLeaf(true, [2]), + }; + const probabilities = assignTreeProbabilities(tree); + + expect(probabilities).toHaveLength(2); + expect(probabilities[0]).toEqual({ + probability: 51, + value: tree.claimLeaf, + }); + expect(probabilities[1]).toEqual({ + probability: 49, + value: tree.refundLeaf, + }); + }); + + test('should assign tree probabilities with claim covenant', () => { + const tree: Omit = { + claimLeaf: createLeaf(true, [1]), + refundLeaf: createLeaf(true, [2]), + covenantClaimLeaf: createLeaf(true, [3]), + }; + const probabilities = assignTreeProbabilities(tree); + + expect(probabilities).toHaveLength(3); + expect(probabilities[0]).toEqual({ + probability: 51, + value: tree.covenantClaimLeaf, + }); + expect(probabilities[1]).toEqual({ + probability: 25, + value: tree.claimLeaf, + }); + expect(probabilities[2]).toEqual({ + probability: 24, + value: tree.refundLeaf, + }); + }); +}); diff --git a/test/unit/liquid/Utils.spec.ts b/test/unit/liquid/Utils.spec.ts new file mode 100644 index 0000000..570691f --- /dev/null +++ b/test/unit/liquid/Utils.spec.ts @@ -0,0 +1,58 @@ +import { crypto } from 'bitcoinjs-lib'; +import { randomBytes } from 'crypto'; +import { getScriptIntrospectionValues } from '../../../lib/liquid/Utils'; +import { + p2pkhOutput, + p2shOutput, + p2trOutput, + p2wpkhOutput, + p2wshOutput, +} from '../../../lib/swap/Scripts'; +import { ECPair } from '../Utils'; + +describe('Liquid Utils', () => { + test('should get P2TR introspection values', () => { + const output = p2trOutput(ECPair.makeRandom().publicKey); + + expect(getScriptIntrospectionValues(output)).toEqual({ + version: 1, + script: output.subarray(2, 40), + }); + }); + + test('should get P2WPKH introspection values', () => { + const output = p2wpkhOutput(crypto.hash160(ECPair.makeRandom().publicKey)); + + expect(getScriptIntrospectionValues(output)).toEqual({ + version: 0, + script: output.subarray(2, 40), + }); + }); + + test('should get P2WSH introspection values', () => { + const output = p2wshOutput(crypto.sha256(randomBytes(32))); + + expect(getScriptIntrospectionValues(output)).toEqual({ + version: 0, + script: output.subarray(2, 40), + }); + }); + + test('should get P2PKH introspection values', () => { + const output = p2pkhOutput(crypto.hash160(ECPair.makeRandom().publicKey)); + + expect(getScriptIntrospectionValues(output)).toEqual({ + version: -1, + script: crypto.sha256(output), + }); + }); + + test('should get P2SH introspection values', () => { + const output = p2shOutput(crypto.hash160(randomBytes(32))); + + expect(getScriptIntrospectionValues(output)).toEqual({ + version: -1, + script: crypto.sha256(output), + }); + }); +}); diff --git a/test/unit/liquid/swap/PreimageDetector.spec.ts b/test/unit/liquid/swap/PreimageDetector.spec.ts index d338572..8d5d153 100644 --- a/test/unit/liquid/swap/PreimageDetector.spec.ts +++ b/test/unit/liquid/swap/PreimageDetector.spec.ts @@ -30,7 +30,7 @@ describe('Liquid PreimageDetector', () => { type | scriptFunc | name ${OutputType.Bech32} | ${swapScript} | ${'P2WSH swap'} ${OutputType.Bech32} | ${reverseSwapScript} | ${'P2WSH reverse swap'} - `(`should detect preimage of $name input`, async ({ type, scriptFunc }) => { + `(`should detect preimage of $name input`, ({ type, scriptFunc }) => { const redeemScript = scriptFunc( crypto.hash160(preimage), claimKeys.publicKey, @@ -62,4 +62,23 @@ describe('Liquid PreimageDetector', () => { const foundPreimage = detectPreimage(0, claimTransaction); expect(foundPreimage).toEqual(preimage); }); + + test('should detect preimage of P2TR covenant claim inputs', () => { + const witness = [ + '95a65f7ca829cb5b6962194197dcdc2702842120621f2b7d9e362ac399609160', + '82012088a914260e080b2811629fb645b488376844000320d2388800d15188209dbd4a290dab27ee9d0f84dd43c7aeafccc1315dcffc1fe7cf6fde994e793fdf8800ce752025b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a8800cf7508102700000000000087', + 'c5c93afa449a4d97e1b212d23ac87f36f71871428c0656fdc620f2bd48b63d5da4054cff664073a3f951ab0e7a646540686cc5dcdb0ee4b2290ade5e8fe85a831625368ca12f9fb66de62446fcb1fe7e9ae77a465dad9cdc8fa21c8c5fc1eaac93', + ].map(getHexBuffer); + + expect( + detectPreimage(0, { + ins: [ + { + witness, + script: Buffer.alloc(0), + }, + ], + }), + ).toEqual(witness[0]); + }); }); diff --git a/test/unit/liquid/swap/ReverseSwapTree.spec.ts b/test/unit/liquid/swap/ReverseSwapTree.spec.ts new file mode 100644 index 0000000..57101a6 --- /dev/null +++ b/test/unit/liquid/swap/ReverseSwapTree.spec.ts @@ -0,0 +1,50 @@ +import { randomBytes } from 'crypto'; +import { networks } from 'liquidjs-lib'; +import { Feature, reverseSwapTree } from '../../../../lib/liquid'; +import { p2trOutput } from '../../../../lib/swap/Scripts'; +import { ECPair } from '../../Utils'; + +describe('ReverseSwapTree', () => { + test('should throw with duplicate features', () => { + expect(() => + reverseSwapTree( + randomBytes(32), + ECPair.makeRandom().publicKey, + ECPair.makeRandom().publicKey, + 123, + [ + { + type: Feature.ClaimCovenant, + expectedAmount: 123, + assetHash: networks.regtest.assetHash, + outputScript: p2trOutput(ECPair.makeRandom().publicKey), + }, + { + type: Feature.ClaimCovenant, + expectedAmount: 123, + assetHash: networks.regtest.assetHash, + outputScript: p2trOutput(ECPair.makeRandom().publicKey), + }, + ], + ), + ).toThrow('duplicate feature'); + }); + + test('should throw with unknown features', () => { + const feature = 'not found'; + + expect(() => + reverseSwapTree( + randomBytes(32), + ECPair.makeRandom().publicKey, + ECPair.makeRandom().publicKey, + 123, + [ + { + type: feature, + } as any, + ], + ), + ).toThrow(`unknown feature: ${feature}`); + }); +}); From eb673ee4bcaef39ad90584e1f3a607f1bbaa01a9 Mon Sep 17 00:00:00 2001 From: michael1011 Date: Tue, 30 Jan 2024 20:38:11 +0100 Subject: [PATCH 3/3] fix: check introspection output asset prefix --- lib/liquid/swap/Claim.ts | 2 +- lib/liquid/swap/ReverseSwapTree.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/liquid/swap/Claim.ts b/lib/liquid/swap/Claim.ts index 93e0d11..4e8df84 100644 --- a/lib/liquid/swap/Claim.ts +++ b/lib/liquid/swap/Claim.ts @@ -194,7 +194,7 @@ export const constructClaimTransaction = ( for (const [i, utxo] of utxos.entries()) { if (utxo.type === OutputType.Taproot) { - if (utxo.cooperative || (!isRefund && utxo.keys === undefined)) { + if (utxo.cooperative || utxo.keys === undefined) { signatures.push(dummyTaprootSignature); continue; } diff --git a/lib/liquid/swap/ReverseSwapTree.ts b/lib/liquid/swap/ReverseSwapTree.ts index 5e4ed5c..0bbd9cb 100644 --- a/lib/liquid/swap/ReverseSwapTree.ts +++ b/lib/liquid/swap/ReverseSwapTree.ts @@ -54,7 +54,8 @@ const createClaimCovenantLeaf = ( claimCovenantOutputIndex, liquidOps.OP_INSPECTOUTPUTASSET, - ops.OP_DROP, + ops.OP_1, + ops.OP_EQUALVERIFY, reverseBuffer(getHexBuffer(assetHash)), ops.OP_EQUALVERIFY,