testing swaps

This commit is contained in:
boufni95 2025-11-04 17:52:53 +00:00
parent c4644b5701
commit 0097dcc46c
8 changed files with 858 additions and 15 deletions

View file

@ -14,8 +14,14 @@
# A trusted peer that will hold a node-level account until channel automation becomes affordable # A trusted peer that will hold a node-level account until channel automation becomes affordable
# The developer is used by default or you may specify your own # The developer is used by default or you may specify your own
# To disable this feature entirely overwrite the env with "null" # To disable this feature entirely overwrite the env with "null"
#LIQUIDITY_PROVIDER_PUB=null # LIQUIDITY_PROVIDER_PUB=null
#DISABLE_LIQUIDITY_PROVIDER=false # DISABLE_LIQUIDITY_PROVIDER=false
# USE_ONLY_LIQUIDITY_PROVIDER=false
#SWAPS
# BOLTZ_HTTP_URL=
# BOLTZ_WEBSOCKET_URL=
# ENABLE_SWAPS=false
#DB #DB
#DATABASE_FILE=db.sqlite #DATABASE_FILE=db.sqlite

480
package-lock.json generated
View file

@ -18,10 +18,13 @@
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
"@types/node": "^17.0.31", "@types/node": "^17.0.31",
"@types/secp256k1": "^4.0.3", "@types/secp256k1": "^4.0.3",
"@vulpemventures/secp256k1-zkp": "^3.2.1",
"axios": "^1.9.0", "axios": "^1.9.0",
"bech32": "^2.0.0", "bech32": "^2.0.0",
"better-sqlite3": "^12.2.0", "better-sqlite3": "^12.2.0",
"bitcoin-core": "^4.2.0", "bitcoin-core": "^4.2.0",
"bitcoinjs-lib": "^6.1.7",
"boltz-core": "^3.0.0",
"chai": "^4.3.7", "chai": "^4.3.7",
"chai-string": "^1.5.0", "chai-string": "^1.5.0",
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
@ -29,6 +32,7 @@
"csv": "^6.3.8", "csv": "^6.3.8",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"eccrypto": "^1.1.6", "eccrypto": "^1.1.6",
"ecpair": "^3.0.0",
"express": "^4.21.2", "express": "^4.21.2",
"globby": "^13.1.2", "globby": "^13.1.2",
"grpc-tools": "^1.12.4", "grpc-tools": "^1.12.4",
@ -40,6 +44,7 @@
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rxjs": "^7.5.5", "rxjs": "^7.5.5",
"secp256k1": "^5.0.1", "secp256k1": "^5.0.1",
"tiny-secp256k1": "^2.2.4",
"ts-node": "^10.7.0", "ts-node": "^10.7.0",
"ts-proto": "^1.131.2", "ts-proto": "^1.131.2",
"typeorm": "^0.3.26", "typeorm": "^0.3.26",
@ -68,6 +73,12 @@
"typescript": "5.5.4" "typescript": "5.5.4"
} }
}, },
"node_modules/@boltz/bitcoin-ops": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@boltz/bitcoin-ops/-/bitcoin-ops-2.0.0.tgz",
"integrity": "sha512-AM7vFNwSD7B4XI6yeRKccWbbD/lvwoFr8U3pqhzryBQo4uMkYe5V3/kMVnml4SNuxzyqdIFu4ur3TId02sC33A==",
"license": "MIT"
},
"node_modules/@bufbuild/protobuf": { "node_modules/@bufbuild/protobuf": {
"version": "2.7.0", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.7.0.tgz", "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.7.0.tgz",
@ -441,6 +452,12 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/@openzeppelin/contracts": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.4.0.tgz",
"integrity": "sha512-eCYgWnLg6WO+X52I16TZt8uEjbtdkgLC0SUX/xnAksjjrQI4Xfn4iBRoI5j55dmlOhDv1Y7BoR3cU7e3WWhC6A==",
"license": "MIT"
},
"node_modules/@pkgjs/parseargs": { "node_modules/@pkgjs/parseargs": {
"version": "0.11.0", "version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@ -1012,6 +1029,16 @@
"integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/randombytes": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/randombytes/-/randombytes-2.0.3.tgz",
"integrity": "sha512-+NRgihTfuURllWCiIAhm1wsJqzsocnqXM77V/CalsdJIYSRGEHMnritxh+6EsBklshC+clo1KgnN14qgSGeQdw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/range-parser": { "node_modules/@types/range-parser": {
"version": "1.2.7", "version": "1.2.7",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
@ -1112,6 +1139,18 @@
"uuid": "bin/uuid" "uuid": "bin/uuid"
} }
}, },
"node_modules/@vulpemventures/secp256k1-zkp": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@vulpemventures/secp256k1-zkp/-/secp256k1-zkp-3.2.1.tgz",
"integrity": "sha512-2U4nuNbXuUgMmxhuoILbRMoD2DE7KND3udk5cYilIS1MHvMtje9ywUm/zsI0g7d7x8g2A57xri+wvqCC/fCnJg==",
"license": "MIT",
"dependencies": {
"long": "^5.2.3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/abbrev": { "node_modules/abbrev": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@ -1684,6 +1723,12 @@
"license": "Apache-2.0", "license": "Apache-2.0",
"optional": true "optional": true
}, },
"node_modules/base-x": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz",
"integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==",
"license": "MIT"
},
"node_modules/base64-js": { "node_modules/base64-js": {
"version": "1.5.1", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@ -1764,12 +1809,54 @@
"file-uri-to-path": "1.0.0" "file-uri-to-path": "1.0.0"
} }
}, },
"node_modules/bip174": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.1.tgz",
"integrity": "sha512-mdFV5+/v0XyNYXjBS6CQPLo9ekCx4gtKZFnJm5PMto7Fs9hTTDpkkzOB7/FtluRI6JbUUAu+snTYfJRgHLZbZQ==",
"license": "MIT",
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/bip174-liquid": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/bip174-liquid/-/bip174-liquid-1.0.3.tgz",
"integrity": "sha512-e69sC0Cq2tBJuhG2+wieXv40DN13YBR/wbIjZp4Mqwpar5vQm8Ldqijdd6N33XG7LtfvQi/zKm5fSzdPY/9mgw==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/bip32": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/bip32/-/bip32-4.0.0.tgz",
"integrity": "sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==",
"license": "MIT",
"dependencies": {
"@noble/hashes": "^1.2.0",
"@scure/base": "^1.1.1",
"typeforce": "^1.11.5",
"wif": "^2.0.6"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/bip65": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/bip65/-/bip65-1.0.3.tgz",
"integrity": "sha512-RQ1nc7xtnLa5XltnCqkoR2zmhuz498RjMJwrLKQzOE049D1HUqnYfon7cVSbwS5UGm0/EQlC2CH+NY3MyITA4Q==",
"license": "ISC",
"engines": {
"node": ">=4.5.0"
}
},
"node_modules/bip66": { "node_modules/bip66": {
"version": "1.1.5", "version": "1.1.5",
"resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz",
"integrity": "sha512-nemMHz95EmS38a26XbbdxIYj5csHd3RMP3H5bwQknX0WYHF01qhpufP42mLOwVICuH2JmhIhXiWs89MfUGL7Xw==", "integrity": "sha512-nemMHz95EmS38a26XbbdxIYj5csHd3RMP3H5bwQknX0WYHF01qhpufP42mLOwVICuH2JmhIhXiWs89MfUGL7Xw==",
"license": "MIT", "license": "MIT",
"optional": true,
"dependencies": { "dependencies": {
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
@ -1792,6 +1879,71 @@
"node": ">=7" "node": ">=7"
} }
}, },
"node_modules/bitcoinjs-lib": {
"version": "6.1.7",
"resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-6.1.7.tgz",
"integrity": "sha512-tlf/r2DGMbF7ky1MgUqXHzypYHakkEnm0SZP23CJKIqNY/5uNAnMbFhMJdhjrL/7anfb/U8+AlpdjPWjPnAalg==",
"license": "MIT",
"dependencies": {
"@noble/hashes": "^1.2.0",
"bech32": "^2.0.0",
"bip174": "^2.1.1",
"bs58check": "^3.0.1",
"typeforce": "^1.11.3",
"varuint-bitcoin": "^1.1.2"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/bitcoinjs-lib/node_modules/base-x": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.1.tgz",
"integrity": "sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw==",
"license": "MIT"
},
"node_modules/bitcoinjs-lib/node_modules/bs58": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz",
"integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==",
"license": "MIT",
"dependencies": {
"base-x": "^4.0.0"
}
},
"node_modules/bitcoinjs-lib/node_modules/bs58check": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz",
"integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==",
"license": "MIT",
"dependencies": {
"@noble/hashes": "^1.2.0",
"bs58": "^5.0.0"
}
},
"node_modules/bitcoinjs-lib/node_modules/varuint-bitcoin": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz",
"integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==",
"license": "MIT",
"dependencies": {
"safe-buffer": "^5.1.1"
}
},
"node_modules/bitset": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/bitset/-/bitset-5.2.3.tgz",
"integrity": "sha512-uZ7++Z60MC9cZ+7YzQ1v9yPDydcjhmcMjGx2yoGTjjSXBoVMmTr2LCRbkpI19S9P/C75hhP7Bsakj+gVzVUDbQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": "*"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/rawify"
}
},
"node_modules/bl": { "node_modules/bl": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@ -1826,6 +1978,26 @@
"safe-buffer": "~5.2.0" "safe-buffer": "~5.2.0"
} }
}, },
"node_modules/blech32": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/blech32/-/blech32-1.1.2.tgz",
"integrity": "sha512-C5qxzoF9KyX88X8Zz18cZ6BOeL0n5/Eg/cDot1frntkArRMwg1djNim5wA6QFWwu0lJ1LN8iiRMN4Lp2kZzdfA==",
"license": "MIT",
"peer": true,
"dependencies": {
"long": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/blech32/node_modules/long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==",
"license": "Apache-2.0",
"peer": true
},
"node_modules/bn.js": { "node_modules/bn.js": {
"version": "4.12.2", "version": "4.12.2",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz",
@ -1871,6 +2043,42 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/boltz-core": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/boltz-core/-/boltz-core-3.0.0.tgz",
"integrity": "sha512-L0jzUnTIb/vir9k6yVlCkV8I29ZeBK7LWq3rrDcp/KP7bB0VvKR5JTceua8g2KBCBM5HOMVDEuPW3c9/82/Nmg==",
"license": "AGPL-3.0",
"dependencies": {
"@boltz/bitcoin-ops": "^2.0.0",
"@openzeppelin/contracts": "^5.2.0",
"@vulpemventures/secp256k1-zkp": "^3.2.1",
"bip32": "^4.0.0",
"bip65": "^1.0.3",
"bip66": "^2.0.0",
"bitcoinjs-lib": "^6.1.7",
"bn.js": "^5.2.1",
"ecpair": "^3.0.0",
"varuint-bitcoin": "^2.0.0"
},
"engines": {
"node": ">=20"
},
"peerDependencies": {
"liquidjs-lib": "^6.0.2-liquid.37"
}
},
"node_modules/boltz-core/node_modules/bip66": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/bip66/-/bip66-2.0.0.tgz",
"integrity": "sha512-kBG+hSpgvZBrkIm9dt5T1Hd/7xGCPEX2npoxAWZfsK1FvjgaxySEh2WizjyIstWXriKo9K9uJ4u0OnsyLDUPXQ==",
"license": "MIT"
},
"node_modules/boltz-core/node_modules/bn.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz",
"integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==",
"license": "MIT"
},
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
"version": "1.1.12", "version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
@ -1914,6 +2122,25 @@
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
}, },
"node_modules/bs58": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz",
"integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==",
"license": "MIT",
"dependencies": {
"base-x": "^5.0.0"
}
},
"node_modules/bs58check": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz",
"integrity": "sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==",
"license": "MIT",
"dependencies": {
"@noble/hashes": "^1.2.0",
"bs58": "^6.0.0"
}
},
"node_modules/buffer": { "node_modules/buffer": {
"version": "5.7.1", "version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
@ -2204,7 +2431,6 @@
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz",
"integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==",
"license": "MIT", "license": "MIT",
"optional": true,
"dependencies": { "dependencies": {
"inherits": "^2.0.4", "inherits": "^2.0.4",
"safe-buffer": "^5.2.1" "safe-buffer": "^5.2.1"
@ -2545,7 +2771,6 @@
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
"license": "MIT", "license": "MIT",
"optional": true,
"dependencies": { "dependencies": {
"cipher-base": "^1.0.1", "cipher-base": "^1.0.1",
"inherits": "^2.0.1", "inherits": "^2.0.1",
@ -2559,7 +2784,6 @@
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"license": "MIT", "license": "MIT",
"optional": true,
"dependencies": { "dependencies": {
"cipher-base": "^1.0.3", "cipher-base": "^1.0.3",
"create-hash": "^1.1.0", "create-hash": "^1.1.0",
@ -2980,6 +3204,52 @@
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
}, },
"node_modules/ecpair": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ecpair/-/ecpair-3.0.0.tgz",
"integrity": "sha512-kf4JxjsRQoD4EBzpYjGAcR0t9i/4oAeRPtyCpKvSwyotgkc6oA4E4M0/e+kep7cXe+mgxAvoeh/jdgH9h5+Wxw==",
"license": "MIT",
"dependencies": {
"uint8array-tools": "^0.0.8",
"valibot": "^0.37.0",
"wif": "^5.0.0"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/ecpair/node_modules/uint8array-tools": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.8.tgz",
"integrity": "sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==",
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/ecpair/node_modules/valibot": {
"version": "0.37.0",
"resolved": "https://registry.npmjs.org/valibot/-/valibot-0.37.0.tgz",
"integrity": "sha512-FQz52I8RXgFgOHym3XHYSREbNtkgSjF9prvMFH1nBsRyfL6SfCzoT1GuSDTlbsuPubM7/6Kbw0ZMQb8A+V+VsQ==",
"license": "MIT",
"peerDependencies": {
"typescript": ">=5"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/ecpair/node_modules/wif": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/wif/-/wif-5.0.0.tgz",
"integrity": "sha512-iFzrC/9ne740qFbNjTZ2FciSRJlHIXoxqk/Y5EnE08QOXu1WjJyCCswwDTYbohAOEnlCtLaAAQBhyaLRFh2hMA==",
"license": "MIT",
"dependencies": {
"bs58check": "^4.0.0"
}
},
"node_modules/ee-first": { "node_modules/ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -3775,7 +4045,6 @@
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
"integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
"license": "MIT", "license": "MIT",
"optional": true,
"dependencies": { "dependencies": {
"inherits": "^2.0.4", "inherits": "^2.0.4",
"readable-stream": "^3.6.0", "readable-stream": "^3.6.0",
@ -3790,7 +4059,6 @@
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT", "license": "MIT",
"optional": true,
"dependencies": { "dependencies": {
"inherits": "^2.0.3", "inherits": "^2.0.3",
"string_decoder": "^1.1.1", "string_decoder": "^1.1.1",
@ -3805,7 +4073,6 @@
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"license": "MIT", "license": "MIT",
"optional": true,
"dependencies": { "dependencies": {
"safe-buffer": "~5.2.0" "safe-buffer": "~5.2.0"
} }
@ -4332,6 +4599,88 @@
"safe-buffer": "~5.1.0" "safe-buffer": "~5.1.0"
} }
}, },
"node_modules/liquidjs-lib": {
"version": "6.0.2-liquid.37",
"resolved": "https://registry.npmjs.org/liquidjs-lib/-/liquidjs-lib-6.0.2-liquid.37.tgz",
"integrity": "sha512-AOPwqg9wtLMNxfqOf8afC+bYYrs3VBsTq/Mq/iOe0F2X3CcbgiLeSAcvOY34jbnUre6U+zmuXKP9bWmxnOG08A==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/randombytes": "^2.0.0",
"bech32": "^2.0.0",
"bip174-liquid": "^1.0.3",
"bip66": "^1.1.0",
"bitcoinjs-lib": "^6.0.2",
"bitset": "^5.1.1",
"blech32": "^1.0.1",
"bs58check": "^2.0.0",
"create-hash": "^1.2.0",
"ecpair": "^2.1.0",
"slip77": "^0.2.0",
"typeforce": "^1.11.3",
"varuint-bitcoin": "^1.1.2"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/liquidjs-lib/node_modules/base-x": {
"version": "3.0.11",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz",
"integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==",
"license": "MIT",
"peer": true,
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/liquidjs-lib/node_modules/bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
"license": "MIT",
"peer": true,
"dependencies": {
"base-x": "^3.0.2"
}
},
"node_modules/liquidjs-lib/node_modules/bs58check": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
"integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
"license": "MIT",
"peer": true,
"dependencies": {
"bs58": "^4.0.0",
"create-hash": "^1.1.0",
"safe-buffer": "^5.1.2"
}
},
"node_modules/liquidjs-lib/node_modules/ecpair": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz",
"integrity": "sha512-cL/mh3MtJutFOvFc27GPZE2pWL3a3k4YvzUWEOvilnfZVlH3Jwgx/7d6tlD7/75tNk8TG2m+7Kgtz0SI1tWcqw==",
"license": "MIT",
"peer": true,
"dependencies": {
"randombytes": "^2.1.0",
"typeforce": "^1.18.0",
"wif": "^2.0.6"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/liquidjs-lib/node_modules/varuint-bitcoin": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz",
"integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==",
"license": "MIT",
"peer": true,
"dependencies": {
"safe-buffer": "^5.1.1"
}
},
"node_modules/lodash": { "node_modules/lodash": {
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
@ -4512,7 +4861,6 @@
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
"integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
"license": "MIT", "license": "MIT",
"optional": true,
"dependencies": { "dependencies": {
"hash-base": "^3.0.0", "hash-base": "^3.0.0",
"inherits": "^2.0.1", "inherits": "^2.0.1",
@ -5765,6 +6113,16 @@
], ],
"license": "MIT" "license": "MIT"
}, },
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"safe-buffer": "^5.1.0"
}
},
"node_modules/range-parser": { "node_modules/range-parser": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@ -5981,7 +6339,6 @@
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
"license": "MIT", "license": "MIT",
"optional": true,
"dependencies": { "dependencies": {
"hash-base": "^3.0.0", "hash-base": "^3.0.0",
"inherits": "^2.0.1" "inherits": "^2.0.1"
@ -6382,6 +6739,28 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/slip77": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/slip77/-/slip77-0.2.0.tgz",
"integrity": "sha512-LQaxb1Hef10kU36qvk71tlSt5BWph7GM0j+t2n5zs169X4QfnNbb6xqKZ38X3ETzGmCQaVdBwr925HDagHra/Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/node": "^13.9.1",
"create-hmac": "^1.1.7",
"typeforce": "^1.18.0"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/slip77/node_modules/@types/node": {
"version": "13.13.52",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz",
"integrity": "sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==",
"license": "MIT",
"peer": true
},
"node_modules/smart-buffer": { "node_modules/smart-buffer": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
@ -6782,6 +7161,27 @@
"safe-buffer": "~5.1.0" "safe-buffer": "~5.1.0"
} }
}, },
"node_modules/tiny-secp256k1": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.4.tgz",
"integrity": "sha512-FoDTcToPqZE454Q04hH9o2EhxWsm7pOSpicyHkgTwKhdKWdsTUuqfP5MLq3g+VjAtl2vSx6JpXGdwA2qpYkI0Q==",
"license": "MIT",
"dependencies": {
"uint8array-tools": "0.0.7"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/tiny-secp256k1/node_modules/uint8array-tools": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.7.tgz",
"integrity": "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==",
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/to-buffer": { "node_modules/to-buffer": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz",
@ -7003,6 +7403,12 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/typeforce": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==",
"license": "MIT"
},
"node_modules/typeorm": { "node_modules/typeorm": {
"version": "0.3.26", "version": "0.3.26",
"resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.26.tgz", "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.26.tgz",
@ -7356,6 +7762,24 @@
"devOptional": true, "devOptional": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/varuint-bitcoin": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-2.0.0.tgz",
"integrity": "sha512-6QZbU/rHO2ZQYpWFDALCDSRsXbAs1VOEmXAxtbtjLtKuMJ/FQ8YbhfxlaiKv5nklci0M6lZtlZyxo9Q+qNnyog==",
"license": "MIT",
"dependencies": {
"uint8array-tools": "^0.0.8"
}
},
"node_modules/varuint-bitcoin/node_modules/uint8array-tools": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.8.tgz",
"integrity": "sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==",
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/vary": { "node_modules/vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@ -7458,6 +7882,44 @@
"string-width": "^1.0.2 || 2 || 3 || 4" "string-width": "^1.0.2 || 2 || 3 || 4"
} }
}, },
"node_modules/wif": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
"integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==",
"license": "MIT",
"dependencies": {
"bs58check": "<3.0.0"
}
},
"node_modules/wif/node_modules/base-x": {
"version": "3.0.11",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz",
"integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==",
"license": "MIT",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/wif/node_modules/bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
"license": "MIT",
"dependencies": {
"base-x": "^3.0.2"
}
},
"node_modules/wif/node_modules/bs58check": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
"integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
"license": "MIT",
"dependencies": {
"bs58": "^4.0.0",
"create-hash": "^1.1.0",
"safe-buffer": "^5.1.2"
}
},
"node_modules/wrap-ansi": { "node_modules/wrap-ansi": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",

View file

@ -36,10 +36,13 @@
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
"@types/node": "^17.0.31", "@types/node": "^17.0.31",
"@types/secp256k1": "^4.0.3", "@types/secp256k1": "^4.0.3",
"@vulpemventures/secp256k1-zkp": "^3.2.1",
"axios": "^1.9.0", "axios": "^1.9.0",
"bech32": "^2.0.0", "bech32": "^2.0.0",
"better-sqlite3": "^12.2.0", "better-sqlite3": "^12.2.0",
"bitcoin-core": "^4.2.0", "bitcoin-core": "^4.2.0",
"bitcoinjs-lib": "^6.1.7",
"boltz-core": "^3.0.0",
"chai": "^4.3.7", "chai": "^4.3.7",
"chai-string": "^1.5.0", "chai-string": "^1.5.0",
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
@ -47,6 +50,7 @@
"csv": "^6.3.8", "csv": "^6.3.8",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"eccrypto": "^1.1.6", "eccrypto": "^1.1.6",
"ecpair": "^3.0.0",
"express": "^4.21.2", "express": "^4.21.2",
"globby": "^13.1.2", "globby": "^13.1.2",
"grpc-tools": "^1.12.4", "grpc-tools": "^1.12.4",
@ -58,6 +62,7 @@
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rxjs": "^7.5.5", "rxjs": "^7.5.5",
"secp256k1": "^5.0.1", "secp256k1": "^5.0.1",
"tiny-secp256k1": "^2.2.4",
"ts-node": "^10.7.0", "ts-node": "^10.7.0",
"ts-proto": "^1.131.2", "ts-proto": "^1.131.2",
"typeorm": "^0.3.26", "typeorm": "^0.3.26",

View file

@ -7,6 +7,7 @@ import { getLogger } from './services/helpers/logger.js';
import { initMainHandler, initSettings } from './services/main/init.js'; import { initMainHandler, initSettings } from './services/main/init.js';
import { nip19 } from 'nostr-tools' import { nip19 } from 'nostr-tools'
import { LoadStorageSettingsFromEnv } from './services/storage/index.js'; import { LoadStorageSettingsFromEnv } from './services/storage/index.js';
import Main from './services/main/index.js';
//@ts-ignore //@ts-ignore
const { nprofileEncode } = nip19 const { nprofileEncode } = nip19
@ -44,6 +45,7 @@ const start = async () => {
adminManager.setAppNprofile(appNprofile) adminManager.setAppNprofile(appNprofile)
const Server = NewServer(serverMethods, serverOptions(mainHandler)) const Server = NewServer(serverMethods, serverOptions(mainHandler))
Server.Listen(mainHandler.settings.getSettings().serviceSettings.servicePort) Server.Listen(mainHandler.settings.getSettings().serviceSettings.servicePort)
await TMP_swapTest_TMP(mainHandler) // TMP -- remove this
} }
start() start()
@ -62,3 +64,9 @@ const exitHandler = async (kill: () => void) => {
process.exit(99); process.exit(99);
}); });
} }
const TMP_swapTest_TMP = async (mainHandler: Main) => {
const i = await mainHandler.lnd.NewInvoice(25000, 'test', 3600, { useProvider: false, from: 'user' })
const decoded = await mainHandler.lnd.DecodeInvoice(i.payRequest)
await mainHandler.paymentManager.swaps.SwapInvoice(i.payRequest, decoded.paymentHash)
}

