diff --git a/package-lock.json b/package-lock.json index c18899545..229a95fb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,10 +38,10 @@ "dotenv-flow": "3.2.0", "duckdb": "0.9.2", "ecpair": "2.1.0", - "elliptic": "6.5.7", + "elliptic": "6.6.0", "escape-goat": "3.0.0", "evt": "1.10.1", - "express": "^4.21.2", + "express": "4.21.2", "fastify": "4.28.1", "fastify-metrics": "11.0.0", "getopts": "2.3.0", @@ -6297,9 +6297,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -6662,18 +6662,6 @@ "node": ">= 6.0.0" } }, - "node_modules/docker-compose/node_modules/yaml": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", - "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", - "dev": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -6839,9 +6827,9 @@ "dev": true }, "node_modules/elliptic": { - "version": "6.5.7", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz", - "integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.0.tgz", + "integrity": "sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -8372,9 +8360,9 @@ "license": "MIT" }, "node_modules/find-my-way": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-8.2.0.tgz", - "integrity": "sha512-HdWXgFYc6b1BJcOBDBwjqWuHJj1WYiqrxSh25qtU4DabpMFdj/gSunNBQb83t+8Zt67D7CXEzJWTkxaShMTMOA==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-8.2.2.tgz", + "integrity": "sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA==", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", @@ -12271,9 +12259,9 @@ "integrity": "sha512-iwqAmg66VjB2LA3BcUxyrOyqck4HLLtSzKnx2VQSnN5piQji598N15P8RRx2d6lPvJ98B1b0cl2VbvQeFeWdig==" }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -15430,6 +15418,14 @@ "node": ">= 0.8" } }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index a7c7372a0..f7e24ee0e 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "dotenv-flow": "3.2.0", "duckdb": "0.9.2", "ecpair": "2.1.0", - "elliptic": "6.5.7", + "elliptic": "6.6.0", "escape-goat": "3.0.0", "evt": "1.10.1", "express": "4.21.2", diff --git a/src/api/routes/faucets.ts b/src/api/routes/faucets.ts index c9b2b04e8..0f736d70b 100644 --- a/src/api/routes/faucets.ts +++ b/src/api/routes/faucets.ts @@ -74,27 +74,39 @@ export const FaucetRoutes: FastifyPluginAsync< preHandler: missingBtcConfigMiddleware, schema: { operationId: 'run_faucet_btc', - summary: 'Add testnet BTC tokens to address', - description: `Add 1 BTC token to the specified testnet BTC address. + summary: 'Add regtest BTC tokens to address', + description: `Add 0.01 BTC token to the specified regtest BTC address. - The endpoint returns the transaction ID, which you can use to view the transaction in a testnet Bitcoin block + The endpoint returns the transaction ID, which you can use to view the transaction in a regtest Bitcoin block explorer. The tokens are delivered once the transaction has been included in a block. - **Note:** This is a testnet only endpoint. This endpoint will not work on the mainnet.`, + **Note:** This is a Bitcoin regtest-only endpoint. This endpoint will not work on the Bitcoin mainnet.`, tags: ['Faucets'], querystring: Type.Object({ address: Type.Optional( Type.String({ - description: 'A valid testnet BTC address', + description: 'A valid regtest BTC address', examples: ['2N4M94S1ZPt8HfxydXzL2P7qyzgVq7MHWts'], }) ), + large: Type.Optional( + Type.Boolean({ + description: 'Request a large amount of regtest BTC than the default', + default: false, + }) + ), + xlarge: Type.Optional( + Type.Boolean({ + description: 'Request an extra large amount of regtest BTC than the default', + default: false, + }) + ), }), body: OptionalNullable( Type.Object({ address: Type.Optional( Type.String({ - description: 'A valid testnet BTC address', + description: 'A valid regtest BTC address', examples: ['2N4M94S1ZPt8HfxydXzL2P7qyzgVq7MHWts'], }) ), @@ -112,7 +124,7 @@ export const FaucetRoutes: FastifyPluginAsync< { title: 'RunFaucetResponse', description: - 'POST request that initiates a transfer of tokens to a specified testnet address', + 'POST request that initiates a transfer of tokens to a specified Bitcoin regtest address', } ), '4xx': Type.Object({ @@ -125,6 +137,21 @@ export const FaucetRoutes: FastifyPluginAsync< async (req, reply) => { await btcFaucetRequestQueue.add(async () => { const address = req.query.address || req.body?.address; + let btcAmount = 0.0001; + + if (req.query.large && req.query.xlarge) { + return await reply.status(400).send({ + error: 'cannot simultaneously request a large and xlarge amount', + success: false, + }); + } + + if (req.query.large) { + btcAmount = 0.01; + } else if (req.query.xlarge) { + btcAmount = 0.5; + } + if (!address) { return await reply.status(400).send({ error: 'address required', @@ -156,7 +183,7 @@ export const FaucetRoutes: FastifyPluginAsync< }); } - const tx = await makeBtcFaucetPayment(btc.networks.regtest, address, 0.5); + const tx = await makeBtcFaucetPayment(btc.networks.regtest, address, btcAmount); await fastify.writeDb?.insertFaucetRequest({ ip: `${ip}`, address: address, @@ -183,7 +210,7 @@ export const FaucetRoutes: FastifyPluginAsync< tags: ['Faucets'], params: Type.Object({ address: Type.String({ - description: 'A valid testnet BTC address', + description: 'A valid regtest BTC address', examples: ['2N4M94S1ZPt8HfxydXzL2P7qyzgVq7MHWts'], }), }), diff --git a/tests/btc-faucet/faucet-btc.test.ts b/tests/btc-faucet/faucet-btc.test.ts index 5d2ae10d0..60e000255 100644 --- a/tests/btc-faucet/faucet-btc.test.ts +++ b/tests/btc-faucet/faucet-btc.test.ts @@ -156,6 +156,40 @@ describe('btc faucet', () => { `/extended/v1/faucets/btc/${addr}` ); expect(balanceResponse.status).toBe(200); + expect(JSON.parse(balanceResponse.text)).toEqual({ balance: 0.0001 }); + }); + + test('faucet http balance endpoint large', async () => { + const addr = getKeyAddress(ECPair.makeRandom({ network: regtest })); + const response = await supertest(apiServer.server).post( + `/extended/v1/faucets/btc?address=${addr}&large=true` + ); + expect(response.status).toBe(200); + await getRpcClient().generatetoaddress({ + address: getKeyAddress(ECPair.makeRandom({ network: regtest })), + nblocks: 1, + }); + const balanceResponse = await supertest(apiServer.server).get( + `/extended/v1/faucets/btc/${addr}` + ); + expect(balanceResponse.status).toBe(200); + expect(JSON.parse(balanceResponse.text)).toEqual({ balance: 0.01 }); + }); + + test('faucet http balance endpoint xlarge', async () => { + const addr = getKeyAddress(ECPair.makeRandom({ network: regtest })); + const response = await supertest(apiServer.server).post( + `/extended/v1/faucets/btc?address=${addr}&xlarge=true` + ); + expect(response.status).toBe(200); + await getRpcClient().generatetoaddress({ + address: getKeyAddress(ECPair.makeRandom({ network: regtest })), + nblocks: 1, + }); + const balanceResponse = await supertest(apiServer.server).get( + `/extended/v1/faucets/btc/${addr}` + ); + expect(balanceResponse.status).toBe(200); expect(JSON.parse(balanceResponse.text)).toEqual({ balance: 0.5 }); });