From 53c512627ac77777061ceaf046a7a0c1ef5d6655 Mon Sep 17 00:00:00 2001 From: chinasa056 Date: Sat, 31 May 2025 16:17:39 +0100 Subject: [PATCH 1/2] feat: implemeted address generaton nand send onchain bitcoin transaction --- src/app.js | 2 + src/controllers/customers/sendBitcoin.js | 73 ++++++++++++++++++++++++ src/index.js | 2 + src/routes/transaction.js | 9 +++ 4 files changed, 86 insertions(+) create mode 100644 src/controllers/customers/sendBitcoin.js create mode 100644 src/routes/transaction.js diff --git a/src/app.js b/src/app.js index 6153f8d..1492a3e 100644 --- a/src/app.js +++ b/src/app.js @@ -1,6 +1,7 @@ import express from 'express'; import dotenv from 'dotenv'; import currencyRoutes from './routes/currencyRoutes.js'; +import { transactionRoute } from './routes/transaction.js'; dotenv.config(); @@ -12,6 +13,7 @@ app.use(express.urlencoded({ extended: true })); // Routes app.use('/api/currency', currencyRoutes); +app.use('/api/currency', transactionRoute); // Error handling middleware app.use((err, req, res) => { diff --git a/src/controllers/customers/sendBitcoin.js b/src/controllers/customers/sendBitcoin.js new file mode 100644 index 0000000..e6237de --- /dev/null +++ b/src/controllers/customers/sendBitcoin.js @@ -0,0 +1,73 @@ +import { AxiosService } from "../../services/axios/AxiosService.js"; + +const BITNOB_BASE_URL = process.env.BITNOB_BASE_URL +const BITNOB_API_KEY = process.env.BITNOB_SANDBOX_API_URL; + +const bitnobClient = new AxiosService(BITNOB_BASE_URL, BITNOB_API_KEY); + +// generate address +export const generateAddress = async (req, res) => { + try { + const { label = 'purchase xbox', customerEmail, formatType = 'bip21', amount = '' } = req.body; + + if (!customerEmail) { + return res.status(400).json({ status: false, message: 'customerEmail is required' }); + }; + + const addressData = { label, customerEmail, formatType, amount }; + const response = await bitnobClient.post('/addresses/generate', addressData); + + console.log("response data:", response.data); + console.log('Full response.data:', JSON.stringify(response.data, null, 2)); + + const { data } = response; + if (data.status) { + return res.status(200).json({ + status: true, + message: 'Address successfully generated', + data: response.data.data, + }); + } else { + return res.status(500).json({ status: false, message: 'Failed to generate address' }); + }; + } catch (error) { + console.error('Generate address error:', error.response?.data || error.message); + return res.status(500).json({ status: false, message: 'Failed to generate address' }); + }; +}; + +// Send bitcoin onchain +export const sendBitcoin = async (req, res) => { + try { + const { satoshis, address, customerEmail, description = '', priorityLevel = 'regular' } = req.body; + + if (!satoshis || !address || !customerEmail) { + return res.status(400).json({ status: false, message: 'satoshis, address, and customerEmail are required' }); + } + + const paymentData = { satoshis, address, customerEmail, description, priorityLevel }; + const response = await bitnobClient.post('/wallets/send_bitcoin', paymentData); + + const { data } = response; + if (data.status === true) { + console.log('sending bitcoin successful', data.data); + + return res.status(200).json({ + status: true, + message: 'Address successfully generated', + data: data + }); + } else { + console.error('Send bitcoin error:', error.response?.data || error.message); + return res.status(400).json({ + status: false, + message: 'Failed to send bitcoin', + data: error.response?.data || error.message + }); + }; + + } catch (error) { + console.error('Send bitcoin error:', error.response?.data || error.message); + return res.status(500).json({ message: 'Internal Server Error', error}); + }; +}; diff --git a/src/index.js b/src/index.js index 1d349d7..f4ad553 100644 --- a/src/index.js +++ b/src/index.js @@ -18,6 +18,7 @@ import { BaseError } from './errors/errors.js'; // Models import './models/wallet.js'; import './models/transaction.js'; +import { transactionRoute } from './routes/transaction.js'; // Load environment variables dotenv.config(); @@ -42,6 +43,7 @@ app.use(urlencoded({ extended: true, limit: '200mb' })); app.use('/api/wallet', walletRoute); app.use(`${BASE_URL}/customers`, customersRouter); app.use(`${BASE_URL}/currency`, currencyRoutes); +app.use(`${BASE_URL}/transaction`, transactionRoute); // Error handling middleware app.use((error, _req, res) => { diff --git a/src/routes/transaction.js b/src/routes/transaction.js new file mode 100644 index 0000000..ac831b6 --- /dev/null +++ b/src/routes/transaction.js @@ -0,0 +1,9 @@ +import Router from 'express'; +import { generateAddress, sendBitcoin } from '../controllers/customers/sendBitcoin.js'; +const router = Router(); + +router.post('/address', generateAddress); + +router.post('/create', sendBitcoin); + +export {router as transactionRoute} From 06b1dfd2783e4235688b74c5e39922826b6ba63c Mon Sep 17 00:00:00 2001 From: chinasa056 Date: Sat, 31 May 2025 16:30:55 +0100 Subject: [PATCH 2/2] fix: resolved eslint errors in sendBitcoin controller --- src/controllers/customers/sendBitcoin.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/controllers/customers/sendBitcoin.js b/src/controllers/customers/sendBitcoin.js index e6237de..9613537 100644 --- a/src/controllers/customers/sendBitcoin.js +++ b/src/controllers/customers/sendBitcoin.js @@ -58,11 +58,9 @@ export const sendBitcoin = async (req, res) => { data: data }); } else { - console.error('Send bitcoin error:', error.response?.data || error.message); return res.status(400).json({ status: false, message: 'Failed to send bitcoin', - data: error.response?.data || error.message }); };