mirror of
https://github.com/Permissionless-Software-Foundation/bch-dex.git
synced 2026-09-22 09:11:59 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c92ffac645 | ||
|
|
216f0b6910 | ||
|
|
c31bf96986 | ||
|
|
7f8ef994a7 | ||
|
|
72ba1c48c2 | ||
|
|
2a78145170 | ||
|
|
d15fee7c7a | ||
|
|
9437b8fb80 |
Generated
+105
-35
@@ -26,7 +26,7 @@
|
||||
"@psf/bch-js": "6.7.3",
|
||||
"axios": "0.27.2",
|
||||
"bch-message-lib": "2.2.1",
|
||||
"bch-nostr": "1.3.1",
|
||||
"bch-nostr": "1.3.3",
|
||||
"bch-token-sweep": "2.2.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"bitcoincashjs-lib": "3.3.3",
|
||||
@@ -53,10 +53,11 @@
|
||||
"koa2-ratelimit": "0.9.1",
|
||||
"libp2p": "1.9.1",
|
||||
"line-reader": "0.4.0",
|
||||
"minimal-slp-wallet": "5.12.0",
|
||||
"minimal-slp-wallet": "5.12.1",
|
||||
"mongoose": "5.13.14",
|
||||
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
|
||||
"nodemailer": "6.7.5",
|
||||
"nostr-tools": "2.10.4",
|
||||
"p2wdb-esm": "2.2.9",
|
||||
"passport-local": "1.0.0",
|
||||
"public-ip": "6.0.1",
|
||||
@@ -5503,7 +5504,7 @@
|
||||
},
|
||||
"node_modules/@scure/base": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/@scure%2fbase/-/base-1.1.1.tgz",
|
||||
"integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==",
|
||||
"funding": [
|
||||
{
|
||||
@@ -5515,7 +5516,7 @@
|
||||
},
|
||||
"node_modules/@scure/bip32": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/@scure%2fbip32/-/bip32-1.3.1.tgz",
|
||||
"integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -5529,7 +5530,7 @@
|
||||
},
|
||||
"node_modules/@scure/bip32/node_modules/@noble/curves": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/@noble%2fcurves/-/curves-1.1.0.tgz",
|
||||
"integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -5541,7 +5542,7 @@
|
||||
},
|
||||
"node_modules/@scure/bip32/node_modules/@noble/curves/node_modules/@noble/hashes": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/@noble%2fhashes/-/hashes-1.3.1.tgz",
|
||||
"integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -5553,7 +5554,7 @@
|
||||
},
|
||||
"node_modules/@scure/bip32/node_modules/@noble/hashes": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/@noble%2fhashes/-/hashes-1.3.3.tgz",
|
||||
"integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -5565,7 +5566,7 @@
|
||||
},
|
||||
"node_modules/@scure/bip39": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/@scure%2fbip39/-/bip39-1.2.1.tgz",
|
||||
"integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -5578,7 +5579,7 @@
|
||||
},
|
||||
"node_modules/@scure/bip39/node_modules/@noble/hashes": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/@noble%2fhashes/-/hashes-1.3.3.tgz",
|
||||
"integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -7383,7 +7384,7 @@
|
||||
},
|
||||
"node_modules/base58-js": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/base58-js/-/base58-js-2.0.0.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/base58-js/-/base58-js-2.0.0.tgz",
|
||||
"integrity": "sha512-nAV5d32QXuGcGptSApkKpC1gGakWBnfJMNjKrYTBh4tb0szfZF+ooueFLy8T4VrY+o4SrE/TyrtUnRZcwZchaA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -7420,9 +7421,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/bch-consumer": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "http://94.130.170.209:4873/bch-consumer/-/bch-consumer-1.6.1.tgz",
|
||||
"integrity": "sha512-ZhyZ54kgF6f3sB7J4ylMBJHSoBXozUdM2bvsm2nTz31515LFfHra9d9w4Ommlmy5BvuDkdX4lUeGSLRvggXnFg==",
|
||||
"version": "1.5.1",
|
||||
"resolved": "http://94.130.170.209:4873/bch-consumer/-/bch-consumer-1.5.1.tgz",
|
||||
"integrity": "sha512-tEmds6Mk7g074+fGflm0d9At2ZV8DFhWErEN0nUzzW4vG5Ega9+yjREY16P/QuwwykzodnleQqOsNwcmvvgnAg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@psf/bch-js": "6.7.3",
|
||||
@@ -7597,9 +7598,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/bch-nostr": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/bch-nostr/-/bch-nostr-1.3.1.tgz",
|
||||
"integrity": "sha512-bSq70zQkJ0ELXnZHqY2NjaZ9ovwL6eMOdvxbajPzuq3ZcNce5r8mTgyFgJASLdloDxFUjfP6yeJBJj0HZzE8Pg==",
|
||||
"version": "1.3.3",
|
||||
"resolved": "http://94.130.170.209:4873/bch-nostr/-/bch-nostr-1.3.3.tgz",
|
||||
"integrity": "sha512-2Mod/PEDr/GJzQq20oSJKwJDtiXYm/Qj5KxIvFqsvBY1SYsHGyDu1FMBQ1UvOhY3ZP5fgiVLbIGvMRuWXqS4oQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"apidoc": "0.53.0",
|
||||
@@ -7610,9 +7611,54 @@
|
||||
"ws": "8.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bch-nostr/node_modules/@noble/ciphers": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "http://94.130.170.209:4873/@noble%2fciphers/-/ciphers-0.5.3.tgz",
|
||||
"integrity": "sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/bch-nostr/node_modules/@noble/curves": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "http://94.130.170.209:4873/@noble%2fcurves/-/curves-1.2.0.tgz",
|
||||
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.3.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/bch-nostr/node_modules/@noble/curves/node_modules/@noble/hashes": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "http://94.130.170.209:4873/@noble%2fhashes/-/hashes-1.3.2.tgz",
|
||||
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/bch-nostr/node_modules/@noble/hashes": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "http://94.130.170.209:4873/@noble%2fhashes/-/hashes-1.3.1.tgz",
|
||||
"integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/bch-nostr/node_modules/apidoc": {
|
||||
"version": "0.53.0",
|
||||
"resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.53.0.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/apidoc/-/apidoc-0.53.0.tgz",
|
||||
"integrity": "sha512-H4hYToCrI6TgSksdVHxS7h5/Xoqr/rR9m9/IOQaYqXbX07cPVbg0O3RM4+bR4tJKG1aqBWKKm+xojQ8+4i7O5A==",
|
||||
"license": "MIT",
|
||||
"os": [
|
||||
@@ -7653,7 +7699,7 @@
|
||||
},
|
||||
"node_modules/bch-nostr/node_modules/bch-message-lib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/bch-message-lib/-/bch-message-lib-2.3.1.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/bch-message-lib/-/bch-message-lib-2.3.1.tgz",
|
||||
"integrity": "sha512-xAWMRvmcP2mYTdp9KgjSQfxlJF4DTloCJrjGx0TumD3HPF9mmYZ/CiCGUAFdQk3LBCavnK0AZi9v3+JTNSnrcA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
@@ -7662,9 +7708,8 @@
|
||||
},
|
||||
"node_modules/bch-nostr/node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"deprecated": "Glob versions prior to v9 are no longer supported",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
@@ -7681,6 +7726,31 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/bch-nostr/node_modules/nostr-tools": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "http://94.130.170.209:4873/nostr-tools/-/nostr-tools-2.10.1.tgz",
|
||||
"integrity": "sha512-fnAxLi92UgyMAEw4fMEhDKzH53uBJ0WkkVPTNfX0b3bspeWWn0n5tDZtKRJbvW0wAGOPmU6LYWi/IKPOsq3p2Q==",
|
||||
"license": "Unlicense",
|
||||
"dependencies": {
|
||||
"@noble/ciphers": "^0.5.1",
|
||||
"@noble/curves": "1.2.0",
|
||||
"@noble/hashes": "1.3.1",
|
||||
"@scure/base": "1.1.1",
|
||||
"@scure/bip32": "1.3.1",
|
||||
"@scure/bip39": "1.2.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"nostr-wasm": "v0.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/bch-token-sweep": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "http://94.130.170.209:4873/bch-token-sweep/-/bch-token-sweep-2.2.1.tgz",
|
||||
@@ -17186,15 +17256,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimal-slp-wallet": {
|
||||
"version": "5.12.0",
|
||||
"resolved": "http://94.130.170.209:4873/minimal-slp-wallet/-/minimal-slp-wallet-5.12.0.tgz",
|
||||
"integrity": "sha512-zSJcBLF/tt7NH0xkuukTJ4BxnC2GIR8kjUJRWW91/LwhI6c2K9qNVV/G5E7SjYx125aHkGk5lq3pjGePsJ18rA==",
|
||||
"version": "5.12.1",
|
||||
"resolved": "http://94.130.170.209:4873/minimal-slp-wallet/-/minimal-slp-wallet-5.12.1.tgz",
|
||||
"integrity": "sha512-DnggKv1KC/Y6qxT6GiplrxfKPgBOdYbu7uK4bWVO+6RgTtcgMxrd4pxCFh4kHV3nV7vKBpE1wsmVZgtZ3x9qcg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@chris.troutner/retry-queue-commonjs": "1.0.8",
|
||||
"@psf/bch-js": "6.8.0",
|
||||
"apidoc": "0.51.0",
|
||||
"bch-consumer": "1.6.1",
|
||||
"bch-consumer": "1.5.1",
|
||||
"bch-donation": "1.1.2",
|
||||
"crypto-js": "4.0.0"
|
||||
}
|
||||
@@ -17971,7 +18041,7 @@
|
||||
},
|
||||
"node_modules/noble-secp256k1": {
|
||||
"version": "1.2.14",
|
||||
"resolved": "https://registry.npmjs.org/noble-secp256k1/-/noble-secp256k1-1.2.14.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/noble-secp256k1/-/noble-secp256k1-1.2.14.tgz",
|
||||
"integrity": "sha512-GSCXyoZBUaaPwVWdYncMEmzlSUjF9J/YeEHpklYJCyg8wPuJP3NzDx0BkiwArzINkdX2HJHvUJhL6vVWPOQQcg==",
|
||||
"deprecated": "Switch to namespaced @noble/secp256k1 for security and feature updates",
|
||||
"license": "MIT"
|
||||
@@ -18226,7 +18296,7 @@
|
||||
},
|
||||
"node_modules/nostr": {
|
||||
"version": "0.2.8",
|
||||
"resolved": "https://registry.npmjs.org/nostr/-/nostr-0.2.8.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/nostr/-/nostr-0.2.8.tgz",
|
||||
"integrity": "sha512-p25OQiEB5x8rWWoWLRRbxtxQiaQgypaQQakSKw5+cp/SW0DXea/soMzqmTXei1I6HrcARuyfvedGTdoEU471Ow==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -18235,9 +18305,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nostr-tools": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.10.1.tgz",
|
||||
"integrity": "sha512-fnAxLi92UgyMAEw4fMEhDKzH53uBJ0WkkVPTNfX0b3bspeWWn0n5tDZtKRJbvW0wAGOPmU6LYWi/IKPOsq3p2Q==",
|
||||
"version": "2.10.4",
|
||||
"resolved": "http://94.130.170.209:4873/nostr-tools/-/nostr-tools-2.10.4.tgz",
|
||||
"integrity": "sha512-biU7sk+jxHgVASfobg2T5ttxOGGSt69wEVBC51sHHOEaKAAdzHBLV/I2l9Rf61UzClhliZwNouYhqIso4a3HYg==",
|
||||
"license": "Unlicense",
|
||||
"dependencies": {
|
||||
"@noble/ciphers": "^0.5.1",
|
||||
@@ -18248,7 +18318,7 @@
|
||||
"@scure/bip39": "1.2.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"nostr-wasm": "v0.1.0"
|
||||
"nostr-wasm": "0.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=5.0.0"
|
||||
@@ -18261,7 +18331,7 @@
|
||||
},
|
||||
"node_modules/nostr-tools/node_modules/@noble/ciphers": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.5.3.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/@noble%2fciphers/-/ciphers-0.5.3.tgz",
|
||||
"integrity": "sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@@ -18270,7 +18340,7 @@
|
||||
},
|
||||
"node_modules/nostr-tools/node_modules/@noble/curves": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/@noble%2fcurves/-/curves-1.2.0.tgz",
|
||||
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -18282,7 +18352,7 @@
|
||||
},
|
||||
"node_modules/nostr-tools/node_modules/@noble/curves/node_modules/@noble/hashes": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/@noble%2fhashes/-/hashes-1.3.2.tgz",
|
||||
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -18294,7 +18364,7 @@
|
||||
},
|
||||
"node_modules/nostr-tools/node_modules/@noble/hashes": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/@noble%2fhashes/-/hashes-1.3.1.tgz",
|
||||
"integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -18306,7 +18376,7 @@
|
||||
},
|
||||
"node_modules/nostr-wasm": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/nostr-wasm/-/nostr-wasm-0.1.0.tgz",
|
||||
"resolved": "http://94.130.170.209:4873/nostr-wasm/-/nostr-wasm-0.1.0.tgz",
|
||||
"integrity": "sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
|
||||
+3
-2
@@ -45,7 +45,7 @@
|
||||
"@psf/bch-js": "6.7.3",
|
||||
"axios": "0.27.2",
|
||||
"bch-message-lib": "2.2.1",
|
||||
"bch-nostr": "1.3.1",
|
||||
"bch-nostr": "1.3.3",
|
||||
"bch-token-sweep": "2.2.1",
|
||||
"bcryptjs": "2.4.3",
|
||||
"bitcoincashjs-lib": "3.3.3",
|
||||
@@ -72,10 +72,11 @@
|
||||
"koa2-ratelimit": "0.9.1",
|
||||
"libp2p": "1.9.1",
|
||||
"line-reader": "0.4.0",
|
||||
"minimal-slp-wallet": "5.12.0",
|
||||
"minimal-slp-wallet": "5.12.1",
|
||||
"mongoose": "5.13.14",
|
||||
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
|
||||
"nodemailer": "6.7.5",
|
||||
"nostr-tools": "2.10.4",
|
||||
"p2wdb-esm": "2.2.9",
|
||||
"passport-local": "1.0.0",
|
||||
"public-ip": "6.0.1",
|
||||
|
||||
@@ -12,7 +12,7 @@ RUN apt-get update
|
||||
RUN apt-get install -y sudo git curl nano gnupg wget
|
||||
|
||||
#Install Node and NPM
|
||||
RUN curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh
|
||||
RUN curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh
|
||||
RUN bash nodesource_setup.sh
|
||||
RUN apt-get install -y nodejs build-essential
|
||||
|
||||
@@ -34,7 +34,7 @@ WORKDIR /home/safeuser
|
||||
|
||||
# Update to the latest version of npm.
|
||||
#RUN npm install -g npm@7.23.0
|
||||
RUN npm install -g npm
|
||||
#RUN npm install -g npm
|
||||
|
||||
# npm mirror to prevent direct dependency on npm.
|
||||
#RUN npm set registry http://94.130.170.209:4873/
|
||||
|
||||
@@ -12,7 +12,7 @@ RUN apt-get update
|
||||
RUN apt-get install -y sudo git curl nano gnupg wget
|
||||
|
||||
#Install Node and NPM
|
||||
RUN curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh
|
||||
RUN curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh
|
||||
RUN bash nodesource_setup.sh
|
||||
RUN apt-get install -y nodejs build-essential
|
||||
|
||||
@@ -34,7 +34,7 @@ WORKDIR /home/safeuser
|
||||
|
||||
# Update to the latest version of npm.
|
||||
#RUN npm install -g npm@7.23.0
|
||||
RUN npm install -g npm
|
||||
#RUN npm install -g npm
|
||||
|
||||
# npm mirror to prevent direct dependency on npm.
|
||||
RUN npm set registry http://94.130.170.209:4873/
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
mongo-p2wdb-service:
|
||||
mongo-dex:
|
||||
image: mongo:4.2.0
|
||||
container_name: mongo-p2wdb-service
|
||||
container_name: mongo-dex
|
||||
ports:
|
||||
- '5666:27017' # <host port>:<container port>
|
||||
volumes:
|
||||
@@ -13,69 +13,11 @@ services:
|
||||
command: mongod --logpath=/dev/null # -- quiet
|
||||
restart: always
|
||||
|
||||
ipfs:
|
||||
# https://github.com/christroutner/trickle-ipfs
|
||||
image: christroutner/trickle-ipfs:v1.0.1
|
||||
#build:
|
||||
# context: ./
|
||||
# dockerfile: Dockerfile
|
||||
container_name: ipfs
|
||||
environment:
|
||||
IPFS_DAEMON_ARGUMENTS: '--enable-pubsub-experiment --migrate=true --agent-version-suffix=docker --routing=dhtclient'
|
||||
UPLOAD_KBPS: '1000'
|
||||
DOWNLOAD_KBPS: '1000'
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
options:
|
||||
max-size: '10m'
|
||||
max-file: '10'
|
||||
mem_limit: 2000mb
|
||||
ports:
|
||||
- 4001:4001
|
||||
- 4003:4003
|
||||
- 172.17.0.1:5001:5001
|
||||
- 172.17.0.1:8080:8080
|
||||
command: [
|
||||
'./start-ipfs.sh'
|
||||
]
|
||||
volumes:
|
||||
- ../data/go-ipfs/data:/root/.ipfs
|
||||
restart: always
|
||||
|
||||
p2wdb:
|
||||
#build:
|
||||
# context: ./p2wdb/
|
||||
# dockerfile: Dockerfile
|
||||
image: christroutner/p2wdb:v4.1.3
|
||||
container_name: p2wdb
|
||||
environment:
|
||||
CONSUMER_URL: 'https://free-bch.fullstack.cash'
|
||||
#ENABLE_BCH_PAYMENT: 1
|
||||
DEBUG_LEVEL: 1
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
options:
|
||||
max-size: '10m'
|
||||
max-file: '10'
|
||||
mem_limit: 1gb
|
||||
links:
|
||||
- mongo-p2wdb-service
|
||||
ports:
|
||||
# <host port>:<container port>
|
||||
- 5667:5667 # REST API
|
||||
#- 5668:5668 # IPFS TCP port
|
||||
#- 5669:5669 # IPFS WS Port
|
||||
volumes:
|
||||
- ../data/ipfsdata/p2wdb:/home/safeuser/ipfs-p2wdb-service/.ipfsdata/p2wdb
|
||||
- ./p2wdb/start-production.sh:/home/safeuser/ipfs-p2wdb-service/start-production.sh
|
||||
#- ../scripts/wallet.json:/home/safeuser/ipfs-p2wdb-service/wallet.json
|
||||
restart: always
|
||||
|
||||
bch-dex:
|
||||
#build:
|
||||
# context: ./bch-dex/
|
||||
# dockerfile: Dockerfile
|
||||
image: christroutner/bch-dex:v2.2.4
|
||||
build:
|
||||
context: ./bch-dex/
|
||||
dockerfile: Dockerfile
|
||||
#image: christroutner/bch-dex:v2.2.4
|
||||
container_name: bch-dex
|
||||
environment:
|
||||
CONSUMER_URL: 'https://free-bch.fullstack.cash'
|
||||
@@ -86,8 +28,8 @@ services:
|
||||
max-file: '10'
|
||||
mem_limit: 1000mb
|
||||
links:
|
||||
- mongo-p2wdb-service
|
||||
- p2wdb
|
||||
- mongo-dex
|
||||
#- p2wdb
|
||||
ports:
|
||||
- '5700:5700' # <host port>:<container port>
|
||||
volumes:
|
||||
@@ -96,13 +38,13 @@ services:
|
||||
restart: always
|
||||
|
||||
dex-ui:
|
||||
#build:
|
||||
# context: ./bch-dex-ui/
|
||||
# dockerfile: Dockerfile
|
||||
image: christroutner/bch-dex-ui:v1.2.4
|
||||
build:
|
||||
context: ./bch-dex-ui/
|
||||
dockerfile: Dockerfile
|
||||
#image: christroutner/bch-dex-ui:v1.2.4
|
||||
container_name: dex-ui
|
||||
environment:
|
||||
SERVER: 'http://192.168.2.3'
|
||||
SERVER: 'http://172.17.0.1'
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
options:
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
# Create a Docker container for the P2WDB
|
||||
#
|
||||
|
||||
#IMAGE BUILD COMMANDS
|
||||
FROM ubuntu:20.04
|
||||
MAINTAINER Chris Troutner <chris.troutner@gmail.com>
|
||||
|
||||
#Update the OS and install any OS packages needed.
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y sudo git curl nano gnupg wget
|
||||
|
||||
#Install Node and NPM
|
||||
RUN curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh
|
||||
RUN bash nodesource_setup.sh
|
||||
RUN apt-get install -y nodejs build-essential
|
||||
|
||||
#Create the user 'safeuser' and add them to the sudo group.
|
||||
RUN useradd -ms /bin/bash safeuser
|
||||
RUN adduser safeuser sudo
|
||||
|
||||
#Set password to 'abcd8765' change value below if you want a different password
|
||||
RUN echo safeuser:abcd8765 | chpasswd
|
||||
|
||||
#Set the working directory to be the users home directory
|
||||
WORKDIR /home/safeuser
|
||||
|
||||
#Setup NPM for non-root global install (like on a mac)
|
||||
RUN mkdir /home/safeuser/.npm-global
|
||||
RUN chown -R safeuser .npm-global
|
||||
RUN echo "export PATH=~/.npm-global/bin:$PATH" >> /home/safeuser/.profile
|
||||
RUN runuser -l safeuser -c "npm config set prefix '~/.npm-global'"
|
||||
|
||||
# Update to the latest version of npm.
|
||||
#RUN npm install -g npm@7.23.0
|
||||
RUN npm install -g npm
|
||||
|
||||
# npm mirror to prevent direct dependency on npm.
|
||||
RUN npm set registry http://94.130.170.209:4873/
|
||||
|
||||
# Switch to user account.
|
||||
#USER safeuser
|
||||
# Prep 'sudo' commands.
|
||||
#RUN echo 'abcd8765' | sudo -S pwd
|
||||
|
||||
# Clone the rest.bitcoin.com repository
|
||||
RUN git clone https://github.com/Permissionless-Software-Foundation/ipfs-p2wdb-service
|
||||
WORKDIR /home/safeuser/ipfs-p2wdb-service
|
||||
RUN mkdir .ipfsdata
|
||||
RUN git checkout ct-unstable
|
||||
|
||||
#RUN npm install fsevents
|
||||
|
||||
# Install dependencies
|
||||
#RUN mkdir .ipfsdata
|
||||
RUN npm install
|
||||
|
||||
# Generate the API docs
|
||||
RUN npm run docs
|
||||
|
||||
# Expose the port the API will be served on.
|
||||
#EXPOSE 5010
|
||||
|
||||
# Start the application.
|
||||
#COPY start-production.sh start-production.sh
|
||||
CMD ["./start-production.sh"]
|
||||
|
||||
#CMD ["npm", "start"]
|
||||
|
||||
# Used for debugging
|
||||
#COPY dummyapp.js dummyapp.js
|
||||
#CMD ["node", "dummyapp.js"]
|
||||
@@ -1,4 +0,0 @@
|
||||
setInterval(function () {
|
||||
const now = new Date()
|
||||
console.log(`ping ${now.toLocaleString()}`)
|
||||
}, 10000)
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# BEGIN: Optional configuration settings
|
||||
|
||||
# This mnemonic is used to set up persistent public key for e2ee
|
||||
# Replace this with your own 12-word mnemonic.
|
||||
export MNEMONIC="mass response fiscal world message exact series swallow forward confirm canoe festival"
|
||||
|
||||
# The human readable name this IPFS node identifies as.
|
||||
export COORD_NAME=generic-p2wdb-production
|
||||
|
||||
# Allow this node to function as a circuit relay. It must not be behind a firewall.
|
||||
#export ENABLE_CIRCUIT_RELAY=true
|
||||
# For browsers to use your circuit realy, you must set up a domain, SSL certificate,
|
||||
# and you must forward that subdomain to the IPFS_WS_PORT.
|
||||
#export CR_DOMAIN=subdomain.yourdomain.com
|
||||
|
||||
# Debug level. 0 = minimal info. 2 = max info.
|
||||
# This value set by docker-compose.yml
|
||||
#export DEBUG_LEVEL=1
|
||||
|
||||
# Log-in information for retrieving a JWT token from FullStack.cash.
|
||||
export FULLSTACKLOGIN=demo@demo.com
|
||||
export FULLSTACKPASS=demo
|
||||
|
||||
# END: Optional configuration settings
|
||||
|
||||
|
||||
# Production database connection string.
|
||||
export DBURL=mongodb://172.17.0.1:5666/p2wdb-service-dev
|
||||
|
||||
# Configure IPFS ports
|
||||
#export IPFS_TCP_PORT=5668
|
||||
#export IPFS_WS_PORT=5669
|
||||
|
||||
# Configure REST API port
|
||||
export PORT=5667
|
||||
|
||||
export P2W_ENV=production
|
||||
export IPFS_HOST=172.17.0.1
|
||||
export IPFS_API_PORT=5001
|
||||
export IPFS_TCP_PORT=4001
|
||||
|
||||
# P2WDB specific env vars
|
||||
#export ORBITDB_NAME=/orbitdb/zdpuAm4fPafpjs5mgbBUJV8Az7kd8Xj1ttD6M1JaAxF8RMRrw/psf-bch-p2wdb-keyvalue-v1.0.0-0004
|
||||
|
||||
npm start
|
||||
+18
-2
@@ -2,8 +2,11 @@
|
||||
Adapter library for working with Nostr.
|
||||
*/
|
||||
|
||||
// Global npm libraries
|
||||
import BchNostr from 'bch-nostr'
|
||||
import { RelayPool } from 'nostr'
|
||||
import RetryQueue from '@chris.troutner/retry-queue'
|
||||
import * as nip19 from 'nostr-tools/nip19'
|
||||
|
||||
class NostrAdapter {
|
||||
constructor (localConfig = { nostrRelay: '', nostrTopic: '' }) {
|
||||
@@ -25,11 +28,17 @@ class NostrAdapter {
|
||||
// Encapsulate dependencies
|
||||
this.bchNostr = new BchNostr()
|
||||
this.RelayPool = RelayPool
|
||||
this.retryQueue = new RetryQueue({
|
||||
concurrency: 1,
|
||||
attempts: 5,
|
||||
retryPeriod: 1000
|
||||
})
|
||||
|
||||
// Bind the 'this' object
|
||||
this.start = this.start.bind(this)
|
||||
this.post = this.post.bind(this)
|
||||
this.read = this.read.bind(this)
|
||||
this.eventId2note = this.eventId2note.bind(this)
|
||||
}
|
||||
|
||||
// Create nostr keys.
|
||||
@@ -71,7 +80,7 @@ class NostrAdapter {
|
||||
msg,
|
||||
tags: [['t', this.topic]]
|
||||
}
|
||||
const eventId = await this.bchNostr.post.uploadToNostr(inObj)
|
||||
const eventId = await this.retryQueue.addToQueue(this.bchNostr.post.uploadToNostr, inObj)
|
||||
return eventId
|
||||
} catch (error) {
|
||||
console.log(`Error in nostr.js/post() ${error.message} `)
|
||||
@@ -103,7 +112,8 @@ class NostrAdapter {
|
||||
})
|
||||
|
||||
pool.on('event', (relay, subId, ev) => {
|
||||
messages.push(ev.content)
|
||||
// console.log('ev: ', ev)
|
||||
messages.push({ content: ev.content, eventId: ev.id })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -115,6 +125,12 @@ class NostrAdapter {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// Convert an Event ID into a `noteabc..` syntax that Astral expects.
|
||||
// This can be used to generate a link to Astral to display the post.
|
||||
eventId2note (eventId) {
|
||||
return nip19.noteEncode(eventId)
|
||||
}
|
||||
}
|
||||
|
||||
export default NostrAdapter
|
||||
|
||||
+10
-4
@@ -5,12 +5,11 @@
|
||||
// Public npm libraries
|
||||
import BchWallet from 'minimal-slp-wallet'
|
||||
import BchTokenSweep from 'bch-token-sweep/index.js'
|
||||
|
||||
import bitcoinJs from 'bitcoincashjs-lib'
|
||||
import RetryQueue from '@chris.troutner/retry-queue'
|
||||
|
||||
// Local libraries
|
||||
import JsonFiles from './json-files.js'
|
||||
|
||||
import config from '../../config/index.js'
|
||||
|
||||
// Hack to get __dirname back.
|
||||
@@ -35,6 +34,11 @@ class WalletAdapter {
|
||||
this.BchWallet = BchWallet
|
||||
this.bchWallet = {} // Will be replaced when initialized.
|
||||
// this.advancedConfig = localConfig.advancedConfig
|
||||
this.retryQueue = new RetryQueue({
|
||||
concurrency: 1,
|
||||
attempts: 5,
|
||||
retryPeriod: 5000
|
||||
})
|
||||
|
||||
// Bind the 'this' object
|
||||
this.moveTokens = this.moveTokens.bind(this)
|
||||
@@ -441,7 +445,7 @@ class WalletAdapter {
|
||||
|
||||
return txObj2
|
||||
} catch (err) {
|
||||
console.error('Error in wallet.js/deserializePartialTx()')
|
||||
console.error('Error in wallet.js/deserializeTx()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -508,7 +512,9 @@ class WalletAdapter {
|
||||
// return csTxHex
|
||||
|
||||
// Broadcast transaction to the network
|
||||
const txid = await this.bchWallet.ar.sendTx(csTxHex)
|
||||
// const txid = await this.bchWallet.ar.sendTx(csTxHex)
|
||||
const txid = await this.retryQueue.addToQueue(this.bchWallet.broadcast, { hex: csTxHex })
|
||||
console.log('completeTx() txid: ', txid)
|
||||
|
||||
return txid
|
||||
} catch (err) {
|
||||
|
||||
@@ -106,9 +106,9 @@ class OfferRESTControllerLib {
|
||||
|
||||
const nostrEventId = ctx.request.body.nostrEventId
|
||||
|
||||
const eventId = await this.useCases.offer.takeOffer(nostrEventId)
|
||||
const { eventId, noteId } = await this.useCases.offer.takeOffer(nostrEventId)
|
||||
|
||||
ctx.body = { eventId }
|
||||
ctx.body = { eventId, noteId }
|
||||
} catch (err) {
|
||||
wlogger.error('Error in takeOffer() REST API handler.')
|
||||
this.handleError(ctx, err)
|
||||
|
||||
@@ -37,9 +37,9 @@ class OrderRESTControllerLib {
|
||||
const orderObj = ctx.request.body.order
|
||||
console.log('orderObj: ', orderObj)
|
||||
|
||||
const hash = await _this.useCases.order.createOrder(orderObj)
|
||||
const { eventId, noteId } = await _this.useCases.order.createOrder(orderObj)
|
||||
|
||||
ctx.body = { hash }
|
||||
ctx.body = { eventId, noteId }
|
||||
} catch (err) {
|
||||
// console.log(`err.message: ${err.message}`)
|
||||
// console.log('err: ', err)
|
||||
|
||||
@@ -30,6 +30,7 @@ class TimerControllers {
|
||||
this.gcOffers = this.gcOffers.bind(this)
|
||||
this.checkDupOffers = this.checkDupOffers.bind(this)
|
||||
this.loadOffers = this.loadOffers.bind(this)
|
||||
|
||||
// State
|
||||
this.gcOrdersInt = null
|
||||
this.gcOffersInt = null
|
||||
@@ -41,7 +42,7 @@ class TimerControllers {
|
||||
startTimers () {
|
||||
this.gcOrdersInt = setInterval(this.gcOrders, 60000 * 5)
|
||||
this.gcOffersInt = setInterval(this.gcOffers, 60000 * 5)
|
||||
this.checkDupOffersInt = setInterval(this.checkDupOffers, 60000 * 4.5)
|
||||
// this.checkDupOffersInt = setInterval(this.checkDupOffers, 60000 * 4.5)
|
||||
this.loadOffersInt = setInterval(this.loadOffers, 60000 * 2)
|
||||
return true
|
||||
}
|
||||
@@ -49,7 +50,7 @@ class TimerControllers {
|
||||
stopTimers () {
|
||||
clearInterval(this.gcOrdersInt)
|
||||
clearInterval(this.gcOffersInt)
|
||||
clearInterval(this.checkDupOffers)
|
||||
// clearInterval(this.checkDupOffers)
|
||||
}
|
||||
|
||||
// Garbage Collect the Orders.
|
||||
|
||||
+10
-2
@@ -17,6 +17,8 @@ class OfferEntity {
|
||||
)
|
||||
}
|
||||
|
||||
// console.log('offer entity validate() offerData: ', offerData)
|
||||
|
||||
const {
|
||||
messageType,
|
||||
messageClass,
|
||||
@@ -30,7 +32,8 @@ class OfferEntity {
|
||||
offerStatus,
|
||||
makerAddr,
|
||||
ticker,
|
||||
tokenType
|
||||
tokenType,
|
||||
nostrEventId
|
||||
} = offerData.data
|
||||
|
||||
// Input Validation
|
||||
@@ -73,6 +76,9 @@ class OfferEntity {
|
||||
if (!tokenType || typeof tokenType !== 'number') {
|
||||
throw new Error("Property 'tokenType' must be a number.")
|
||||
}
|
||||
if (!nostrEventId || typeof nostrEventId !== 'string') {
|
||||
throw new Error("Property 'nostrEventId' must be a string.")
|
||||
}
|
||||
|
||||
// Convert the timestamp to a number.
|
||||
let timestamp = new Date(offerData.timestamp)
|
||||
@@ -96,8 +102,10 @@ class OfferEntity {
|
||||
offerStatus: offerStatus || this.offerStatus[0],
|
||||
makerAddr,
|
||||
ticker,
|
||||
tokenType
|
||||
tokenType,
|
||||
nostrEventId
|
||||
}
|
||||
// console.log('offer entity validatedOfferData: ', validatedOfferData)
|
||||
|
||||
return validatedOfferData
|
||||
}
|
||||
|
||||
+155
-49
@@ -49,20 +49,37 @@ class OfferUseCases {
|
||||
this.retryQueue = new RetryQueue({ retryPeriod: 1000, attempts: 3 })
|
||||
|
||||
// Bind 'this' object to functions
|
||||
this.createOffer = this.createOffer.bind(this)
|
||||
this.detectNsfw = this.detectNsfw.bind(this)
|
||||
this.categorizeToken = this.categorizeToken.bind(this)
|
||||
this.listOffers = this.listOffers.bind(this)
|
||||
this.listNftOffers = this.listNftOffers.bind(this)
|
||||
this.listFungibleOffers = this.listFungibleOffers.bind(this)
|
||||
this.takeOffer = this.takeOffer.bind(this)
|
||||
this.ensureFunds = this.ensureFunds.bind(this)
|
||||
this.findOfferByEvent = this.findOfferByEvent.bind(this)
|
||||
this.findOfferByTxid = this.findOfferByTxid.bind(this)
|
||||
this.acceptCounterOffer = this.acceptCounterOffer.bind(this)
|
||||
this.removeDuplicateOffers = this.removeDuplicateOffers.bind(this)
|
||||
this.removeStaleOffers = this.removeStaleOffers.bind(this)
|
||||
this.flagOffer = this.flagOffer.bind(this)
|
||||
this.loadOffers = this.loadOffers.bind(this)
|
||||
|
||||
// State
|
||||
this.seenOffers = []
|
||||
this.seenCounterOffers = []
|
||||
}
|
||||
|
||||
// This method is called by timer controller to load offers from a Nostr topic.
|
||||
async createOffer (offerObj) {
|
||||
try {
|
||||
console.log('Use Case createOffer(offerObj): ', offerObj)
|
||||
// console.log('Use Case createOffer(offerObj): ', offerObj)
|
||||
|
||||
// Return if Offer already exists in database with the same utxo transaction id.
|
||||
try {
|
||||
await this.findOfferByTxid(offerObj.data.utxoTxid)
|
||||
|
||||
console.log('Offer already found in local database.')
|
||||
// console.log('Offer already found in local database.')
|
||||
return false
|
||||
} catch (err) { /* exit quietly */ }
|
||||
|
||||
@@ -75,6 +92,14 @@ class OfferUseCases {
|
||||
// console.log('WARN: Counter Offer innappropriately routed to createOffer()')
|
||||
// }
|
||||
|
||||
// Quickly skip over offers that have already been processed.
|
||||
const eventId = offerObj.data.nostrEventId
|
||||
if (this.seenOffers.includes(eventId)) {
|
||||
// console.log(`Offer with event ID ${eventId} already processed. Skipping.`)
|
||||
return false
|
||||
}
|
||||
this.seenOffers.push(eventId)
|
||||
|
||||
// Verify that UTXO in offer is unspent. If it is spent, then ignore the
|
||||
// offer.
|
||||
const utxo = {
|
||||
@@ -83,7 +108,7 @@ class OfferUseCases {
|
||||
}
|
||||
// const utxoStatus = await this.adapters.wallet.bchWallet.utxoIsValid(utxo)
|
||||
const utxoStatus = await this.retryQueue.addToQueue(this.adapters.wallet.bchWallet.utxoIsValid, utxo)
|
||||
console.log('utxoStatus: ', utxoStatus)
|
||||
// console.log('utxoStatus: ', utxoStatus)
|
||||
// if (utxoStatus === null) return false
|
||||
if (!utxoStatus) return false
|
||||
|
||||
@@ -94,13 +119,15 @@ class OfferUseCases {
|
||||
offerObj.timestamp = new Date().getTime()
|
||||
|
||||
const offerEntity = this.offerEntity.validate(offerObj)
|
||||
console.log('offerEntity: ', offerEntity)
|
||||
// console.log('offerEntity: ', offerEntity)
|
||||
|
||||
console.log(`New Offer for token ID ${offerEntity.tokenId} detected from Nostr post ${eventId}`)
|
||||
|
||||
// Get data about the token.
|
||||
const tokenId = offerEntity.tokenId
|
||||
// const tokenData = await this.adapters.wallet.bchWallet.getTokenData(tokenId)
|
||||
const tokenData = await this.retryQueue.addToQueue(this.adapters.wallet.bchWallet.getTokenData, tokenId)
|
||||
console.log(`tokenData: ${JSON.stringify(tokenData, null, 2)}`)
|
||||
// console.log(`tokenData: ${JSON.stringify(tokenData, null, 2)}`)
|
||||
|
||||
// Generate a 'display category' for the token. This will allow the
|
||||
// front end UI to figure out how to display the token.
|
||||
@@ -142,16 +169,29 @@ class OfferUseCases {
|
||||
|
||||
// Retrieve the mutable data from Filecoin/IPFS.
|
||||
// const url = `https://${cid}.ipfs.w3s.link/data.json`
|
||||
const url = `${this.config.ipfsGateway}${cid}/data.json`
|
||||
const result = await this.axios.get(url)
|
||||
const mutableData = result.data
|
||||
console.log(`mutableData: ${JSON.stringify(mutableData, null, 2)}`)
|
||||
let mutableData = {}
|
||||
|
||||
try {
|
||||
// Try the conventional data URL.
|
||||
const url = `${this.config.ipfsGateway}${cid}/data.json`
|
||||
const result = await this.axios.get(url)
|
||||
mutableData = result.data
|
||||
// console.log(`mutableData: ${JSON.stringify(mutableData, null, 2)}`)
|
||||
} catch (err) {
|
||||
// Try the newer data URL.
|
||||
const url = `${this.config.ipfsGateway}${cid}`
|
||||
const result = await this.axios.get(url)
|
||||
mutableData = result.data
|
||||
// console.log(`mutableData: ${JSON.stringify(mutableData, null, 2)}`)
|
||||
}
|
||||
console.log('mutableData: ', mutableData)
|
||||
|
||||
// Logical tests
|
||||
const hasNsfw = !!mutableData.nsfw
|
||||
const nsfwSetTrue = mutableData.nsfw === true
|
||||
const nsfwStringTrue = mutableData.nsfw === 'true'
|
||||
const nsfwDetected = hasNsfw && (nsfwSetTrue || nsfwStringTrue)
|
||||
// console.log(`hasNsfw: ${hasNsfw}, nsfwSetTrue: ${nsfwSetTrue}, nsfwStringTrue: ${nsfwStringTrue}, nsfwDetected: ${nsfwDetected}`)
|
||||
|
||||
if (nsfwDetected) {
|
||||
console.log('NSFW flag set as true')
|
||||
@@ -294,7 +334,7 @@ class OfferUseCases {
|
||||
|
||||
// Note : should be added to retry-queue?
|
||||
const utxoStatus = await this.adapters.wallet.bchWallet.utxoIsValid(utxo)
|
||||
console.log('utxoStatus: ', utxoStatus)
|
||||
// console.log('utxoStatus: ', utxoStatus)
|
||||
if (!utxoStatus) {
|
||||
console.log(`utxo txid: ${offerInfo.utxoTxid}, vout: ${offerInfo.utxoVout}`)
|
||||
|
||||
@@ -307,8 +347,8 @@ class OfferUseCases {
|
||||
await this.ensureFunds(offerInfo)
|
||||
|
||||
// Get UTXOs.
|
||||
const utxos = this.adapters.wallet.bchWallet.utxos.utxoStore
|
||||
console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
||||
// const utxos = this.adapters.wallet.bchWallet.utxos.utxoStore
|
||||
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
||||
|
||||
// Calculate amount of sats to generate a counter offer.
|
||||
let satsToMove = Math.ceil(offerInfo.numTokens * parseInt(offerInfo.rateInBaseUnit))
|
||||
@@ -349,18 +389,20 @@ class OfferUseCases {
|
||||
// TODO: This will trigger the webhook. Find some way of triggering the
|
||||
// webhook on new offers, but not on counteroffers
|
||||
const nostrData = {
|
||||
wif: this.adapters.wallet.bchWallet.walletInfo.privateKey,
|
||||
data: takenOfferInfo,
|
||||
appId: this.config.p2wdbAppId
|
||||
// wif: this.adapters.wallet.bchWallet.walletInfo.privateKey,
|
||||
data: takenOfferInfo
|
||||
// appId: this.config.p2wdbAppId
|
||||
}
|
||||
const resultEventId = await this.adapters.nostr.post(nostrData)
|
||||
const resultEventId = await this.adapters.nostr.post(JSON.stringify(nostrData))
|
||||
|
||||
const noteId = this.adapters.nostr.eventId2note(resultEventId)
|
||||
|
||||
// Delete the Offer from the database, so that the user doesn't attempt
|
||||
// to take the offer more than once.
|
||||
offerInfo.remove()
|
||||
// offerInfo.remove()
|
||||
|
||||
// Return the P2WDB CID
|
||||
return resultEventId
|
||||
return { eventId: resultEventId, noteId }
|
||||
|
||||
// return 'fake-hash'
|
||||
} catch (err) {
|
||||
@@ -448,27 +490,27 @@ class OfferUseCases {
|
||||
}
|
||||
|
||||
async findOfferByTxid (utxoTxid) {
|
||||
try {
|
||||
// try {
|
||||
if (typeof utxoTxid !== 'string' || !utxoTxid) {
|
||||
throw new Error('utxoTxid must be a string')
|
||||
}
|
||||
|
||||
const offer = await this.OfferModel.findOne({ utxoTxid })
|
||||
|
||||
// TODO: Offer should be found by TXID, then if there is more than one
|
||||
// result, they should be filtered by the vout property. That will leave
|
||||
// one remaining UTXO.
|
||||
|
||||
if (!offer) {
|
||||
throw new Error('offer not found')
|
||||
}
|
||||
|
||||
return offer
|
||||
} catch (error) {
|
||||
console.error('Error in use-cases/offer/findOfferByTxid(): ', error.message)
|
||||
throw error
|
||||
// try {
|
||||
// try {
|
||||
if (typeof utxoTxid !== 'string' || !utxoTxid) {
|
||||
throw new Error('utxoTxid must be a string')
|
||||
}
|
||||
|
||||
const offer = await this.OfferModel.findOne({ utxoTxid })
|
||||
|
||||
// TODO: Offer should be found by TXID, then if there is more than one
|
||||
// result, they should be filtered by the vout property. That will leave
|
||||
// one remaining UTXO.
|
||||
|
||||
if (!offer) {
|
||||
throw new Error('offer not found')
|
||||
}
|
||||
|
||||
return offer
|
||||
// } catch (error) {
|
||||
// // console.error('Error in use-cases/offer/findOfferByTxid(): ', error.message)
|
||||
// throw error
|
||||
// }
|
||||
}
|
||||
|
||||
// This function is called by the P2WDB webhook REST API handler. When a
|
||||
@@ -477,19 +519,66 @@ class OfferUseCases {
|
||||
// and broadcasts the transaction to accept the Counter Offer.
|
||||
async acceptCounterOffer (offerData) {
|
||||
try {
|
||||
console.log(`acceptCounterOffer() offerData: ${JSON.stringify(offerData, null, 2)}`)
|
||||
// console.log(`acceptCounterOffer() offerData: ${JSON.stringify(offerData, null, 2)}`)
|
||||
|
||||
// Quickly skip over offers that have already been processed.
|
||||
const eventId = offerData.data.nostrEventId
|
||||
if (this.seenOffers.includes(eventId)) {
|
||||
// console.log(`Offer with event ID ${eventId} already processed. Skipping.`)
|
||||
return false
|
||||
}
|
||||
|
||||
// See if this instance of bch-dex is managing the Order associated with
|
||||
// the incoming Counter Offer.
|
||||
|
||||
// Note : this should be handle by nostrEvent id or UtxoId?
|
||||
const orderHash = offerData.data.nostrEventId
|
||||
// Note : this should be handled by nostrEvent id or UtxoId?
|
||||
// const orderHash = offerData.data.nostrEventId
|
||||
let orderData = {}
|
||||
try {
|
||||
orderData = await this.orderUseCase.findOrderByEvent(orderHash)
|
||||
console.log(`orderData: ${JSON.stringify(orderData, null, 2)}`)
|
||||
orderData = await this.orderUseCase.findOrderByUtxo(offerData)
|
||||
// console.log(`orderData: ${JSON.stringify(orderData, null, 2)}`)
|
||||
} catch (err) {
|
||||
console.log('Order matching this Counter Offer is not managed by this instance of bch-dex. Exiting.')
|
||||
console.log('Order matching this Counter Offer is not managed by this instance of bch-dex. Skipping.')
|
||||
|
||||
// Add order to list of seen orders, so that we don't spent time trying to validate it again.
|
||||
this.seenOffers.push(eventId)
|
||||
|
||||
return 'N/A'
|
||||
}
|
||||
|
||||
// Verify that the UTXO for sale is valid.
|
||||
let utxoStatus = null
|
||||
try {
|
||||
// Get the status of the UTXO associate with this Offer.
|
||||
const utxo = {
|
||||
tx_hash: offerData.data.utxoTxid,
|
||||
tx_pos: offerData.data.utxoVout
|
||||
}
|
||||
// console.log(`Checking this UTXO: ${JSON.stringify(utxo, null, 2)}`)
|
||||
|
||||
// utxoStatus = await this.adapters.wallet.bchWallet.utxoIsValid(utxo)
|
||||
utxoStatus = await this.retryQueue.addToQueue(this.adapters.wallet.bchWallet.utxoIsValid, utxo)
|
||||
console.log('utxoStatus: ', utxoStatus)
|
||||
} catch (err) {
|
||||
console.log('acceptCounterOffer() err validating UTXO: ', err)
|
||||
|
||||
// Handle corner case of bad-data in the Offer model.
|
||||
if (err.isAxiosError) {
|
||||
console.log('Error trying to contact wallet service: ', err)
|
||||
return 'N/A'
|
||||
} else {
|
||||
return 'N/A'
|
||||
}
|
||||
}
|
||||
|
||||
// If the Offer UTXO is spent, exit.
|
||||
if (utxoStatus === false) {
|
||||
// Add order to list of seen orders, so that we don't spent time trying to validate it again.
|
||||
this.seenOffers.push(eventId)
|
||||
|
||||
console.log(`Aborting Counter Offer from Event ID ${eventId}`)
|
||||
console.log(`https://astral.psfoundation.info/${this.adapters.nostr.eventId2note(eventId)}`)
|
||||
|
||||
return 'N/A'
|
||||
}
|
||||
|
||||
@@ -525,7 +614,7 @@ class OfferUseCases {
|
||||
|
||||
return txid
|
||||
} catch (err) {
|
||||
console.error('Error in acceptCounterOffer()')
|
||||
console.error('Error in acceptCounterOffer(): ', err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -613,7 +702,7 @@ class OfferUseCases {
|
||||
|
||||
// If the Offer UTXO is spent, delete the Offer model.
|
||||
if (utxoStatus === false) {
|
||||
console.log('utxoStatus: ', utxoStatus)
|
||||
// console.log('utxoStatus: ', utxoStatus)
|
||||
console.log(`Spent UTXO detected. Deleting this Offer: ${JSON.stringify(thisOffer, null, 2)}`)
|
||||
await thisOffer.remove()
|
||||
}
|
||||
@@ -674,15 +763,32 @@ class OfferUseCases {
|
||||
try {
|
||||
// Retrieve offers array.
|
||||
const offers = await this.adapters.nostr.read()
|
||||
// console.log('offers: ', offers)
|
||||
|
||||
for (let i = 0; i < offers.length; i++) {
|
||||
try {
|
||||
const offer = offers[i]
|
||||
|
||||
// offer data
|
||||
const offerObj = JSON.parse(offer)
|
||||
const offerObj = JSON.parse(offer.content)
|
||||
|
||||
// Try to create new offer
|
||||
await this.createOffer(offerObj)
|
||||
// Append the Nostr Event ID to the offer object
|
||||
offerObj.data.nostrEventId = offer.eventId
|
||||
// console.log('loadOffers() offerObj: ', offerObj)
|
||||
|
||||
if (offerObj.data.dataType === 'offer') {
|
||||
// Try to create new offer
|
||||
await this.createOffer(offerObj)
|
||||
}
|
||||
|
||||
if (offerObj.data.dataType === 'counter-offer') {
|
||||
// console.log('Counter offer detected: ', offerObj)
|
||||
// console.log('Counter offer detected: ', offerObj.data.nostrEventId)
|
||||
console.log(`Counter offer detected: https://astral.psfoundation.info/${this.adapters.nostr.eventId2note(offerObj.data.nostrEventId)}`)
|
||||
await this.acceptCounterOffer(offerObj)
|
||||
}
|
||||
|
||||
// Ignore the post if it doesn't fit the above filters.
|
||||
} catch (error) {
|
||||
/* exit quietly */
|
||||
}
|
||||
|
||||
+40
-8
@@ -31,23 +31,25 @@ class OrderLib {
|
||||
|
||||
// Bind subfunctions to the 'this' object.
|
||||
this.ensureFunds = this.ensureFunds.bind(this)
|
||||
this.createOrder = this.createOrder.bind(this)
|
||||
this.findOrderByUtxo = this.findOrderByUtxo.bind(this)
|
||||
}
|
||||
|
||||
// Create a new order model and add it to the Mongo database.
|
||||
async createOrder (entryObj) {
|
||||
try {
|
||||
console.log('createOrder(entryObj): ', entryObj)
|
||||
// console.log('createOrder(entryObj): ', entryObj)
|
||||
if (!entryObj) return false
|
||||
|
||||
if (!entryObj.tokenId) throw new Error('entry does not contain required properties')
|
||||
|
||||
// Specify the address to send payment.
|
||||
entryObj.makerAddr = this.adapters.wallet.bchWallet.walletInfo.cashAddress
|
||||
console.log('entryObj.makerAddr: ', entryObj.makerAddr)
|
||||
// console.log('entryObj.makerAddr: ', entryObj.makerAddr)
|
||||
|
||||
// Input Validation
|
||||
const orderEntity = this.orderEntity.inputValidate(entryObj)
|
||||
console.log('orderEntity: ', orderEntity)
|
||||
// console.log('orderEntity: ', orderEntity)
|
||||
|
||||
// Optimize the wallet to speed up working with it.
|
||||
console.log('Optimizing wallet before creating new order.')
|
||||
@@ -102,10 +104,12 @@ class OrderLib {
|
||||
const order = new this.OrderModel(orderEntity)
|
||||
await order.save()
|
||||
|
||||
return eventId
|
||||
const noteId = this.adapters.nostr.eventId2note(eventId)
|
||||
|
||||
return { eventId, noteId }
|
||||
} catch (err) {
|
||||
// console.log("Error in use-cases/entry.js/createEntry()", err.message)
|
||||
wlogger.error('Error in use-cases/order.js/createOrder())')
|
||||
wlogger.error('Error in use-cases/order.js/createOrder(): ', err)
|
||||
console.log('error entryObj: ', entryObj)
|
||||
throw err
|
||||
}
|
||||
@@ -129,7 +133,7 @@ class OrderLib {
|
||||
|
||||
// Get UTXOs.
|
||||
const utxos = this.adapters.wallet.bchWallet.utxos.utxoStore
|
||||
console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
||||
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
||||
|
||||
if (orderEntity.buyOrSell.includes('sell')) {
|
||||
// Sell Order
|
||||
@@ -191,6 +195,34 @@ class OrderLib {
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve an Order model from the database. Find it by its UTXO (TXID & Vout)
|
||||
async findOrderByUtxo (offerData = {}) {
|
||||
try {
|
||||
// console.log('findOrderByUtxo() offerData: ', offerData)
|
||||
|
||||
// const order = await this.OrderModel.findOne({ nostrEventId })
|
||||
const order = await this.OrderModel.findOne({ utxoTxid: offerData.data.utxoTxid, utxoVout: offerData.data.utxoVout })
|
||||
// const order = await this.OrderModel.findOne({ utxoTxid: offerData.data.utxoTxid })
|
||||
// const order = await this.OrderModel.findOne({ tokenId: offerData.data.tokenId })
|
||||
console.log('findOrderByUtxo() order: ', order)
|
||||
|
||||
if (!order) {
|
||||
throw new Error('order not found')
|
||||
}
|
||||
if (!order.nostrEventId) {
|
||||
throw new Error('order not found')
|
||||
}
|
||||
|
||||
const orderObject = order.toObject()
|
||||
// return this.offerEntity.validateFromModel(offerObject)
|
||||
|
||||
return orderObject
|
||||
} catch (err) {
|
||||
console.error('Error in findOrderByUtxo(): ', err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// This function is called by the garbage collection timer controller. It
|
||||
// checks the UTXO associated with each Order in the database. If the UTXO
|
||||
// has been spent, the Order is deleted from the database.
|
||||
@@ -201,7 +233,7 @@ class OrderLib {
|
||||
|
||||
// Get all Orders in the database.
|
||||
const orders = await this.OrderModel.find({})
|
||||
console.log('orders: ', orders)
|
||||
// console.log('orders: ', orders)
|
||||
|
||||
// Loop through each Order and ensure the UTXO is still valid.
|
||||
for (let i = 0; i < orders.length; i++) {
|
||||
@@ -239,7 +271,7 @@ class OrderLib {
|
||||
|
||||
// If the Order UTXO is spent, delete the Order model.
|
||||
if (utxoStatus === false) {
|
||||
console.log('utxoStatus: ', utxoStatus)
|
||||
// console.log('utxoStatus: ', utxoStatus)
|
||||
console.log(`Spent UTXO detected. Deleting this Order: ${JSON.stringify(thisOrder, null, 2)}`)
|
||||
await thisOrder.remove()
|
||||
}
|
||||
|
||||
@@ -67,11 +67,12 @@ describe('#Order-REST-Router', () => {
|
||||
}
|
||||
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.useCases.order, 'createOrder').resolves('testHash')
|
||||
sandbox.stub(uut.useCases.order, 'createOrder').resolves({ eventId: 'testEventId', noteId: 'testNoteId' })
|
||||
|
||||
await uut.createOrder(ctx)
|
||||
|
||||
assert.equal(ctx.body.hash, 'testHash')
|
||||
assert.equal(ctx.body.eventId, 'testEventId')
|
||||
assert.equal(ctx.body.noteId, 'testNoteId')
|
||||
})
|
||||
|
||||
it('should catch and throw an error', async () => {
|
||||
|
||||
@@ -237,6 +237,36 @@ describe('#Offer-Entity', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if nostrEventId is not included', () => {
|
||||
try {
|
||||
const offerData = {
|
||||
data: {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'fakeId',
|
||||
buyOrSell: 'buy',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 350,
|
||||
numTokens: 1,
|
||||
utxoTxid: 'fakeTxid',
|
||||
utxoVout: 0,
|
||||
offerStatus: 'posted',
|
||||
makerAddr: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||
tokenType: 1
|
||||
}
|
||||
}
|
||||
uut.validate(offerData)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(
|
||||
err.message,
|
||||
"Property 'nostrEventId' must be a string."
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should validate a new offer', () => {
|
||||
const offerObj = {
|
||||
appId: 'swapTest555',
|
||||
@@ -255,7 +285,8 @@ describe('#Offer-Entity', () => {
|
||||
offerStatus: 'posted',
|
||||
makerAddr: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||
ticker: 'TROUT',
|
||||
tokenType: 1
|
||||
tokenType: 1,
|
||||
nostrEventId: 'test'
|
||||
},
|
||||
timestamp: '2021-09-20T17:54:26.395Z',
|
||||
localTimeStamp: '9/20/2021, 10:54:26 AM',
|
||||
|
||||
@@ -166,7 +166,8 @@ const p2wdb = {
|
||||
|
||||
const nostr = {
|
||||
post: async () => {return true },
|
||||
read: async () => { return true }
|
||||
read: async () => { return true },
|
||||
eventId2note: () => { return 'testNoteId' }
|
||||
}
|
||||
|
||||
export default { ipfs, localdb, bch, wallet, p2wdb, bchjs, nostr}
|
||||
|
||||
@@ -140,14 +140,15 @@ const offerMockData = {
|
||||
'241c06bf61384b8623477e419bf4779edbcc7e3bc862f0f179a9ed2967069b87',
|
||||
utxoVout: 0,
|
||||
makerAddr: 'address',
|
||||
tokenType: 1
|
||||
tokenType: 1,
|
||||
nostrEventId: 'test'
|
||||
}
|
||||
}
|
||||
|
||||
const deserealizeTxMock = {
|
||||
//...
|
||||
vout: [
|
||||
{
|
||||
{
|
||||
value: 0,
|
||||
scriptPubKey: {
|
||||
addresses: ['bitcoincash:qzy97glp47ut7tstm5g0tlrmkhk742795gkmyc7478']
|
||||
|
||||
@@ -48,6 +48,7 @@ describe('#offer-use-case', () => {
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if order use cases are not passed in', () => {
|
||||
try {
|
||||
uut = new OfferLib({ adapters })
|
||||
@@ -72,6 +73,7 @@ describe('#offer-use-case', () => {
|
||||
assert.include(error.message, 'Cannot read properties of undefined')
|
||||
}
|
||||
})
|
||||
|
||||
it('should return false if offer already exist', async () => {
|
||||
const offerObj = mockData.offerMockData
|
||||
|
||||
@@ -82,6 +84,7 @@ describe('#offer-use-case', () => {
|
||||
const result = await uut.createOffer(offerObj)
|
||||
assert.isFalse(result)
|
||||
})
|
||||
|
||||
it('should return false for invalid utxo', async () => {
|
||||
const offerObj = mockData.offerMockData
|
||||
|
||||
@@ -147,6 +150,7 @@ describe('#offer-use-case', () => {
|
||||
|
||||
assert.equal(result, 'fungible')
|
||||
})
|
||||
|
||||
it('should unknow type', async () => {
|
||||
try {
|
||||
// Mock dependencies
|
||||
@@ -191,6 +195,7 @@ describe('#offer-use-case', () => {
|
||||
|
||||
assert.equal(result, false)
|
||||
})
|
||||
|
||||
it('should handle error', async () => {
|
||||
try {
|
||||
// Mock dependencies and force desired code path.
|
||||
@@ -204,6 +209,7 @@ describe('#offer-use-case', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#removeStaleOffers', () => {
|
||||
it('remove offer with wrong utxoState', async () => {
|
||||
// Mock dependencies and force desired code path.
|
||||
@@ -212,6 +218,7 @@ describe('#offer-use-case', () => {
|
||||
|
||||
await uut.removeStaleOffers()
|
||||
})
|
||||
|
||||
it('remove offer with wrong txid', async () => {
|
||||
// Mock dependencies and force desired code path.
|
||||
sandbox.stub(uut.OfferModel, 'find').resolves([{ remove: async () => { } }])
|
||||
@@ -219,6 +226,7 @@ describe('#offer-use-case', () => {
|
||||
|
||||
await uut.removeStaleOffers()
|
||||
})
|
||||
|
||||
it('remove expired offer ', async () => {
|
||||
const tsMock = new Date()
|
||||
tsMock.setMonth(tsMock.getMonth() - 3)
|
||||
@@ -230,6 +238,7 @@ describe('#offer-use-case', () => {
|
||||
|
||||
await uut.removeStaleOffers()
|
||||
})
|
||||
|
||||
it('should handle axios error ', async () => {
|
||||
const testErr = new Error()
|
||||
testErr.isAxiosError = true
|
||||
@@ -240,6 +249,7 @@ describe('#offer-use-case', () => {
|
||||
|
||||
await uut.removeStaleOffers()
|
||||
})
|
||||
|
||||
it('should handle error ', async () => {
|
||||
try {
|
||||
const testErr = new Error('unknow error')
|
||||
@@ -255,6 +265,7 @@ describe('#offer-use-case', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#findOfferByTxid', () => {
|
||||
it('should throw an error if input is not provided', async () => {
|
||||
try {
|
||||
@@ -264,6 +275,7 @@ describe('#offer-use-case', () => {
|
||||
assert.equal(error.message, 'utxoTxid must be a string')
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if offer is not found', async () => {
|
||||
try {
|
||||
// Mock dependencies and force desired code path.
|
||||
@@ -284,6 +296,7 @@ describe('#offer-use-case', () => {
|
||||
assert.isObject(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#detectNsfw', () => {
|
||||
it('should return false for wrong cid format', async () => {
|
||||
const result = await uut.detectNsfw({ mutableData: '' })
|
||||
@@ -297,6 +310,7 @@ describe('#offer-use-case', () => {
|
||||
const result = await uut.detectNsfw({ mutableData: 'ipfs://bafybeibqnsmmh6bkf2wwextetki4tly65z4r4qkrrpl5xwgvzdzjley6wm' })
|
||||
assert.isTrue(result)
|
||||
})
|
||||
|
||||
it('should return true if nft string detected', async () => {
|
||||
// Mock dependencies and force desired code path.
|
||||
sandbox.stub(uut.axios, 'get').resolves({ data: { nsfw: 'true' } })
|
||||
@@ -304,6 +318,7 @@ describe('#offer-use-case', () => {
|
||||
const result = await uut.detectNsfw({ mutableData: 'ipfs://bafybeibqnsmmh6bkf2wwextetki4tly65z4r4qkrrpl5xwgvzdzjley6wm' })
|
||||
assert.isTrue(result)
|
||||
})
|
||||
|
||||
it('should return false if nfsw property does not exist', async () => {
|
||||
// Mock dependencies and force desired code path.
|
||||
sandbox.stub(uut.axios, 'get').resolves({ data: {} })
|
||||
@@ -311,6 +326,7 @@ describe('#offer-use-case', () => {
|
||||
const result = await uut.detectNsfw({ mutableData: 'ipfs://bafybeibqnsmmh6bkf2wwextetki4tly65z4r4qkrrpl5xwgvzdzjley6wm' })
|
||||
assert.isFalse(result)
|
||||
})
|
||||
|
||||
it('should return false on error', async () => {
|
||||
// Mock dependencies and force desired code path.
|
||||
sandbox.stub(uut.axios, 'get').throws(new Error('test error'))
|
||||
@@ -319,6 +335,7 @@ describe('#offer-use-case', () => {
|
||||
assert.isFalse(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#listOffers', () => {
|
||||
it('should handle error', async () => {
|
||||
try {
|
||||
@@ -350,6 +367,7 @@ describe('#offer-use-case', () => {
|
||||
assert.isArray(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#listNftOffers', () => {
|
||||
it('should handle error', async () => {
|
||||
try {
|
||||
@@ -380,6 +398,7 @@ describe('#offer-use-case', () => {
|
||||
assert.isArray(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#listFungibleOffers', () => {
|
||||
it('should handle error', async () => {
|
||||
try {
|
||||
@@ -411,6 +430,7 @@ describe('#offer-use-case', () => {
|
||||
assert.isArray(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#takeOffer', () => {
|
||||
it('should handle error if input is not provided', async () => {
|
||||
try {
|
||||
@@ -420,6 +440,7 @@ describe('#offer-use-case', () => {
|
||||
assert.include(err.message, 'eventId must be a string')
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle error for wrong offer status', async () => {
|
||||
try {
|
||||
// Mock dependencies
|
||||
@@ -432,6 +453,7 @@ describe('#offer-use-case', () => {
|
||||
assert.include(err.message, 'offer status is not "posted", so offer is dead and can not be countered.')
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle error for invalid utxo', async () => {
|
||||
try {
|
||||
// Mock dependencies
|
||||
@@ -460,6 +482,7 @@ describe('#offer-use-case', () => {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle error if counter offer cant be calculated', async () => {
|
||||
try {
|
||||
// Mock dependencies
|
||||
@@ -474,6 +497,7 @@ describe('#offer-use-case', () => {
|
||||
assert.include(err.message, 'Could not calculate the amount of BCH to generate counter offer')
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle error if counter offer cant be calculated', async () => {
|
||||
try {
|
||||
// Mock dependencies
|
||||
@@ -488,6 +512,7 @@ describe('#offer-use-case', () => {
|
||||
assert.include(err.message, 'Could not calculate the amount of BCH to generate counter offer')
|
||||
}
|
||||
})
|
||||
|
||||
it('should take offer', async () => {
|
||||
// Mock data
|
||||
const offerMock = Object.assign({}, mockData.offerMockData.data)
|
||||
@@ -561,6 +586,7 @@ describe('#offer-use-case', () => {
|
||||
assert.include(err.message, 'Buy offers are not supported yet.')
|
||||
}
|
||||
})
|
||||
|
||||
it('should return true', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.p2wdb, 'checkForSufficientFunds').resolves(true)
|
||||
@@ -570,6 +596,7 @@ describe('#offer-use-case', () => {
|
||||
assert.isTrue(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#findOrderByEvent', () => {
|
||||
it('should throw an error if hash is not provided', async () => {
|
||||
try {
|
||||
@@ -579,6 +606,7 @@ describe('#offer-use-case', () => {
|
||||
assert.include(err.message, 'nostrEventId must be a string')
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if order is not found!', async () => {
|
||||
try {
|
||||
// Mock dependencies
|
||||
@@ -591,6 +619,7 @@ describe('#offer-use-case', () => {
|
||||
assert.include(err.message, 'offer not found')
|
||||
}
|
||||
})
|
||||
|
||||
it('should return offer by eventId', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.OfferModel, 'findOne').resolves({ toObject: () => { return { hash: 'hash' } } })
|
||||
@@ -599,6 +628,7 @@ describe('#offer-use-case', () => {
|
||||
assert.isObject(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#flagOffer', () => {
|
||||
it('should throw an error if input is not provided', async () => {
|
||||
try {
|
||||
@@ -608,6 +638,7 @@ describe('#offer-use-case', () => {
|
||||
assert.include(err.message, '"data" property is required')
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if offer is not found!', async () => {
|
||||
try {
|
||||
// Mock dependencies
|
||||
@@ -625,6 +656,7 @@ describe('#offer-use-case', () => {
|
||||
assert.include(err.message, 'not found in the database')
|
||||
}
|
||||
})
|
||||
|
||||
it('should flag offer', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut, 'findOfferByEvent').resolves({ flags: ['a', 'b', 'c'], save: () => { } })
|
||||
@@ -652,12 +684,14 @@ describe('#offer-use-case', () => {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
|
||||
it('should skip internal function errors ', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.nostr, 'read').resolves([mockData.offerMockData])
|
||||
|
||||
await uut.loadOffers()
|
||||
})
|
||||
|
||||
it('should review and load offers', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.nostr, 'read').resolves([JSON.stringify(mockData.offerMockData)])
|
||||
@@ -665,6 +699,7 @@ describe('#offer-use-case', () => {
|
||||
await uut.loadOffers()
|
||||
})
|
||||
})
|
||||
|
||||
describe('#acceptCounterOffer', () => {
|
||||
it('should return if order is not found!', async () => {
|
||||
// Mock dependencies
|
||||
@@ -673,6 +708,7 @@ describe('#offer-use-case', () => {
|
||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
assert.equal(result, 'N/A')
|
||||
})
|
||||
|
||||
it('should handle error if counter offer cant be calculated', async () => {
|
||||
try {
|
||||
// Mock Data
|
||||
@@ -681,28 +717,35 @@ describe('#offer-use-case', () => {
|
||||
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByEvent').resolves(mock)
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
|
||||
await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
console.log('result: ', result)
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Could not calculate the amount of BCH offered in the Counter Offer')
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle error for wrong transaction output', async () => {
|
||||
try {
|
||||
// Mock dependencies
|
||||
// Mock Data
|
||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByEvent').resolves(mockData.offerMockData.data)
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet.bchjs.BitcoinCash, 'toSatoshi').returns(0)
|
||||
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
||||
|
||||
await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
await uut.acceptCounterOffer({ data: mock })
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'The Counter Offer has an output of ')
|
||||
assert.include(err.message, 'which does not match the required')
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle error for wrong transaction output address', async () => {
|
||||
try {
|
||||
// Mock data
|
||||
@@ -713,6 +756,7 @@ describe('#offer-use-case', () => {
|
||||
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByEvent').resolves(mock)
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet.bchjs.BitcoinCash, 'toSatoshi').returns(0)
|
||||
|
||||
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
||||
@@ -724,6 +768,7 @@ describe('#offer-use-case', () => {
|
||||
assert.include(err.message, 'which does not match the Maker address')
|
||||
}
|
||||
})
|
||||
|
||||
it('should return tx id', async () => {
|
||||
// Mock data
|
||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||
|
||||
@@ -181,7 +181,8 @@ describe('#order-use-case', () => {
|
||||
const result = await uut.createOrder(entryObj)
|
||||
console.log('result: ', result)
|
||||
|
||||
assert.isString(result)
|
||||
assert.property(result, 'eventId')
|
||||
assert.property(result, 'noteId')
|
||||
})
|
||||
|
||||
it('should catch and throw an error', async () => {
|
||||
|
||||
Reference in New Issue
Block a user