diff --git a/api/typeDefs/wallet.js b/api/typeDefs/wallet.js index 061ec837b0..809f49f530 100644 --- a/api/typeDefs/wallet.js +++ b/api/typeDefs/wallet.js @@ -119,6 +119,16 @@ const typeDefs = gql` noffer: String! ): WalletRecvClink! + upsertWalletSendSpark( + ${shared}, + mnemonic: VaultEntryInput! + ): WalletSendSpark! + + upsertWalletRecvSpark( + ${shared}, + identityPublicKey: String! + ): WalletRecvSpark! + # tests testWalletRecvNWC( url: String! @@ -159,6 +169,10 @@ const typeDefs = gql` noffer: String! ): Boolean! + testWalletRecvSpark( + identityPublicKey: String! + ): Boolean! + # delete deleteWallet(id: ID!): Boolean @@ -235,6 +249,7 @@ const typeDefs = gql` | WalletSendLNC | WalletSendCLNRest | WalletSendClink + | WalletSendSpark | WalletRecvNWC | WalletRecvLNbits | WalletRecvPhoenixd @@ -243,6 +258,7 @@ const typeDefs = gql` | WalletRecvCLNRest | WalletRecvLNDGRPC | WalletRecvClink + | WalletRecvSpark type WalletSettings { receiveCreditsBelowSats: Int! @@ -309,6 +325,11 @@ const typeDefs = gql` secretKey: VaultEntry! } + type WalletSendSpark { + id: ID! + mnemonic: VaultEntry! + } + type WalletRecvNWC { id: ID! url: String! @@ -356,6 +377,11 @@ const typeDefs = gql` noffer: String! } + type WalletRecvSpark { + id: ID! + identityPublicKey: String! + } + input AutowithdrawSettings { autoWithdrawThreshold: Int! autoWithdrawMaxFeePercent: Float! diff --git a/package-lock.json b/package-lock.json index 9779d4db78..3788bad1bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@apollo/server": "^4.11.0", "@as-integrations/next": "^3.1.0", "@auth/prisma-adapter": "^2.7.0", + "@buildonspark/spark-sdk": "^0.4.2", "@cashu/cashu-ts": "^2.4.1", "@graphql-tools/schema": "^10.0.6", "@lightninglabs/lnc-web": "^0.3.2-alpha", @@ -31,6 +32,7 @@ "async-retry": "^1.3.3", "aws-sdk": "^2.1691.0", "bech32": "^2.0.0", + "bip39": "^3.1.0", "bolt11": "^1.4.1", "bootstrap": "^5.3.3", "canonical-json": "0.0.4", @@ -2438,6 +2440,152 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@bitcoinerlab/secp256k1": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@bitcoinerlab/secp256k1/-/secp256k1-1.2.0.tgz", + "integrity": "sha512-jeujZSzb3JOZfmJYI0ph1PVpCRV5oaexCgy+RvCXV8XlY+XFB/2n3WOcvBsKLsOw78KYgnQrQWb2HrKE4be88Q==", + "license": "MIT", + "dependencies": { + "@noble/curves": "^1.7.0" + } + }, + "node_modules/@bufbuild/protobuf": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.10.0.tgz", + "integrity": "sha512-fdRs9PSrBF7QUntpZpq6BTw58fhgGJojgg39m9oFOJGZT+nip9b0so5cYY1oWl5pvemDLr0cPPsH46vwThEbpQ==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@buildonspark/spark-sdk": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@buildonspark/spark-sdk/-/spark-sdk-0.4.2.tgz", + "integrity": "sha512-d9Yf2oSvZ90iaRr4Fdo8UgDgZz3aKS3Yfa1/26WBmmJIwJp80jNREWgLi3ud6DOauPxngJTzvTUzfoWN24DmlQ==", + "license": "Apache-2.0", + "dependencies": { + "@bitcoinerlab/secp256k1": "^1.1.1", + "@bufbuild/protobuf": "^2.2.5", + "@lightsparkdev/core": "^1.4.4", + "@noble/curves": "^1.8.0", + "@noble/hashes": "^1.7.0", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^2.0.0", + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/instrumentation-fetch": "^0.203.0", + "@opentelemetry/instrumentation-undici": "^0.14.0", + "@opentelemetry/sdk-trace-base": "^2.0.0", + "@opentelemetry/sdk-trace-node": "^2.0.1", + "@opentelemetry/sdk-trace-web": "^2.0.1", + "@scure/base": "^1.2.4", + "@scure/bip32": "^1.6.2", + "@scure/bip39": "^1.5.4", + "@scure/btc-signer": "^1.5.0", + "abort-controller-x": "^0.4.3", + "abortcontroller-polyfill": "^1.7.8", + "async-mutex": "^0.5.0", + "bare-crypto": "^1.9.2", + "bare-fetch": "^2.4.1", + "buffer": "^6.0.3", + "eciesjs": "^0.4.13", + "eventemitter3": "^5.0.1", + "js-base64": "^3.7.7", + "light-bolt11-decoder": "^3.2.0", + "nice-grpc": "^2.1.10", + "nice-grpc-client-middleware-retry": "^3.1.10", + "nice-grpc-common": "^2.0.2", + "nice-grpc-opentelemetry": "^0.1.18", + "nice-grpc-web": "^3.3.7", + "ts-proto": "^2.6.1", + "uuidv7": "^1.0.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "react": ">=18.2.0", + "react-native": ">=0.71.0", + "react-native-get-random-values": ">=1.11.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-native": { + "optional": true + }, + "react-native-get-random-values": { + "optional": true + } + } + }, + "node_modules/@buildonspark/spark-sdk/node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@buildonspark/spark-sdk/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@buildonspark/spark-sdk/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@buildonspark/spark-sdk/node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@buildonspark/spark-sdk/node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@buildonspark/spark-sdk/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, "node_modules/@cashu/cashu-ts": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@cashu/cashu-ts/-/cashu-ts-2.4.1.tgz", @@ -2523,6 +2671,20 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@ecies/ciphers": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ecies/ciphers/-/ciphers-0.2.4.tgz", + "integrity": "sha512-t+iX+Wf5nRKyNzk8dviW3Ikb/280+aEJAnw9YXvCp2tYGPSkMki+NRY+8aNLmVFv3eNtMdvViPNOPxS8SZNP+w==", + "license": "MIT", + "engines": { + "bun": ">=1", + "deno": ">=2", + "node": ">=16" + }, + "peerDependencies": { + "@noble/ciphers": "^1.0.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.23.1", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", @@ -4233,6 +4395,38 @@ "crypto-js": "4.2.0" } }, + "node_modules/@lightsparkdev/core": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@lightsparkdev/core/-/core-1.4.5.tgz", + "integrity": "sha512-SQo1wNNMfJNFdZPFsbYOylEa6t5X9S+FnKneju9qbvWZz9vfsb6B+MkvVW7DUGoMhisjtPzmR691qedfvstWIg==", + "license": "Apache-2.0", + "dependencies": { + "dayjs": "^1.11.7", + "graphql": "^16.6.0", + "graphql-ws": "^5.11.3", + "secp256k1": "^5.0.1", + "ws": "^8.12.1", + "zen-observable-ts": "^1.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@lightsparkdev/core/node_modules/secp256k1": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-5.0.1.tgz", + "integrity": "sha512-lDFs9AAIaWP9UCdtWrotXWWF9t8PWgQDcxqgAnpM9rMqxb3Oaq2J0thzPVSxBwdJgyQtkU/sYtFtbM1RSt/iYA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "elliptic": "^6.5.7", + "node-addon-api": "^5.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@next/env": { "version": "14.2.25", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.25.tgz", @@ -4650,6 +4844,244 @@ "yarn": "^1.22.10" } }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.203.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.203.0.tgz", + "integrity": "sha512-9B9RU0H7Ya1Dx/Rkyc4stuBZSGVQF27WigitInx2QQoj6KUpEFYPKoWjdFTunJYxmXmh17HeBvbMa1EhGyPmqQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.2.0.tgz", + "integrity": "sha512-qRkLWiUEZNAmYapZ7KGS5C4OmBLcP/H2foXeOEaowYCR0wi89fHejrfYfbuLVCMLp/dWZXKvQusdbUEZjERfwQ==", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.2.0.tgz", + "integrity": "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.203.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.203.0.tgz", + "integrity": "sha512-ke1qyM+3AK2zPuBPb6Hk/GCsc5ewbLvPNkEuELx/JmANeEp6ZjnZ+wypPAJSucTw0wvCGrUaibDSdcrGFoWxKQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.203.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fetch": { + "version": "0.203.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fetch/-/instrumentation-fetch-0.203.0.tgz", + "integrity": "sha512-Z+mls3rOP2BaVykDZLLZPvchjj9l2oj3dYG1GTnrc27Y8o3biE+5M1b0izblycbbQHXjMPHQCpmjHbLMQuWtBg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/instrumentation": "0.203.0", + "@opentelemetry/sdk-trace-web": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fetch/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fetch/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fetch/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fetch/node_modules/@opentelemetry/sdk-trace-web": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-web/-/sdk-trace-web-2.0.1.tgz", + "integrity": "sha512-R4/i0rISvAujG4Zwk3s6ySyrWG+Db3SerZVM4jZ2lEzjrNylF7nRAy1hVvWe8gTbwIxX+6w6ZvZwdtl2C7UQHQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation-undici": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.14.0.tgz", + "integrity": "sha512-2HN+7ztxAReXuxzrtA3WboAKlfP5OsPA57KQn2AdYZbJ3zeRPcLXyW4uO/jpLE6PLm0QRtmeGCmfYpqRlwgSwg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.203.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.7.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", + "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.2.0.tgz", + "integrity": "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/resources": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-node": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.2.0.tgz", + "integrity": "sha512-+OaRja3f0IqGG2kptVeYsrZQK9nKRSpfFrKtRBq4uh6nIB8bTBgaGvYQrQoRrQWQMA5dK5yLhDMDc0dvYvCOIQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/context-async-hooks": "2.2.0", + "@opentelemetry/core": "2.2.0", + "@opentelemetry/sdk-trace-base": "2.2.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-web": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-web/-/sdk-trace-web-2.2.0.tgz", + "integrity": "sha512-x/LHsDBO3kfqaFx5qSzBljJ5QHsRXrvS4MybBDy1k7Svidb8ZyIPudWVzj3s5LpPkYZIgi9e+7tdsNCnptoelw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/sdk-trace-base": "2.2.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.37.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.37.0.tgz", + "integrity": "sha512-JD6DerIKdJGmRp4jQyX5FlrQjA4tjOw1cvfsPAZXfOOEErMUHjPcPSICS+6WnM0nB0efSFARh0KAZss+bvExOA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/@panva/hkdf": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz", @@ -5322,6 +5754,57 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@scure/btc-signer": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@scure/btc-signer/-/btc-signer-1.8.1.tgz", + "integrity": "sha512-8nX9T++dFyKpvqksNHfSi9CgRsGnHAQtCdIQ1y1GmbCGLpV97v4MUyemUUT6uDumKL3oo3m4niyY6A32nmdLuQ==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5", + "micro-packed": "~0.7.3" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/btc-signer/node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/btc-signer/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/btc-signer/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@shocknet/clink-sdk": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@shocknet/clink-sdk/-/clink-sdk-1.4.0.tgz", @@ -6607,6 +7090,18 @@ "react-dom": "^17 || ^18" } }, + "node_modules/abort-controller-x": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/abort-controller-x/-/abort-controller-x-0.4.3.tgz", + "integrity": "sha512-VtUwTNU8fpMwvWGn4xE93ywbogTYsuT+AUxAXOeelbXuQVIwNmC5YLeho9sH4vZ4ITW8414TTAOG1nW6uIVHCA==", + "license": "MIT" + }, + "node_modules/abortcontroller-polyfill": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.8.tgz", + "integrity": "sha512-9f1iZ2uWh92VcrU9Y8x+LdM4DLj75VE0MJB8zuF1iUnroEptStw+DQ8EQPMUdfe5k+PkB1uUfDQfWbhstH8LrQ==", + "license": "MIT" + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -6620,9 +7115,10 @@ } }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -7103,6 +7599,20 @@ "node": ">= 6" } }, + "node_modules/b4a": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", + "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -7300,43 +7810,240 @@ "@babel/core": "^7.0.0" } }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "dev": true, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/barcode-detector": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-2.2.11.tgz", + "integrity": "sha512-N50XZ6Rav2sxTgHXOc38/mkpVJMan11GZ8Yqi1pPMZpTJSXuZ/FpIee6OtLehZX/Vs4ZOzGbp1DgXzFCfKggWA==", + "dependencies": { + "@types/dom-webcodecs": "^0.1.13", + "zxing-wasm": "1.2.14" + } + }, + "node_modules/bare-crypto": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/bare-crypto/-/bare-crypto-1.12.0.tgz", + "integrity": "sha512-GLeZOS2RQkEawVNPvBKmVZQWwSs4jLhculTvuOfLdP+RTMN1Gv3pz+oI9fcQj7/LE2QJM4cPOHfx4u0izBaTHA==", + "license": "Apache-2.0", + "dependencies": { + "bare-stream": "^2.6.3" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-dns": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/bare-dns/-/bare-dns-2.1.4.tgz", + "integrity": "sha512-abwjHmpWqSRNB7V5615QxPH92L71AVzFm/kKTs8VYiNTAi2xVdonpv0BjJ0hwXLwomoW+xsSOPjW6PZPO14asg==", + "license": "Apache-2.0", + "engines": { + "bare": ">=1.7.0" + } + }, + "node_modules/bare-events": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.1.tgz", + "integrity": "sha512-oxSAxTS1hRfnyit2CL5QpAOS5ixfBjj6ex3yTNvXyY/kE719jQ/IjuESJBK2w5v4wwQRAHGseVJXx9QBYOtFGQ==", + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fetch": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/bare-fetch/-/bare-fetch-2.5.0.tgz", + "integrity": "sha512-2f/mx0hw4CDH2yX2cT7tVZGPnXcUswZCYu/EY72hHfbAipZJwZtDl8f3DsXJG+yXyPBNw3TNPicMbYPpfuaIfw==", + "license": "Apache-2.0", + "dependencies": { + "bare-form-data": "^1.1.3", + "bare-http1": "^4.0.2", + "bare-https": "^2.0.0", + "bare-stream": "^2.7.0", + "bare-zlib": "^1.3.0" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-url": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-url": { + "optional": true + } + } + }, + "node_modules/bare-form-data": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bare-form-data/-/bare-form-data-1.1.6.tgz", + "integrity": "sha512-q1IN7dVo/lEhTlVkVQdULZvoBx6eTI94co0NtO7/A3JLFL/aZGA1wAHgcNEPrlkqTK9jTEdtzQXSoqGzlVjzgg==", + "license": "Apache-2.0", + "dependencies": { + "bare-stream": "^2.6.5" + } + }, + "node_modules/bare-http-parser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bare-http-parser/-/bare-http-parser-1.0.0.tgz", + "integrity": "sha512-ZI3EFTFp8gHshWlUWl1vZo7KdZgH1hf/mNNDm+9pDVC5fk2dIfKGPQIEciBq3cIWR4JqDQTa6qCxPCqHqVel2g==", + "license": "Apache-2.0" + }, + "node_modules/bare-http1": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/bare-http1/-/bare-http1-4.1.5.tgz", + "integrity": "sha512-YT6tf5R7eIt1VBBc/mpNDXqbxl21WoYGdBXT5anQz2Xt4G2w2gKjmlkDPFwDARZd5wmgH5D2iIiRWAKwbKgVTQ==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.6.0", + "bare-http-parser": "^1.0.0", + "bare-stream": "^2.3.0", + "bare-tcp": "^2.0.3" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-url": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-url": { + "optional": true + } + } + }, + "node_modules/bare-https": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bare-https/-/bare-https-2.1.0.tgz", + "integrity": "sha512-Sk3RUhXr7rt1Yq4im6xoGYGKz06denjsqM60igKA0IK6Kd3qDlLLZogrWsh3hDsB2kKt60092G3SIMoD9PAR6g==", + "license": "Apache-2.0", + "dependencies": { + "bare-http1": "^4.0.0", + "bare-tcp": "^2.0.0", + "bare-tls": "^2.0.0" + } + }, + "node_modules/bare-net": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/bare-net/-/bare-net-2.2.0.tgz", + "integrity": "sha512-UF7cAbHsGE+H6uEqWF5IULBow1x58chZz4g3ALgHtv7wZsFcCbRDt0JKWEumf5Oma3QWS1Q6aLi0Rpll8RElMg==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.2.2", + "bare-pipe": "^4.0.0", + "bare-stream": "^2.0.0", + "bare-tcp": "^2.0.0" + } + }, + "node_modules/bare-pipe": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bare-pipe/-/bare-pipe-4.1.0.tgz", + "integrity": "sha512-0TD3NUIhh7KgPMRLyEBqSXlTZ8X/jcw1ulAjmErDWwoLdIF9FdVXvbpbzyKIl45sr9ZQ4k5AKThAOlrrtZcrXg==", + "license": "Apache-2.0", "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" + "bare-events": "^2.0.0", + "bare-stream": "^2.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "bare": ">=1.16.0" + } + }, + "node_modules/bare-stream": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.7.0.tgz", + "integrity": "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==", + "license": "Apache-2.0", + "dependencies": { + "streamx": "^2.21.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } } }, - "node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/bare-tcp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bare-tcp/-/bare-tcp-2.1.0.tgz", + "integrity": "sha512-5DpPDWxJJ/pdbY4aMFPKBQvEizjvmgKOO75D/V0ELpLvauIuSAS0cWcZoqNPI3rAIYqIjpBu+xGLXHavjG67hw==", + "license": "Apache-2.0", + "dependencies": { + "bare-dns": "^2.0.4", + "bare-events": "^2.5.4", + "bare-stream": "^2.6.4" + }, + "engines": { + "bare": ">=1.16.0" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "node_modules/bare-tls": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/bare-tls/-/bare-tls-2.1.5.tgz", + "integrity": "sha512-ouc6RqjizIRsUQJcboUI6GiIvwUr30F9xTPzyWFrDpkA1iDsWitLC/mSHjeVXU1H58rvFvnH1xENY8vhJH5e6A==", + "license": "Apache-2.0", + "dependencies": { + "bare-net": "^2.0.1", + "bare-stream": "^2.6.4" + }, + "engines": { + "bare": ">=1.7.0" + } }, - "node_modules/barcode-detector": { - "version": "2.2.11", - "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-2.2.11.tgz", - "integrity": "sha512-N50XZ6Rav2sxTgHXOc38/mkpVJMan11GZ8Yqi1pPMZpTJSXuZ/FpIee6OtLehZX/Vs4ZOzGbp1DgXzFCfKggWA==", + "node_modules/bare-zlib": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/bare-zlib/-/bare-zlib-1.3.1.tgz", + "integrity": "sha512-VP93GFzhrTdWh9mXNocn7XsP/nF5JQluiiSsbTvsQ4yIYlhEHRMF9lQmZZDXwzK9PNYaVGUV1bdQuqp0Mj7MHw==", + "license": "Apache-2.0", "dependencies": { - "@types/dom-webcodecs": "^0.1.13", - "zxing-wasm": "1.2.14" + "bare-stream": "^2.0.0" } }, "node_modules/base-x": { @@ -7439,6 +8146,27 @@ "node": ">=8.0.0" } }, + "node_modules/bip39": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz", + "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==", + "license": "ISC", + "dependencies": { + "@noble/hashes": "^1.2.0" + } + }, + "node_modules/bip39/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/bip66": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", @@ -7936,6 +8664,18 @@ "resolved": "https://registry.npmjs.org/canonical-json/-/canonical-json-0.0.4.tgz", "integrity": "sha512-2sW7x0m/P7dqEnO0O87U7RTVQAaa7MELcd+Jd9FA6CYgYtwJ1TlDWIYMD8nuMkH1KoThsJogqgLyklrt9d/Azw==" }, + "node_modules/case-anything": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.13.tgz", + "integrity": "sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==", + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -8064,8 +8804,7 @@ "node_modules/cjs-module-lexer": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" }, "node_modules/classnames": { "version": "2.5.1", @@ -8857,6 +9596,12 @@ "url": "https://github.com/sponsors/kossnocorp" } }, + "node_modules/dayjs": { + "version": "1.11.18", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz", + "integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", @@ -9168,6 +9913,15 @@ "tslib": "^2.0.3" } }, + "node_modules/dprint-node": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/dprint-node/-/dprint-node-1.0.8.tgz", + "integrity": "sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg==", + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3" + } + }, "node_modules/dset": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", @@ -9220,6 +9974,62 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/eciesjs": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/eciesjs/-/eciesjs-0.4.16.tgz", + "integrity": "sha512-dS5cbA9rA2VR4Ybuvhg6jvdmp46ubLn3E+px8cG/35aEDNclrqoCjg6mt0HYZ/M+OoESS3jSkCrqk1kWAEhWAw==", + "license": "MIT", + "dependencies": { + "@ecies/ciphers": "^0.2.4", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "^1.9.7", + "@noble/hashes": "^1.8.0" + }, + "engines": { + "bun": ">=1", + "deno": ">=2", + "node": ">=16" + } + }, + "node_modules/eciesjs/node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/eciesjs/node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/eciesjs/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/ecpair": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz", @@ -10291,6 +11101,15 @@ "node": ">=0.8.x" } }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -10467,6 +11286,12 @@ "node": ">=6.0.0" } }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -11122,6 +11947,18 @@ "graphql": ">=0.8.0" } }, + "node_modules/graphql-ws": { + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.2.tgz", + "integrity": "sha512-E1uccsZxt/96jH/OwmLPuXMACILs76pKF2i3W861LpKBCYtGIyPQGtWLuBLkND4ox1KHns70e83PS4te50nvPQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "graphql": ">=0.11 <=16" + } + }, "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -11698,6 +12535,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-in-the-middle": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.15.0.tgz", + "integrity": "sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==", + "license": "Apache-2.0", + "dependencies": { + "acorn": "^8.14.0", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -14484,6 +15333,12 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/js-base64": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", + "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", + "license": "BSD-3-Clause" + }, "node_modules/js-sha256": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", @@ -15446,6 +16301,27 @@ "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.2.1.tgz", "integrity": "sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ==" }, + "node_modules/micro-packed": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.7.3.tgz", + "integrity": "sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==", + "license": "MIT", + "dependencies": { + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-packed/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/micromark": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", @@ -16100,6 +16976,12 @@ "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==" }, + "node_modules/module-details-from-path": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", + "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", + "license": "MIT" + }, "node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -16278,6 +17160,107 @@ "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", "license": "ISC" }, + "node_modules/nice-grpc": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/nice-grpc/-/nice-grpc-2.1.13.tgz", + "integrity": "sha512-IkXNok2NFyYh0WKp1aJFwFV3Ue2frBkJ16ojrmgX3Tc9n0g7r0VU+ur3H/leDHPPGsEeVozdMynGxYT30k3D/Q==", + "license": "MIT", + "dependencies": { + "@grpc/grpc-js": "^1.14.0", + "abort-controller-x": "^0.4.0", + "nice-grpc-common": "^2.0.2" + } + }, + "node_modules/nice-grpc-client-middleware-retry": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/nice-grpc-client-middleware-retry/-/nice-grpc-client-middleware-retry-3.1.12.tgz", + "integrity": "sha512-CHKIeHznAePOsT2dLeGwoOFaybQz6LvkIsFfN8SLcyGyTR7AB6vZMaECJjx+QPL8O2qVgaVE167PdeOmQrPuag==", + "license": "MIT", + "dependencies": { + "abort-controller-x": "^0.4.0", + "nice-grpc-common": "^2.0.2" + } + }, + "node_modules/nice-grpc-common": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/nice-grpc-common/-/nice-grpc-common-2.0.2.tgz", + "integrity": "sha512-7RNWbls5kAL1QVUOXvBsv1uO0wPQK3lHv+cY1gwkTzirnG1Nop4cBJZubpgziNbaVc/bl9QJcyvsf/NQxa3rjQ==", + "license": "MIT", + "dependencies": { + "ts-error": "^1.0.6" + } + }, + "node_modules/nice-grpc-opentelemetry": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/nice-grpc-opentelemetry/-/nice-grpc-opentelemetry-0.1.19.tgz", + "integrity": "sha512-rjYVFbmSTE/g3XtxIh37PgEtE1ZOcwFoSHeLBCMRz9GAeGwZd23020QObgElF2UgU6kn1wpH8taWdprNr+3wfg==", + "license": "MIT", + "dependencies": { + "@opentelemetry/api": "^1.8.0", + "@opentelemetry/semantic-conventions": "^1.22.0", + "abort-controller-x": "^0.4.0", + "ipaddr.js": "^2.0.1", + "nice-grpc-common": "^2.0.2" + } + }, + "node_modules/nice-grpc-opentelemetry/node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/nice-grpc-web": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nice-grpc-web/-/nice-grpc-web-3.3.8.tgz", + "integrity": "sha512-VOVzjcgl90lhoZgjXDg9hG8clIxe6NBk84R3p0P21CGitMesHMTV8g5adnDKQ4i60FJT1uk2EwepSyv1cND8JQ==", + "license": "MIT", + "dependencies": { + "abort-controller-x": "^0.4.0", + "isomorphic-ws": "^5.0.0", + "js-base64": "^3.7.2", + "nice-grpc-common": "^2.0.2" + } + }, + "node_modules/nice-grpc/node_modules/@grpc/grpc-js": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.0.tgz", + "integrity": "sha512-N8Jx6PaYzcTRNzirReJCtADVoq4z7+1KQ4E70jTg/koQiMoUSN1kbNjPOqpPbhMFhfU1/l7ixspPl8dNY+FoUg==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.8.0", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/nice-grpc/node_modules/@grpc/proto-loader": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz", + "integrity": "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.5.3", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/nice-grpc/node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -17501,10 +18484,11 @@ } }, "node_modules/protobufjs": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", - "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", + "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", "hasInstallScript": true, + "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -18439,6 +19423,20 @@ "node": ">=0.10.0" } }, + "node_modules/require-in-the-middle": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.2.tgz", + "integrity": "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -19558,6 +20556,17 @@ "node": ">=10.0.0" } }, + "node_modules/streamx": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", + "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -19949,6 +20958,15 @@ "node": ">=8" } }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -20108,6 +21126,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-error": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/ts-error/-/ts-error-1.0.6.tgz", + "integrity": "sha512-tLJxacIQUM82IR7JO1UUkKlYuUTmoY9HBJAmNWFzheSlDS5SPMcNIepejHJa4BpPQLAcbRhRf3GDJzyj6rbKvA==", + "license": "MIT" + }, "node_modules/ts-invariant": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz", @@ -20119,6 +21143,39 @@ "node": ">=8" } }, + "node_modules/ts-poet": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-6.12.0.tgz", + "integrity": "sha512-xo+iRNMWqyvXpFTaOAvLPA5QAWO6TZrSUs5s4Odaya3epqofBu/fMLHEWl8jPmjhA0s9sgj9sNvF1BmaQlmQkA==", + "license": "Apache-2.0", + "dependencies": { + "dprint-node": "^1.0.8" + } + }, + "node_modules/ts-proto": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-2.8.1.tgz", + "integrity": "sha512-suKxr/MaDwCZhWPykXGIanxqFUE79zwN5SUKMCmVzyf32ZZeKSt2aut9kcx9DmXFocf2v1Jpr2ITWIQH4Xz+Bw==", + "license": "ISC", + "dependencies": { + "@bufbuild/protobuf": "^2.0.0", + "case-anything": "^2.1.13", + "ts-poet": "^6.12.0", + "ts-proto-descriptors": "2.0.0" + }, + "bin": { + "protoc-gen-ts_proto": "protoc-gen-ts_proto" + } + }, + "node_modules/ts-proto-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-2.0.0.tgz", + "integrity": "sha512-wHcTH3xIv11jxgkX5OyCSFfw27agpInAd6yh89hKG6zqIXnjW9SYqSER2CVQxdPj4czeOhGagNvZBEbJPy7qkw==", + "license": "ISC", + "dependencies": { + "@bufbuild/protobuf": "^2.0.0" + } + }, "node_modules/tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -21039,6 +22096,15 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/uuidv7": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uuidv7/-/uuidv7-1.0.2.tgz", + "integrity": "sha512-8JQkH4ooXnm1JCIhqTMbtmdnYEn6oKukBxHn1Ic9878jMkL7daTI7anTExfY18VRCX7tcdn5quzvCb6EWrR8PA==", + "license": "Apache-2.0", + "bin": { + "uuidv7": "cli.js" + } + }, "node_modules/v8-to-istanbul": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", diff --git a/package.json b/package.json index 82bb6dfde4..044eb5d4e3 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@apollo/server": "^4.11.0", "@as-integrations/next": "^3.1.0", "@auth/prisma-adapter": "^2.7.0", + "@buildonspark/spark-sdk": "^0.4.2", "@cashu/cashu-ts": "^2.4.1", "@graphql-tools/schema": "^10.0.6", "@lightninglabs/lnc-web": "^0.3.2-alpha", @@ -36,6 +37,7 @@ "async-retry": "^1.3.3", "aws-sdk": "^2.1691.0", "bech32": "^2.0.0", + "bip39": "^3.1.0", "bolt11": "^1.4.1", "bootstrap": "^5.3.3", "canonical-json": "0.0.4", diff --git a/prisma/migrations/20250923052230_spark/migration.sql b/prisma/migrations/20250923052230_spark/migration.sql new file mode 100644 index 0000000000..83f9b50de5 --- /dev/null +++ b/prisma/migrations/20250923052230_spark/migration.sql @@ -0,0 +1,68 @@ +-- AlterEnum +ALTER TYPE "WalletName" ADD VALUE 'SPARK'; COMMIT; + +-- AlterEnum +ALTER TYPE "WalletProtocolName" ADD VALUE 'SPARK'; COMMIT; + +-- AlterEnum +ALTER TYPE "WalletSendProtocolName" ADD VALUE 'SPARK'; COMMIT; + +-- AlterEnum +ALTER TYPE "WalletRecvProtocolName" ADD VALUE 'SPARK'; COMMIT; + +INSERT INTO "WalletTemplate" ("name", "sendProtocols", "recvProtocols") +VALUES ('SPARK', '{SPARK}', '{SPARK}'); + +-- CreateTable +CREATE TABLE "WalletSendSpark" ( + "id" SERIAL NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "protocolId" INTEGER NOT NULL, + "mnemonicVaultId" INTEGER NOT NULL, + + CONSTRAINT "WalletSendSpark_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "WalletSendSpark_protocolId_key" ON "WalletSendSpark"("protocolId"); + +-- CreateIndex +CREATE UNIQUE INDEX "WalletSendSpark_mnemonicVaultId_key" ON "WalletSendSpark"("mnemonicVaultId"); + +-- AddForeignKey +ALTER TABLE "WalletSendSpark" ADD CONSTRAINT "WalletSendSpark_protocolId_fkey" FOREIGN KEY ("protocolId") REFERENCES "WalletProtocol"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "WalletSendSpark" ADD CONSTRAINT "WalletSendSpark_mnemonicVaultId_fkey" FOREIGN KEY ("mnemonicVaultId") REFERENCES "Vault"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +CREATE TABLE "WalletRecvSpark" ( + "id" SERIAL NOT NULL, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "protocolId" INTEGER NOT NULL, + "identityPublicKey" TEXT NOT NULL, + + CONSTRAINT "WalletRecvSpark_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "WalletRecvSpark_protocolId_key" ON "WalletRecvSpark"("protocolId"); + +-- AddForeignKey +ALTER TABLE "WalletRecvSpark" ADD CONSTRAINT "WalletRecvSpark_protocolId_fkey" FOREIGN KEY ("protocolId") REFERENCES "WalletProtocol"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +CREATE TRIGGER wallet_to_jsonb + AFTER INSERT OR UPDATE ON "WalletSendSpark" + FOR EACH ROW + EXECUTE PROCEDURE wallet_to_jsonb(); + +CREATE TRIGGER wallet_to_jsonb + AFTER INSERT OR UPDATE ON "WalletRecvSpark" + FOR EACH ROW + EXECUTE PROCEDURE wallet_to_jsonb(); + +CREATE TRIGGER wallet_clear_vault + AFTER DELETE ON "WalletSendSpark" + FOR EACH ROW + EXECUTE PROCEDURE wallet_clear_vault(); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c20511ffc2..6c54b9abc0 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -239,6 +239,7 @@ model Vault { walletSendCLNRestRune WalletSendCLNRest? @relation("clnRune") walletSendClink WalletSendClink? @relation("clinkNdebit") walletSendClinkSecretKey WalletSendClink? @relation("clinkSecretKey") + walletSendSparkMnemonic WalletSendSpark? @relation("sparkMnemonic") } model WalletLog { @@ -1233,6 +1234,7 @@ enum WalletProtocolName { CLN_REST LND_GRPC CLINK + SPARK } enum WalletSendProtocolName { @@ -1244,6 +1246,7 @@ enum WalletSendProtocolName { LNC CLN_REST CLINK + SPARK } enum WalletRecvProtocolName { @@ -1255,6 +1258,7 @@ enum WalletRecvProtocolName { CLN_REST LND_GRPC CLINK + SPARK } enum WalletProtocolStatus { @@ -1290,6 +1294,7 @@ enum WalletName { LN_ADDR CASH_APP BLITZ + SPARK } model WalletTemplate { @@ -1348,6 +1353,7 @@ model WalletProtocol { walletSendLNC WalletSendLNC? walletSendCLNRest WalletSendCLNRest? walletSendClink WalletSendClink? + walletSendSpark WalletSendSpark? walletRecvNWC WalletRecvNWC? walletRecvLNbits WalletRecvLNbits? @@ -1357,6 +1363,7 @@ model WalletProtocol { walletRecvCLNRest WalletRecvCLNRest? walletRecvLNDGRPC WalletRecvLNDGRPC? walletRecvClink WalletRecvClink? + walletRecvSpark WalletRecvSpark? @@unique(name: "WalletProtocol_walletId_send_name_key", [walletId, send, name]) @@index([walletId]) @@ -1453,6 +1460,16 @@ model WalletSendClink { secretKey Vault? @relation("clinkSecretKey", fields: [secretKeyVaultId], references: [id]) } +model WalletSendSpark { + id Int @id @default(autoincrement()) + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @default(now()) @updatedAt @map("updated_at") + protocolId Int @unique + protocol WalletProtocol @relation(fields: [protocolId], references: [id], onDelete: Cascade) + mnemonicVaultId Int @unique + mnemonic Vault? @relation("sparkMnemonic", fields: [mnemonicVaultId], references: [id]) +} + model WalletRecvNWC { id Int @id @default(autoincrement()) createdAt DateTime @default(now()) @map("created_at") @@ -1531,3 +1548,12 @@ model WalletRecvClink { protocol WalletProtocol @relation(fields: [protocolId], references: [id], onDelete: Cascade) noffer String } + +model WalletRecvSpark { + id Int @id @default(autoincrement()) + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @default(now()) @updatedAt @map("updated_at") + protocolId Int @unique + protocol WalletProtocol @relation(fields: [protocolId], references: [id], onDelete: Cascade) + identityPublicKey String +} diff --git a/public/wallets/breez-dark.svg b/public/wallets/breez-dark.svg new file mode 100644 index 0000000000..57ba8fcdc5 --- /dev/null +++ b/public/wallets/breez-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/wallets/breez.svg b/public/wallets/breez.svg new file mode 100644 index 0000000000..c7b98772a2 --- /dev/null +++ b/public/wallets/breez.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/wallets/spark-dark.svg b/public/wallets/spark-dark.svg new file mode 100644 index 0000000000..302b527916 --- /dev/null +++ b/public/wallets/spark-dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/public/wallets/spark.svg b/public/wallets/spark.svg new file mode 100644 index 0000000000..80627e4ce3 --- /dev/null +++ b/public/wallets/spark.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/wallets/client/components/form/hooks.js b/wallets/client/components/form/hooks.js index 579ed176e8..9be529991a 100644 --- a/wallets/client/components/form/hooks.js +++ b/wallets/client/components/form/hooks.js @@ -84,8 +84,11 @@ function useProtocolFormState (protocol) { export function useProtocolForm (protocol) { const [formState, setFormState] = useProtocolFormState(protocol) + const [complementaryFormState] = useProtocolFormState({ name: protocol.name, send: !protocol.send }) const [nwcSendFormState] = useProtocolFormState({ name: 'NWC', send: true }) + const [sparkFormState] = useProtocolFormState({ name: 'SPARK', send: true }) + const wallet = useWallet() const lud16Domain = walletLud16Domain(wallet.name) const fields = protocolFields(protocol) @@ -94,13 +97,17 @@ export function useProtocolForm (protocol) { // after init, we use formState as the source of truth everywhere let value = formState?.config?.[field.name] ?? protocol.config?.[field.name] + if (!value && field.initial) { + value = typeof field.initial === 'function' ? field.initial() : field.initial + } + if (!value && field.share) { value = complementaryFormState?.config?.[field.name] } if (protocol.name === 'LN_ADDR' && field.name === 'address' && lud16Domain) { - // automatically set lightning addresses from NWC urls if lud16 parameter is present if (nwcSendFormState?.config?.url) { + // automatically set lightning addresses from NWC urls if lud16 parameter is present ... const { lud16 } = parseNwcUrl(nwcSendFormState.config.url) if (lud16?.split('@')[1] === lud16Domain) value = lud16 } @@ -110,6 +117,12 @@ export function useProtocolForm (protocol) { } } + if (protocol.name === 'SPARK' && field.name === 'identityPublicKey') { + if (sparkFormState?.config?.identityPublicKey) { + value = sparkFormState.config.identityPublicKey + } + } + return { ...acc, [field.name]: value || '' diff --git a/wallets/client/components/form/index.js b/wallets/client/components/form/index.js index 55dc93e974..53bfd9b38e 100644 --- a/wallets/client/components/form/index.js +++ b/wallets/client/components/form/index.js @@ -9,7 +9,7 @@ import Text from '@/components/text' import Info from '@/components/info' import { useFormState, useMaxSteps, useNext, useStepIndex } from '@/components/multi-step-form' import { isTemplate, isWallet, protocolDisplayName, protocolFormId, protocolLogName, walletLud16Domain } from '@/wallets/lib/util' -import { WalletGuide, WalletLayout, WalletLayoutHeader, WalletLayoutImageOrName, WalletLogs } from '@/wallets/client/components' +import { WalletGuide, WalletLayout, WalletLayoutHeader, WalletLayoutImageOrName, WalletLayoutWarning, WalletLogs } from '@/wallets/client/components' import { TemplateLogsProvider, useTestSendPayment, useWalletLogger, useTestCreateInvoice, useWalletSupport } from '@/wallets/client/hooks' import ArrowRight from '@/svgs/arrow-right-s-fill.svg' import { useFormikContext } from 'formik' @@ -45,6 +45,7 @@ export function WalletMultiStepForm ({ wallet }) { + {steps.map(step => { // WalletForm is aware of the current step via hooks @@ -180,7 +181,7 @@ function WalletProtocolFormField ({ type, ...props }) { const [protocol] = useProtocol() const formik = useFormikContext() - function transform ({ validate, encrypt, editable, help, share, ...props }) { + function transform ({ validate, encrypt, editable, help, share, initial, ...props }) { const [upperHint, bottomHint] = Array.isArray(props.hint) ? props.hint : [null, props.hint] const parseHelpText = text => Array.isArray(text) ? text.join('\n\n') : text diff --git a/wallets/client/components/layout.js b/wallets/client/components/layout.js index 0c08386095..72782381b4 100644 --- a/wallets/client/components/layout.js +++ b/wallets/client/components/layout.js @@ -1,8 +1,10 @@ +import { Alert } from 'react-bootstrap' +import Link from 'next/link' import Layout from '@/components/layout' import { useWalletImage } from '@/wallets/client/hooks' -import { walletDisplayName, walletGuideUrl } from '@/wallets/lib/util' -import Link from 'next/link' +import { walletDisplayName, walletGuideUrl, walletWarning } from '@/wallets/lib/util' import InfoIcon from '@/svgs/information-fill.svg' +import Text from '@/components/text' export function WalletLayout ({ children }) { // TODO(wallet-v2): py-5 doesn't work, I think it gets overriden by the layout class @@ -69,3 +71,16 @@ export function WalletGuide ({ name }) { ) } + +export function WalletLayoutWarning ({ name }) { + const warning = walletWarning(name) + if (!warning) return null + + if (warning) { + return ( + + {warning} + + ) + } +} diff --git a/wallets/client/fragments/protocol.js b/wallets/client/fragments/protocol.js index 6d2175e386..cbf4a3b955 100644 --- a/wallets/client/fragments/protocol.js +++ b/wallets/client/fragments/protocol.js @@ -265,6 +265,34 @@ export const UPSERT_WALLET_RECEIVE_CLINK = gql` } ` +export const UPSERT_WALLET_SEND_SPARK = gql` + mutation upsertWalletSendSpark( + ${shared.variables}, + $mnemonic: VaultEntryInput! + ) { + upsertWalletSendSpark( + ${shared.arguments}, + mnemonic: $mnemonic + ) { + id + } + } +` + +export const UPSERT_WALLET_RECEIVE_SPARK = gql` + mutation upsertWalletRecvSpark( + ${shared.variables}, + $identityPublicKey: String! + ) { + upsertWalletRecvSpark( + ${shared.arguments}, + identityPublicKey: $identityPublicKey + ) { + id + } + } +` + // tests export const TEST_WALLET_RECEIVE_NWC = gql` @@ -314,3 +342,9 @@ export const TEST_WALLET_RECEIVE_CLINK = gql` testWalletRecvClink(noffer: $noffer) } ` + +export const TEST_WALLET_RECEIVE_SPARK = gql` + mutation testWalletRecvSpark($identityPublicKey: String!) { + testWalletRecvSpark(identityPublicKey: $identityPublicKey) + } +` diff --git a/wallets/client/fragments/wallet.js b/wallets/client/fragments/wallet.js index f018e1f549..f9d93a31fe 100644 --- a/wallets/client/fragments/wallet.js +++ b/wallets/client/fragments/wallet.js @@ -87,6 +87,12 @@ const WALLET_PROTOCOL_FIELDS = gql` ...VaultEntryFields } } + ... on WalletSendSpark { + id + encryptedMnemonic: mnemonic { + ...VaultEntryFields + } + } ... on WalletRecvNWC { id url @@ -126,6 +132,10 @@ const WALLET_PROTOCOL_FIELDS = gql` id noffer } + ... on WalletRecvSpark { + id + identityPublicKey + } } } ` diff --git a/wallets/client/hooks/query.js b/wallets/client/hooks/query.js index 83ece5eac1..aed96b44f3 100644 --- a/wallets/client/hooks/query.js +++ b/wallets/client/hooks/query.js @@ -21,6 +21,8 @@ import { UPSERT_WALLET_SEND_WEBLN, UPSERT_WALLET_SEND_CLN_REST, UPSERT_WALLET_SEND_CLINK, + UPSERT_WALLET_SEND_SPARK, + UPSERT_WALLET_RECEIVE_SPARK, WALLETS, UPDATE_WALLET_ENCRYPTION, RESET_WALLETS, @@ -35,6 +37,7 @@ import { TEST_WALLET_RECEIVE_CLN_REST, TEST_WALLET_RECEIVE_LND_GRPC, TEST_WALLET_RECEIVE_CLINK, + TEST_WALLET_RECEIVE_SPARK, DELETE_WALLET } from '@/wallets/client/fragments' import { gql, useApolloClient, useMutation, useQuery } from '@apollo/client' @@ -321,6 +324,8 @@ function protocolUpsertMutation (protocol) { return protocol.send ? UPSERT_WALLET_SEND_WEBLN : NOOP_MUTATION case 'CLINK': return protocol.send ? UPSERT_WALLET_SEND_CLINK : UPSERT_WALLET_RECEIVE_CLINK + case 'SPARK': + return protocol.send ? UPSERT_WALLET_SEND_SPARK : UPSERT_WALLET_RECEIVE_SPARK default: return NOOP_MUTATION } @@ -346,6 +351,8 @@ function protocolTestMutation (protocol) { return TEST_WALLET_RECEIVE_LND_GRPC case 'CLINK': return TEST_WALLET_RECEIVE_CLINK + case 'SPARK': + return TEST_WALLET_RECEIVE_SPARK default: return NOOP_MUTATION } diff --git a/wallets/client/protocols/index.js b/wallets/client/protocols/index.js index 29efb9036c..0fe4fda2d9 100644 --- a/wallets/client/protocols/index.js +++ b/wallets/client/protocols/index.js @@ -6,6 +6,7 @@ import * as webln from './webln' import * as lnc from './lnc' import * as clnRest from './clnRest' import * as clink from './clink' +import * as spark from './spark' export * from './util' @@ -56,5 +57,6 @@ export default [ webln, lnc, clnRest, - clink + clink, + spark ] diff --git a/wallets/client/protocols/spark.js b/wallets/client/protocols/spark.js new file mode 100644 index 0000000000..af341402b7 --- /dev/null +++ b/wallets/client/protocols/spark.js @@ -0,0 +1,42 @@ +import { withSparkWallet } from '@/wallets/lib/protocols/spark' +import { sleep } from '@/lib/time' + +export const name = 'SPARK' + +const SPARK_PAYMENT_STATUS_POLL_INTERVAL_MS = 250 + +export async function sendPayment (bolt11, { mnemonic }, { signal }) { + return await withSparkWallet( + mnemonic, + async wallet => { + // this can throw immediately, for example if invoice is from a different network + // or the wallet does have insufficient funds + const payment = await wallet.payLightningInvoice({ invoice: bolt11 }) + + // payments are async, we need to poll for status + while (!signal.aborted) { + const sendRequest = await wallet.getLightningSendRequest(payment.id) + if (sendRequest.paymentPreimage) { + return sendRequest.paymentPreimage + } + switch (sendRequest.status) { + case 'LIGHTNING_PAYMENT_FAILED': + // requests don't seem to include an error message: + // https://github.com/buildonspark/spark/blob/66f1cef206920745cec5df3b1e5339337fcf4b71/sdks/js/packages/spark-sdk/src/graphql/objects/LightningSendRequest.ts#L12-L48 + throw new Error('Spark lightning send request failed') + case 'LIGHTNING_PAYMENT_PENDING': + default: + await sleep(SPARK_PAYMENT_STATUS_POLL_INTERVAL_MS) + } + } + } + ) +} + +export async function testSendPayment ({ mnemonic }, { signal }) { + const identityPublicKey = await withSparkWallet( + mnemonic, + wallet => wallet.getIdentityPublicKey() + ) + return { identityPublicKey } +} diff --git a/wallets/lib/crypto.js b/wallets/lib/crypto.js index e59b7fc99b..5e9b536de4 100644 --- a/wallets/lib/crypto.js +++ b/wallets/lib/crypto.js @@ -1,4 +1,5 @@ import bip39Words from '@/lib/bip39-words' +import * as bip39 from 'bip39' export async function deriveKey (passphrase, salt) { const enc = new TextEncoder() @@ -77,7 +78,5 @@ export async function decrypt (key, { iv, value }) { } export function generateRandomPassphrase () { - const rand = new Uint32Array(12) - window.crypto.getRandomValues(rand) - return Array.from(rand).map(i => bip39Words[i % bip39Words.length]).join(' ') + return bip39.generateMnemonic(128, null, bip39Words) } diff --git a/wallets/lib/protocols/index.js b/wallets/lib/protocols/index.js index f89a59af5e..8258af0e0f 100644 --- a/wallets/lib/protocols/index.js +++ b/wallets/lib/protocols/index.js @@ -8,10 +8,11 @@ import phoenixdSuite from './phoenixd' import blinkSuite from './blink' import webln from './webln' import clinkSuite from './clink' +import sparkSuite from './spark' /** * Protocol names as used in the database - * @typedef {'NWC'|'LNBITS'|'PHOENIXD'|'BLINK'|'WEBLN'|'LN_ADDR'|'LNC'|'CLN_REST'|'LND_GRPC'|'CLINK'} ProtocolName + * @typedef {'NWC'|'LNBITS'|'PHOENIXD'|'BLINK'|'WEBLN'|'LN_ADDR'|'LNC'|'CLN_REST'|'LND_GRPC'|'CLINK'|'SPARK'} ProtocolName * @typedef {'text'|'password'} InputType */ @@ -49,5 +50,6 @@ export default [ ...lnbitsSuite, ...blinkSuite, webln, - ...clinkSuite + ...clinkSuite, + ...sparkSuite ] diff --git a/wallets/lib/protocols/spark.js b/wallets/lib/protocols/spark.js new file mode 100644 index 0000000000..4b24191071 --- /dev/null +++ b/wallets/lib/protocols/spark.js @@ -0,0 +1,60 @@ +import { bip39Validator, identityPublicKeyValidator } from '@/wallets/lib/validate' +import { generateRandomPassphrase } from '@/wallets/lib/crypto' +import { SparkWallet } from '@buildonspark/spark-sdk' + +// Spark +// https://spark.money/ +// https://github.com/buildonspark/spark +// https://docs.spark.money/api-reference + +export default [ + { + name: 'SPARK', + send: true, + displayName: 'Spark', + fields: [ + { + name: 'mnemonic', + label: 'mnemonic', + type: 'password', + required: true, + validate: bip39Validator(), + encrypt: true, + initial: generateRandomPassphrase, + disabled: true + } + ], + relationName: 'walletSendSpark' + }, + { + name: 'SPARK', + send: false, + displayName: 'Spark', + fields: [ + { + name: 'identityPublicKey', + label: 'identity public key', + type: 'password', + required: true, + validate: identityPublicKeyValidator() + } + ], + relationName: 'walletRecvSpark' + } +] + +export async function withSparkWallet (mnemonic, cb) { + const { wallet } = await SparkWallet.initialize({ + mnemonicOrSeed: mnemonic, + options: { network: 'MAINNET' } + }) + try { + return await cb(wallet) + } finally { + await wallet.cleanupConnections() + } +} + +export async function withRandomSparkWallet (cb) { + return await withSparkWallet(undefined, cb) +} diff --git a/wallets/lib/util.js b/wallets/lib/util.js index 2a43e0963c..b58ea36093 100644 --- a/wallets/lib/util.js +++ b/wallets/lib/util.js @@ -11,6 +11,14 @@ export function walletDisplayName (name) { return walletJson(name)?.displayName || titleCase(name) } +export function walletWarning (name) { + let { warning } = walletJson(name) + if (Array.isArray(warning)) { + warning = warning.join('\n') + } + return warning +} + export function walletImage (name) { return walletJson(name)?.image } diff --git a/wallets/lib/validate.js b/wallets/lib/validate.js index 9c3945749d..4b8d2e52fd 100644 --- a/wallets/lib/validate.js +++ b/wallets/lib/validate.js @@ -1,4 +1,5 @@ import bip39Words from '@/lib/bip39-words' +import * as bip39 from 'bip39' import { decodeRune } from '@/lib/cln' import { B64_URL_REGEX } from '@/lib/format' import { isInvoicableMacaroon, isInvoiceMacaroon } from '@/lib/macaroon' @@ -147,6 +148,12 @@ export const bip39Validator = ({ min = 12, max = 24 } = {}) => .test({ name: 'bip39', test: async (value, context) => { + // legacy mnemonics don't include a checksum so if validation with the + // bip39 library fails we assume it's an old mnemonic and use legacy validation + if (bip39.validateMnemonic(value, bip39Words)) { + return true + } + const words = value ? value.trim().split(/[\s]+/) : [] for (const w of words) { try { @@ -198,3 +205,19 @@ export const urlValidator = (...args) => }) export const hexValidator = (length) => string().hex().length(length, `must be exactly ${length} hex chars`) + +export const identityPublicKeyValidator = () => string() + .test({ + name: 'identityPublicKey', + test: (identityPublicKey, context) => { + try { + if (!identityPublicKey.startsWith('02') && !identityPublicKey.startsWith('03')) { + throw new Error('must start with 02 or 03') + } + hexValidator(64).validateSync(identityPublicKey.slice(2)) + } catch (err) { + return context.createError({ message: err.message }) + } + return true + } + }) diff --git a/wallets/lib/wallets.json b/wallets/lib/wallets.json index 1975a9d26b..a2637f79fa 100644 --- a/wallets/lib/wallets.json +++ b/wallets/lib/wallets.json @@ -168,5 +168,15 @@ "displayName": "Blitz Wallet", "image": "/wallets/blitz.png", "url": "https://blitz-wallet.com/" + }, + { + "name": "SPARK", + "displayName": "Spark", + "image": "/wallets/spark.svg", + "url": "https://spark.money/", + "warning": [ + "**Spark balances are public.**", + "Anyone with your identity public key can look up your balance on [www.sparkscan.io](https://www.sparkscan.io/)." + ] } ] diff --git a/wallets/server/protocols/index.js b/wallets/server/protocols/index.js index 6bf8ca043b..6151e217d0 100644 --- a/wallets/server/protocols/index.js +++ b/wallets/server/protocols/index.js @@ -6,6 +6,7 @@ import * as phoenixd from './phoenixd' import * as blink from './blink' import * as lndGrpc from './lndGrpc' import * as clink from './clink' +import * as spark from './spark' export * from './util' @@ -58,5 +59,6 @@ export default [ phoenixd, blink, lndGrpc, - clink + clink, + spark ] diff --git a/wallets/server/protocols/spark.js b/wallets/server/protocols/spark.js new file mode 100644 index 0000000000..5c690972ca --- /dev/null +++ b/wallets/server/protocols/spark.js @@ -0,0 +1,21 @@ +import { msatsToSats } from '@/lib/format' +import { withRandomSparkWallet } from '@/wallets/lib/protocols/spark' + +export const name = 'SPARK' + +export async function createInvoice ({ msats, description }, { identityPublicKey }, { signal }) { + return await withRandomSparkWallet( + async wallet => { + const { invoice: { encodedInvoice: bolt11 } } = await wallet.createLightningInvoice({ + amountSats: msatsToSats(msats), + memo: description, + receiverIdentityPubkey: identityPublicKey + }) + return bolt11 + } + ) +} + +export async function testCreateInvoice ({ identityPublicKey }, { signal }) { + return await createInvoice({ msats: 1000, description: 'SN test invoice' }, { identityPublicKey }, { signal }) +} diff --git a/wallets/server/resolvers/util.js b/wallets/server/resolvers/util.js index 5553ef4dfe..ffa7e921f3 100644 --- a/wallets/server/resolvers/util.js +++ b/wallets/server/resolvers/util.js @@ -21,6 +21,8 @@ export function mapWalletResolveTypes (wallet) { return 'WalletRecvLNDGRPC' case 'CLINK': return send ? 'WalletSendClink' : 'WalletRecvClink' + case 'SPARK': + return send ? 'WalletSendSpark' : 'WalletRecvSpark' default: return null }