341
src/services/lnd/swaps.ts Normal file
View file

@ -0,0 +1,341 @@
import zkpInit from '@vulpemventures/secp256k1-zkp';
import axios from 'axios';
import { crypto, initEccLib, Transaction, address, Network } from 'bitcoinjs-lib';
// import bolt11 from 'bolt11';
import {
Musig, SwapTreeSerializer, TaprootUtils, detectSwap,
constructClaimTransaction, targetFee, OutputType
} from 'boltz-core';
import { randomBytes, createHash } from 'crypto';
import { ECPairFactory, ECPairInterface } from 'ecpair';
import * as ecc from 'tiny-secp256k1';
import ws from 'ws';
import { getLogger, PubLogger, ERROR } from '../helpers/logger.js';
import SettingsManager from '../main/settingsManager.js';
type InvoiceSwapResponse = { id: string, claimPublicKey: string, swapTree: string }
type InvoiceSwapInfo = { paymentHash: string, keys: ECPairInterface }
type InvoiceSwapData = { createdResponse: InvoiceSwapResponse, info: InvoiceSwapInfo }
type TransactionSwapResponse = { id: string, refundPublicKey: string, swapTree: string }
type TransactionSwapInfo = { destinationAddress: string, network: Network, preimage: Buffer, keys: ECPairInterface, txHex: string }
type TransactionSwapData = { createdResponse: TransactionSwapResponse, info: TransactionSwapInfo }
export class Swaps {
settings: SettingsManager
log: PubLogger
constructor(settings: SettingsManager) {
this.settings = settings
this.log = getLogger({ component: 'SwapsService' })
initEccLib(ecc)
}
SwapInvoice = async (invoice: string, paymentHash: string) => {
if (!this.settings.getSettings().swapsSettings.enableSwaps) {
this.log(ERROR, 'Swaps are not enabled');
return;
}
const keys = ECPairFactory(ecc).makeRandom()
const refundPublicKey = Buffer.from(keys.publicKey).toString('hex')
const req = { invoice, to: 'BTC', from: 'BTC', refundPublicKey }
const url = `${this.settings.getSettings().swapsSettings.boltzHttpUrl}/v2/swap/submarine`
this.log('Sending invoice swap request to', url);
const createdResponse = await loggedPost<InvoiceSwapResponse>(this.log, url, req)
if (!createdResponse) {
return;
}
this.log('Created invoice swap');
this.log(createdResponse);
const webSocket = new ws(`${this.settings.getSettings().swapsSettings.boltzWebSocketUrl}/v2/ws`)
const subReq = { op: 'subscribe', channel: 'swap.update', args: [createdResponse.id] }
webSocket.on('open', () => {
webSocket.send(JSON.stringify(subReq))
})
webSocket.on('message', async (rawMsg) => {
try {
await this.handleSwapInvoiceMessage(rawMsg, { createdResponse, info: { paymentHash, keys } }, () => webSocket.close())
} catch (err: any) {
this.log(ERROR, 'Error handling invoice WebSocket message', err.message)
webSocket.close()
return
}
});
}
handleSwapInvoiceMessage = async (rawMsg: ws.RawData, data: InvoiceSwapData, closeWebSocket: () => void) => {
const msg = JSON.parse(rawMsg.toString('utf-8'));
if (msg.event !== 'update') {
return;
}
this.log('Got invoice WebSocket update');
this.log(msg);
switch (msg.args[0].status) {
// "invoice.set" means Boltz is waiting for an onchain transaction to be sent
case 'invoice.set':
this.log('Waiting for onchain transaction');
return;
// Create a partial signature to allow Boltz to do a key path spend to claim the mainchain coins
case 'transaction.claim.pending':
await this.handleInvoiceClaimPending(data)
return;
case 'transaction.claimed':
this.log('Invoice swap successful');
closeWebSocket()
return;
}
}
handleInvoiceClaimPending = async (data: InvoiceSwapData) => {
this.log('Creating cooperative claim transaction');
const { createdResponse, info } = data
const { paymentHash, keys } = info
const { boltzHttpUrl } = this.settings.getSettings().swapsSettings
// Get the information request to create a partial signature
const url = `${boltzHttpUrl}/v2/swap/submarine/${createdResponse.id}/claim`
const claimTxDetails = await loggedGet<{ preimage: string, transactionHash: string, pubNonce: string }>(this.log, url)
if (!claimTxDetails) {
return;
}
// Verify that Boltz actually paid the invoice by comparing the preimage hash
// of the invoice to the SHA256 hash of the preimage from the response
const claimTxPreimageHash = createHash('sha256').update(Buffer.from(claimTxDetails.preimage, 'hex')).digest()
const invoicePreimageHash = Buffer.from(paymentHash, 'hex')
if (!claimTxPreimageHash.equals(invoicePreimageHash)) {
this.log(ERROR, 'Boltz provided invalid preimage');
return;
}
const boltzPublicKey = Buffer.from(createdResponse.claimPublicKey, 'hex')
// Create a musig signing instance
const musig = new Musig(await zkpInit(), keys, randomBytes(32), [
boltzPublicKey,
Buffer.from(keys.publicKey),
]);
// Tweak that musig with the Taptree of the swap scripts
TaprootUtils.tweakMusig(
musig,
SwapTreeSerializer.deserializeSwapTree(createdResponse.swapTree).tree,
);
// Aggregate the nonces
musig.aggregateNonces([
[boltzPublicKey, Buffer.from(claimTxDetails.pubNonce, 'hex')],
]);
// Initialize the session to sign the transaction hash from the response
musig.initializeSession(
Buffer.from(claimTxDetails.transactionHash, 'hex'),
);
// Give our public nonce and the partial signature to Boltz
const claimUrl = `${boltzHttpUrl}/v2/swap/submarine/${createdResponse.id}/claim`
const claimReq = {
pubNonce: Buffer.from(musig.getPublicNonce()).toString('hex'),
partialSignature: Buffer.from(musig.signPartial()).toString('hex'),
}
const claimResponse = await loggedPost<{ pubNonce: string, partialSignature: string }>(this.log, claimUrl, claimReq)
if (!claimResponse) {
return;
}
this.log('Claim response', claimResponse)
}
SwapTransaction = async (destinationAddress: string, invoiceAmount: number, network: Network) => {
if (!this.settings.getSettings().swapsSettings.enableSwaps) {
this.log(ERROR, 'Swaps are not enabled');
return;
}
const preimage = randomBytes(32);
const keys = ECPairFactory(ecc).makeRandom()
const url = `${this.settings.getSettings().swapsSettings.boltzHttpUrl}/v2/swap/reverse`
const req = {
invoiceAmount,
to: 'BTC',
from: 'BTC',
claimPublicKey: Buffer.from(keys.publicKey).toString('hex'),
preimageHash: createHash('sha256').update(preimage).digest('hex'),
}
const createdResponse = await loggedPost<TransactionSwapResponse>(this.log, url, req)
if (!createdResponse) {
return;
}
this.log('Created transaction swap');
this.log(createdResponse);
const webSocket = new ws(`${this.settings.getSettings().swapsSettings.boltzWebSocketUrl}/v2/ws`)
const subReq = { op: 'subscribe', channel: 'swap.update', args: [createdResponse.id] }
webSocket.on('open', () => {
webSocket.send(JSON.stringify(subReq))
})
webSocket.on('message', async (rawMsg) => {
try {
await this.handleSwapTransactionMessage(rawMsg, { createdResponse, info: { destinationAddress, network, preimage, keys, txHex: '' } }, () => webSocket.close())
} catch (err: any) {
this.log(ERROR, 'Error handling transaction WebSocket message', err.message)
webSocket.close()
return
}
})
}
handleSwapTransactionMessage = async (rawMsg: ws.RawData, data: TransactionSwapData, closeWebSocket: () => void) => {
const msg = JSON.parse(rawMsg.toString('utf-8'));
if (msg.event !== 'update') {
return;
}
this.log('Got WebSocket update');
this.log(msg);
switch (msg.args[0].status) {
// "swap.created" means Boltz is waiting for the invoice to be paid
case 'swap.created':
this.log('Waiting invoice to be paid');
return;
// "transaction.mempool" means that Boltz sent an onchain transaction
case 'transaction.mempool':
data.info.txHex = msg.args[0].transaction.hex
await this.handleTransactionMempool(data)
return
case 'invoice.settled':
this.log('Transaction swap successful');
closeWebSocket()
return;
}
}
handleTransactionMempool = async (data: TransactionSwapData) => {
this.log('Creating claim transaction');
const { createdResponse, info } = data
const { destinationAddress, network, keys, preimage, txHex } = info
const boltzPublicKey = Buffer.from(
createdResponse.refundPublicKey,
'hex',
);
// Create a musig signing session and tweak it with the Taptree of the swap scripts
const musig = new Musig(await zkpInit(), keys, randomBytes(32), [
boltzPublicKey,
Buffer.from(keys.publicKey),
]);
const tweakedKey = TaprootUtils.tweakMusig(
musig,
SwapTreeSerializer.deserializeSwapTree(createdResponse.swapTree).tree,
);
// Parse the lockup transaction and find the output relevant for the swap
const lockupTx = Transaction.fromHex(txHex);
const swapOutput = detectSwap(tweakedKey, lockupTx);
if (swapOutput === undefined) {
this.log(ERROR, 'No swap output found in lockup transaction');
return;
}
// Create a claim transaction to be signed cooperatively via a key path spend
const claimTx = targetFee(2, (fee) =>
constructClaimTransaction(
[
{
...swapOutput,
keys,
preimage,
cooperative: true,
type: OutputType.Taproot,
txHash: lockupTx.getHash(),
},
],
address.toOutputScript(destinationAddress, network),
fee,
),
);
const { boltzHttpUrl } = this.settings.getSettings().swapsSettings
// Get the partial signature from Boltz
const claimUrl = `${boltzHttpUrl}/v2/swap/reverse/${createdResponse.id}/claim`
const claimReq = {
index: 0,
transaction: claimTx.toHex(),
preimage: preimage.toString('hex'),
pubNonce: Buffer.from(musig.getPublicNonce()).toString('hex'),
}
const boltzSig = await loggedPost<{ pubNonce: string, partialSignature: string }>(this.log, claimUrl, claimReq)
if (!boltzSig) {
return;
}
// Aggregate the nonces
musig.aggregateNonces([
[boltzPublicKey, Buffer.from(boltzSig.pubNonce, 'hex')],
]);
// Initialize the session to sign the claim transaction
musig.initializeSession(
claimTx.hashForWitnessV1(
0,
[swapOutput.script],
[swapOutput.value],
Transaction.SIGHASH_DEFAULT,
),
);
// Add the partial signature from Boltz
musig.addPartial(
boltzPublicKey,
Buffer.from(boltzSig.partialSignature, 'hex'),
);
// Create our partial signature
musig.signPartial();
// Witness of the input to the aggregated signature
claimTx.ins[0].witness = [musig.aggregatePartials()];
// Broadcast the finalized transaction
const broadcastUrl = `${boltzHttpUrl}/v2/chain/BTC/transaction`
const broadcastReq = {
hex: claimTx.toHex(),
}
const broadcastResponse = await loggedPost(this.log, broadcastUrl, broadcastReq)
if (!broadcastResponse) {
return;
}
this.log('Transaction broadcasted', broadcastResponse)
}
}
const loggedPost = async <T>(log: PubLogger, url: string, req: any): Promise<T | null> => {
try {
const { data } = await axios.post(url, req)
return data as T
} catch (err: any) {
if (err.response?.data) {
log(ERROR, 'Error sending request', err.response.data)
return null
}
log(ERROR, 'Error sending request', err.message)
return null
}
}
const loggedGet = async <T>(log: PubLogger, url: string): Promise<T | null> => {
try {
const { data } = await axios.get(url)
return data as T
} catch (err: any) {
if (err.response?.data) {
log(ERROR, 'Error getting request', err.response.data)
return null
}
log(ERROR, 'Error getting request', err.message)
return null
}
}

