From e466d698990d6ae525edfb25f1f4664d813bc894 Mon Sep 17 00:00:00 2001 From: Robert Andasan Date: Thu, 14 Nov 2024 21:12:58 +0800 Subject: [PATCH 1/8] Include get endpoints for abe support --- src/apiServices/assetApi.ts | 77 ++++++++++++++++++++++++++++++++++++ src/routes.ts | 21 ++++++++++ src/services/assetService.ts | 55 ++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 src/apiServices/assetApi.ts create mode 100644 src/services/assetService.ts diff --git a/src/apiServices/assetApi.ts b/src/apiServices/assetApi.ts new file mode 100644 index 0000000..9d5745a --- /dev/null +++ b/src/apiServices/assetApi.ts @@ -0,0 +1,77 @@ +import log from '../lib/log'; +import { + showFiatAssets, + showCryptoAssets, + getPurchaseDetailByPurchaseId, + submitPurchase, + getPurchaseHistory +} from '../services/assetService'; + +async function getFiatAssets(req, res) { + try { + const value = await showFiatAssets(); + res.json(value); + } catch (error) { + log.error(error); + res.sendStatus(404); + } +} + +async function getCryptoAssets(req, res) { + try { + const value = await showCryptoAssets(); + res.json(value); + } catch (error) { + log.error(error); + res.sendStatus(404); + } +} + +async function getPurchaseDetailsByPurchaseId(req, res) { + try { + let { purchaseid } = req.params; + purchaseid = purchaseid ?? req.query.purchaseid; + const value = await getPurchaseDetailByPurchaseId(purchaseid); + res.json(value); + } catch (error) { + log.error(error); + res.sendStatus(404); + } +} + +async function sendPurchase(req, res) { + try { + let { purchaseid } = req.params; + purchaseid = purchaseid ?? req.query.purchaseid; + + let { providerid } = req.params; + providerid = providerid ?? req.query.providerid; + + const value = await submitPurchase(purchaseid, providerid); + res.json(value); + } catch (error) { + log.error(error); + res.sendStatus(404); + } +} + +async function getAllPurchase(req, res) { + try { + let { zelid } = req.params; + zelid = zelid ?? req.query.zelid; + + const value = await getPurchaseHistory(zelid); + res.json(value); + } catch (error) { + log.error(error); + res.sendStatus(404); + } +} + +export default { + getFiatAssets, + getCryptoAssets, + getPurchaseDetailsByPurchaseId, + sendPurchase, + getAllPurchase +} \ No newline at end of file diff --git a/src/routes.ts b/src/routes.ts index 8fa7244..5804022 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -4,6 +4,7 @@ import ratesApi from './apiServices/ratesApi'; import ticketsApi from './apiServices/ticketsApi'; import feeService from './services/networkFeesService'; import tokenApi from './apiServices/tokenApi'; +import assetApi from './apiServices/assetApi'; export default (app) => { // return sync data @@ -36,6 +37,26 @@ export default (app) => { app.post('/v1/ticket', (req, res) => { ticketsApi.postTicket(req, res); }); + // get fiat assets + app.get('/v1/assetinfo/assets/fiat', (req, res) => { + assetApi.getFiatAssets(req, res); + }); + // get crypto assets + app.get('/v1/assetinfo/assets/crypto', (req, res) => { + assetApi.getCryptoAssets(req, res); + }); + // get purchase by id + app.get('/v1/assetinfo/purchase/id/:purchaseid?', (req, res) => { + assetApi.getPurchaseDetailsByPurchaseId(req, res); + }); + // send purchase + app.get('/v1/assetinfo/purchase/send/:purchaseid?/:providerid?', (req, res) => { + assetApi.sendPurchase(req, res); + }); + // get purchase history + app.get('/v1/assetinfo/purchase/history/:zelid?', (req, res) => { + assetApi.getAllPurchase(req, res); + }); // get token information endpoint app.get('/v1/tokeninfo/:network?/:address?', (req, res) => { tokenApi.getTokenInfo(req, res); diff --git a/src/services/assetService.ts b/src/services/assetService.ts new file mode 100644 index 0000000..d0863ae --- /dev/null +++ b/src/services/assetService.ts @@ -0,0 +1,55 @@ +import axios from 'axios'; + +export async function showFiatAssets () { + try { + const response = await axios.get('https://abe.zelcore.io/v1/purchase/sellassets'); + return response.data; + } catch(error) { + console.log(error); + return {}; + }; +} + +export async function showCryptoAssets () { + try { + const response = await axios.get('https://abe.zelcore.io/v1/purchase/buyassets'); + return response.data; + } catch(error) { + console.log(error); + return {}; + }; +} + +export async function getPurchaseDetailByPurchaseId (purchaseid: string) { + try { + const response = await axios.get(`https://abe.zelcore.io/v1/purchase/detail?purchaseid=${purchaseid}`); + return response.data; + } catch(error) { + console.log(error); + return {}; + }; +} + +export async function submitPurchase (purchaseid: string, providerid: string) { + try { + const response = await axios.get(`https://abe.zelcore.io/v1/purchase/submit?purchaseid=${purchaseid}&providerid=${providerid}`); + return response.data; + } catch(error) { + console.log(error); + return {}; + }; +} + +export async function getPurchaseHistory (zelid: string) { + try { + const response = await axios.get(`https://abe.zelcore.io/v1/offramp/user/history?zelid=${zelid}`); + return response.data; + } catch(error) { + console.log(error); + return {}; + }; +} + + + + From 736cd538d76d1922b5aee6f009671c824c55a7aa Mon Sep 17 00:00:00 2001 From: Robert Andasan Date: Fri, 15 Nov 2024 12:38:59 +0800 Subject: [PATCH 2/8] Added post endpoints --- src/apiServices/assetApi.ts | 61 +++++++++++++++++++++++++++++++-- src/routes.ts | 21 ++++++++++-- src/services/assetService.ts | 66 +++++++++++++++++++++++++++++++++--- 3 files changed, 139 insertions(+), 9 deletions(-) diff --git a/src/apiServices/assetApi.ts b/src/apiServices/assetApi.ts index 9d5745a..bd01b5a 100644 --- a/src/apiServices/assetApi.ts +++ b/src/apiServices/assetApi.ts @@ -4,7 +4,11 @@ import { showCryptoAssets, getPurchaseDetailByPurchaseId, submitPurchase, - getPurchaseHistory + getPurchaseHistory, + getPurchaseDetails, + getPurchaseDetailsSelectedAsset, + createPurchase, + getPurchaseStatus } from '../services/assetService'; async function getFiatAssets(req, res) { @@ -68,10 +72,63 @@ async function getAllPurchase(req, res) { } } +async function getAllPurchaseDetails(req, res) { + try { + const data = req.data; + const value = await getPurchaseDetails(data); + res.json(value); + } catch (error) { + log.error(error); + res.sendStatus(404); + } +} + +async function getPurchaseDetailsOnSelectedAsset(req, res) { + try { + const data = req.data; + const value = await getPurchaseDetailsSelectedAsset(data); + res.json(value); + } catch (error) { + log.error(error); + res.sendStatus(404); + } +} + +async function createPurchaseDetails(req, res) { + try { + const data = req.data; + + let { zelid } = req.params; + zelid = zelid ?? req.query.zelid; + + const value = await createPurchase(data, zelid); + res.json(value); + } catch (error) { + log.error(error); + res.sendStatus(404); + } +} + +async function getAllPurchaseStatus(req, res) { + try { + const data = req.data; + const value = await getPurchaseStatus(data); + res.json(value); + } catch (error) { + log.error(error); + res.sendStatus(404); + } +} + + export default { getFiatAssets, getCryptoAssets, getPurchaseDetailsByPurchaseId, sendPurchase, - getAllPurchase + getAllPurchase, + getAllPurchaseDetails, + getPurchaseDetailsOnSelectedAsset, + createPurchaseDetails, + getAllPurchaseStatus } \ No newline at end of file diff --git a/src/routes.ts b/src/routes.ts index 5804022..00185ac 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -37,6 +37,10 @@ export default (app) => { app.post('/v1/ticket', (req, res) => { ticketsApi.postTicket(req, res); }); + // get token information endpoint + app.get('/v1/tokeninfo/:network?/:address?', (req, res) => { + tokenApi.getTokenInfo(req, res); + }); // get fiat assets app.get('/v1/assetinfo/assets/fiat', (req, res) => { assetApi.getFiatAssets(req, res); @@ -57,8 +61,19 @@ export default (app) => { app.get('/v1/assetinfo/purchase/history/:zelid?', (req, res) => { assetApi.getAllPurchase(req, res); }); - // get token information endpoint - app.get('/v1/tokeninfo/:network?/:address?', (req, res) => { - tokenApi.getTokenInfo(req, res); + app.post('/v1/assetinfo/purchase/details', (req, res) => { + assetApi.getAllPurchaseDetails(req, res); + }); + // send purchase + app.post('/v1/assetinfo/purchase/details/assets', (req, res) => { + assetApi.getPurchaseDetailsOnSelectedAsset(req, res); + }); + // get purchase history + app.post('/v1/assetinfo/purchase/create/:zelid?', (req, res) => { + assetApi.createPurchaseDetails(req, res); + }); + // get purchase history + app.post('/v1/assetinfo/purchase/status', (req, res) => { + assetApi.getAllPurchaseStatus(req, res); }); }; diff --git a/src/services/assetService.ts b/src/services/assetService.ts index d0863ae..fe9b94a 100644 --- a/src/services/assetService.ts +++ b/src/services/assetService.ts @@ -6,7 +6,7 @@ export async function showFiatAssets () { return response.data; } catch(error) { console.log(error); - return {}; + return {message: "Error occured in processing"}; }; } @@ -16,7 +16,7 @@ export async function showCryptoAssets () { return response.data; } catch(error) { console.log(error); - return {}; + return {message: "Error occured in processing"}; }; } @@ -26,7 +26,7 @@ export async function getPurchaseDetailByPurchaseId (purchaseid: string) { return response.data; } catch(error) { console.log(error); - return {}; + return {message: "Error occured in processing"}; }; } @@ -36,7 +36,7 @@ export async function submitPurchase (purchaseid: string, providerid: string) { return response.data; } catch(error) { console.log(error); - return {}; + return {message: "Error occured in processing"}; }; } @@ -44,6 +44,63 @@ export async function getPurchaseHistory (zelid: string) { try { const response = await axios.get(`https://abe.zelcore.io/v1/offramp/user/history?zelid=${zelid}`); return response.data; + } catch(error) { + console.log(error); + return {message: "Error occured in processing"}; + }; +} + +export async function getPurchaseDetails (data: any) { + try { + const response = await axios.post(`https://abe.zelcore.io/v1/purchase/pairdetails`, data, { + headers: { + 'Content-Type' : 'application/json' + } + }); + return response.data; + } catch(error) { + console.log(error); + return {message: "Error occured in processing"}; + }; +} + +export async function getPurchaseDetailsSelectedAsset (data: any) { + try { + const response = await axios.post(`https://abe.zelcore.io/v1/purchase/pairdetailssellamount`, data, { + headers: { + 'Content-Type' : 'application/json' + } + }); + return response.data; + } catch(error) { + console.log(error); + return {message: "Error occured in processing"}; + }; +} + +export async function createPurchase (data: any, zelid: string) { + try { + const response = await axios.post(`https://abe.zelcore.io/v1/purchase/createpurchase`, data, { + headers: { + 'Content-Type' : 'application/json', + 'zedid': zelid + } + }); + return response.data; + } catch(error) { + console.log(error); + return {message: "Error occured in processing"}; + }; +} + +export async function getPurchaseStatus (data: any) { + try { + const response = await axios.post(`https://abe.zelcore.io/v1/purchase/status`, data, { + headers: { + 'Content-Type' : 'application/json' + } + }); + return response.data; } catch(error) { console.log(error); return {}; @@ -53,3 +110,4 @@ export async function getPurchaseHistory (zelid: string) { + From 153b664be0eee26a5dba389d805d7a33d92ee7c7 Mon Sep 17 00:00:00 2001 From: Robert Andasan Date: Mon, 25 Nov 2024 18:42:14 +0800 Subject: [PATCH 3/8] Added test cases for asset --- tests/unit/assetApi.spec.ts | 406 ++++++++++++++++++++++++++++++++++++ 1 file changed, 406 insertions(+) create mode 100644 tests/unit/assetApi.spec.ts diff --git a/tests/unit/assetApi.spec.ts b/tests/unit/assetApi.spec.ts new file mode 100644 index 0000000..6b7656b --- /dev/null +++ b/tests/unit/assetApi.spec.ts @@ -0,0 +1,406 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions */ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck test suite +import chai from 'chai'; +import assetService from '../../src/services/assetService'; +import assetApi from '../../src/apiServices/assetApi'; +import sinon from 'sinon'; +import httpMocks from 'node-mocks-http'; + +const { expect, assert } = chai; + +describe('Asset API', function () { + describe('Asset API: Correctly verifies asset data', function () { + afterEach(function () { + sinon.restore(); + }); + + it('should return getFiatAssets successful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'GET', + url: 'test', + }); + const res = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await assetApi.getFiatAssets(request, res); + expect(JSON.parse(res._getData())).to.have.property('status'); + expect(JSON.parse(res._getData())).to.have.property('data'); + }); + + it('should return getCryptoAssets successful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'GET', + url: 'test', + }); + const res = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await assetApi.getCryptoAssets(request, res); + expect(JSON.parse(res._getData())).to.have.property('status'); + expect(JSON.parse(res._getData())).to.have.property('data'); + expect(JSON.parse(res._getData()).data[0]).to.have.property('idzelcore'); + expect(JSON.parse(res._getData()).data[0]).to.have.property('ticker'); + expect(JSON.parse(res._getData()).data[0]).to.have.property('name'); + expect(JSON.parse(res._getData()).data[0]).to.have.property('contract'); + expect(JSON.parse(res._getData()).data[0]).to.have.property('chain'); + expect(JSON.parse(res._getData()).data[0]).to.have.property('idguardarian'); + expect(JSON.parse(res._getData()).data[0]).to.have.property('idguardarianlimit'); + }); + + it('should return getPurchaseDetailsByPurchaseId successful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'GET', + url: 'test', + params: { + purchaseid: "58f9cce7-abcb-4468-96f1-d0bc75000ec4" + } + }); + const res = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await assetApi.getPurchaseDetailsByPurchaseId(request, res); + expect(JSON.parse(res._getData())).to.have.property('status'); + expect(JSON.parse(res._getData())).to.have.property('data'); + expect(JSON.parse(res._getData()).data).to.have.property('purchaseId'); + expect(JSON.parse(res._getData()).data).to.have.property('buyAddress'); + expect(JSON.parse(res._getData()).data).to.have.property('buyAmount'); + expect(JSON.parse(res._getData()).data).to.have.property('buyAsset'); + expect(JSON.parse(res._getData()).data).to.have.property('buyTxid'); + expect(JSON.parse(res._getData()).data).to.have.property('cardId'); + expect(JSON.parse(res._getData()).data).to.have.property('country'); + + expect(JSON.parse(res._getData()).data).to.have.property('createdAt'); + expect(JSON.parse(res._getData()).data).to.have.property('networkFee'); + expect(JSON.parse(res._getData()).data).to.have.property('providerBuyAssetId'); + expect(JSON.parse(res._getData()).data).to.have.property('providerCustomerId'); + expect(JSON.parse(res._getData()).data).to.have.property('providerId'); + expect(JSON.parse(res._getData()).data).to.have.property('providerSellAssetId'); + expect(JSON.parse(res._getData()).data).to.have.property('rate'); + + expect(JSON.parse(res._getData()).data).to.have.property('sellAmount'); + expect(JSON.parse(res._getData()).data).to.have.property('sellAsset'); + expect(JSON.parse(res._getData()).data).to.have.property('status'); + expect(JSON.parse(res._getData()).data).to.have.property('transactionFee'); + expect(JSON.parse(res._getData()).data).to.have.property('zelid'); + expect(JSON.parse(res._getData()).data).to.have.property('providerCardId'); + }); + + it('should return sendPurchase successful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'GET', + url: 'test', + params: { + purchaseid: "58f9cce7-abcb-4468-96f1-d0bc75000ec4", + providerid: "idmoonpay" + } + }); + const response = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await sinon + .stub(assetApi, 'sendPurchase') + .returns({ + "status": "success", + "data": { + "purchaseId": "58f9cce7-abcb-4468-96f1-d0bc75000ec4", + "buyAddress": "0x88ede65cb154660a84d996467bdef80e17de1576", + "buyAmount": "0.15800000", + "buyAsset": "ethereum", + "buyTxid": "0x978458e5dc7d3f449051da2e6be702df754370e4fd29f526d6a8eb0b206dd18b", + "cardId": "d7b631c8-0ffe-499f-a661-93869e4d3454", + "country": "CZE", + "createdAt": 1670426311349, + "networkFee": "9.89000000", + "providerBuyAssetId": "eth", + "providerCustomerId": "271170dd-8db6-472c-9828-67e0df5b609a", + "providerId": "idmoonpay", + "providerSellAssetId": "czk", + "rate": "30224.43037975", + "sellAmount": "5000.25000000", + "sellAsset": "CZK", + "status": "finished", + "transactionFee": "214.90000000", + "zelid": "1CbErtneaX2QVyUfwU7JGB7VzvPgrgc3uC", + "providerCardId": "d7b631c8-0ffe-499f-a661-93869e4d3454" + } + }); + const res = await assetApi.sendPurchase(request, res); + expect(res).to.have.property('status'); + expect(res).to.have.property('data'); + expect(res.data).to.have.property('purchaseId'); + expect(res.data).to.have.property('buyAddress'); + expect(res.data).to.have.property('buyAmount'); + expect(res.data).to.have.property('buyAsset'); + expect(res.data).to.have.property('buyTxid'); + expect(res.data).to.have.property('cardId'); + expect(res.data).to.have.property('country'); + + expect(res.data).to.have.property('createdAt'); + expect(res.data).to.have.property('networkFee'); + expect(res.data).to.have.property('providerBuyAssetId'); + expect(res.data).to.have.property('providerCustomerId'); + expect(res.data).to.have.property('providerId'); + expect(res.data).to.have.property('providerSellAssetId'); + expect(res.data).to.have.property('rate'); + + expect(res.data).to.have.property('sellAmount'); + expect(res.data).to.have.property('sellAsset'); + expect(res.data).to.have.property('status'); + expect(res.data).to.have.property('transactionFee'); + expect(res.data).to.have.property('zelid'); + expect(res.data).to.have.property('providerCardId'); + }); + + it('should return getAllPurchase successful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'GET', + url: 'test', + params: { + zelid: "1BoatSLRHtKNngkdXEeobR76b53LETtpyT" + } + }); + const response = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await sinon + .stub(assetApi, 'getAllPurchase') + .returns({ + "status": "success", + "data": [{ + "purchaseId": "58f9cce7-abcb-4468-96f1-d0bc75000ec4", + "buyAddress": "0x88ede65cb154660a84d996467bdef80e17de1576", + "buyAmount": "0.15800000", + "buyAsset": "ethereum", + "buyTxid": "0x978458e5dc7d3f449051da2e6be702df754370e4fd29f526d6a8eb0b206dd18b", + "cardId": "d7b631c8-0ffe-499f-a661-93869e4d3454", + "country": "CZE", + "createdAt": 1670426311349, + "networkFee": "9.89000000", + "providerBuyAssetId": "eth", + "providerCustomerId": "271170dd-8db6-472c-9828-67e0df5b609a", + "providerId": "idmoonpay", + "providerSellAssetId": "czk", + "rate": "30224.43037975", + "sellAmount": "5000.25000000", + "sellAsset": "CZK", + "status": "finished", + "transactionFee": "214.90000000", + "zelid": "1CbErtneaX2QVyUfwU7JGB7VzvPgrgc3uC", + "providerCardId": "d7b631c8-0ffe-499f-a661-93869e4d3454" + }] + }); + const res = await assetApi.getAllPurchase(request, res); + expect(res).to.have.property('status'); + expect(res).to.have.property('data'); + expect(res.data[0]).to.have.property('purchaseId'); + expect(res.data[0]).to.have.property('buyAddress'); + expect(res.data[0]).to.have.property('buyAmount'); + expect(res.data[0]).to.have.property('buyAsset'); + expect(res.data[0]).to.have.property('buyTxid'); + expect(res.data[0]).to.have.property('cardId'); + expect(res.data[0]).to.have.property('country'); + + expect(res.data[0]).to.have.property('createdAt'); + expect(res.data[0]).to.have.property('networkFee'); + expect(res.data[0]).to.have.property('providerBuyAssetId'); + expect(res.data[0]).to.have.property('providerCustomerId'); + expect(res.data[0]).to.have.property('providerId'); + expect(res.data[0]).to.have.property('providerSellAssetId'); + expect(res.data[0]).to.have.property('rate'); + + expect(res.data[0]).to.have.property('sellAmount'); + expect(res.data[0]).to.have.property('sellAsset'); + expect(res.data[0]).to.have.property('status'); + expect(res.data[0]).to.have.property('transactionFee'); + expect(res.data[0]).to.have.property('zelid'); + expect(res.data[0]).to.have.property('providerCardId'); + }); + + it('should return getAllPurchaseDetails successful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'POST', + url: 'test', + data: { + sellAsset: "EUR", + buyAsset: "litecoin" + } + }); + const response = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await sinon + .stub(assetApi, 'getAllPurchaseDetails') + .returns({ + "status": "success", + "data": { + "buyAsset": "litecoin", + "sellAsset": "EUR", + "providers": [ + { + "providerId": "idmoonpay", + "minSellAmount": "30.00000000", + "maxSellAmount": "10000.00000000", + "rate": "62.27019339", + "precision": "2", + "networkFee": "0.06000000", + "transactionFee": "3.99000000" + } + ] + } + }); + const res = await assetApi.getAllPurchaseDetails(request, res); + expect(res).to.have.property('status'); + expect(res).to.have.property('data'); + expect(res.data).to.have.property('buyAsset'); + expect(res.data).to.have.property('sellAsset'); + expect(res.data.providers[0]).to.have.property('providerId'); + expect(res.data.providers[0]).to.have.property('minSellAmount'); + expect(res.data.providers[0]).to.have.property('maxSellAmount'); + expect(res.data.providers[0]).to.have.property('rate'); + expect(res.data.providers[0]).to.have.property('precision'); + expect(res.data.providers[0]).to.have.property('networkFee'); + expect(res.data.providers[0]).to.have.property('transactionFee'); + }); + + it('should return getPurchaseDetailsOnSelectedAsset successful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'POST', + url: 'test', + data: { + sellAsset: "EUR", + buyAsset: "litecoin", + sellAmount: "450.00" + } + }); + const response = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await sinon + .stub(assetApi, 'getPurchaseDetailsOnSelectedAsset') + .returns({ + "status": "success", + "data": { + "buyAsset": "litecoin", + "sellAsset": "EUR", + "providers": [ + { + "providerId": "idmoonpay", + "minSellAmount": "30.00000000", + "maxSellAmount": "10000.00000000", + "sellAmount": "450.00", + "buyAmount": "6.901", + "rate": "62.38709614", + "precision": "2", + "networkFee": "0.06000000", + "transactionFee": "19.38000000" + } + ] + } + }); + const res = await assetApi.getPurchaseDetailsOnSelectedAsset(request, res); + expect(res).to.have.property('status'); + expect(res).to.have.property('data'); + expect(res.data).to.have.property('buyAsset'); + expect(res.data).to.have.property('sellAsset'); + expect(res.data.providers[0]).to.have.property('providerId'); + expect(res.data.providers[0]).to.have.property('minSellAmount'); + expect(res.data.providers[0]).to.have.property('maxSellAmount'); + expect(res.data.providers[0]).to.have.property('sellAmount'); + expect(res.data.providers[0]).to.have.property('buyAmount'); + expect(res.data.providers[0]).to.have.property('rate'); + expect(res.data.providers[0]).to.have.property('precision'); + expect(res.data.providers[0]).to.have.property('networkFee'); + expect(res.data.providers[0]).to.have.property('transactionFee'); + }); + + it('should return createPurchaseDetails successful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'POST', + url: 'test', + params: { + zelid: "1BoatSLRHtKNngkdXEeobR76b53LETtpyT" + }, + data: { + providerId: "idmoonpay", + sellAsset: "USD", + buyAsset: "bitcoin", + sellAmount: "300", + buyAddress: "1CbErtneaX2QVyUfwU7JGB7VzvPgrgc3uC" + } + }); + const response = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await sinon + .stub(assetApi, 'createPurchaseDetails') + .returns({ + "status": "success", + "data": { + "providerId": "idmoonpay", + "zelid": "1BoatSLRHtKNngkdXEeobR76b53LETtpyT", + "createdAt": 1671365683080, + "status": "new", + "sellAsset": "USD", + "providerSellAssetId": "usd", + "buyAsset": "bitcoin", + "providerBuyAssetId": "btc", + "buyAddress": "1CbErtneaX2QVyUfwU7JGB7VzvPgrgc3uC", + "buyAddressExtraId": null, + "sellAmount": "300.00", + "buyAmount": "0.01657", + "rate": "17313.08623661", + "widget": "https://buy-sandbox.moonpay.com?apiKey=pk_test_1LCSMjhCP0H5FSywT0MJSPPNjLmJvv&theme=dark¤cyCode=btc&baseCurrencyCode=usd&walletAddress=1CbErtneaX2QVyUfwU7JGB7VzvPgrgc3uC&baseCurrencyAmount=300.00&walletAddressTag=1BoatSLRHtKNngkdXEeobR76b53LETtpyT&redirectURL=zel%3A&colorCode=#C556E2&signature=38770a45323a97a63aef2f0c0875af2a95d49305971078882cebec986491517e" + } + }); + const res = await assetApi.createPurchaseDetails(request, res); + expect(res).to.have.property('status'); + expect(res).to.have.property('data'); + expect(res.data).to.have.property('providerId'); + expect(res.data).to.have.property('zelid'); + expect(res.data).to.have.property('status'); + expect(res.data).to.have.property('sellAsset'); + expect(res.data).to.have.property('providerSellAssetId'); + expect(res.data).to.have.property('buyAsset'); + expect(res.data).to.have.property('providerBuyAssetId'); + expect(res.data).to.have.property('buyAddress'); + expect(res.data).to.have.property('buyAddressExtraId'); + expect(res.data).to.have.property('sellAmount'); + expect(res.data).to.have.property('buyAmount'); + expect(res.data).to.have.property('rate'); + expect(res.data).to.have.property('widget'); + }); + + it('should return createPurchaseDetails successful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'POST', + url: 'test', + data: { + providerId: "idmoonpay", + purchaseId: "58f9cce7-abcb-4468-96f1-d0bc75000ec4" + } + }); + const response = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await sinon + .stub(assetApi, 'createPurchaseDetails') + .returns({ + "status": "success", + "data": "finished" + }); + const res = await assetApi.createPurchaseDetails(request, res); + expect(res).to.have.property('status'); + expect(res).to.have.property('data'); + }); + }); +}); From 881378cfecc2d9db8dc605ffdc7bee75e23d183c Mon Sep 17 00:00:00 2001 From: Robert Andasan Date: Mon, 25 Nov 2024 19:02:07 +0800 Subject: [PATCH 4/8] Added test cases for token --- tests/unit/tokenApi.spec.ts | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/unit/tokenApi.spec.ts diff --git a/tests/unit/tokenApi.spec.ts b/tests/unit/tokenApi.spec.ts new file mode 100644 index 0000000..7596472 --- /dev/null +++ b/tests/unit/tokenApi.spec.ts @@ -0,0 +1,46 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions */ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck test suite +import chai from 'chai'; +import tokenService from '../../src/services/tokenService'; +import tokenApi from '../../src/apiServices/tokenApi'; +import sinon from 'sinon'; +import httpMocks from 'node-mocks-http'; + +const { expect, assert } = chai; + +describe('Token API', function () { + describe('Token API: Correctly verifies asset data', function () { + afterEach(function () { + sinon.restore(); + }); + + it('should return getTokenInfo successful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'GET', + url: 'test', + params: { + network: "eth", + address: "0x455e53cbb86018ac2b8092fdcd39d8444affc3f6" + } + }); + await sinon + .stub(tokenApi, 'getTokenInfo') + .returns({ + decimal: "18", + logo: "http://eth.svg", + name: "Ethereum", + symbol: "eth" + }); + const response = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + const res = await tokenApi.getTokenInfo(request, res); + expect(res).to.have.property('decimal'); + expect(res).to.have.property('logo'); + expect(res).to.have.property('name'); + expect(res).to.have.property('symbol'); + }); + }); +}); From 14621853932232043a039c9083ef60260f05fc77 Mon Sep 17 00:00:00 2001 From: Robert Andasan Date: Mon, 25 Nov 2024 19:07:25 +0800 Subject: [PATCH 5/8] Cleanup --- tests/unit/assetApi.spec.ts | 3 +-- tests/unit/tokenApi.spec.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/unit/assetApi.spec.ts b/tests/unit/assetApi.spec.ts index 6b7656b..35af4a3 100644 --- a/tests/unit/assetApi.spec.ts +++ b/tests/unit/assetApi.spec.ts @@ -2,12 +2,11 @@ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck test suite import chai from 'chai'; -import assetService from '../../src/services/assetService'; import assetApi from '../../src/apiServices/assetApi'; import sinon from 'sinon'; import httpMocks from 'node-mocks-http'; -const { expect, assert } = chai; +const { expect } = chai; describe('Asset API', function () { describe('Asset API: Correctly verifies asset data', function () { diff --git a/tests/unit/tokenApi.spec.ts b/tests/unit/tokenApi.spec.ts index 7596472..37bac3e 100644 --- a/tests/unit/tokenApi.spec.ts +++ b/tests/unit/tokenApi.spec.ts @@ -2,12 +2,11 @@ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck test suite import chai from 'chai'; -import tokenService from '../../src/services/tokenService'; import tokenApi from '../../src/apiServices/tokenApi'; import sinon from 'sinon'; import httpMocks from 'node-mocks-http'; -const { expect, assert } = chai; +const { expect } = chai; describe('Token API', function () { describe('Token API: Correctly verifies asset data', function () { From c3e13af6f6dfcd6c64fcf53657f0e2c22f64ffad Mon Sep 17 00:00:00 2001 From: Robert Andasan Date: Mon, 25 Nov 2024 19:10:56 +0800 Subject: [PATCH 6/8] Cleanup --- tests/unit/assetApi.spec.ts | 12 ++++++------ tests/unit/tokenApi.spec.ts | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/unit/assetApi.spec.ts b/tests/unit/assetApi.spec.ts index 35af4a3..4d9191b 100644 --- a/tests/unit/assetApi.spec.ts +++ b/tests/unit/assetApi.spec.ts @@ -128,7 +128,7 @@ describe('Asset API', function () { "providerCardId": "d7b631c8-0ffe-499f-a661-93869e4d3454" } }); - const res = await assetApi.sendPurchase(request, res); + const res = await assetApi.sendPurchase(request, response); expect(res).to.have.property('status'); expect(res).to.have.property('data'); expect(res.data).to.have.property('purchaseId'); @@ -194,7 +194,7 @@ describe('Asset API', function () { "providerCardId": "d7b631c8-0ffe-499f-a661-93869e4d3454" }] }); - const res = await assetApi.getAllPurchase(request, res); + const res = await assetApi.getAllPurchase(request, response); expect(res).to.have.property('status'); expect(res).to.have.property('data'); expect(res.data[0]).to.have.property('purchaseId'); @@ -254,7 +254,7 @@ describe('Asset API', function () { ] } }); - const res = await assetApi.getAllPurchaseDetails(request, res); + const res = await assetApi.getAllPurchaseDetails(request, response); expect(res).to.have.property('status'); expect(res).to.have.property('data'); expect(res.data).to.have.property('buyAsset'); @@ -304,7 +304,7 @@ describe('Asset API', function () { ] } }); - const res = await assetApi.getPurchaseDetailsOnSelectedAsset(request, res); + const res = await assetApi.getPurchaseDetailsOnSelectedAsset(request, response); expect(res).to.have.property('status'); expect(res).to.have.property('data'); expect(res.data).to.have.property('buyAsset'); @@ -360,7 +360,7 @@ describe('Asset API', function () { "widget": "https://buy-sandbox.moonpay.com?apiKey=pk_test_1LCSMjhCP0H5FSywT0MJSPPNjLmJvv&theme=dark¤cyCode=btc&baseCurrencyCode=usd&walletAddress=1CbErtneaX2QVyUfwU7JGB7VzvPgrgc3uC&baseCurrencyAmount=300.00&walletAddressTag=1BoatSLRHtKNngkdXEeobR76b53LETtpyT&redirectURL=zel%3A&colorCode=#C556E2&signature=38770a45323a97a63aef2f0c0875af2a95d49305971078882cebec986491517e" } }); - const res = await assetApi.createPurchaseDetails(request, res); + const res = await assetApi.createPurchaseDetails(request, response); expect(res).to.have.property('status'); expect(res).to.have.property('data'); expect(res.data).to.have.property('providerId'); @@ -397,7 +397,7 @@ describe('Asset API', function () { "status": "success", "data": "finished" }); - const res = await assetApi.createPurchaseDetails(request, res); + const res = await assetApi.createPurchaseDetails(request, response); expect(res).to.have.property('status'); expect(res).to.have.property('data'); }); diff --git a/tests/unit/tokenApi.spec.ts b/tests/unit/tokenApi.spec.ts index 37bac3e..76e87b6 100644 --- a/tests/unit/tokenApi.spec.ts +++ b/tests/unit/tokenApi.spec.ts @@ -35,7 +35,7 @@ describe('Token API', function () { eventEmiiter: require('events').EventEmitter, req: request, }); - const res = await tokenApi.getTokenInfo(request, res); + const res = await tokenApi.getTokenInfo(request, response); expect(res).to.have.property('decimal'); expect(res).to.have.property('logo'); expect(res).to.have.property('name'); From 6c48797d2253a32d561f9824cad82d73bcabd433 Mon Sep 17 00:00:00 2001 From: Robert Andasan Date: Mon, 25 Nov 2024 19:38:08 +0800 Subject: [PATCH 7/8] Added test cases --- tests/unit/assetApi.spec.ts | 126 +++++++++++++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 3 deletions(-) diff --git a/tests/unit/assetApi.spec.ts b/tests/unit/assetApi.spec.ts index 4d9191b..9bbe926 100644 --- a/tests/unit/assetApi.spec.ts +++ b/tests/unit/assetApi.spec.ts @@ -155,6 +155,26 @@ describe('Asset API', function () { expect(res.data).to.have.property('providerCardId'); }); + it('should return sendPurchase unsuccessful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'GET', + url: 'test', + params: { + purchaseid: "58f9cce7-abcb-4468-96f1-d0bc75000ec4", + providerid: "idmoonpay" + } + }); + const response = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await assetApi.sendPurchase(request, response); + expect(JSON.parse(response._getData())).to.have.property('status'); + expect(JSON.parse(response._getData())).to.have.property('data'); + expect(JSON.parse(response._getData()).data).to.have.property('name'); + expect(JSON.parse(response._getData()).data).to.have.property('message'); + }); + it('should return getAllPurchase successful result if value is valid', async function () { const request = httpMocks.createRequest({ method: 'GET', @@ -221,6 +241,26 @@ describe('Asset API', function () { expect(res.data[0]).to.have.property('providerCardId'); }); + it('should return getAllPurchase unsuccessful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'GET', + url: 'test', + params: { + purchaseid: "58f9cce7-abcb-4468-96f1-d0bc75000ec4", + providerid: "idmoonpay" + } + }); + const response = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await assetApi.getAllPurchase(request, response); + expect(JSON.parse(response._getData())).to.have.property('status'); + expect(JSON.parse(response._getData())).to.have.property('data'); + expect(JSON.parse(response._getData()).data).to.have.property('name'); + expect(JSON.parse(response._getData()).data).to.have.property('message'); + }); + it('should return getAllPurchaseDetails successful result if value is valid', async function () { const request = httpMocks.createRequest({ method: 'POST', @@ -268,6 +308,26 @@ describe('Asset API', function () { expect(res.data.providers[0]).to.have.property('transactionFee'); }); + it('should return getAllPurchaseDetails unsuccessful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'GET', + url: 'test', + params: { + purchaseid: "58f9cce7-abcb-4468-96f1-d0bc75000ec4", + providerid: "idmoonpay" + } + }); + const response = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await assetApi.getAllPurchaseDetails(request, response); + expect(JSON.parse(response._getData())).to.have.property('status'); + expect(JSON.parse(response._getData())).to.have.property('data'); + expect(JSON.parse(response._getData()).data).to.have.property('name'); + expect(JSON.parse(response._getData()).data).to.have.property('message'); + }); + it('should return getPurchaseDetailsOnSelectedAsset successful result if value is valid', async function () { const request = httpMocks.createRequest({ method: 'POST', @@ -320,6 +380,26 @@ describe('Asset API', function () { expect(res.data.providers[0]).to.have.property('transactionFee'); }); + it('should return getPurchaseDetailsOnSelectedAsset unsuccessful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'GET', + url: 'test', + params: { + purchaseid: "58f9cce7-abcb-4468-96f1-d0bc75000ec4", + providerid: "idmoonpay" + } + }); + const response = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await assetApi.getPurchaseDetailsOnSelectedAsset(request, response); + expect(JSON.parse(response._getData())).to.have.property('status'); + expect(JSON.parse(response._getData())).to.have.property('data'); + expect(JSON.parse(response._getData()).data).to.have.property('name'); + expect(JSON.parse(response._getData()).data).to.have.property('message'); + }); + it('should return createPurchaseDetails successful result if value is valid', async function () { const request = httpMocks.createRequest({ method: 'POST', @@ -378,7 +458,27 @@ describe('Asset API', function () { expect(res.data).to.have.property('widget'); }); - it('should return createPurchaseDetails successful result if value is valid', async function () { + it('should return createPurchaseDetails unsuccessful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'GET', + url: 'test', + params: { + purchaseid: "58f9cce7-abcb-4468-96f1-d0bc75000ec4", + providerid: "idmoonpay" + } + }); + const response = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await assetApi.createPurchaseDetails(request, response); + expect(JSON.parse(response._getData())).to.have.property('status'); + expect(JSON.parse(response._getData())).to.have.property('data'); + expect(JSON.parse(response._getData()).data).to.have.property('name'); + expect(JSON.parse(response._getData()).data).to.have.property('message'); + }); + + it('should return getAllPurchaseStatus successful result if value is valid', async function () { const request = httpMocks.createRequest({ method: 'POST', url: 'test', @@ -392,14 +492,34 @@ describe('Asset API', function () { req: request, }); await sinon - .stub(assetApi, 'createPurchaseDetails') + .stub(assetApi, 'getAllPurchaseStatus') .returns({ "status": "success", "data": "finished" }); - const res = await assetApi.createPurchaseDetails(request, response); + const res = await assetApi.getAllPurchaseStatus(request, response); expect(res).to.have.property('status'); expect(res).to.have.property('data'); }); + + it('should return getAllPurchaseStatus unsuccessful result if value is valid', async function () { + const request = httpMocks.createRequest({ + method: 'GET', + url: 'test', + params: { + purchaseid: "58f9cce7-abcb-4468-96f1-d0bc75000ec4", + providerid: "idmoonpay" + } + }); + const response = httpMocks.createResponse({ + eventEmiiter: require('events').EventEmitter, + req: request, + }); + await assetApi.getAllPurchaseStatus(request, response); + expect(JSON.parse(response._getData())).to.have.property('status'); + expect(JSON.parse(response._getData())).to.have.property('data'); + expect(JSON.parse(response._getData()).data).to.have.property('name'); + expect(JSON.parse(response._getData()).data).to.have.property('message'); + }); }); }); From b01c9ce6a4ea56e45b413bd8b4f1054be0fe87bc Mon Sep 17 00:00:00 2001 From: Robert Andasan Date: Fri, 13 Dec 2024 20:52:51 +0800 Subject: [PATCH 8/8] Added provider list get --- src/apiServices/assetApi.ts | 44 ++++++++++++++++++++++++++++-------- src/routes.ts | 4 ++++ src/services/assetService.ts | 10 ++++++++ 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/apiServices/assetApi.ts b/src/apiServices/assetApi.ts index bd01b5a..cd98f87 100644 --- a/src/apiServices/assetApi.ts +++ b/src/apiServices/assetApi.ts @@ -8,7 +8,8 @@ import { getPurchaseDetails, getPurchaseDetailsSelectedAsset, createPurchase, - getPurchaseStatus + getPurchaseStatus, + getProviders } from '../services/assetService'; async function getFiatAssets(req, res) { @@ -31,6 +32,16 @@ async function getCryptoAssets(req, res) { } } +async function getAssetProviders(req, res) { + try { + const value = await getProviders(); + res.json(value); + } catch (error) { + log.error(error); + res.sendStatus(404); + } +} + async function getPurchaseDetailsByPurchaseId(req, res) { try { let { purchaseid } = req.params; @@ -74,8 +85,11 @@ async function getAllPurchase(req, res) { async function getAllPurchaseDetails(req, res) { try { - const data = req.data; - const value = await getPurchaseDetails(data); + let body = ''; + await req.on('data', (data) => { + body += data; + }); + const value = await getPurchaseDetails(body); res.json(value); } catch (error) { log.error(error); @@ -85,8 +99,11 @@ async function getAllPurchaseDetails(req, res) { async function getPurchaseDetailsOnSelectedAsset(req, res) { try { - const data = req.data; - const value = await getPurchaseDetailsSelectedAsset(data); + let body = ''; + await req.on('data', (data) => { + body += data; + }); + const value = await getPurchaseDetailsSelectedAsset(body); res.json(value); } catch (error) { log.error(error); @@ -96,12 +113,15 @@ async function getPurchaseDetailsOnSelectedAsset(req, res) { async function createPurchaseDetails(req, res) { try { - const data = req.data; + let body = ''; + await req.on('data', (data) => { + body += data; + }); let { zelid } = req.params; zelid = zelid ?? req.query.zelid; - const value = await createPurchase(data, zelid); + const value = await createPurchase(body, zelid); res.json(value); } catch (error) { log.error(error); @@ -111,8 +131,11 @@ async function createPurchaseDetails(req, res) { async function getAllPurchaseStatus(req, res) { try { - const data = req.data; - const value = await getPurchaseStatus(data); + let body = ''; + await req.on('data', (data) => { + body += data; + }); + const value = await getPurchaseStatus(body); res.json(value); } catch (error) { log.error(error); @@ -130,5 +153,6 @@ export default { getAllPurchaseDetails, getPurchaseDetailsOnSelectedAsset, createPurchaseDetails, - getAllPurchaseStatus + getAllPurchaseStatus, + getAssetProviders } \ No newline at end of file diff --git a/src/routes.ts b/src/routes.ts index 00185ac..d7b20ef 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -49,6 +49,10 @@ export default (app) => { app.get('/v1/assetinfo/assets/crypto', (req, res) => { assetApi.getCryptoAssets(req, res); }); + // get asset providers + app.get('/v1/assetinfo/assets/providers', (req, res) => { + assetApi.getAssetProviders(req, res); + }); // get purchase by id app.get('/v1/assetinfo/purchase/id/:purchaseid?', (req, res) => { assetApi.getPurchaseDetailsByPurchaseId(req, res); diff --git a/src/services/assetService.ts b/src/services/assetService.ts index fe9b94a..24ae69a 100644 --- a/src/services/assetService.ts +++ b/src/services/assetService.ts @@ -107,6 +107,16 @@ export async function getPurchaseStatus (data: any) { }; } +export async function getProviders () { + try { + const response = await axios.get('https://abe.zelcore.io/v1/purchases'); + return response.data; + } catch(error) { + console.log(error); + return {message: "Error occured in processing"}; + }; +} +