View file

@ -17,6 +17,7 @@ import { LiquidityManager } from './liquidityManager.js'
import { Utils } from '../helpers/utilsWrapper.js' import { Utils } from '../helpers/utilsWrapper.js'
import { UserInvoicePayment } from '../storage/entity/UserInvoicePayment.js' import { UserInvoicePayment } from '../storage/entity/UserInvoicePayment.js'
import SettingsManager from './settingsManager.js' import SettingsManager from './settingsManager.js'
import { Swaps } from '../lnd/swaps.js'
interface UserOperationInfo { interface UserOperationInfo {
serial_id: number serial_id: number
paid_amount: number paid_amount: number
@ -51,6 +52,7 @@ export default class {
watchDog: Watchdog watchDog: Watchdog
liquidityManager: LiquidityManager liquidityManager: LiquidityManager
utils: Utils utils: Utils
swaps: Swaps
constructor(storage: Storage, lnd: LND, settings: SettingsManager, liquidityManager: LiquidityManager, utils: Utils, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb) { constructor(storage: Storage, lnd: LND, settings: SettingsManager, liquidityManager: LiquidityManager, utils: Utils, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb) {
this.storage = storage this.storage = storage
this.settings = settings this.settings = settings
@ -58,6 +60,7 @@ export default class {
this.liquidityManager = liquidityManager this.liquidityManager = liquidityManager
this.utils = utils this.utils = utils
this.watchDog = new Watchdog(settings, this.liquidityManager, this.lnd, this.storage, this.utils, this.liquidityManager.rugPullTracker) this.watchDog = new Watchdog(settings, this.liquidityManager, this.lnd, this.storage, this.utils, this.liquidityManager.rugPullTracker)
this.swaps = new Swaps(settings)
this.addressPaidCb = addressPaidCb this.addressPaidCb = addressPaidCb
this.invoicePaidCb = invoicePaidCb this.invoicePaidCb = invoicePaidCb
} }

View file

@ -165,7 +165,22 @@ export const LoadLiquiditySettingsFromEnv = (dbEnv: Record<string, string | unde
//const liquidityProviderPub = process.env.LIQUIDITY_PROVIDER_PUB === "null" ? "" : (process.env.LIQUIDITY_PROVIDER_PUB || "76ed45f00cea7bac59d8d0b7d204848f5319d7b96c140ffb6fcbaaab0a13d44e") //const liquidityProviderPub = process.env.LIQUIDITY_PROVIDER_PUB === "null" ? "" : (process.env.LIQUIDITY_PROVIDER_PUB || "76ed45f00cea7bac59d8d0b7d204848f5319d7b96c140ffb6fcbaaab0a13d44e")
const liquidityProviderPub = chooseEnv("LIQUIDITY_PROVIDER_PUB", dbEnv, "76ed45f00cea7bac59d8d0b7d204848f5319d7b96c140ffb6fcbaaab0a13d44e", addToDb) const liquidityProviderPub = chooseEnv("LIQUIDITY_PROVIDER_PUB", dbEnv, "76ed45f00cea7bac59d8d0b7d204848f5319d7b96c140ffb6fcbaaab0a13d44e", addToDb)
const disableLiquidityProvider = chooseEnvBool("DISABLE_LIQUIDITY_PROVIDER", dbEnv, false, addToDb) || liquidityProviderPub === "null" const disableLiquidityProvider = chooseEnvBool("DISABLE_LIQUIDITY_PROVIDER", dbEnv, false, addToDb) || liquidityProviderPub === "null"
return { liquidityProviderPub, useOnlyLiquidityProvider: false, disableLiquidityProvider } const useOnlyLiquidityProvider = chooseEnvBool("USE_ONLY_LIQUIDITY_PROVIDER", dbEnv, false, addToDb)
return { liquidityProviderPub, useOnlyLiquidityProvider, disableLiquidityProvider }
}
export type SwapsSettings = {
boltzHttpUrl: string
boltzWebSocketUrl: string
enableSwaps: boolean
}
export const LoadSwapsSettingsFromEnv = (dbEnv: Record<string, string | undefined>, addToDb?: EnvCacher): SwapsSettings => {
return {
boltzHttpUrl: chooseEnv("BOLTZ_HTTP_URL", dbEnv, "http://127.0.0.1:9001", addToDb),
boltzWebSocketUrl: chooseEnv("BOLTZ_WEBSOCKET_URL", dbEnv, "ws://127.0.0.1:9004", addToDb),
enableSwaps: chooseEnvBool("ENABLE_SWAPS", dbEnv, false, addToDb)
}
} }

View file

@ -5,7 +5,8 @@ import {
LiquiditySettings, LndNodeSettings, LndSettings, LoadLiquiditySettingsFromEnv, LiquiditySettings, LndNodeSettings, LndSettings, LoadLiquiditySettingsFromEnv,
LoadLSPSettingsFromEnv, LSPSettings, ServiceFeeSettings, ServiceSettings, LoadServiceFeeSettingsFromEnv, LoadLSPSettingsFromEnv, LSPSettings, ServiceFeeSettings, ServiceSettings, LoadServiceFeeSettingsFromEnv,
LoadNostrRelaySettingsFromEnv, LoadServiceSettingsFromEnv, LoadWatchdogSettingsFromEnv, LoadNostrRelaySettingsFromEnv, LoadServiceSettingsFromEnv, LoadWatchdogSettingsFromEnv,
LoadLndNodeSettingsFromEnv, LoadLndSettingsFromEnv, NostrRelaySettings, WatchdogSettings LoadLndNodeSettingsFromEnv, LoadLndSettingsFromEnv, NostrRelaySettings, WatchdogSettings, SwapsSettings, LoadSwapsSettingsFromEnv
} from "./settings.js" } from "./settings.js"
export default class SettingsManager { export default class SettingsManager {
storage: Storage storage: Storage
@ -27,6 +28,7 @@ export default class SettingsManager {
serviceFeeSettings: LoadServiceFeeSettingsFromEnv(dbEnv, addToDb), serviceFeeSettings: LoadServiceFeeSettingsFromEnv(dbEnv, addToDb),
serviceSettings: LoadServiceSettingsFromEnv(dbEnv, addToDb), serviceSettings: LoadServiceSettingsFromEnv(dbEnv, addToDb),
watchDogSettings: LoadWatchdogSettingsFromEnv(dbEnv, addToDb), watchDogSettings: LoadWatchdogSettingsFromEnv(dbEnv, addToDb),
swapsSettings: LoadSwapsSettingsFromEnv(dbEnv, addToDb),
} }
} }
@ -148,5 +150,6 @@ type FullSettings = {
nostrRelaySettings: NostrRelaySettings, nostrRelaySettings: NostrRelaySettings,
serviceFeeSettings: ServiceFeeSettings, serviceFeeSettings: ServiceFeeSettings,
serviceSettings: ServiceSettings, serviceSettings: ServiceSettings,
lspSettings: LSPSettings lspSettings: LSPSettings,
swapsSettings: SwapsSettings
} }