init commit

This commit is contained in:
2025-11-07 22:24:40 +01:00
parent a5373286bf
commit 15b8f36d4d
217 changed files with 168229 additions and 0 deletions

264
README.md
View File

@@ -0,0 +1,264 @@
# Cryptocurrency Exchange Platform
A comprehensive cryptocurrency exchange server built with Node.js, TypeScript, and Express. This platform supports trading of Bitcoin, Ethereum, and Tron cryptocurrencies with Iranian Rial (IRR) support.
## Features
- **Multi-Cryptocurrency Support**: Bitcoin (BTC), Ethereum (ETH), and Tron (TRX)
- **User Authentication**: Email and phone verification, session management
- **Wallet Management**: Secure wallet operations with support for multiple cryptocurrencies
- **Trading System**: Buy/sell orders, offer management, and order matching
- **Price Statistics**: Real-time and historical price data (hourly, daily, weekly, monthly, yearly)
- **Real-time Updates**: WebSocket integration via Socket.io for live updates
- **Admin Panel**: Administrative tools for managing the exchange
- **Support Tickets**: Integrated ticketing system for customer support
- **Automated Backups**: Daily database backups
- **Rate Limiting**: Brute force protection and rate limiting
## Tech Stack
- **Runtime**: Node.js
- **Language**: TypeScript
- **Framework**: Express.js
- **Database**: MongoDB (Mongoose)
- **Cache**: Redis
- **Message Queue**: AMQP (RabbitMQ)
- **Real-time**: Socket.io
- **Blockchain Libraries**:
- `bitcoin-core` for Bitcoin
- `web3` and `ethereumjs-tx` for Ethereum
- `tronweb` for Tron
- **Other**: Winston (logging), Nodemailer (emails), bcrypt (hashing)
## Prerequisites
- Node.js (v14 or higher)
- MongoDB
- Redis
- RabbitMQ (AMQP)
- TypeScript
## Installation
1. Clone the repository:
```bash
git clone <repository-url>
cd Exchange
```
2. Navigate to the server directory:
```bash
cd server
```
3. Install dependencies:
```bash
npm install
```
4. Create a `.env` file in the server directory with the following variables:
```env
# Database
MONGO_DATABASE=mongodb://localhost:27017/exchange
MONGO_DATABASE_NAME_TICKETS=trudesk
# Session
SESSION_SECRET=your-session-secret-key
# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
# REDIS_PASS=your-redis-password
# AMQP (RabbitMQ)
AMQP_URL=amqp://localhost
# Email (Nodemailer)
NODEMAILER_HOST=smtp.gmail.com
NODEMAILER_PORT=587
NODEMAILER_USER=your-email@gmail.com
NODEMAILER_PASS=your-email-password
SENDER_ADDRESS=your-email@gmail.com
# API
API=http://localhost:3001
# External APIs
CURRENCY_API_KEY=your-nomics-api-key
SMS_API_ACCESS_KEY=your-sms-api-key
SMS_API_PHONE_PATTERN_CODE=your-sms-pattern-code
SMS_API_DEFINITE_SENDER_NUMBER=your-sms-sender-number
# Ticket System
TICKET_START_CONVERSATION=your-ticket-api-url
TICKET_GET_MESSAGES_URL=your-ticket-api-url
TICKET_CREATE_TICKET_URL=your-ticket-api-url
TICKET_ADD_COMMENT_URL=your-ticket-api-url
TICKET_SEND_MESSAGE_URL=your-ticket-api-url
SUPPORT_ROLE_ID=your-support-role-id
USER_ROLE_ID=your-user-role-id
ACCESS_TOKEN=your-access-token
# Crypto
CRYPTO_SECRET=your-crypto-secret
SALT_I=10
OBJECTID_RIAL=your-rial-currency-object-id
# Feature Flags
BUYFROMOFFERS=true
# Chart
CHART_LIMIT=20
# Test
TEST_API_URL=http://localhost:3001
NODE_ENV=development
```
5. Compile TypeScript (if needed):
```bash
npx tsc
```
## Running the Application
### Development Mode
```bash
npm start
```
The server will start on `http://localhost:3001`
### Test Mode
```bash
npm run test-env
```
### Running Tests
```bash
npm test
```
## Project Structure
```
server/
├── api/ # API utilities and integrations
│ ├── walletApi/ # Blockchain wallet APIs (Bitcoin, Ethereum, Tron)
│ ├── amqp.ts # AMQP message queue configuration
│ ├── logger.ts # Winston logger configuration
│ ├── redis.ts # Redis client configuration
│ └── socket.ts # Socket.io configuration
├── db/ # Database models and schemas
│ ├── user.ts # User model
│ ├── currencies.ts # Currency model
│ ├── activeOffers.ts # Active trading offers
│ ├── acceptedOffers.ts # Accepted offers
│ └── ... # Other models
├── middlewares/ # Express middlewares
│ ├── auth.ts # Authentication middleware
│ ├── validation.ts # Request validation
│ ├── errorHandler.ts # Error handling
│ └── preventBruteForce.ts # Rate limiting
├── routes/ # API routes
│ ├── auth.ts # Authentication routes
│ ├── user.ts # User routes
│ ├── wallet.ts # Wallet routes
│ ├── admin.ts # Admin routes
│ ├── service.ts # Service routes
│ └── tickets.ts # Support ticket routes
├── scripts/ # Utility scripts
│ ├── priceStats.ts # Price statistics
│ ├── currenciesadder.ts # Currency management
│ └── localPriceScript.ts # Local price tracking
└── test/ # Test files
```
## API Endpoints
### Authentication (`/auth`)
- `GET /auth` - Check authentication status
- `POST /register` - User registration
- `POST /login` - User login
- `GET /logout` - User logout
- `POST /verify` - Verify email/phone
### User (`/user`)
- `GET /getUserWallet` - Get user wallet balance
- `GET /getUserOffers` - Get user's trading offers
- `POST /createOffer` - Create a new trading offer
- `GET /getUserTransactions` - Get user transaction history
### Wallet (`/wallet`)
- `GET /getEtheriumNonce` - Get Ethereum nonce
- `POST /transferToExchange` - Transfer cryptocurrency to exchange
- `POST /transferFromExchange` - Transfer cryptocurrency from exchange
- `POST /transferToExchangeById` - Transfer by transaction ID
### Service (`/service`)
- `GET /getDeafultAcceptedOffers` - Get default accepted offers
- `GET /getPriceChart` - Get price chart data
- `GET /getCurrencies` - Get supported currencies
### Admin (`/admin`)
- Admin-specific endpoints for managing the exchange
### Tickets (`/tickets`)
- Support ticket management endpoints
## Key Features
### Automated Tasks
- Daily database backups (runs at 11:59 PM)
- Continuous price statistics updates
- Local price tracking (hourly, daily, weekly, monthly, yearly)
- Dollar to Rial price updates
### Security
- Session-based authentication
- CSRF protection
- Rate limiting and brute force protection
- Password hashing with bcrypt
- Input validation
### Real-time Features
- Socket.io for real-time updates
- Online user tracking
- Live price updates
## Logging
The application uses Winston for logging. Logs are written to:
- `combined.log` - All logs
- `error.log` - Error logs
- `exceptions.log` - Uncaught exceptions
## Database
The application uses MongoDB with the following main databases:
- `exchange` - Main application data
- `trudesk` - Support ticket system
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Write tests if applicable
5. Submit a pull request
## License
MIT
## Notes
- Make sure MongoDB, Redis, and RabbitMQ are running before starting the server
- Configure all environment variables in the `.env` file
- The application includes automated backup scripts that run daily
- Price statistics are updated continuously for real-time trading data

BIN
server/.DS_Store vendored Normal file

Binary file not shown.

57
server/.env Executable file
View File

@@ -0,0 +1,57 @@
#API address
API=http://localhost:3001
#session
SESSION_SECRET=test
#mongo
MONGO_SECRET=aaaaa
MONGO_DATABASE=mongodb://localhost:27017/exchange
SALT_I=10
MONGO_DATABASE_NAME=exchange
#nodemailer
NODEMAILER_HOST=mail.polychain.ir
NODEMAILER_PORT=465
NODEMAILER_USER=admin@polychain.ir
NODEMAILER_PASS=@polychainAdmin
SENDER_ADDRESS=<admin@polychain.ir>
#AMQP
AMQP_URL=amqp://guest:guest@localhost
#REDIS
REDIS_PORT=6379
REDIS_HOST=localhost
CRYPTO_SECRET=abcde
BUYFROMOFFERS=true
MONGO_DATABASE_NAME_TICKETS=trudesk
TICKET_GET_MESSAGES_URL=http://localhost:8118/api/v1/users/create
TICKET_CREATE_TICKET_URL=http://localhost:8118/api/v1/tickets/create
TICKET_ADD_COMMENT_URL=http://localhost:8118/api/v1/tickets/addcomment
TICKET_TICKET_URL=http://localhost:8118/api/v1/tickets/
ACCESS_TOKEN=556a5e513dc8a4e3c0b1643886a9cf3f636b1945
SUPPORT_ROLE_ID=5fb21707795091261c6d2194
USER_ROLE_ID=5fb21707795091261c6d2192
# CURRENCY_API
CURRENCY_API_KEY=6ba4711649395555617a5bd91a416dac
process.env.ADMIN_ETHERIUM_ACCOUNT_ADDRESS=0x868453967f6806ef86de7cf5e57a32ab28b875b4
process.env.ADMIN_ETHERIUM_ACCOUNT_PASSWORD=exchange
process.env.CLIENT_ETHERIUM_ACCOUNT_ADDRESS=0xC1BC3cB61722c959030aF512883F2E884baF5702
process.env.CLIENT_ETHERIUM_ACCOUNT_PRIVATE_KEY=64061456066baa81c5097c895b5176fb3e1452eaf6f6776e2d7bf07ddb9accfe
# ObjectIDS
OBJECTID_RIAL=5f719d994923c95630df06be
CHART_LIMIT=20

100
server/api/amqp.js Executable file
View File

@@ -0,0 +1,100 @@
'use strict';
exports.__esModule = true;
exports.publishQueueConnection = void 0;
// This script fetches queued messages from RabbitMQ and delivers these to SMTP
var nodemailer = require("nodemailer");
var amqp = require("amqp");
var queueHost = process.env.AMQP_URL;
var queueName = 'outgoing';
var smtpHost = {
host: process.env.NODEMAILER_HOST,
port: process.env.NODEMAILER_PORT,
// NB! Must be pooled connection, otherwise 'idle' is never fired and nothing gets sent
pool: true,
auth: {
user: process.env.NODEMAILER_USER,
pass: process.env.NODEMAILER_PASS
},
tls: {
// testserver uses self signed certificate, so we need to lax a bit
rejectUnauthorized: false
},
logger: false
};
// array of prefetched messages waiting for delivery
var waiting = [];
// Create a SMTP transporter object
var transporter = nodemailer.createTransport(smtpHost, {
// default message fields
from: process.env.SENDER_ADDRESS
});
// Create connection to RabbitMQ
var queueConnection = amqp.createConnection({
url: queueHost
});
queueConnection.on('error', function (e) {
console.log('Error from amqp: ', e);
});
queueConnection.on('ready', function (err) {
console.log('AMPQ server is running on port 5672.');
queueConnection.queue(queueName, { durable: true }, function (q) {
q.bind('#');
q.subscribe({
ack: true,
prefetchCount: 10 // prefetch 10 messages
}, function (message, headers, deliveryInfo, ack) {
// check if the message object is even valid
if (!message || !message.to) {
console.log('Invalid message, skipping');
// reject, do not requeue
return ack.reject();
}
// push to cache
waiting.push({
message: message,
deliveryTag: deliveryInfo.deliveryTag.toString('hex'),
ack: ack
});
// try to flush cached messages by sending these to SMTP
flushWaitingMessages();
});
});
});
// Whenever transporter gets into idling, try to send some mail
transporter.on('idle', flushWaitingMessages);
// Flushes cached messages to nodemailer for delivery
function flushWaitingMessages() {
// actual send function
var send = function (data) {
// sendMail does not immediatelly send, instead it tries to allocate a free connection to SMTP server
// and if fails, then pushes the message into internal queue. As we only prefetch 10 messages
// then the internal queue can never grow into something too large. At most there will be 5 messages
// idling in the queue (another 5 are being currently sent by the default number of 5 connections)
transporter.sendMail(data.message, function (err, info) {
if (err) {
console.log('Message failed (%s): %s', data.deliveryTag, err.message);
// reject and requeue on error (wait 1 sec. before requeueing)
// NB! If the failure is permanent then this approach results in an
// infinite loop since failing message is never removed from the queue
setTimeout(function () {
data.ack.reject(true);
}, 1000);
return;
}
console.log('Message delivered (%s): %s', data.deliveryTag, info.response);
data.ack.acknowledge();
});
};
// send cached messages if transporter is idling
while (transporter.isIdle() && waiting.length) {
send(waiting.shift());
}
}
exports.publishQueueConnection = function (mailOptions) {
console.log('publishQueueConnection');
queueConnection.publish(queueName, mailOptions, function (err) {
if (err) {
console.log(err);
}
});
};

112
server/api/amqp.ts Executable file
View File

@@ -0,0 +1,112 @@
'use strict'
// This script fetches queued messages from RabbitMQ and delivers these to SMTP
import * as nodemailer from 'nodemailer'
import * as amqp from 'amqp'
const queueHost = process.env.AMQP_URL
const queueName = 'outgoing'
const smtpHost = {
host: process.env.NODEMAILER_HOST,
port: process.env.NODEMAILER_PORT,
// NB! Must be pooled connection, otherwise 'idle' is never fired and nothing gets sent
pool: true,
auth: {
user: process.env.NODEMAILER_USER,
pass: process.env.NODEMAILER_PASS
},
tls: {
// testserver uses self signed certificate, so we need to lax a bit
rejectUnauthorized: false
},
logger: false
}
// array of prefetched messages waiting for delivery
const waiting = []
// Create a SMTP transporter object
const transporter = nodemailer.createTransport(smtpHost, {
// default message fields
from: process.env.SENDER_ADDRESS
})
// Create connection to RabbitMQ
const queueConnection = amqp.createConnection({
url: queueHost
})
queueConnection.on('error', function (e) {
console.log('Error from amqp: ', e)
})
queueConnection.on('ready', function (err) {
console.log('AMPQ server is running on port 5672.')
queueConnection.queue(queueName, { durable: true }, function (q) {
q.bind('#')
q.subscribe({
ack: true, // do not fetch next messages until previous are acked
prefetchCount: 10 // prefetch 10 messages
}, function (message, headers, deliveryInfo, ack) {
// check if the message object is even valid
if (!message || !message.to) {
console.log('Invalid message, skipping')
// reject, do not requeue
return ack.reject()
}
// push to cache
waiting.push({
message: message,
deliveryTag: deliveryInfo.deliveryTag.toString('hex'),
ack: ack
})
// try to flush cached messages by sending these to SMTP
flushWaitingMessages()
})
})
})
// Whenever transporter gets into idling, try to send some mail
transporter.on('idle', flushWaitingMessages)
// Flushes cached messages to nodemailer for delivery
function flushWaitingMessages () {
// actual send function
var send = function (data) {
// sendMail does not immediatelly send, instead it tries to allocate a free connection to SMTP server
// and if fails, then pushes the message into internal queue. As we only prefetch 10 messages
// then the internal queue can never grow into something too large. At most there will be 5 messages
// idling in the queue (another 5 are being currently sent by the default number of 5 connections)
transporter.sendMail(data.message, function (err, info) {
if (err) {
console.log('Message failed (%s): %s', data.deliveryTag, err.message)
// reject and requeue on error (wait 1 sec. before requeueing)
// NB! If the failure is permanent then this approach results in an
// infinite loop since failing message is never removed from the queue
setTimeout(function () {
data.ack.reject(true)
}, 1000)
return
}
console.log('Message delivered (%s): %s', data.deliveryTag, info.response)
data.ack.acknowledge()
})
}
// send cached messages if transporter is idling
while (transporter.isIdle() && waiting.length) {
send(waiting.shift())
}
}
export const publishQueueConnection = (mailOptions) => {
console.log('publishQueueConnection')
queueConnection.publish(queueName, mailOptions, (err) => {
if (err) {
console.log(err)
}
})
}

46
server/api/logger.js Executable file
View File

@@ -0,0 +1,46 @@
"use strict";
exports.__esModule = true;
exports.LoggerStream = exports.logger = void 0;
var winston = require("winston");
var _a = winston.format, combine = _a.combine, timestamp = _a.timestamp, label = _a.label, prettyPrint = _a.prettyPrint, colorize = _a.colorize, json = _a.json, splat = _a.splat;
/// /////////////////////////////////////////////////////////////////////////////
/// ///////////////////////Winston Logger///////////////////////////////////////
/// ////////////////////////////////////////////////////////////////////////////
exports.logger = winston.createLogger({
exitOnError: false,
format: combine(timestamp(), prettyPrint(), colorize(), splat()),
level: 'info',
// format: winston.format.json(),
// defaultMeta: { service: 'user-service' },
transports: [
//
// - Write to all logs with level `info` and below to `combined.log`
// - Write all logs error (and below) to `error.log`.
//
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
],
exceptionHandlers: [
new winston.transports.File({ filename: 'exceptions.log' })
]
});
// if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'development') {
exports.logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
// }
// logger.stream = {
// write: function (message: string, encoding: any) {
// logger.info(message)
// }
// }
var LoggerStream = /** @class */ (function () {
function LoggerStream() {
}
LoggerStream.prototype.write = function (message) {
exports.logger.info(message);
};
return LoggerStream;
}());
exports.LoggerStream = LoggerStream;
//module.exports = logger

48
server/api/logger.ts Executable file
View File

@@ -0,0 +1,48 @@
import * as winston from 'winston'
const { combine, timestamp, label, prettyPrint, colorize, json, splat } = winston.format
/// /////////////////////////////////////////////////////////////////////////////
/// ///////////////////////Winston Logger///////////////////////////////////////
/// ////////////////////////////////////////////////////////////////////////////
export const logger = winston.createLogger({
exitOnError: false,
format: combine(
timestamp(),
prettyPrint(),
colorize(),
splat()
),
level: 'info',
// format: winston.format.json(),
// defaultMeta: { service: 'user-service' },
transports: [
//
// - Write to all logs with level `info` and below to `combined.log`
// - Write all logs error (and below) to `error.log`.
//
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
],
exceptionHandlers: [
new winston.transports.File({ filename: 'exceptions.log' })
]
})
// if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'development') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}))
// }
// logger.stream = {
// write: function (message: string, encoding: any) {
// logger.info(message)
// }
// }
export class LoggerStream {
write(message: string) {
logger.info(message);
}
}
//module.exports = logger

31
server/api/myError.js Executable file
View File

@@ -0,0 +1,31 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var myError = /** @class */ (function (_super) {
__extends(myError, _super);
function myError(messageEnglish, statusCode, clientCode, clientMessage, title) {
var _newTarget = this.constructor;
var _this = _super.call(this, messageEnglish) || this;
_this.messageEnglish = messageEnglish;
_this.statusCode = statusCode;
_this.clientCode = clientCode;
_this.clientMessage = clientMessage;
_this.title = title;
Object.setPrototypeOf(_this, _newTarget.prototype); // restore prototype chain
return _this;
}
return myError;
}(Error));
exports["default"] = myError;

25
server/api/myError.ts Executable file
View File

@@ -0,0 +1,25 @@
import { cli } from "winston/lib/winston/config";
export default class myError extends Error {
messageEnglish: string;
statusCode: Number;
clientCode: Number;
clientMessage: string;
title: string;
constructor(
messageEnglish ?: string,
statusCode?: Number,
clientCode?: Number,
clientMessage?: string,
title?: string
) {
super(messageEnglish);
this.messageEnglish = messageEnglish;
this.statusCode = statusCode;
this.clientCode = clientCode;
this.clientMessage = clientMessage;
this.title = title;
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
}
}

326
server/api/query.js Executable file
View File

@@ -0,0 +1,326 @@
"use strict";
exports.__esModule = true;
exports.searchOnActiveOffers = exports.searchOnTxs = void 0;
var redis = require("../api/redis");
var acceptedOffers_1 = require("../db/acceptedOffers");
var ActiveOffers_1 = require("../db/ActiveOffers");
exports.searchOnTxs = function (_a) {
var curId = _a.curId, txType = _a.txType, rial = _a.rial;
var itemsMap = new Map();
var items = ['curId'];
var definedItems = [];
itemsMap.set('curId', curId);
items.map(function (element) {
if (itemsMap.get(element)) {
definedItems.push(element);
}
});
var query = [];
var queryMap = new Map();
queryMap.set('curId', [{ $or: [
{ $and: [{ curGivenId: curId }, { curTakenId: rial._id }] },
{ $and: [{ curTakenId: curId }, { curGivenId: rial._id }] }
] }]);
var definedItemsMap = definedItems.map(function (element) {
query.push.apply(query, queryMap.get(element));
});
if (query.length === 0) {
query = [{ $or: [{ curTakenId: rial._id }, { curGivenId: rial._id }] }];
}
console.log('query: ', query);
return Promise.all(definedItemsMap)
.then(function () {
return acceptedOffers_1.Accepted_Offers.find({ $and: query })
.then(function (result) {
var modifiedResult = [];
if (itemsMap.get('curId')) {
return redis.hashGetAll(curId.toString())
.then(function (curObj) {
result.map(function (e) {
if (e.curTakenId.toString() === rial._id.toString() && txType === 'sell') {
modifiedResult.push({
GcurrencyName: curObj.currencyName,
GpersianName: curObj.per_name,
GshortName: curObj.ab_name,
Gvalue: e.curGivenVal,
Gicon: curObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curTakenVal,
Ticon: rial.icon,
txType: 'sell'
});
}
else if (e.curGivenId.toString() === rial._id.toString() && txType === 'buy') {
modifiedResult.push({
GcurrencyName: curObj.currencyName,
GpersianName: curObj.per_name,
GshortName: curObj.ab_name,
Gvalue: e.curTakenVal,
Gicon: curObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curGivenVal,
Ticon: rial.icon,
txType: 'buy'
});
}
else if (txType === 'all') {
if (e.curTakenId.toString() === rial._id.toString()) {
modifiedResult.push({
GcurrencyName: curObj.currencyName,
GpersianName: curObj.per_name,
GshortName: curObj.ab_name,
Gvalue: e.curGivenVal,
Gicon: curObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curTakenVal,
Ticon: rial.icon,
txType: 'sell'
});
}
else if (e.curGivenId.toString() === rial._id.toString()) {
modifiedResult.push({
GcurrencyName: curObj.currencyName,
GpersianName: curObj.per_name,
GshortName: curObj.ab_name,
Gvalue: e.curTakenVal,
Gicon: curObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curGivenVal,
Ticon: rial.icon,
txType: 'buy'
});
}
}
});
return modifiedResult;
})["catch"](function (err) {
throw err;
});
}
else {
var resultMap = result.map(function (e) {
console.log('eeeeeeeee: ', e);
if (e.curTakenId.toString() === rial._id.toString() && txType === 'sell') {
return redis.hashGetAll(e.curGivenId.toString())
.then(function (curGivenObj) {
modifiedResult.push({
GcurrencyName: curGivenObj.currencyName,
GpersianName: curGivenObj.per_name,
GshortName: curGivenObj.ab_name,
Gvalue: e.curGivenVal,
Gicon: curGivenObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curTakenVal,
Ticon: rial.icon,
txType: 'sell'
});
})["catch"](function (err) {
console.log(err);
});
}
else if (e.curGivenId.toString() === rial._id.toString() && txType === 'buy') {
return redis.hashGetAll(e.curTakenId.toString())
.then(function (curTakenObj) {
modifiedResult.push({
GcurrencyName: curTakenObj.currencyName,
GpersianName: curTakenObj.per_name,
GshortName: curTakenObj.ab_name,
Gvalue: e.curTakenVal,
Gicon: curTakenObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curGivenVal,
Ticon: rial.icon,
txType: 'buy'
});
})["catch"](function (err) {
console.log(err);
});
}
else if (txType === 'all') {
if (e.curTakenId.toString() === rial._id.toString()) {
return redis.hashGetAll(e.curGivenId.toString())
.then(function (curGivenObj) {
modifiedResult.push({
GcurrencyName: curGivenObj.currencyName,
GpersianName: curGivenObj.per_name,
GshortName: curGivenObj.ab_name,
Gvalue: e.curGivenVal,
Gicon: curGivenObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curTakenVal,
Ticon: rial.icon,
txType: 'sell'
});
})["catch"](function (err) {
console.log(err);
});
}
else if (e.curGivenId.toString() === rial._id.toString()) {
return redis.hashGetAll(e.curTakenId.toString())
.then(function (curTakenObj) {
modifiedResult.push({
GcurrencyName: curTakenObj.currencyName,
GpersianName: curTakenObj.per_name,
GshortName: curTakenObj.ab_name,
Gvalue: e.curTakenVal,
Gicon: curTakenObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curGivenVal,
Ticon: rial.icon,
txType: 'buy'
});
})["catch"](function (err) {
console.log(err);
});
}
}
});
return Promise.all(resultMap)
.then(function () {
return modifiedResult;
})["catch"](function (err) {
throw err;
});
}
})["catch"](function (err) {
throw err;
});
})["catch"](function (err) {
throw err;
});
};
exports.searchOnActiveOffers = function (_a) {
var offerId = _a.offerId, curGivenId = _a.curGivenId, curGivenVal = _a.curGivenVal, curTakenId = _a.curTakenId, curTakenVal = _a.curTakenVal, expDate = _a.expDate, created_at = _a.created_at;
var itemsMap = new Map();
var items = ['offerId', 'curGivenId', 'curGivenVal', 'curTakenId', 'curTakenVal', 'expDate', 'created_at'];
var definedItems = [];
itemsMap.set('offerId', offerId);
itemsMap.set('curGivenId', curGivenId);
itemsMap.set('curGivenVal', curGivenVal);
itemsMap.set('curTakenId', curTakenId);
itemsMap.set('curTakenVal', curTakenVal);
itemsMap.set('expDate', expDate);
itemsMap.set('created_at', created_at);
items.map(function (element) {
if (itemsMap.get(element)) {
if (element === 'expDate') {
if (expDate.from || expDate.to) {
definedItems.push(element);
}
}
else if (element === 'created_at') {
if (created_at.from || created_at.to) {
definedItems.push(element);
}
}
else if (element === 'curGivenVal') {
if (curGivenVal.from || curGivenVal.to) {
definedItems.push(element);
}
}
else if (element === 'curTakenVal') {
if (curTakenVal.from || curTakenVal.to) {
definedItems.push(element);
}
}
else {
definedItems.push(element);
}
}
});
var query = [{ expDate: { $gt: Date.now() } }];
var queryMap = new Map();
var queryExpDate;
var queryCreatedAt;
var queryCurGivenVal;
var queryCurTakenVal;
if (definedItems.includes('expDate')) {
if (expDate.from && expDate.to) {
queryExpDate = { expDate: { $gt: expDate.from, $lt: expDate.to } };
}
else if (expDate.from && !expDate.to) {
queryExpDate = { expDate: { $gt: expDate.from } };
}
else if (!expDate.from && expDate.to) {
queryExpDate = { expDate: { $lt: expDate.to } };
}
}
if (definedItems.includes('created_at')) {
if (created_at.from && created_at.to) {
queryCreatedAt = { created_at: { $gt: created_at.from, $lt: created_at.to } };
}
else if (created_at.from && !created_at.to) {
queryCreatedAt = { created_at: { $gt: created_at.from } };
}
else if (!created_at.from && created_at.to) {
queryCreatedAt = { created_at: { $lt: created_at.to } };
}
}
if (definedItems.includes('curGivenVal')) {
if (curGivenVal.from && curGivenVal.to) {
queryCurGivenVal = { curGivenVal: { $gte: curGivenVal.from, $lte: curGivenVal.to } };
}
else if (curGivenVal.from && !curGivenVal.to) {
queryCurGivenVal = { curGivenVal: { $gte: curGivenVal.from } };
}
else if (!curGivenVal.from && curGivenVal.to) {
queryCurGivenVal = { curGivenVal: { $lte: curGivenVal.to } };
}
}
if (definedItems.includes('curTakenVal')) {
if (curTakenVal.from && curTakenVal.to) {
queryCurTakenVal = { curTakenVal: { $gte: curTakenVal.from, $lte: curTakenVal.to } };
}
else if (curTakenVal.from && !curTakenVal.to) {
queryCurTakenVal = { curTakenVal: { $gte: curTakenVal.from } };
}
else if (!curTakenVal.from && curTakenVal.to) {
queryCurTakenVal = { curTakenVal: { $lte: curTakenVal.to } };
}
}
queryMap.set('offerId', { offerId: offerId });
queryMap.set('curGivenId', { curGivenId: curGivenId });
queryMap.set('curGivenVal', queryCurGivenVal);
queryMap.set('curTakenId', { curTakenId: curTakenId });
queryMap.set('curTakenVal', queryCurTakenVal);
queryMap.set('expDate', queryExpDate);
queryMap.set('created_at', queryCreatedAt);
var definedItemsMap = definedItems.map(function (element) {
query.push(queryMap.get(element));
});
return Promise.all(definedItemsMap)
.then(function () {
return ActiveOffers_1.Active_Offers.find({ $and: query })
.then(function (result) {
return result;
})["catch"](function (err) {
throw err;
});
})["catch"](function (err) {
throw err;
});
};

334
server/api/query.ts Executable file
View File

@@ -0,0 +1,334 @@
import * as _ from 'lodash'
import * as redis from '../api/redis'
import { Accepted_Offers } from '../db/acceptedOffers';
import { Active_Offers } from '../db/ActiveOffers';
export const searchOnTxs = ({ curId, txType, rial }) => {
const itemsMap = new Map()
const items = ['curId']
const definedItems = []
itemsMap.set('curId', curId)
items.map((element) => {
if(itemsMap.get(element)) {
definedItems.push(element)
}
})
let query = []
let queryMap = new Map()
queryMap.set('curId', [ { $or: [
{ $and: [{ curGivenId: curId }, { curTakenId: rial._id } ] },
{ $and: [{ curTakenId: curId }, { curGivenId: rial._id } ] }
] } ] )
const definedItemsMap = definedItems.map((element) => {
query.push.apply(query, queryMap.get(element))
})
if(query.length === 0) {
query = [ { $or: [ { curTakenId: rial._id }, { curGivenId: rial._id } ] } ]
}
console.log('query: ', query)
return Promise.all(definedItemsMap)
.then(() => {
return Accepted_Offers.find({ $and: query })
.then((result) => {
let modifiedResult = []
if(itemsMap.get('curId')) {
return redis.hashGetAll(curId.toString())
.then((curObj: any) => {
result.map((e) => {
if (e.curTakenId.toString() === rial._id.toString() && txType === 'sell') {
modifiedResult.push ({
GcurrencyName: curObj.currencyName,
GpersianName: curObj.per_name,
GshortName: curObj.ab_name,
Gvalue: e.curGivenVal,
Gicon: curObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curTakenVal,
Ticon: rial.icon,
txType: 'sell'
})
} else if (e.curGivenId.toString() === rial._id.toString() && txType === 'buy') {
modifiedResult.push ({
GcurrencyName: curObj.currencyName,
GpersianName: curObj.per_name,
GshortName: curObj.ab_name,
Gvalue: e.curTakenVal,
Gicon: curObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curGivenVal,
Ticon: rial.icon,
txType: 'buy'
})
} else if (txType === 'all') {
if (e.curTakenId.toString() === rial._id.toString()) {
modifiedResult.push ({
GcurrencyName: curObj.currencyName,
GpersianName: curObj.per_name,
GshortName: curObj.ab_name,
Gvalue: e.curGivenVal,
Gicon: curObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curTakenVal,
Ticon: rial.icon,
txType: 'sell'
})
} else if (e.curGivenId.toString() === rial._id.toString()) {
modifiedResult.push ({
GcurrencyName: curObj.currencyName,
GpersianName: curObj.per_name,
GshortName: curObj.ab_name,
Gvalue: e.curTakenVal,
Gicon: curObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curGivenVal,
Ticon: rial.icon,
txType: 'buy'
})
}
}
})
return modifiedResult
})
.catch((err) => {
throw err
})
} else {
const resultMap = result.map((e) => {
console.log('eeeeeeeee: ', e)
if (e.curTakenId.toString() === rial._id.toString() && txType === 'sell') {
return redis.hashGetAll(e.curGivenId.toString())
.then((curGivenObj: any) => {
modifiedResult.push ({
GcurrencyName: curGivenObj.currencyName,
GpersianName: curGivenObj.per_name,
GshortName: curGivenObj.ab_name,
Gvalue: e.curGivenVal,
Gicon: curGivenObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curTakenVal,
Ticon: rial.icon,
txType: 'sell'
})
})
.catch((err) => {
console.log(err)
})
} else if (e.curGivenId.toString() === rial._id.toString() && txType === 'buy') {
return redis.hashGetAll(e.curTakenId.toString())
.then((curTakenObj: any) => {
modifiedResult.push({
GcurrencyName: curTakenObj.currencyName,
GpersianName: curTakenObj.per_name,
GshortName: curTakenObj.ab_name,
Gvalue: e.curTakenVal,
Gicon: curTakenObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curGivenVal,
Ticon: rial.icon,
txType: 'buy'
})
})
.catch((err) => {
console.log(err)
})
} else if (txType === 'all') {
if (e.curTakenId.toString() === rial._id.toString()) {
return redis.hashGetAll(e.curGivenId.toString())
.then((curGivenObj: any) => {
modifiedResult.push ({
GcurrencyName: curGivenObj.currencyName,
GpersianName: curGivenObj.per_name,
GshortName: curGivenObj.ab_name,
Gvalue: e.curGivenVal,
Gicon: curGivenObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curTakenVal,
Ticon: rial.icon,
txType: 'sell'
})
})
.catch((err) => {
console.log(err)
})
} else if (e.curGivenId.toString() === rial._id.toString()) {
return redis.hashGetAll(e.curTakenId.toString())
.then((curTakenObj: any) => {
modifiedResult.push ({
GcurrencyName: curTakenObj.currencyName,
GpersianName: curTakenObj.per_name,
GshortName: curTakenObj.ab_name,
Gvalue: e.curTakenVal,
Gicon: curTakenObj.icon,
acceptedDate: e.created_at,
TcurrencyName: rial.currencyName,
TpersianName: rial.per_name,
TshortName: rial.ab_name,
Tvalue: e.curGivenVal,
Ticon: rial.icon,
txType: 'buy'
})
})
.catch((err) => {
console.log(err)
})
}
}
})
return Promise.all(resultMap)
.then(() => {
return modifiedResult
})
.catch((err) => {
throw err
})
}
})
.catch((err) => {
throw err
})
})
.catch((err) => {
throw err
})
}
export const searchOnActiveOffers = ({ offerId, curGivenId, curGivenVal, curTakenId, curTakenVal, expDate, created_at }) => {
const itemsMap = new Map()
const items = ['offerId', 'curGivenId', 'curGivenVal', 'curTakenId', 'curTakenVal', 'expDate', 'created_at']
const definedItems = []
itemsMap.set('offerId', offerId)
itemsMap.set('curGivenId', curGivenId)
itemsMap.set('curGivenVal', curGivenVal)
itemsMap.set('curTakenId', curTakenId)
itemsMap.set('curTakenVal', curTakenVal)
itemsMap.set('expDate', expDate)
itemsMap.set('created_at', created_at)
items.map((element) => {
if(itemsMap.get(element)) {
if (element === 'expDate') {
if(expDate.from || expDate.to) {
definedItems.push(element)
}
} else if (element === 'created_at') {
if(created_at.from || created_at.to) {
definedItems.push(element)
}
} else if (element === 'curGivenVal') {
if(curGivenVal.from || curGivenVal.to) {
definedItems.push(element)
}
} else if (element === 'curTakenVal') {
if(curTakenVal.from || curTakenVal.to) {
definedItems.push(element)
}
} else {
definedItems.push(element)
}
}
})
let query = [ { expDate: { $gt: Date.now() } } ]
let queryMap = new Map()
let queryExpDate
let queryCreatedAt
let queryCurGivenVal
let queryCurTakenVal
if (definedItems.includes('expDate')) {
if (expDate.from && expDate.to) {
queryExpDate = { expDate: { $gt: expDate.from, $lt: expDate.to } }
} else if (expDate.from && !expDate.to) {
queryExpDate = { expDate: { $gt: expDate.from } }
} else if (!expDate.from && expDate.to) {
queryExpDate = { expDate: { $lt: expDate.to } }
}
}
if (definedItems.includes('created_at')) {
if (created_at.from && created_at.to) {
queryCreatedAt = { created_at: { $gt: created_at.from, $lt: created_at.to } }
} else if (created_at.from && !created_at.to) {
queryCreatedAt = { created_at: { $gt: created_at.from } }
} else if (!created_at.from && created_at.to) {
queryCreatedAt = { created_at: { $lt: created_at.to } }
}
}
if (definedItems.includes('curGivenVal')) {
if (curGivenVal.from && curGivenVal.to) {
queryCurGivenVal = { curGivenVal: { $gte: curGivenVal.from, $lte: curGivenVal.to } }
} else if (curGivenVal.from && !curGivenVal.to) {
queryCurGivenVal = { curGivenVal: { $gte: curGivenVal.from } }
} else if (!curGivenVal.from && curGivenVal.to) {
queryCurGivenVal = { curGivenVal: { $lte: curGivenVal.to } }
}
}
if (definedItems.includes('curTakenVal')) {
if (curTakenVal.from && curTakenVal.to) {
queryCurTakenVal = { curTakenVal: { $gte: curTakenVal.from, $lte: curTakenVal.to } }
} else if (curTakenVal.from && !curTakenVal.to) {
queryCurTakenVal = { curTakenVal: { $gte: curTakenVal.from } }
} else if (!curTakenVal.from && curTakenVal.to) {
queryCurTakenVal = { curTakenVal: { $lte: curTakenVal.to } }
}
}
queryMap.set('offerId', { offerId: offerId })
queryMap.set('curGivenId', { curGivenId: curGivenId })
queryMap.set('curGivenVal', queryCurGivenVal)
queryMap.set('curTakenId', { curTakenId: curTakenId })
queryMap.set('curTakenVal', queryCurTakenVal)
queryMap.set('expDate', queryExpDate)
queryMap.set('created_at', queryCreatedAt)
const definedItemsMap = definedItems.map((element) => {
query.push(queryMap.get(element))
})
return Promise.all(definedItemsMap)
.then(() => {
return Active_Offers.find({ $and: query })
.then((result) => {
return result
})
.catch((err) => {
throw err
})
})
.catch((err) => {
throw err
})
}

116
server/api/redis.js Executable file
View File

@@ -0,0 +1,116 @@
"use strict";
exports.__esModule = true;
exports.getCurrentPrice = exports.hashSetMembers = exports.hashHMset = exports.hashGetAll = exports.hashset = exports.hashget = exports.globalRedisClient = void 0;
var redis = require("redis");
var myError_1 = require("./myError");
exports.globalRedisClient = redis.createClient({
port: process.env.REDIS_PORT,
host: process.env.REDIS_HOST,
enable_offline_queue: false
});
// globalRedisClient.auth(process.env.REDIS_PASS, (err) => {
// if (err) console.log(err);
// })
exports.globalRedisClient.on('connect', function (err) {
if (err) {
console.log(err);
}
else {
console.log('Redis-server is connected');
}
});
exports.globalRedisClient.on('error', function (err) {
console.log('Error ' + err);
});
exports.hashget = function (tag) {
return new Promise(function (resolve, reject) {
exports.globalRedisClient.get(tag, function (err, reply) {
if (err) {
reject(err);
}
else {
resolve(reply);
}
});
});
};
exports.hashset = function (tag, val) {
return new Promise(function (resolve, reject) {
exports.globalRedisClient.set(tag, val, function (err, reply) {
if (err) {
reject(err);
}
else {
resolve(reply);
}
});
});
};
exports.hashGetAll = function (tag) {
return new Promise(function (resolve, reject) {
exports.globalRedisClient.hgetall(tag, function (err, reply) {
if (err) {
reject(err);
}
else {
resolve(reply);
}
});
});
};
exports.hashHMset = function (tag, val) {
return new Promise(function (resolve, reject) {
exports.globalRedisClient.hmset(tag, val, function (err, reply) {
if (err) {
reject(err);
}
else {
resolve(reply);
}
});
});
};
exports.hashSetMembers = function (tag) {
return new Promise(function (resolve, reject) {
exports.globalRedisClient.smembers(tag, function (err, reply) {
if (err) {
reject(err);
}
else {
resolve(reply);
}
});
});
};
function getCurrentPrice(currency) {
//API for getting current currency price
return exports.hashGetAll(currency.toString())
.then(function (currencyInfo) {
return exports.hashGetAll(currencyInfo.ab_name.toString() + "-g")
.then(function (currencyInstantPrice) {
if (currencyInstantPrice) {
return exports.hashget("dollarPrice")
.then(function (rialPrice) {
if (rialPrice) {
return Number(currencyInstantPrice.current) * Number(rialPrice);
}
else {
var error = new myError_1["default"]('It is not possible to get price currently!', 400, 11, 'امکان قیمت گیری در حال حاضر وجود ندارد!', 'خطا رخ داد');
throw error;
}
})["catch"](function (err) {
throw err;
});
}
else {
var error = new myError_1["default"]('It is not possible to get price currently!', 400, 11, 'امکان قیمت گیری در حال حاضر وجود ندارد!', 'خطا رخ داد');
throw error;
}
})["catch"](function (err) {
throw err;
});
})["catch"](function (err) {
throw err;
});
}
exports.getCurrentPrice = getCurrentPrice;

127
server/api/redis.ts Executable file
View File

@@ -0,0 +1,127 @@
import * as redis from 'redis'
import myError from './myError'
export const globalRedisClient = redis.createClient({
port: process.env.REDIS_PORT,
host: process.env.REDIS_HOST,
enable_offline_queue: false
})
// globalRedisClient.auth(process.env.REDIS_PASS, (err) => {
// if (err) console.log(err);
// })
globalRedisClient.on('connect', function (err) {
if(err) {
console.log(err)
} else {
console.log('Redis-server is connected')
}
})
globalRedisClient.on('error', function (err) {
console.log('Error ' + err)
})
export const hashget = (tag) => { // It is corresponded to hashset
return new Promise((resolve, reject) => {
globalRedisClient.get(tag, (err, reply) => {
if (err) {
reject(err)
} else {
resolve(reply)
}
})
})
}
export const hashset = (tag, val) => { // value could be only a string
return new Promise((resolve, reject) => {
globalRedisClient.set(tag, val, (err, reply) => {
if (err) {
reject(err)
} else {
resolve(reply)
}
})
})
}
export const hashGetAll = (tag) => { // It is corresponded to hashHMset
return new Promise((resolve, reject) => {
globalRedisClient.hgetall(tag, (err, reply) => {
if (err) {
reject(err)
} else {
resolve(reply)
}
})
})
}
export const hashHMset = (tag, val) => { // value could be object!
return new Promise((resolve, reject) => {
globalRedisClient.hmset(tag, val, (err, reply) => {
if (err) {
reject(err)
} else {
resolve(reply)
}
})
})
}
export const hashSetMembers = (tag) => {
return new Promise((resolve, reject) => {
globalRedisClient.smembers(tag, (err, reply) => {
if (err) {
reject(err)
} else {
resolve(reply)
}
})
})
}
export function getCurrentPrice(currency){
//API for getting current currency price
return hashGetAll(currency.toString())
.then((currencyInfo: any) => {
return hashGetAll(currencyInfo.ab_name.toString() + "-g")
.then((currencyInstantPrice: any) => {
if(currencyInstantPrice) {
return hashget("dollarPrice")
.then((rialPrice) => {
if(rialPrice) {
return Number(currencyInstantPrice.current) * Number(rialPrice)
} else {
const error = new myError(
'It is not possible to get price currently!',
400,
11,
'امکان قیمت گیری در حال حاضر وجود ندارد!',
'خطا رخ داد'
)
throw error
}
})
.catch((err) => {
throw err
})
} else {
const error = new myError(
'It is not possible to get price currently!',
400,
11,
'امکان قیمت گیری در حال حاضر وجود ندارد!',
'خطا رخ داد'
)
throw error
}
})
.catch((err) => {
throw err
})
})
.catch((err) => {
throw err
})
}

52
server/api/socket.js Executable file
View File

@@ -0,0 +1,52 @@
"use strict";
exports.__esModule = true;
exports.getonlineNotLoginUsers = exports.getonlineLoginUsers = exports.startIo = void 0;
// import * as scocketIo from 'socket.io'
var scocketIo = require('socket.io');
var redis = require("redis");
var client = redis.createClient();
var logger_1 = require("./logger");
var onlineLoginUsers = null;
var onlineNotLoginUsers = null;
var socketConnection = function socketConnection(socket) {
logger_1.logger.info("Client connected [id=" + socket.id + "]");
};
var socketDisconnection = function socketDisconnection(socket) {
logger_1.logger.info("Client gone [id=" + socket.id + "]");
};
exports.startIo = function (server) {
var io = scocketIo(server, {
serveClient: false,
cors: {
origin: '*'
}
});
io.on('connection', socketConnection);
io.on('disconnect', socketDisconnection);
onlineLoginUsers = io.of('/onlineLoginUsers');
onlineNotLoginUsers = io.of('/onlineNotLoginUsers');
onlineLoginUsers.on('connection', function (socket) {
logger_1.logger.info("Client connected [id=" + socket.id + "]");
console.log('socket.handshake', socket.handshake.session);
if (socket.handshake.session.userId) {
client.sadd(socket.handshake.session.userId, socket.id, function (err, reply) {
if (err)
logger_1.logger.warn(err);
});
logger_1.logger.info("A logged in client connected in :" + socket.id);
socket.on('disconnect', function () {
logger_1.logger.info("Client gone [id=" + socket.id + "]");
client.srem(socket.handshake.session.userId, socket.id, function (err, reply) {
logger_1.logger.info("socket with id " + socket.id + " is closed!");
});
});
}
});
return io;
};
exports.getonlineLoginUsers = function () {
return onlineLoginUsers;
};
exports.getonlineNotLoginUsers = function () {
return onlineNotLoginUsers;
};

55
server/api/socket.ts Executable file
View File

@@ -0,0 +1,55 @@
// import * as scocketIo from 'socket.io'
const scocketIo = require('socket.io')
import * as redis from 'redis'
var client = redis.createClient()
import { logger } from './logger'
let onlineLoginUsers = null
let onlineNotLoginUsers = null
var socketConnection = function socketConnection (socket) {
logger.info(`Client connected [id=${socket.id}]`)
}
var socketDisconnection = function socketDisconnection (socket) {
logger.info(`Client gone [id=${socket.id}]`)
}
export const startIo = (server) => {
const io = scocketIo(server, {
serveClient: false,
cors: {
origin: '*',
}
})
io.on('connection', socketConnection)
io.on('disconnect', socketDisconnection)
onlineLoginUsers = io.of('/onlineLoginUsers')
onlineNotLoginUsers = io.of('/onlineNotLoginUsers')
onlineLoginUsers.on('connection', function (socket) {
logger.info(`Client connected [id=${socket.id}]`)
console.log('socket.handshake', socket.handshake.session)
if (socket.handshake.session.userId) {
client.sadd(socket.handshake.session.userId, socket.id, (err, reply) => {
if (err) logger.warn(err)
})
logger.info(`A logged in client connected in :${socket.id}`)
socket.on('disconnect', () => {
logger.info(`Client gone [id=${socket.id}]`)
client.srem(socket.handshake.session.userId, socket.id, (err, reply) => {
logger.info(`socket with id ${socket.id} is closed!`)
})
})
}
})
return io
}
export const getonlineLoginUsers = () => {
return onlineLoginUsers
}
export const getonlineNotLoginUsers = () => {
return onlineNotLoginUsers
}

190
server/api/suggestOffers.js Executable file
View File

@@ -0,0 +1,190 @@
"use strict";
exports.__esModule = true;
exports.prepForKS = exports.knapsack = exports.suggestOffers = exports.normalizing = void 0;
var moment = require('moment-timezone');
var math = require('mathjs');
var ActiveOffers_1 = require("../db/ActiveOffers");
function normalizing(arr, asc) {
var mArr = math.matrix(arr);
var min = math.min(mArr).valueOf();
var max = math.max(mArr).valueOf();
var nArr = mArr;
var i;
if (max == min) {
for (i = 0; i < math.size(mArr).get([0]); i++) {
nArr = math.subset(nArr, math.index(i), max);
}
return nArr.valueOf();
}
if (asc) {
for (i = 0; i < math.size(mArr).get([0]); i++) {
nArr = math.subset(nArr, math.index(i), (((mArr.get([i]) - min) / (max - min)) + 1));
}
return nArr.valueOf();
}
else {
for (i = 0; i < math.size(mArr).get([0]); i++) {
nArr = math.subset(nArr, math.index(i), 2 - (((mArr.get([i]) - min) / (max - min))));
}
return nArr.valueOf();
}
}
exports.normalizing = normalizing;
function suggestOffers(_a) {
var userId = _a.userId, price = _a.price, capacity = _a.capacity, offerType = _a.offerType, currencyId = _a.currencyId, rialId = _a.rialId;
if (offerType == 'buy') {
// get all offers except the user's offers
var maxPrice = price + 0.05 * price;
return ActiveOffers_1.Active_Offers.find({ $and: [
{ userId: { $ne: userId } },
{ expDate: { $gt: Date.now() } },
{ curTakenId: currencyId },
{ curGivenId: rialId },
{ curGivenVal: { $lt: maxPrice } }
]
})
.then(function (offers) {
if (offers && Array.isArray(offers) && offers.length > 0) {
var offerIds_1 = [];
var offerFeatures = [];
var prices_1 = [];
var values_1 = [];
var expDate_1 = [];
offers.forEach(function (off) {
offerIds_1.push(off._id.toString());
prices_1.push(off.curGivenVal);
values_1.push(off.curTakenVal);
expDate_1.push(Math.round((moment(off.expDate) - moment()) / 60000));
});
prices_1 = normalizing(prices_1, false);
expDate_1 = normalizing(expDate_1, false);
var weights = values_1;
offerFeatures = math.concat(math.concat(math.reshape(math.matrix(prices_1), [prices_1.length, 1]), math.reshape(math.matrix(values_1), [values_1.length, 1]), 1), math.reshape(math.matrix(expDate_1), [expDate_1.length, 1]), 1).valueOf();
var coefs = [[0.3], [0.2], [0.5]];
var data = prepForKS(offerIds_1, offerFeatures, weights, coefs);
var sugOffers = knapsack(data, capacity);
return sugOffers;
}
else {
console.log("There is no offer to suggest");
}
})["catch"](function (err) {
console.log("Error in middlewares/suggestOffers.ts : ", err);
});
}
else {
if (offerType == 'sell') {
// get all offers except the user's offers
var maxPrice = price + 0.05 * price;
ActiveOffers_1.Active_Offers.find({ $and: [
{ userId: { $ne: userId } },
{ expDate: { $gt: Date.now() } },
{ curGivenId: currencyId },
{ curTakenId: rialId },
{ curTakenVal: { $lt: maxPrice } }
]
})
.then(function (offers) {
if (offers && Array.isArray(offers) && offers.length > 0) {
var offerIds_2 = [];
var offerFeatures = [];
var prices_2 = [];
var values_2 = [];
var expDate_2 = [];
offers.forEach(function (off) {
offerIds_2.push(off._id.toString());
prices_2.push(off.curTakenVal);
values_2.push(off.curGivenVal);
expDate_2.push(Math.round((moment(off.expDate) - moment()) / 60000));
});
prices_2 = normalizing(prices_2, true);
expDate_2 = normalizing(expDate_2, false);
var weights = values_2;
offerFeatures = math.concat(math.concat(math.reshape(math.matrix(prices_2), [prices_2.length, 1]), math.reshape(math.matrix(values_2), [values_2.length, 1]), 1), math.reshape(math.matrix(expDate_2), [expDate_2.length, 1]), 1).valueOf();
var coefs = [[0.3], [0.2], [0.5]];
var data = prepForKS(offerIds_2, offerFeatures, weights, coefs);
var sugOffers = knapsack(data, capacity);
return sugOffers;
}
else {
console.log("There is no offer to suggest");
}
})["catch"](function (err) {
console.log("Error in middlewares/suggestOffers.ts : ", err);
});
}
else {
console.log("offerType must be buy or sell");
}
}
}
exports.suggestOffers = suggestOffers;
function knapsack(items, capacity) {
// This implementation uses dynamic programming.
// Variable 'memo' is a grid(2-dimentional array) to store optimal solution for sub-problems,
// which will be later used as the code execution goes on.
// This is called memoization in programming.
// The cell will store best solution objects for different capacities and selectable items.
var memo = [];
// Filling the sub-problem solutions grid.
for (var i = 0; i < items.length; i++) {
// Variable 'cap' is the capacity for sub-problems. In this example, 'cap' ranges from 1 to 6.
var row = [];
for (var cap = 1; cap <= capacity; cap++) {
row.push(getSolution(i, cap));
}
memo.push(row);
}
// The right-bottom-corner cell of the grid contains the final solution for the whole problem.
return (getLast());
function getLast() {
var lastRow = memo[memo.length - 1];
return lastRow[lastRow.length - 1];
}
function getSolution(row, cap) {
var NO_SOLUTION = { maxValue: 0, subset: [] };
// the column number starts from zero.
var col = cap - 1;
var lastItem = items[row];
// The remaining capacity for the sub-problem to solve.
var remaining = cap - lastItem.w;
// Refer to the last solution for this capacity,
// which is in the cell of the previous row with the same column
var lastSolution = row > 0 ? memo[row - 1][col] || NO_SOLUTION : NO_SOLUTION;
// Refer to the last solution for the remaining capacity,
// which is in the cell of the previous row with the corresponding column
var lastSubSolution = row > 0 ? memo[row - 1][remaining - 1] || NO_SOLUTION : NO_SOLUTION;
// If any one of the items weights greater than the 'cap', return the last solution
if (remaining < 0) {
return lastSolution;
}
// Compare the current best solution for the sub-problem with a specific capacity
// to a new solution trial with the lastItem(new item) added
var lastValue = lastSolution.maxValue;
var lastSubValue = lastSubSolution.maxValue;
var newValue = lastSubValue + lastItem.v;
if (newValue >= lastValue) {
// copy the subset of the last sub-problem solution
var _lastSubSet = lastSubSolution.subset.slice();
_lastSubSet.push(lastItem);
return { maxValue: newValue, subset: _lastSubSet };
}
else {
return lastSolution;
}
}
}
exports.knapsack = knapsack;
function prepForKS(offerIds, offerFeatures, weights, coefs) {
var values = math.multiply(math.matrix(offerFeatures), math.matrix(coefs));
var data = math.concat(math.concat(math.reshape(math.matrix(offerIds), [offerIds.length, 1]), values, 1), math.reshape(math.matrix(weights), [weights.length, 1]), 1).valueOf();
var dataObj = Object.values(data.reduce(function (c, _a) {
var n = _a[0], v = _a[1], w = _a[2];
c[n] = c[n] || { id: n, v: v, w: w };
c[n].v = v;
c[n].w = w;
return c;
}, {}));
return dataObj;
}
exports.prepForKS = prepForKS;

201
server/api/suggestOffers.ts Executable file
View File

@@ -0,0 +1,201 @@
const moment = require( 'moment-timezone')
const math = require('mathjs');
import { Active_Offers } from '../db/ActiveOffers';
export function normalizing(arr, asc) {
let mArr = math.matrix(arr)
const min = math.min(mArr).valueOf()
const max = math.max(mArr).valueOf()
let nArr = mArr
let i
if(max == min){
for(i=0; i < math.size(mArr).get([0]);i++) {
nArr = math.subset(nArr, math.index(i), max )
}
return nArr.valueOf()
}
if(asc) {
for(i=0; i < math.size(mArr).get([0]);i++) {
nArr = math.subset(nArr, math.index(i), (((mArr.get([i]) - min)/(max - min)) + 1))
}
return nArr.valueOf()
} else {
for(i=0; i < math.size(mArr).get([0]); i++) {
nArr = math.subset(nArr, math.index(i), 2 - (((mArr.get([i]) - min)/(max - min))))
}
return nArr.valueOf()
}
}
export function suggestOffers({ userId, price, capacity, offerType, currencyId, rialId }) {
if(offerType == 'buy') {
// get all offers except the user's offers
let maxPrice = price + 0.05*price
return Active_Offers.find({ $and:
[
{ userId :{ $ne: userId} },
{ expDate: { $gt: Date.now() } },
{ curTakenId: currencyId },
{ curGivenId: rialId },
{ curGivenVal: { $lt: maxPrice }}
]
})
.then((offers) => {
if(offers && Array.isArray(offers) && offers.length > 0) {
let offerIds = []
let offerFeatures = []
let prices = []
let values = []
let expDate = []
offers.forEach(off => {
offerIds.push(off._id.toString())
prices.push(off.curGivenVal)
values.push(off.curTakenVal)
expDate.push(Math.round((moment(off.expDate) - moment())/60000))
})
prices = normalizing(prices, false)
expDate = normalizing(expDate, false)
let weights = values
offerFeatures = math.concat(math.concat(math.reshape(math.matrix(prices), [prices.length, 1]),
math.reshape(math.matrix(values), [values.length, 1]), 1),
math.reshape(math.matrix(expDate), [expDate.length, 1]), 1).valueOf()
let coefs = [[0.3], [0.2], [0.5]]
let data = prepForKS(offerIds, offerFeatures, weights, coefs)
let sugOffers = knapsack(data, capacity)
return sugOffers
} else {
console.log("There is no offer to suggest")
}
})
.catch((err) => {
console.log("Error in middlewares/suggestOffers.ts : ", err)
})
} else {
if(offerType == 'sell') {
// get all offers except the user's offers
let maxPrice = price + 0.05*price
Active_Offers.find({ $and:
[
{ userId :{ $ne: userId} },
{ expDate: { $gt: Date.now() } },
{ curGivenId: currencyId },
{ curTakenId: rialId },
{ curTakenVal: { $lt: maxPrice }}
]
})
.then((offers) => {
if(offers && Array.isArray(offers) && offers.length > 0) {
let offerIds = []
let offerFeatures = []
let prices = []
let values = []
let expDate = []
offers.forEach(off => {
offerIds.push(off._id.toString())
prices.push(off.curTakenVal)
values.push(off.curGivenVal)
expDate.push(Math.round((moment(off.expDate) - moment())/60000))
})
prices = normalizing(prices, true)
expDate = normalizing(expDate, false)
let weights = values
offerFeatures = math.concat(math.concat(math.reshape(math.matrix(prices), [prices.length, 1]),
math.reshape(math.matrix(values), [values.length, 1]), 1),
math.reshape(math.matrix(expDate), [expDate.length, 1]), 1).valueOf()
let coefs = [[0.3], [0.2], [0.5]]
let data = prepForKS(offerIds, offerFeatures, weights, coefs)
let sugOffers = knapsack(data, capacity)
return sugOffers
} else {
console.log("There is no offer to suggest")
}
})
.catch((err) => {
console.log("Error in middlewares/suggestOffers.ts : ", err)
})
} else {
console.log("offerType must be buy or sell")
}
}
}
export function knapsack(items, capacity) {
// This implementation uses dynamic programming.
// Variable 'memo' is a grid(2-dimentional array) to store optimal solution for sub-problems,
// which will be later used as the code execution goes on.
// This is called memoization in programming.
// The cell will store best solution objects for different capacities and selectable items.
var memo = [];
// Filling the sub-problem solutions grid.
for (var i = 0; i < items.length; i++) {
// Variable 'cap' is the capacity for sub-problems. In this example, 'cap' ranges from 1 to 6.
var row = [];
for (var cap = 1; cap <= capacity; cap++) {
row.push(getSolution(i,cap));
}
memo.push(row);
}
// The right-bottom-corner cell of the grid contains the final solution for the whole problem.
return(getLast());
function getLast(){
var lastRow = memo[memo.length - 1];
return lastRow[lastRow.length - 1];
}
function getSolution(row,cap){
const NO_SOLUTION = {maxValue:0, subset:[]};
// the column number starts from zero.
var col = cap - 1;
var lastItem = items[row];
// The remaining capacity for the sub-problem to solve.
var remaining = cap - lastItem.w;
// Refer to the last solution for this capacity,
// which is in the cell of the previous row with the same column
var lastSolution = row > 0 ? memo[row - 1][col] || NO_SOLUTION : NO_SOLUTION;
// Refer to the last solution for the remaining capacity,
// which is in the cell of the previous row with the corresponding column
var lastSubSolution = row > 0 ? memo[row - 1][remaining - 1] || NO_SOLUTION : NO_SOLUTION;
// If any one of the items weights greater than the 'cap', return the last solution
if(remaining < 0){
return lastSolution;
}
// Compare the current best solution for the sub-problem with a specific capacity
// to a new solution trial with the lastItem(new item) added
var lastValue = lastSolution.maxValue;
var lastSubValue = lastSubSolution.maxValue;
var newValue = lastSubValue + lastItem.v;
if(newValue >= lastValue) {
// copy the subset of the last sub-problem solution
var _lastSubSet = lastSubSolution.subset.slice();
_lastSubSet.push(lastItem);
return {maxValue: newValue, subset:_lastSubSet};
} else {
return lastSolution;
}
}
}
export function prepForKS(offerIds, offerFeatures, weights, coefs) {
let values = math.multiply(math.matrix(offerFeatures), math.matrix(coefs))
let data = math.concat(math.concat(math.reshape(math.matrix(offerIds), [offerIds.length, 1]), values, 1),
math.reshape(math.matrix(weights), [weights.length, 1]), 1).valueOf()
let dataObj = Object.values(data.reduce((c, [n, v, w]) => {
c[n] = c[n] || {id: n, v, w};
c[n].v = v
c[n].w = w
return c;
}, {}));
return dataObj
}

153
server/api/walletApi/bitcoin.js Executable file
View File

@@ -0,0 +1,153 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
exports.bitcoinTransferToExchangeById = exports.bitcoinTransferFromExchange = void 0;
var Client = require('bitcoin-core');
var myError_1 = require("../myError");
var _ = require("lodash");
exports.bitcoinTransferFromExchange = function (value, receiver) { return __awaiter(void 0, void 0, void 0, function () {
var client, query_options;
return __generator(this, function (_a) {
client = new Client({
network: 'testnet',
username: 'polychain',
password: '3QtnxrB7P5y4EpBdad1MkCeB2RHmArvcarw7udgXsAce',
host: "127.0.0.1",
port: 8332
});
query_options = {
"minimumAmount": value,
//"maximumAmount":value,
"maximumCount": 1
};
return [2 /*return*/, client.listUnspent(0, 9999999, [], true, query_options)
.then(function (unspentTx) {
if (unspentTx[0]) {
var txid = unspentTx[0].txid;
var vout = unspentTx[0].vout;
var txValue = unspentTx[0].amount;
var txFee = value * (0.001);
var StxFee = txFee.toFixed(8);
var totalValue = Number(value) + Number(StxFee);
var change = txValue - totalValue;
var Schange = change.toFixed(8);
var nodeAddress = unspentTx[0].address;
var input = [{
"txid": txid,
"vout": vout
}];
var output = [];
var obj = {};
var obj_2 = {};
obj[receiver] = value;
obj_2[nodeAddress] = Schange;
output.push(obj, obj_2);
return client.createRawTransaction(input, output)
.then(function (txHex) {
return client.signRawTransactionWithWallet(txHex)
.then(function (sinedHex) {
return client.sendRawTransaction(sinedHex.hex)
.then(function (txHashOrId) {
return txHashOrId;
})["catch"](function (err) {
console.log("error in sendsigned", err);
throw err;
});
})["catch"](function (err) {
console.log("error in sign ", err);
throw err;
});
})["catch"](function (err) {
console.log("error in create raw tx", err);
throw err;
});
}
else {
var error = new myError_1["default"]('you do not have unspent trancaction', 400, 5, 'تراکنش خرج نشده پیدا نشد', 'خطا رخ داد');
throw error;
}
})["catch"](function (err) {
console.log("error in lisutxo", err);
throw err;
})];
});
}); };
exports.bitcoinTransferToExchangeById = function (txId) { return __awaiter(void 0, void 0, void 0, function () {
var btcAddress, client;
return __generator(this, function (_a) {
btcAddress = ["tb1qfpf6lss60wmle9wanetjxjjt6lc6z65mapk50s"];
client = new Client({
network: 'testnet',
username: 'polychain',
password: '3QtnxrB7P5y4EpBdad1MkCeB2RHmArvcarw7udgXsAce',
host: "127.0.0.1",
port: 8332
});
return [2 /*return*/, client.getTransaction(txId)
.then(function (txInfo) {
if (txInfo) {
var tx = _.find(txInfo.details, function (i) { return i.category.toString() === "receive" && btcAddress.includes(i.address.toString()); });
if (tx) {
var status_1;
if (txInfo.confirmations >= 6) {
status_1 = "Confirmed";
}
else {
status_1 = "pending";
}
var info = {
"txAddress": tx.address,
"txAmount": tx.amount,
"status": status_1
};
return info;
}
else {
var error = new myError_1["default"]('tx not found', 400, 5, 'تراکنش یافت نشد', 'خطا رخ داد');
throw error;
}
}
else {
var error = new myError_1["default"]('transaction not found', 400, 5, 'تراکنش مربوطه پیدا نشد.', 'خطا رخ داد');
throw error;
}
})["catch"](function (err) {
throw err;
})];
});
}); };

132
server/api/walletApi/bitcoin.ts Executable file
View File

@@ -0,0 +1,132 @@
const Client = require('bitcoin-core')
import myError from '../myError'
import * as _ from 'lodash'
export const bitcoinTransferFromExchange = async(value, receiver) => {
const client = new Client({
network: 'testnet',
username: 'polychain',
password: '3QtnxrB7P5y4EpBdad1MkCeB2RHmArvcarw7udgXsAce',
host:"127.0.0.1",
port:8332
})
const query_options = {
"minimumAmount":value,
//"maximumAmount":value,
"maximumCount":1 ,
}
return client.listUnspent(0, 9999999, [], true, query_options)
.then((unspentTx) => {
if(unspentTx[0]) {
const txid = unspentTx[0].txid
const vout = unspentTx[0].vout
const txValue = unspentTx[0].amount
let txFee = value*(0.001)
const StxFee = txFee.toFixed(8)
const totalValue = Number(value) + Number(StxFee)
let change = txValue - totalValue
const Schange = change.toFixed(8)
const nodeAddress = unspentTx[0].address
const input = [{
"txid": txid,
"vout": vout,
}]
let output = []
let obj = {}
let obj_2 ={}
obj[receiver] = value
obj_2[nodeAddress] = Schange
output.push(obj,obj_2)
return client.createRawTransaction(input,output)
.then((txHex) => {
return client.signRawTransactionWithWallet(txHex)
.then((sinedHex) => {
return client.sendRawTransaction(sinedHex.hex)
.then((txHashOrId) => {
return txHashOrId
})
.catch((err) => {
console.log("error in sendsigned",err)
throw err
})
})
.catch((err)=>{
console.log("error in sign ",err)
throw err
})
})
.catch((err )=> {
console.log("error in create raw tx",err)
throw err
})
} else {
const error = new myError(
'you do not have unspent trancaction',
400,
5,
'تراکنش خرج نشده پیدا نشد',
'خطا رخ داد'
)
throw error
}
})
.catch((err) => {
console.log("error in lisutxo",err)
throw err
})
}
export const bitcoinTransferToExchangeById = async(txId) => {
const btcAddress = ["tb1qfpf6lss60wmle9wanetjxjjt6lc6z65mapk50s"]
const client = new Client({
network: 'testnet',
username: 'polychain',
password: '3QtnxrB7P5y4EpBdad1MkCeB2RHmArvcarw7udgXsAce',
host: "127.0.0.1",
port: 8332
})
return client.getTransaction(txId)
.then((txInfo) => {
if(txInfo){
const tx = _.find(txInfo.details, (i) => { return i.category.toString() === "receive" && btcAddress.includes(i.address.toString())})
if(tx) {
let status
if(txInfo.confirmations>=6)
{
status = "Confirmed"
}else{
status = "pending"
}
const info = {
"txAddress":tx.address,
"txAmount":tx.amount,
"status":status
}
return info
} else {
const error = new myError(
'tx not found',
400,
5,
'تراکنش یافت نشد',
'خطا رخ داد'
)
throw error
}
} else {
const error = new myError(
'transaction not found',
400,
5,
'تراکنش مربوطه پیدا نشد.',
'خطا رخ داد'
)
throw error
}
})
.catch((err) => {
throw err
})
}

201
server/api/walletApi/etheriuem.js Executable file
View File

@@ -0,0 +1,201 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
exports.getAccounts = exports.receiveEtherFromClient = exports.sendEther = exports.getEtheriumNonce = exports.checkTransaction = exports.getBalance = exports.createPersonalAccount = exports.createAccount = void 0;
var ethereumjs_common_1 = require("ethereumjs-common");
var Web3 = require('web3');
var Tx = require('ethereumjs-tx').Transaction;
exports.createAccount = function () {
var web3 = new Web3("http://localhost:8545");
var data = web3.eth.accounts.create();
return data;
};
exports.createPersonalAccount = function () {
var web3 = new Web3("http://localhost:8545");
return web3.eth.personal.newAccount("exchange")
.then(function (result) {
return result;
})["catch"](function (err) {
console.log(err);
});
};
exports.getBalance = function (account) { return __awaiter(void 0, void 0, void 0, function () {
var web3;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, new Web3("http://localhost:8545")];
case 1:
web3 = _a.sent();
return [2 /*return*/, web3.eth.getBalance(account.toString())
.then(function (balance) {
return balance;
})["catch"](function (err) {
throw err;
})];
}
});
}); };
exports.checkTransaction = function (transactionId) { return __awaiter(void 0, void 0, void 0, function () {
var web3;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, new Web3("http://localhost:8545")];
case 1:
web3 = _a.sent();
return [2 /*return*/, web3.eth.getTransactionReceipt(transactionId)
.then(function (txR) {
if (txR.blockNumber == undefined) {
throw "transaction receipt not found";
}
else {
return web3.eth.getTransaction(transactionId)
.then(function (tx) {
if (tx.blockNumber == undefined || tx.value == undefined) {
throw "transaction receipt not found";
}
else {
return tx;
}
})["catch"](function (err) {
throw err;
});
}
})["catch"](function (err) {
throw (err);
})];
}
});
}); };
exports.getEtheriumNonce = (function (address) {
var web3 = new Web3("http://localhost:8545");
return web3.eth.getTransactionCount(address, 'pending')
.then(function (nonce) {
//got nonce proceed with creating and signing transaction
return nonce;
})["catch"](function (err) {
throw err;
});
});
exports.sendEther = function (account, value) { return __awaiter(void 0, void 0, void 0, function () {
var web3;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, new Web3("http://localhost:8545")];
case 1:
web3 = _a.sent();
//unlock it for a period of 15 secs
return [2 /*return*/, web3.eth.personal.unlockAccount("0x868453967f6806ef86de7cf5e57a32ab28b875b4", "exchange", 15000)
.then(function (unlocked) {
return web3.eth.sendTransaction({
//from: process.env.ADMIN_ETHERIUM_ACCOUNT_ADDRESS,
from: '0x868453967f6806ef86de7cf5e57a32ab28b875b4',
to: account.toString(),
value: web3.utils.toWei(value.toString())
})
.then(function (receipt) {
// then lock it
return web3.eth.personal.lockAccount("0x868453967f6806ef86de7cf5e57a32ab28b875b4")
.then(function () {
return receipt;
})["catch"](function (err) {
return receipt;
});
})["catch"](function (err) {
throw err;
});
})["catch"](function (err) {
throw (err);
})];
}
});
}); };
exports.receiveEtherFromClient = function (transactionHash) {
//receive transaction from the ui and send it
var web3 = new Web3("http://localhost:8545");
var rawTx = undefined;
var transaction = undefined;
//custom network
var customCommon = ethereumjs_common_1["default"].forCustomChain('mainnet', {
name: 'my-network',
networkId: 1981,
chainId: 1981
}, 'petersburg');
var preData = function () {
var privateKey = Buffer.from('64061456066baa81c5097c895b5176fb3e1452eaf6f6776e2d7bf07ddb9accfe', 'hex');
//parameters should be hex string starting with 0x
var txParams = {
nonce: '0x01',
gas: 50002,
gasPrice: Number(web3.utils.toWei('601', 'gwei')),
to: '0x868453967f6806ef86de7cf5e57a32ab28b875b4',
value: 10000003
};
// The second parameter is not necessary if these values are used
var tx = new Tx(txParams, { common: customCommon });
tx.sign(privateKey);
var serializedTx = tx.serialize();
return rawTx = '0x' + serializedTx.toString('hex');
};
return Promise.all([preData()])
.then(function () {
return web3.eth.sendSignedTransaction(rawTx)
.then(function (result) {
return result;
})["catch"](function (err) {
throw err;
});
})["catch"](function (err) {
throw err;
});
};
exports.getAccounts = function () { return __awaiter(void 0, void 0, void 0, function () {
var web3;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, new Web3("http://localhost:8545")];
case 1:
web3 = _a.sent();
return [2 /*return*/, web3.eth.getAccounts()
.then(function (result) {
console.log("all acounts is ", result);
})["catch"](function (err) {
throw err;
})];
}
});
}); };

157
server/api/walletApi/etheriuem.ts Executable file
View File

@@ -0,0 +1,157 @@
import Common from 'ethereumjs-common'
const Web3 = require('web3');
const Tx = require('ethereumjs-tx').Transaction;
export const createAccount = () => {
const web3 = new Web3( "http://localhost:8545");
const data = web3.eth.accounts.create()
return data
}
export const createPersonalAccount = () => {
const web3 = new Web3( "http://localhost:8545");
return web3.eth.personal.newAccount("exchange")
.then((result) => {
return result
})
.catch((err) => {
console.log(err)
})
}
export const getBalance = async (account) => {
const web3 = await new Web3( "http://localhost:8545");
return web3.eth.getBalance(account.toString())
.then((balance) => {
return balance
})
.catch((err) => {
throw err
})
}
export const checkTransaction = async (transactionId) => {
const web3 = await new Web3( "http://localhost:8545");
return web3.eth.getTransactionReceipt(transactionId)
.then((txR) => {
if (txR.blockNumber == undefined) {
throw "transaction receipt not found";
} else {
return web3.eth.getTransaction(transactionId)
.then((tx) => {
if (tx.blockNumber == undefined|| tx.value == undefined) {
throw "transaction receipt not found";
} else {
return tx
}
})
.catch((err) => {
throw err
})
}
}).catch((err)=>{
throw(err)
})
}
export const getEtheriumNonce=((address) => {
const web3 = new Web3( "http://localhost:8545");
return web3.eth.getTransactionCount(address,'pending')
.then((nonce) => {
//got nonce proceed with creating and signing transaction
return nonce;
})
.catch((err) => {
throw err
})
})
export const sendEther = async (account,value) => {
const web3 = await new Web3( "http://localhost:8545");
//unlock it for a period of 15 secs
return web3.eth.personal.unlockAccount("0x868453967f6806ef86de7cf5e57a32ab28b875b4","exchange", 15000)
.then((unlocked) => {
return web3.eth.sendTransaction({
//from: process.env.ADMIN_ETHERIUM_ACCOUNT_ADDRESS,
from: '0x868453967f6806ef86de7cf5e57a32ab28b875b4',
to: account.toString(),
value: web3.utils.toWei (value.toString())
})
.then((receipt) => {
// then lock it
return web3.eth.personal.lockAccount("0x868453967f6806ef86de7cf5e57a32ab28b875b4")
.then(() => {
return receipt
})
.catch((err) => {
return receipt
})
})
.catch((err) =>{
throw err
})
}).catch((err)=>{
throw(err)
})
}
export const receiveEtherFromClient = (transactionHash) => {
//receive transaction from the ui and send it
const web3 = new Web3( "http://localhost:8545");
let rawTx = undefined
let transaction = undefined
//custom network
const customCommon = Common.forCustomChain(
'mainnet',
{
name: 'my-network',
networkId: 1981,
chainId: 1981,
},
'petersburg',
)
const preData = () => {
const privateKey = Buffer.from(
'64061456066baa81c5097c895b5176fb3e1452eaf6f6776e2d7bf07ddb9accfe',
'hex'
)
//parameters should be hex string starting with 0x
const txParams = {
nonce: '0x01',
gas: 50002,
gasPrice: Number(web3.utils.toWei('601', 'gwei')),
to: '0x868453967f6806ef86de7cf5e57a32ab28b875b4',
value: 10000003
}
// The second parameter is not necessary if these values are used
const tx = new Tx(txParams,{common : customCommon})
tx.sign(privateKey)
const serializedTx = tx.serialize()
return rawTx = '0x' + serializedTx.toString('hex');
}
return Promise.all([preData()])
.then(()=>{
return web3.eth.sendSignedTransaction(rawTx)
.then((result) => {
return result;
})
.catch((err) => {
throw err;
})
})
.catch((err) => {
throw err
})
}
export const getAccounts = async () => {
const web3 = await new Web3( "http://localhost:8545");
return web3.eth.getAccounts()
.then((result)=>{
console.log("all acounts is ", result)
})
.catch((err)=>{
throw err
})
}

View File

@@ -0,0 +1,220 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
exports.transferFromExchangeApi = void 0;
var myError_1 = require("../myError");
var currencies_1 = require("../../db/currencies");
var bitcoin = require("../walletApi/bitcoin");
var etheriuem = require("../walletApi/etheriuem");
var mongoose = require("mongoose");
var user_1 = require("../../db/user");
var _ = require("lodash");
var pendingTransfers_1 = require("../../db/pendingTransfers");
exports.transferFromExchangeApi = function (currencyId, value, receiver, userId) { return __awaiter(void 0, void 0, void 0, function () {
var info, resObj, checkStatus, session;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
checkStatus = function () {
return null;
};
return [4 /*yield*/, mongoose.startSession()];
case 1:
session = _a.sent();
return [2 /*return*/, session.withTransaction(function () { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, user_1.User.findOne({ _id: userId }).session(session)
.then(function (user) { return __awaiter(void 0, void 0, void 0, function () {
var error;
return __generator(this, function (_a) {
if (user) {
return [2 /*return*/, currencies_1.Currencies.findOne({ _id: currencyId })
.then(function (cur) { return __awaiter(void 0, void 0, void 0, function () {
var CurAbName, curInWall_1, error, error, error;
return __generator(this, function (_a) {
CurAbName = "";
if (cur) {
curInWall_1 = _.find(user.wallet, function (i) { return i.currency.toString() === currencyId.toString(); });
if (curInWall_1) {
if (curInWall_1.value >= Number(value)) {
CurAbName = cur.ab_name;
switch (CurAbName) {
case "BTC":
checkStatus = function () {
return bitcoin.bitcoinTransferFromExchange(value, receiver)
.then(function (txHash) {
info = {
status: "pending",
txHash: txHash
};
})["catch"](function (err) {
throw err;
});
};
case "ETH":
return [2 /*return*/, etheriuem.sendEther(receiver.toString(), value)
.then(function (result) { return __awaiter(void 0, void 0, void 0, function () {
var bodySuccessfulOffer, bodyTransaction;
return __generator(this, function (_a) {
if (result && result.transactionHash) {
bodySuccessfulOffer = {
userId: user._id,
transactions: []
};
bodyTransaction = {
txId: result.transactionHash,
currencyId: currencyId,
currencyName: CurAbName,
value: Number(value),
type: 'send'
};
bodySuccessfulOffer.transactions.push(bodyTransaction);
}
else if (result) {
throw ("could not get any transaction " + result);
}
else {
throw ("could not get result ");
}
return [2 /*return*/];
});
}); })["catch"](function (err) {
throw err;
})];
case "TRX":
}
return [2 /*return*/, Promise.all([checkStatus()])
.then(function () {
return pendingTransfers_1.PendingTransfers.findOne({ userId: userId }).session(session)
.then(function (userPending) { return __awaiter(void 0, void 0, void 0, function () {
var usrPending;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!userPending) return [3 /*break*/, 2];
userPending.transactions.push({
txId: info.txHash,
currencyId: currencyId,
currencyName: CurAbName,
value: value,
type: "send"
});
return [4 /*yield*/, userPending.save()];
case 1:
_a.sent();
return [3 /*break*/, 4];
case 2:
usrPending = {
userId: userId,
transactions: [{
txId: info.txHash,
currencyId: currencyId,
currencyName: CurAbName,
value: value,
type: "id"
}]
};
return [4 /*yield*/, pendingTransfers_1.PendingTransfers.create([usrPending], { session: session })];
case 3:
_a.sent();
_a.label = 4;
case 4:
curInWall_1.value -= value;
return [4 /*yield*/, user.save()];
case 5:
_a.sent();
resObj =
{
status: "success",
txValue: value,
txHash: info.txHash
};
return [2 /*return*/];
}
});
}); })["catch"](function (err) {
throw err;
});
})["catch"](function (err) {
throw err;
})];
}
else {
error = new myError_1["default"]('you do not have enough currency ', 400, 5, 'موجودی کافی نمی باشد', 'خطا رخ داد');
throw error;
}
}
else {
error = new myError_1["default"]('currency not found in user wallet', 400, 5, 'ارز در کیف پول پیدا نشد', 'خطا رخ داد');
throw error;
}
}
else {
error = new myError_1["default"]('currency not found', 400, 5, 'ارز پیدا نشد', 'خطا رخ داد');
throw error;
}
return [2 /*return*/];
});
}); })["catch"](function (err) {
throw err;
})];
}
else {
error = new myError_1["default"]('user not found', 400, 5, 'کاربر پیدا نشد.', 'خطا رخ داد');
throw error;
}
return [2 /*return*/];
});
}); })["catch"](function (err) {
throw err;
})];
});
}); })
.then(function () {
return resObj;
})["catch"](function (err) {
console.log("error in with Transaction", err);
throw ("error in with transaction");
})["finally"](function () {
session.endSession();
})["catch"](function (err) {
throw err;
})];
}
});
}); };

View File

@@ -0,0 +1,189 @@
import myError from '../myError'
import { Currencies } from '../../db/currencies'
import * as bitcoin from '../walletApi/bitcoin'
import * as etheriuem from '../walletApi/etheriuem'
import * as tron from '../walletApi/tron'
import * as mongoose from 'mongoose'
import { User } from '../../db/user'
import * as _ from 'lodash'
import { PendingTransfers } from '../../db/pendingTransfers'
import { SuccessfulTransfers } from '../../db/successfulTransfers'
export const transferFromExchangeApi = async(currencyId, value, receiver, userId) => {
let info
let resObj
let checkStatus = () => {
return null
}
const session = await mongoose.startSession()
return session.withTransaction(async() => {
return User.findOne({_id:userId}).session(session)
.then(async (user)=>{
if(user){
return Currencies.findOne({_id:currencyId})
.then(async(cur) => {
let CurAbName = ""
if(cur){
let curInWall = _.find(user.wallet, (i) => { return i.currency.toString() === currencyId.toString()})
if(curInWall) {
if(curInWall.value >= Number(value)){
CurAbName = cur.ab_name
switch(CurAbName) {
case "BTC":
checkStatus = () => {
return bitcoin.bitcoinTransferFromExchange(value,receiver)
.then((txHash) => {
info = {
status:"pending",
txHash:txHash
}
})
.catch((err)=>{
throw err
})
}
case "ETH":
return etheriuem.sendEther(receiver.toString(),value)
.then(async (result) => {
if(result&&result.transactionHash) {
const bodySuccessfulOffer = {
userId: user._id ,
transactions : []
}
const bodyTransaction = {
txId : result.transactionHash,
currencyId : currencyId,
currencyName : CurAbName,
value : Number(value),
type : 'send'
}
bodySuccessfulOffer.transactions.push(bodyTransaction)
} else if(result) {
throw ("could not get any transaction "+ result)
} else {
throw ("could not get result ")
}
})
.catch((err) => {
throw err
})
case "TRX":
}
return Promise.all([checkStatus()])
.then(() =>{
return PendingTransfers.findOne({ userId:userId }).session(session)
.then(async (userPending) => {
if(userPending){
userPending.transactions.push({
txId: info.txHash,
currencyId: currencyId,
currencyName: CurAbName,
value: value,
type: "send"
})
await userPending.save()
} else {
const usrPending = {
userId: userId,
transactions: [{
txId: info.txHash,
currencyId: currencyId,
currencyName: CurAbName,
value: value,
type: "id"
}]
}
await PendingTransfers.create([usrPending],{ session })
}
curInWall.value -= value
await user.save()
resObj =
{
status:"success",
txValue:value,
txHash:info.txHash
}
}).catch((err)=>{
throw err
})
}).catch((err)=>{
throw err
})
} else {
const error = new myError(
'you do not have enough currency ',
400,
5,
'موجودی کافی نمی باشد',
'خطا رخ داد'
)
throw error
}
} else {
const error = new myError(
'currency not found in user wallet',
400,
5,
'ارز در کیف پول پیدا نشد',
'خطا رخ داد'
)
throw error
}
} else {
const error = new myError(
'currency not found',
400,
5,
'ارز پیدا نشد',
'خطا رخ داد'
)
throw error
}
}).catch((err)=>{
throw err
})
} else {
const error = new myError(
'user not found',
400,
5,
'کاربر پیدا نشد.',
'خطا رخ داد'
)
throw error
}
}).catch((err)=>{
throw err
})
})
.then(() => {
return resObj
})
.catch((err) => {
console.log("error in with Transaction",err)
throw("error in with transaction")
})
.finally(() => {
session.endSession()
})
.catch((err) => {
throw err
})
}

View File

@@ -0,0 +1,128 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
exports.transferInWithTxId = void 0;
var Client = require('bitcoin-core');
var _ = require("lodash");
exports.transferInWithTxId = function (currency, txId) { return __awaiter(void 0, void 0, void 0, function () {
var client_1;
return __generator(this, function (_a) {
switch (currency) {
case "BTC":
client_1 = new Client({
network: 'testnet',
username: 'polychain',
password: '3QtnxrB7P5y4EpBdad1MkCeB2RHmArvcarw7udgXsAce',
host: "127.0.0.1",
port: 8332
});
client_1.listTransactions("*", 100, 0)
.theb(function (txs) {
var tx = _.find(txs, function (i) { return i.txid.toString() === txId.toString(); });
if (tx) {
if (tx.address === "node address") {
var amount_1 = tx.amount;
client_1.getBlockCount()
.then(function (blockCount) {
if (blockCount - Number(tx.blockindex) > 6) {
return amount_1;
}
else {
//
}
})["catch"](function (err) {
throw err;
});
}
else {
}
}
})["catch"](function (err) {
throw err;
});
break;
case "ETH":
//
break;
case "TRX":
//
break;
}
return [2 /*return*/];
});
}); };
// fetch("connect to your bitcoin node",{
// method: "POST",
// body:{"jsonrpc": "1.0", "id":"curltest",
// "method": "listtransactions",
// "params": [txId]
// },
// headers:header
// })
// .then(res => res.json())
// .then((txs) => {
// const tx = _.find(txs, (i) => { return i.txid.toString()=== txId.toString()})
// if(tx){
// const blockIndex = Number(tx.blockindex)
// const txValue = Number(tx.vout)
// fetch("connect to your bitcoin node",{
// method: "POST",
// body:{"jsonrpc": "1.0", "id":"curltest",
// "method": "getblockcount",
// "params": []
// },
// headers:header
// })
// .then(res => res.json())
// .then((blockCount) => {
// if(Number(blockCount)-blockIndex>=6) {
// let cur = _.find(user.wallet, (i) => { return i.currency.toString()=== currencyId.toString() })
// cur.value += txValue
// } else {
// //wait for transaction confirmation
// }
// }).catch((err)=>{
// next(err)
// })
// } else {
// //throw errrrrorrrrrr
// }
// })
// .catch((err) => {
// next(err)
// })

View File

@@ -0,0 +1,114 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
exports.transferToApi = void 0;
var Client = require('bitcoin-core');
exports.transferToApi = function (currency, value, receiver) { return __awaiter(void 0, void 0, void 0, function () {
var client_1, query_options;
return __generator(this, function (_a) {
switch (currency) {
case "BTC":
client_1 = new Client({
network: 'testnet',
username: 'polychain',
password: '3QtnxrB7P5y4EpBdad1MkCeB2RHmArvcarw7udgXsAce',
host: "127.0.0.1",
port: 8332
});
query_options = {
"minimumAmount": value
};
client_1.listUnspent(1, 1, [], true, query_options)
.then(function (unspentTx) {
if (unspentTx[0]) {
var txid = unspentTx[0].txid;
var txValue = Number(unspentTx[0].amount);
var change = txValue - value;
var nodeAddress_1 = unspentTx[0].address;
var input = [{
"txid": txid,
"vout": Number(txValue)
}];
var output = [
{
"receiver": txValue,
"nodeAddress": change
},
{
"data": "Hi"
},
];
client_1.createRawTransaction(input, output)
.then(function (txHex) {
client_1.dumpprivkey(nodeAddress_1)
.then(function (priKey) {
client_1.signRawTransactionWithKey(txHex, [priKey])
.then(function (sinedHex) {
client_1.sendRawTransaction(sinedHex)
.then(function (txHashOrId) {
return txHashOrId;
})["catch"](function (err) {
throw (err);
});
})["catch"](function (err) {
throw (err);
});
})["catch"](function (err) {
throw (err);
});
})["catch"](function (err) {
throw (err);
});
}
else {
// throw err
}
})["catch"](function (err) {
console.log('the error is', err);
});
break;
case "ETH":
//
break;
case "TRX":
//
break;
}
return [2 /*return*/];
});
}); };

View File

@@ -0,0 +1,100 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
exports.transferToExchangeApi = void 0;
var Client = require('bitcoin-core');
var myError_1 = require("../myError");
var currencies_1 = require("../../db/currencies");
exports.transferToExchangeApi = function (currencyId, signedRawTxHex, value) { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
currencies_1.Currencies.findOne({ _id: currencyId })
.then(function (cur) {
var CurAbName = "";
if (cur) {
value = Number(value);
CurAbName = cur.ab_name;
switch (CurAbName) {
case "BTC":
// const client = new Client({
// network: 'testnet',
// username: 'polychain',
// password: '3QtnxrB7P5y4EpBdad1MkCeB2RHmArvcarw7udgXsAce',
// host:"127.0.0.1",
// port:8332
// })
// client.decodeRawTransaction(signedRawTxHex)
// .then((tx) => {
// if(tx) {
// const txValue = Number(tx[0].vout[0].value)
// if(txValue===Number(value)) {
// client.sendRawTransaction(signedRawTxHex)
// .then((txHashOrId) => {
// return txHashOrId
// })
// .catch((err) => {
// throw(err)
// })
// } else {
// //
// }
// } else {
// //
// }
// })
// .catch((err) => {
// throw err
// })
break;
case "ETH":
//
break;
case "TRX":
//
break;
}
}
else {
var error = new myError_1["default"]('currency not found', 400, 5, 'ارز مربوطه پیدا نشد.', 'خطا رخ داد');
throw error;
}
})["catch"](function (err) {
throw err;
});
return [2 /*return*/];
});
}); };

View File

@@ -0,0 +1,70 @@
const Client = require('bitcoin-core')
import { conformsTo } from 'lodash'
import myError from '../myError'
import { Currencies } from '../../db/currencies'
export const transferToExchangeApi = async(currencyId,signedRawTxHex,value) => {
Currencies.findOne({_id:currencyId})
.then((cur)=>{
let CurAbName = ""
if(cur){
value = Number(value)
CurAbName = cur.ab_name
switch(CurAbName) {
case "BTC":
// const client = new Client({
// network: 'testnet',
// username: 'polychain',
// password: '3QtnxrB7P5y4EpBdad1MkCeB2RHmArvcarw7udgXsAce',
// host:"127.0.0.1",
// port:8332
// })
// client.decodeRawTransaction(signedRawTxHex)
// .then((tx) => {
// if(tx) {
// const txValue = Number(tx[0].vout[0].value)
// if(txValue===Number(value)) {
// client.sendRawTransaction(signedRawTxHex)
// .then((txHashOrId) => {
// return txHashOrId
// })
// .catch((err) => {
// throw(err)
// })
// } else {
// //
// }
// } else {
// //
// }
// })
// .catch((err) => {
// throw err
// })
break;
case "ETH":
//
break;
case "TRX":
//
break;
}
}else{
const error = new myError(
'currency not found',
400,
5,
'ارز مربوطه پیدا نشد.',
'خطا رخ داد'
)
throw error
}
}).catch((err)=>{
throw err
})
}

View File

@@ -0,0 +1,363 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
exports.transferToExchangeByIdApi = void 0;
var _ = require("lodash");
var myError_1 = require("../myError");
var currencies_1 = require("../../db/currencies");
var user_1 = require("../../db/user");
var mongoose = require("mongoose");
var bitcoin = require("../walletApi/bitcoin");
var etherium = require("./etheriuem");
var tron = require("./tron");
var pendingTransfers_1 = require("../../db/pendingTransfers");
var successfulTransfers_1 = require("../../db/successfulTransfers");
exports.transferToExchangeByIdApi = function (currencyId, txId, userId) { return __awaiter(void 0, void 0, void 0, function () {
var info, resObj, userHaveDoc, checkStatus, session;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
userHaveDoc = false;
checkStatus = function () {
return null;
};
return [4 /*yield*/, mongoose.startSession()];
case 1:
session = _a.sent();
return [2 /*return*/, session.withTransaction(function () {
return user_1.User.findOne({ _id: userId }).session(session)
.then(function (user) {
if (user) {
return pendingTransfers_1.PendingTransfers.findOne({ userId: userId })
.then(function (userPending) {
if (userPending && userPending.userId.toString() === userId.toString()) {
userHaveDoc = true;
var pendingTx = _.find(userPending.transactions, function (i) { return i.txId.toString() === txId.toString(); });
if (pendingTx) {
var error = new myError_1["default"]('transaction already exsist', 400, 5, 'تراکنش قبلا وجود دارد', 'خطا رخ داد');
throw error;
}
}
return currencies_1.Currencies.findOne({ _id: currencyId })
.then(function (cur) {
var CurAbName = "";
if (cur) {
CurAbName = cur.ab_name;
switch (CurAbName) {
case "BTC":
checkStatus = function () {
return bitcoin.bitcoinTransferToExchangeById(txId)
.then(function (result) {
info = result;
})["catch"](function (err) {
throw err;
});
};
break;
case "ETH":
return etherium.checkTransaction(txId)
.then(function (transaction) {
if (transaction && transaction.hash.toString() === txId.toString()) {
var curInWall = _.find(user.wallet, function (i) { return i.currency.toString() === currencyId.toString(); });
if (curInWall) {
curInWall.value += Number(transaction.value);
}
else {
}
return;
}
else {
throw "transaction not valid";
}
})["catch"](function (err) {
console.log("api error: ", err);
});
//
case "TRX":
return tron.validateByTXId(txId)
.then(function (transaction) {
if (transaction.result) {
var resObj_1 = {
status: "successful",
txValue: transaction
};
return resObj_1;
}
else {
var resObj_2 = {
status: "pending",
txValue: transaction
};
}
})["catch"](function (err) {
throw (err);
});
// default
}
return Promise.all([checkStatus()])
.then(function () {
if (userHaveDoc) {
userPending.transactions.push({
txId: txId,
currencyId: currencyId,
currencyName: CurAbName,
value: info.txAmount,
type: "id"
});
userPending.save()
.then(function () {
if (info.status === 'Confirmed') {
return successfulTransfers_1.SuccessfulTransfers.findOne({ userId: userId }).session(session)
.then(function (userSuccess) { return __awaiter(void 0, void 0, void 0, function () {
var usrSuccess;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(userSuccess && userSuccess.userId.toString() === userId.toString())) return [3 /*break*/, 2];
userSuccess.transactions.push({
txId: txId,
currencyId: currencyId,
currencyName: CurAbName,
value: info.txAmount,
type: "id"
});
return [4 /*yield*/, userSuccess.save()];
case 1:
_a.sent();
return [3 /*break*/, 4];
case 2:
usrSuccess = {
userId: userId,
transactions: [{
txId: txId,
currencyId: currencyId,
currencyName: CurAbName,
value: info.txAmount,
type: "id"
}]
};
return [4 /*yield*/, successfulTransfers_1.SuccessfulTransfers.create([usrSuccess], { session: session })];
case 3:
_a.sent();
_a.label = 4;
case 4: return [2 /*return*/, pendingTransfers_1.PendingTransfers.findOne({ userId: userId }).session(session)
.then(function (userPendinAfterSave) { return __awaiter(void 0, void 0, void 0, function () {
var cur;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
userPendinAfterSave.transactions = _.filter(userPendinAfterSave.transactions, function (i) { return i.txId.toString() !== txId.toString(); });
return [4 /*yield*/, userPendinAfterSave.save()];
case 1:
_a.sent();
cur = _.find(user.wallet, function (i) { return i.currency.toString() === currencyId.toString(); });
if (!cur) return [3 /*break*/, 3];
cur.value += info.txAmount;
return [4 /*yield*/, user.save()];
case 2:
_a.sent();
return [3 /*break*/, 5];
case 3:
user.wallet.push({
currency: currencyId,
value: info.txAmount
});
return [4 /*yield*/, user.save()];
case 4:
_a.sent();
_a.label = 5;
case 5:
resObj = {
status: 'successful',
value: info.txAmount
};
return [2 /*return*/];
}
});
}); })["catch"](function (err) {
throw err;
})];
}
});
}); })["catch"](function (err) {
throw err;
});
}
else {
resObj = {
status: 'pending',
value: info.txAmount
};
}
})["catch"](function (err) {
throw err;
});
}
else {
var usrPending = {
userId: userId,
transactions: [{
txId: txId,
currencyId: currencyId,
currencyName: CurAbName,
value: info.txAmount,
type: "id"
}]
};
pendingTransfers_1.PendingTransfers.create([usrPending])
.then(function () {
if (info.status === 'Confirmed') {
return successfulTransfers_1.SuccessfulTransfers.findOne({ userId: userId }).session(session)
.then(function (userSuccess) { return __awaiter(void 0, void 0, void 0, function () {
var usrSuccess;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(userSuccess && userSuccess.userId.toString() === userId.toString())) return [3 /*break*/, 2];
userSuccess.transactions.push({
txId: txId,
currencyId: currencyId,
currencyName: CurAbName,
value: info.txAmount,
type: "id"
});
return [4 /*yield*/, userSuccess.save()];
case 1:
_a.sent();
return [3 /*break*/, 4];
case 2:
usrSuccess = {
userId: userId,
transactions: [{
txId: txId,
currencyId: currencyId,
currencyName: CurAbName,
value: info.txAmount,
type: "id"
}]
};
return [4 /*yield*/, successfulTransfers_1.SuccessfulTransfers.create([usrSuccess], { session: session })];
case 3:
_a.sent();
_a.label = 4;
case 4: return [2 /*return*/, pendingTransfers_1.PendingTransfers.findOne({ userId: userId }).session(session)
.then(function (userPendinAfterSave) { return __awaiter(void 0, void 0, void 0, function () {
var cur;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
userPendinAfterSave.transactions = _.filter(userPendinAfterSave.transactions, function (i) { return i.txId.toString() !== txId.toString(); });
return [4 /*yield*/, userPendinAfterSave.save()];
case 1:
_a.sent();
cur = _.find(user.wallet, function (i) { return i.currency.toString() === currencyId.toString(); });
if (!cur) return [3 /*break*/, 3];
cur.value += info.txAmount;
return [4 /*yield*/, user.save()];
case 2:
_a.sent();
return [3 /*break*/, 5];
case 3:
user.wallet.push({
currency: currencyId,
value: info.txAmount
});
return [4 /*yield*/, user.save()];
case 4:
_a.sent();
_a.label = 5;
case 5:
resObj = {
status: 'successful',
value: info.txAmount
};
return [2 /*return*/];
}
});
}); })["catch"](function (err) {
throw err;
})];
}
});
}); })["catch"](function (err) {
throw err;
});
}
else {
resObj = {
status: 'pending',
value: info.txAmount
};
}
})["catch"](function (err) {
throw err;
});
}
})["catch"](function (err) {
throw err;
});
}
else {
var error = new myError_1["default"]('currency not found', 400, 5, 'ارز مربوطه پیدا نشد.', 'خطا رخ داد');
throw error;
}
})["catch"](function (err) {
throw err;
});
})["catch"](function (err) {
throw err;
});
}
else {
var error = new myError_1["default"]('user not found', 400, 5, 'کاربر پیدا نشد.', 'خطا رخ داد');
throw error;
}
})["catch"](function (err) {
throw err;
});
})
.then(function () {
return resObj;
})["catch"](function (err) {
throw ("error in with Transaction" + ":" + err);
})["finally"](function () {
session.endSession();
})];
}
});
}); };

View File

@@ -0,0 +1,291 @@
import * as _ from 'lodash'
import myError from '../myError'
import { Currencies } from '../../db/currencies'
import { User } from '../../db/user'
import * as mongoose from 'mongoose'
import * as bitcoin from '../walletApi/bitcoin'
import * as etherium from './etheriuem'
import * as tron from './tron'
import { PendingTransfers } from '../../db/pendingTransfers'
import { SuccessfulTransfers } from '../../db/successfulTransfers'
export const transferToExchangeByIdApi = async(currencyId, txId, userId) => {
let info
let resObj
let userHaveDoc = false
let checkStatus = () => {
return null
}
const session = await mongoose.startSession()
return session.withTransaction(() => {
return User.findOne({ _id: userId }).session(session)
.then((user) => {
if(user) {
return PendingTransfers.findOne({ userId: userId })
.then((userPending) => {
if(userPending && userPending.userId.toString() === userId.toString()) {
userHaveDoc = true
let pendingTx = _.find(userPending.transactions, (i) => { return i.txId.toString() === txId.toString() })
if(pendingTx) {
const error = new myError(
'transaction already exsist',
400,
5,
'تراکنش قبلا وجود دارد',
'خطا رخ داد'
)
throw error
}
}
return Currencies.findOne({ _id: currencyId })
.then((cur) => {
let CurAbName = ""
if(cur) {
CurAbName = cur.ab_name
switch(CurAbName) {
case "BTC":
checkStatus = () => {
return bitcoin.bitcoinTransferToExchangeById(txId)
.then((result) => {
info = result
})
.catch((err) => {
throw err
})
}
break;
case "ETH":
return etherium.checkTransaction(txId)
.then((transaction) => {
if(transaction && transaction.hash.toString() === txId.toString()) {
let curInWall = _.find(user.wallet, (i) => { return i.currency.toString()=== currencyId.toString()})
if(curInWall) {
curInWall.value += Number(transaction.value)
} else {
}
return
} else {
throw "transaction not valid"
}
})
.catch((err)=>{
console.log("api error: ",err)
})
//
case "TRX":
return tron.validateByTXId(txId)
.then((transaction: any) => {
if(transaction.result) {
const resObj = {
status:"successful",
txValue : transaction
}
return resObj
} else {
const resObj = {
status:"pending",
txValue : transaction
}
}
})
.catch((err) => {
throw(err)
})
// default
}
return Promise.all([checkStatus()])
.then(() => {
if(userHaveDoc) {
userPending.transactions.push({
txId:txId,
currencyId:currencyId,
currencyName:CurAbName,
value:info.txAmount,
type:"id"
})
userPending.save()
.then(() => {
if(info.status === 'Confirmed') {
return SuccessfulTransfers.findOne({ userId: userId }).session(session)
.then(async (userSuccess) => {
if(userSuccess && userSuccess.userId.toString() === userId.toString()) {
userSuccess.transactions.push({
txId,
currencyId,
currencyName: CurAbName,
value: info.txAmount,
type: "id"
})
await userSuccess.save()
} else {
const usrSuccess = {
userId:userId,
transactions: [{
txId,
currencyId,
currencyName: CurAbName,
value: info.txAmount,
type: "id"
}]
}
await SuccessfulTransfers.create([usrSuccess], { session })
}
return PendingTransfers.findOne({ userId:userId }).session(session)
.then(async (userPendinAfterSave) => {
userPendinAfterSave.transactions = _.filter(userPendinAfterSave.transactions, (i) => { return i.txId.toString() !== txId.toString() })
await userPendinAfterSave.save()
let cur = _.find(user.wallet, (i) => { return i.currency.toString() === currencyId.toString()})
if(cur) {
cur.value +=info.txAmount
await user.save()
} else {
user.wallet.push({
currency: currencyId,
value: info.txAmount
})
await user.save()
}
resObj = {
status: 'successful',
value: info.txAmount
}
}).catch((err)=>{
throw err
})
}).catch((err)=>{
throw err
})
} else {
resObj = {
status: 'pending',
value: info.txAmount
}
}
})
.catch((err) => {
throw err
})
} else {
const usrPending = {
userId:userId,
transactions: [{
txId,
currencyId,
currencyName: CurAbName,
value: info.txAmount,
type: "id"
}]
}
PendingTransfers.create([usrPending])
.then(() => {
if(info.status === 'Confirmed') {
return SuccessfulTransfers.findOne({ userId: userId }).session(session)
.then(async (userSuccess) => {
if(userSuccess && userSuccess.userId.toString() === userId.toString()) {
userSuccess.transactions.push({
txId,
currencyId,
currencyName: CurAbName,
value: info.txAmount,
type: "id"
})
await userSuccess.save()
} else {
const usrSuccess = {
userId:userId,
transactions: [{
txId,
currencyId,
currencyName: CurAbName,
value: info.txAmount,
type: "id"
}]
}
await SuccessfulTransfers.create([usrSuccess], { session })
}
return PendingTransfers.findOne({ userId:userId }).session(session)
.then(async (userPendinAfterSave) => {
userPendinAfterSave.transactions = _.filter(userPendinAfterSave.transactions, (i) => { return i.txId.toString() !== txId.toString() })
await userPendinAfterSave.save()
let cur = _.find(user.wallet, (i) => { return i.currency.toString() === currencyId.toString()})
if(cur) {
cur.value +=info.txAmount
await user.save()
} else {
user.wallet.push({
currency: currencyId,
value: info.txAmount
})
await user.save()
}
resObj = {
status: 'successful',
value: info.txAmount
}
}).catch((err)=>{
throw err
})
}).catch((err)=>{
throw err
})
} else {
resObj = {
status: 'pending',
value: info.txAmount
}
}
})
.catch((err) => {
throw err
})
}
})
.catch((err) => {
throw err
})
} else {
const error = new myError(
'currency not found',
400,
5,
'ارز مربوطه پیدا نشد.',
'خطا رخ داد'
)
throw error
}
})
.catch((err) => {
throw err
})
})
.catch((err) => {
throw err
})
} else {
const error = new myError(
'user not found',
400,
5,
'کاربر پیدا نشد.',
'خطا رخ داد'
)
throw error
}
})
.catch((err) => {
throw err
})
})
.then(() => {
return resObj
})
.catch((err) => {
throw ("error in with Transaction"+ ":" + err)
})
.finally(() => {
session.endSession()
})
}

109
server/api/walletApi/tron.js Executable file
View File

@@ -0,0 +1,109 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
exports.TRONTransferFrom = exports.validateByTXId = void 0;
var tronWeb = require("tronweb");
// export function TRONTransferTo(userId, systemAccount, userAccount, privateKey, amount){
// User.findOne({ _id : userId })
// .then((user) => {
// if(user && user._id.toString() === userId.toString()){
// const HttpProvider = tronWeb.providers.HttpProvider;
// const fullNode = new HttpProvider("https://api.shasta.trongrid.io");
// const solidityNode = new HttpProvider("https://api.shasta.trongrid.io");
// const eventServer = new HttpProvider("https://api.shasta.trongrid.io");
// const tw = new tronWeb(fullNode,solidityNode,eventServer,privateKey);
// const am = amount * 1000000
// tw.trx.getAccount(userAccount.toString()).then((usrAcc) =>{
// if(usrAcc){
// tw.trx.sendTransaction(systemAccount, am)
// }else{
// const error = "user Tron Account not fount"
// console.log("Error in TRONTransferTo : ", error)
// }
// })
// .catch((err) => console.log(err))
// }else{
// const error = 'user not fount'
// console.log('Error in TRONTransferTo : ', error)
// }
// })
// .catch((err) => console.log('Error in TRONTransferTo : ', err))
// }
function validateByTXId(hash) {
return __awaiter(this, void 0, void 0, function () {
var systemPrivateKey, HttpProvider, fullNode, solidityNode, eventServer, TronWeb;
return __generator(this, function (_a) {
systemPrivateKey = '4a8f251556d19ab6625c0cc012a3c534bf978e6a099d0bb8f42d6539579a10c5';
HttpProvider = tronWeb.providers.HttpProvider;
fullNode = new HttpProvider("https://api.shasta.trongrid.io");
solidityNode = new HttpProvider("https://api.shasta.trongrid.io");
eventServer = new HttpProvider("https://api.shasta.trongrid.io");
TronWeb = new tronWeb(fullNode, solidityNode, eventServer, systemPrivateKey);
console.log("here : ", TronWeb);
TronWeb.trx.getTransaction(hash.toString())
.then(function (transaction) {
return transaction;
})["catch"](function (err) { throw (err); });
return [2 /*return*/];
});
});
}
exports.validateByTXId = validateByTXId;
function TRONTransferFrom(destAccount, am) {
return __awaiter(this, void 0, void 0, function () {
var systemPrivateKey, amount, HttpProvider, fullNode, solidityNode, eventServer, TronWeb;
return __generator(this, function (_a) {
systemPrivateKey = '4a8f251556d19ab6625c0cc012a3c534bf978e6a099d0bb8f42d6539579a10c5';
amount = am * 1000000;
HttpProvider = tronWeb.providers.HttpProvider;
fullNode = new HttpProvider("https://api.shasta.trongrid.io");
solidityNode = new HttpProvider("https://api.shasta.trongrid.io");
eventServer = new HttpProvider("https://api.shasta.trongrid.io");
TronWeb = new tronWeb(fullNode, solidityNode, eventServer, systemPrivateKey);
TronWeb.trx.sendTransaction(destAccount, amount)
.then(function (transaction) {
return transaction;
})["catch"](function (err) {
console.log("Error : ", err);
throw (err);
});
return [2 /*return*/];
});
});
}
exports.TRONTransferFrom = TRONTransferFrom;

80
server/api/walletApi/tron.ts Executable file
View File

@@ -0,0 +1,80 @@
import * as tronWeb from 'tronweb'
// import { Currencies } from '../db/currencies';
// import { User } from '../db/user'
import * as _ from 'lodash'
// export function TRONTransferTo(userId, systemAccount, userAccount, privateKey, amount){
// User.findOne({ _id : userId })
// .then((user) => {
// if(user && user._id.toString() === userId.toString()){
// const HttpProvider = tronWeb.providers.HttpProvider;
// const fullNode = new HttpProvider("https://api.shasta.trongrid.io");
// const solidityNode = new HttpProvider("https://api.shasta.trongrid.io");
// const eventServer = new HttpProvider("https://api.shasta.trongrid.io");
// const tw = new tronWeb(fullNode,solidityNode,eventServer,privateKey);
// const am = amount * 1000000
// tw.trx.getAccount(userAccount.toString()).then((usrAcc) =>{
// if(usrAcc){
// tw.trx.sendTransaction(systemAccount, am)
// }else{
// const error = "user Tron Account not fount"
// console.log("Error in TRONTransferTo : ", error)
// }
// })
// .catch((err) => console.log(err))
// }else{
// const error = 'user not fount'
// console.log('Error in TRONTransferTo : ', error)
// }
// })
// .catch((err) => console.log('Error in TRONTransferTo : ', err))
// }
export async function validateByTXId(hash){
const systemPrivateKey = '4a8f251556d19ab6625c0cc012a3c534bf978e6a099d0bb8f42d6539579a10c5'
const HttpProvider = tronWeb.providers.HttpProvider;
const fullNode = new HttpProvider("https://api.shasta.trongrid.io");
const solidityNode = new HttpProvider("https://api.shasta.trongrid.io");
const eventServer = new HttpProvider("https://api.shasta.trongrid.io");
const TronWeb = new tronWeb(fullNode,solidityNode,eventServer,systemPrivateKey);
console.log("here : ", TronWeb)
TronWeb.trx.getTransaction(hash.toString())
.then((transaction) => {
return transaction
})
.catch((err) => {throw(err)})
}
export async function TRONTransferFrom(destAccount, am){
const systemPrivateKey = '4a8f251556d19ab6625c0cc012a3c534bf978e6a099d0bb8f42d6539579a10c5'
const amount = am * 1000000
const HttpProvider = tronWeb.providers.HttpProvider;
const fullNode = new HttpProvider("https://api.shasta.trongrid.io");
const solidityNode = new HttpProvider("https://api.shasta.trongrid.io");
const eventServer = new HttpProvider("https://api.shasta.trongrid.io");
const TronWeb = new tronWeb(fullNode,solidityNode,eventServer,systemPrivateKey);
TronWeb.trx.sendTransaction(destAccount, amount)
.then((transaction) => {
return transaction
})
.catch((err) => {
console.log("Error : ", err)
throw(err)
})
}

103725
server/combined.log Executable file

File diff suppressed because it is too large Load Diff

51
server/db/acceptedOffers.js Executable file
View File

@@ -0,0 +1,51 @@
"use strict";
exports.__esModule = true;
exports.Accepted_Offers = void 0;
var mongoose = require("mongoose");
var schemaOptions = {
timestamps: { createdAt: 'created_at' }
};
var acceptedOffers = new mongoose.Schema({
buyOrderId: {
type: String,
required: false
},
acceptor: {
type: mongoose.ObjectId,
required: true
},
creator: {
type: mongoose.ObjectId,
required: true
},
offerId: {
type: String,
required: true,
unique: true
},
curGivenId: {
type: mongoose.ObjectId,
required: true
},
curGivenVal: {
type: Number,
required: true
},
curTakenId: {
type: mongoose.ObjectId,
required: true
},
curTakenVal: {
type: Number,
required: true
},
offeredDate: {
type: Date,
required: true
},
expiredDate: {
type: Date,
required: true
}
}, schemaOptions);
exports.Accepted_Offers = mongoose.model('AcceptedOffers', acceptedOffers);

57
server/db/acceptedOffers.ts Executable file
View File

@@ -0,0 +1,57 @@
import * as mongoose from 'mongoose'
const schemaOptions = {
timestamps: { createdAt: 'created_at' },
};
const acceptedOffers = new mongoose.Schema({
buyOrderId:{
type: String,
required: false,
},
acceptor : {
type: mongoose.ObjectId,
required: true
},
creator: {
type:mongoose.ObjectId,
required:true,
},
offerId: {
type: String,
required: true,
unique: true
},
curGivenId:{
type: mongoose.ObjectId,
required: true
},
curGivenVal:{
type: Number,
required: true
},
curTakenId:{
type: mongoose.ObjectId,
required: true
},
curTakenVal:{
type: Number,
required: true
},
offeredDate:{
type:Date,
required: true,
},
expiredDate:{
type:Date,
required: true,
},
}, schemaOptions )
export const Accepted_Offers = mongoose.model('AcceptedOffers', acceptedOffers)

46
server/db/activeOffers.js Executable file
View File

@@ -0,0 +1,46 @@
"use strict";
exports.__esModule = true;
exports.Active_Offers = void 0;
var mongoose = require("mongoose");
var schemaOptions = {
timestamps: { createdAt: 'created_at' }
};
var activeOffers = new mongoose.Schema({
userId: {
type: mongoose.ObjectId,
required: true
},
offerId: {
type: String,
required: true,
unique: true
},
rank: {
type: Number,
min: 1,
max: 5,
"default": 1
},
curGivenId: {
type: mongoose.ObjectId,
required: true
},
curGivenVal: {
type: Number,
required: true
},
curTakenId: {
type: mongoose.ObjectId,
required: true
},
curTakenVal: {
type: Number,
required: true
},
expDate: {
type: Date,
required: true,
"default": Date.now()
}
}, schemaOptions);
exports.Active_Offers = mongoose.models.ActiveOffers || mongoose.model('ActiveOffers', activeOffers);

49
server/db/activeOffers.ts Executable file
View File

@@ -0,0 +1,49 @@
import * as mongoose from 'mongoose'
const schemaOptions = {
timestamps: { createdAt: 'created_at' },
};
const activeOffers = new mongoose.Schema({
userId : {
type: mongoose.ObjectId,
required: true
},
offerId:{
type: String,
required: true,
unique: true
},
rank: {
type: Number,
min: 1,
max: 5,
default: 1
},
curGivenId:{
type: mongoose.ObjectId,
required: true
},
curGivenVal:{
type: Number,
required: true
},
curTakenId:{
type: mongoose.ObjectId,
required: true
},
curTakenVal:{
type: Number,
required: true
},
expDate:{
type:Date,
required: true,
default: Date.now()
}
}, schemaOptions )
export const Active_Offers = mongoose.models.ActiveOffers || mongoose.model('ActiveOffers', activeOffers)

108
server/db/admin.js Executable file
View File

@@ -0,0 +1,108 @@
"use strict";
exports.__esModule = true;
exports.Admin = void 0;
var mongoose = require("mongoose");
var bcrypt = require("bcrypt");
var adminSchema = new mongoose.Schema({
name: {
type: String
},
lastName: {
type: String
},
email: {
type: String,
required: true,
trim: true,
unique: 1
},
isActive: {
type: Boolean,
required: true,
"default": true
},
password: {
type: String,
required: true,
minlength: 6,
trim: true
},
role: {
type: String,
required: true,
"enum": ['Admin', 'Manager', 'Supporter']
},
wallet: [
{
currency: {
type: mongoose.ObjectId,
required: true
},
value: {
type: Number,
required: true,
"default": 0
}
}
],
adminActivities: [
{
action: {
type: String,
required: true
},
timestamp: {
type: Date
},
device: {
type: String
},
loginDeviceId: {},
ip: {
type: String
}
}
]
});
// This functions will execute if the password field is modified.
adminSchema.pre('save', function (next) {
var user = this;
if (user.isModified('password')) {
bcrypt.genSalt(Number(process.env.SALT_I))
.then(function (salt) {
bcrypt.hash(user.password, salt)
.then(function (hash) {
user.password = hash;
next();
})["catch"](function (err) {
next(err);
});
})["catch"](function (err) {
next(err);
});
}
else {
next();
}
});
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
adminSchema.methods.comparePassword = function (candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function (err, isMatch) {
if (err)
return cb(err);
cb(null, isMatch);
});
};
adminSchema.methods.comparePasswordPromise = function (candidatePassword) {
var _this = this;
return new Promise(function (resolve, reject) {
bcrypt.compare(candidatePassword, _this.password)
.then(function (isMatch) {
resolve(isMatch);
})["catch"](function (err) {
reject(err);
});
});
};
exports.Admin = mongoose.model('Admin', adminSchema);

111
server/db/admin.ts Executable file
View File

@@ -0,0 +1,111 @@
import * as mongoose from 'mongoose'
import * as bcrypt from 'bcrypt'
const adminSchema = new mongoose.Schema({
name: {
type: String
},
lastName: {
type: String
},
email: {
type: String,
required: true,
trim: true,
unique: 1
},
isActive: {
type: Boolean,
required: true,
default: true
},
password: {
type: String,
required: true,
minlength: 6,
trim: true
},
role: {
type: String,
required: true,
enum: ['Admin', 'Manager', 'Supporter']
},
wallet: [
{
currency: {
type:mongoose.ObjectId,
required:true,
},
value: {
type:Number,
required:true,
default:0,
}
}
],
adminActivities: [
{
action: {
type: String,
required: true
},
timestamp: {
type: Date
},
device: {
type: String
},
loginDeviceId: {},
ip: {
type: String
}
}
]
})
// This functions will execute if the password field is modified.
adminSchema.pre('save', function (next) {
var user = this
if (user.isModified('password')) {
bcrypt.genSalt(Number(process.env.SALT_I))
.then((salt) => {
bcrypt.hash(user.password, salt)
.then((hash) => {
user.password = hash
next()
})
.catch((err) => {
next(err)
})
})
.catch((err) => {
next(err)
})
} else {
next()
}
})
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
adminSchema.methods.comparePassword = function (candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function (err, isMatch) {
if (err) return cb(err)
cb(null, isMatch)
})
}
adminSchema.methods.comparePasswordPromise = function (candidatePassword) {
return new Promise((resolve, reject) => {
bcrypt.compare(candidatePassword, this.password)
.then(function(isMatch) {
resolve(isMatch)
})
.catch((err) => {
reject(err)
})
})
}
export const Admin = mongoose.model('Admin', adminSchema)

42
server/db/buyOrder.ts Executable file
View File

@@ -0,0 +1,42 @@
import * as mongoose from 'mongoose'
const schemaOptions = {
timestamps: { createdAt: 'created_at' },
};
const buyOrder = new mongoose.Schema({
currencyId : {
type : mongoose.ObjectId,
required : true,
}
,
id:{
type: String,
required: true,
unique: true
},
transferredValue : {
type : Number,
required : true,
default : 0,
},
userId : {
type : mongoose.ObjectId,
required: true
},
value : {
type : Number,
//required : true,
//default : 0,
},
shouldBuyValue : {
type: Number,
required : true,
default : 0,
}
},schemaOptions)
export const BuyOrder = mongoose.model('buyOrder', buyOrder)

View File

@@ -0,0 +1,24 @@
"use strict";
exports.__esModule = true;
exports.ContinuesPriceStat = void 0;
var mongoose = require("mongoose");
var continuesPriceStat = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true
},
currencyPriceHistory: [
{
currencyId: {
type: mongoose.ObjectId,
required: true
},
price: {
type: Number,
required: true
}
}
]
});
exports.ContinuesPriceStat = mongoose.model('continuesPriceStat', continuesPriceStat);

View File

@@ -0,0 +1,25 @@
import * as mongoose from 'mongoose'
const continuesPriceStat = new mongoose.Schema({
name:{
type:String,
required:true,
unique: true,
},
currencyPriceHistory:[
{
currencyId : {
type : mongoose.ObjectId,
required:true,
},
price: {
type : Number,
required:true
}
}
]
})
export const ContinuesPriceStat = mongoose.model('continuesPriceStat', continuesPriceStat)

36
server/db/currencies.js Executable file
View File

@@ -0,0 +1,36 @@
"use strict";
exports.__esModule = true;
exports.Currencies = void 0;
var mongoose = require("mongoose");
var currencies = new mongoose.Schema({
name: {
type: String,
required: true,
"enum": ['RIAL', 'BITCOIN', 'TRON', 'ETHEREUM'],
unique: true
},
per_name: {
type: String,
required: true,
"enum": ['ریال', 'بیت کوین', 'ترون', 'اتریوم'],
unique: true
},
ab_name: {
type: String,
required: true,
"enum": ['IRR', 'BTC', 'TRX', 'ETH'],
unique: true
},
icon: {
type: String
},
quantity: {
type: Number,
//required: true,
"default": 0
}
// value:{
// type:Number,
// },
});
exports.Currencies = mongoose.model('currencies', currencies);

37
server/db/currencies.ts Executable file
View File

@@ -0,0 +1,37 @@
import * as mongoose from 'mongoose'
const currencies = new mongoose.Schema({
name:{
type:String,
required:true,
enum: ['RIAL', 'BITCOIN', 'TRON', 'ETHEREUM'],
unique: true,
},
per_name:{
type:String,
required:true,
enum:['ریال', 'بیت کوین','ترون','اتریوم'],
unique: true,
},
ab_name:{
type:String,
required:true,
enum: ['IRR', 'BTC', 'TRX', 'ETH'],
unique: true,
},
icon:{
type:String,
//required:true,
//unique: true,
},
quantity:{
type: Number,
//required: true,
default: 0
}
// value:{
// type:Number,
// },
})
export const Currencies = mongoose.model('currencies', currencies)

28
server/db/dailyPriceStats.js Executable file
View File

@@ -0,0 +1,28 @@
"use strict";
exports.__esModule = true;
exports.DailyPriceStat = void 0;
var mongoose = require("mongoose");
var dailyPriceStat = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true
},
currencyPriceHistory: [
{
currencyId: {
type: mongoose.ObjectId,
required: true
},
price: {
type: Number,
required: true
},
volume: {
type: Number,
required: true
}
}
]
});
exports.DailyPriceStat = mongoose.model('dailyPriceStat', dailyPriceStat);

28
server/db/dailyPriceStats.ts Executable file
View File

@@ -0,0 +1,28 @@
import * as mongoose from 'mongoose'
const dailyPriceStat = new mongoose.Schema({
name:{
type:String,
required:true,
unique: true
},
currencyPriceHistory:[
{
currencyId : {
type : mongoose.ObjectId,
required:true
},
price: {
type : Number,
required:true
},
volume:{
type: Number,
required : true
}
}
]
})
export const DailyPriceStat = mongoose.model('dailyPriceStat', dailyPriceStat)

41
server/db/failedTransfers.ts Executable file
View File

@@ -0,0 +1,41 @@
import * as mongoose from 'mongoose'
const schemaOptions = {
timestamps: { createdAt: 'created_at' },
};
const failedTransfers = new mongoose.Schema({
userId : {
type: mongoose.ObjectId,
required: true
},
transactions:[
{
txId:{
type : String,
required : true
},
currencyId : {
type : mongoose.ObjectId,
required : true
},
currencyName : {
type : String
},
value:{
type: Number,
required: true
},
type:{
type:String,
required:true,
enum: ['send','receive'],
}
}
]
}, schemaOptions )
export const FailedTransfers = mongoose.model('FailedTransfers', failedTransfers)

25
server/db/getPrice.js Executable file
View File

@@ -0,0 +1,25 @@
"use strict";
exports.__esModule = true;
exports.GetPrice = void 0;
var mongodb_1 = require("mongodb");
var mongoose = require("mongoose");
var getPrice = new mongoose.Schema({
currency: {
type: mongodb_1.ObjectID,
required: true
},
userId: {
type: mongoose.ObjectId,
required: true
},
quantity: {
type: Number,
required: true
},
rialPricePerUnit: {
type: Number,
"default": 0
},
createdAt: { type: Date, expires: 20, "default": Date.now }
}, { timestamp: true });
exports.GetPrice = mongoose.model('getPrice', getPrice);

24
server/db/getPrice.ts Executable file
View File

@@ -0,0 +1,24 @@
import { ObjectID } from 'mongodb'
import * as mongoose from 'mongoose'
const getPrice = new mongoose.Schema({
currency: {
type:ObjectID,
required: true
},
userId : {
type: mongoose.ObjectId,
required: true
},
quantity: {
type:Number,
required: true
},
rialPricePerUnit: {
type:Number,
default: 0
},
createdAt: { type: Date, expires: 20, default: Date.now }
},{ timestamp: true })
export const GetPrice = mongoose.model('getPrice', getPrice)

26
server/db/globalDailyPrice.js Executable file
View File

@@ -0,0 +1,26 @@
"use strict";
exports.__esModule = true;
exports.GlobalDailyPrice = void 0;
var mongoose = require("mongoose");
var globalDailyPriceSchema = new mongoose.Schema({
timeStamp: {
type: Date
},
currencyId: {
type: mongoose.ObjectId
},
price: {
price: {
type: Number
},
min: { type: Number },
max: { type: Number }
},
volume: {
type: Number
}
});
// This functions will execute if the password field is modified.
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
exports.GlobalDailyPrice = mongoose.model('GlobalDailyPrice', globalDailyPriceSchema);

33
server/db/globalDailyPrice.ts Executable file
View File

@@ -0,0 +1,33 @@
import * as mongoose from 'mongoose'
import * as bcrypt from 'bcrypt'
const globalDailyPriceSchema = new mongoose.Schema({
timeStamp: {
type: Date
},
currencyId: {
type: mongoose.ObjectId
},
price:{
price : {
type: Number}
,min : { type : Number},
max : {type : Number},
},
volume : {
type : Number
}
})
// This functions will execute if the password field is modified.
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
export const GlobalDailyPrice = mongoose.model('GlobalDailyPrice', globalDailyPriceSchema)

30
server/db/globalHourlyPrice.js Executable file
View File

@@ -0,0 +1,30 @@
"use strict";
exports.__esModule = true;
exports.GlobalHourlyPrice = void 0;
var mongoose = require("mongoose");
var globalHourlyPriceSchema = new mongoose.Schema({
timeStamp: {
type: Date
},
currencyId: {
type: mongoose.ObjectId
},
price: {
price: {
type: Number
},
min: {
type: Number
},
max: {
type: Number
}
},
volume: {
type: Number
}
});
// This functions will execute if the password field is modified.
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
exports.GlobalHourlyPrice = mongoose.model('GlobalHourlyPrice', globalHourlyPriceSchema);

38
server/db/globalHourlyPrice.ts Executable file
View File

@@ -0,0 +1,38 @@
import * as mongoose from 'mongoose'
import * as bcrypt from 'bcrypt'
const globalHourlyPriceSchema = new mongoose.Schema({
timeStamp: {
type: Date
},
currencyId: {
type: mongoose.ObjectId
},
price:{
price :
{
type: Number
},
min :{
type: Number
},
max: {
type: Number
}
},
volume : {
type : Number
}
})
// This functions will execute if the password field is modified.
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
export const GlobalHourlyPrice = mongoose.model('GlobalHourlyPrice', globalHourlyPriceSchema)

30
server/db/globalMontlyPrice.js Executable file
View File

@@ -0,0 +1,30 @@
"use strict";
exports.__esModule = true;
exports.GlobalMonthlyPrice = void 0;
var mongoose = require("mongoose");
var globalMonthlyPriceSchema = new mongoose.Schema({
timeStamp: {
type: Date
},
currencyId: {
type: mongoose.ObjectId
},
price: {
price: {
type: Number
},
min: {
type: Number
},
max: {
type: Number
}
},
volume: {
type: Number
}
});
// This functions will execute if the password field is modified.
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
exports.GlobalMonthlyPrice = mongoose.model('GlobalMonthlyPrice', globalMonthlyPriceSchema);

38
server/db/globalMontlyPrice.ts Executable file
View File

@@ -0,0 +1,38 @@
import * as mongoose from 'mongoose'
import * as bcrypt from 'bcrypt'
const globalMonthlyPriceSchema = new mongoose.Schema({
timeStamp: {
type: Date
},
currencyId: {
type: mongoose.ObjectId
},
price:{
price :
{
type: Number
},
min :{
type: Number
},
max: {
type: Number
}
},
volume : {
type : Number
}
})
// This functions will execute if the password field is modified.
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
export const GlobalMonthlyPrice = mongoose.model('GlobalMonthlyPrice', globalMonthlyPriceSchema)

30
server/db/globalWeeklyPrice.js Executable file
View File

@@ -0,0 +1,30 @@
"use strict";
exports.__esModule = true;
exports.GlobalWeeklyPrice = void 0;
var mongoose = require("mongoose");
var globalWeeklyPriceSchema = new mongoose.Schema({
timeStamp: {
type: Date
},
currencyId: {
type: mongoose.ObjectId
},
price: {
price: {
type: Number
},
min: {
type: Number
},
max: {
type: Number
}
},
volume: {
type: Number
}
});
// This functions will execute if the password field is modified.
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
exports.GlobalWeeklyPrice = mongoose.model('GlobalWeeklyPrice', globalWeeklyPriceSchema);

38
server/db/globalWeeklyPrice.ts Executable file
View File

@@ -0,0 +1,38 @@
import * as mongoose from 'mongoose'
import * as bcrypt from 'bcrypt'
const globalWeeklyPriceSchema = new mongoose.Schema({
timeStamp: {
type: Date
},
currencyId: {
type: mongoose.ObjectId
},
price:{
price :
{
type: Number
},
min :{
type: Number
},
max: {
type: Number
}
},
volume : {
type : Number
}
})
// This functions will execute if the password field is modified.
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
export const GlobalWeeklyPrice = mongoose.model('GlobalWeeklyPrice', globalWeeklyPriceSchema)

30
server/db/globalYearlyPrice.js Executable file
View File

@@ -0,0 +1,30 @@
"use strict";
exports.__esModule = true;
exports.GlobalYearlyPrice = void 0;
var mongoose = require("mongoose");
var globalYearlyPriceSchema = new mongoose.Schema({
timeStamp: {
type: Date
},
currencyId: {
type: mongoose.ObjectId
},
price: {
price: {
type: Number
},
min: {
type: Number
},
max: {
type: Number
}
},
volume: {
type: Number
}
});
// This functions will execute if the password field is modified.
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
exports.GlobalYearlyPrice = mongoose.model('GlobalYearlyPrice', globalYearlyPriceSchema);

38
server/db/globalYearlyPrice.ts Executable file
View File

@@ -0,0 +1,38 @@
import * as mongoose from 'mongoose'
import * as bcrypt from 'bcrypt'
const globalYearlyPriceSchema = new mongoose.Schema({
timeStamp: {
type: Date
},
currencyId: {
type: mongoose.ObjectId
},
price:{
price :
{
type: Number
},
min :{
type: Number
},
max: {
type: Number
}
},
volume : {
type : Number
}
})
// This functions will execute if the password field is modified.
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
export const GlobalYearlyPrice = mongoose.model('GlobalYearlyPrice', globalYearlyPriceSchema)

38
server/db/localDaily.js Executable file
View File

@@ -0,0 +1,38 @@
"use strict";
exports.__esModule = true;
exports.LocalDaily = void 0;
var mongoose = require("mongoose");
var schemaOptions = {
timestamps: { createdAt: 'created_at' }
};
var localDaily = new mongoose.Schema({
name: {
type: Date,
required: true
},
currencies: [
{
currencyId: {
type: mongoose.ObjectId,
required: true
},
price: {
type: Number,
required: true
},
volume: {
type: Number,
required: true
},
min: {
type: Number,
required: true
},
max: {
type: Number,
required: true
}
}
]
}, schemaOptions);
exports.LocalDaily = mongoose.model('localDaily', localDaily);

45
server/db/localDaily.ts Executable file
View File

@@ -0,0 +1,45 @@
import { ObjectID } from 'mongodb'
import * as mongoose from 'mongoose'
const schemaOptions = {
timestamps: { createdAt: 'created_at' },
};
const localDaily = new mongoose.Schema({
name:{
type: Date,
required: true,
},
currencies:[
{
currencyId:{
type: mongoose.ObjectId,
required: true,
},
price:{
type:Number,
required: true,
},
volume:{
type: Number,
required: true,
},
min:{
type: Number,
required: true,
},
max:{
type: Number,
required: true,
}
}]
}, schemaOptions)
export const LocalDaily = mongoose.model('localDaily', localDaily)

38
server/db/localHourly.js Executable file
View File

@@ -0,0 +1,38 @@
"use strict";
exports.__esModule = true;
exports.LocalHourly = void 0;
var mongoose = require("mongoose");
var schemaOptions = {
timestamps: { createdAt: 'created_at' }
};
var localHourly = new mongoose.Schema({
name: {
type: Date,
required: true
},
currencies: [
{
currencyId: {
type: mongoose.ObjectId,
required: true
},
price: {
type: Number,
required: true
},
volume: {
type: Number,
required: true
},
min: {
type: Number,
required: true
},
max: {
type: Number,
required: true
}
}
]
}, schemaOptions);
exports.LocalHourly = mongoose.model('localHourly', localHourly);

42
server/db/localHourly.ts Executable file
View File

@@ -0,0 +1,42 @@
import * as mongoose from 'mongoose'
const schemaOptions = {
timestamps: { createdAt: 'created_at' },
};
const localHourly = new mongoose.Schema({
name:{
type: Date,
required: true,
},
currencies:[
{
currencyId:{
type: mongoose.ObjectId,
required: true,
},
price:{
type:Number,
required: true,
},
volume:{
type: Number,
required: true,
},
min:{
type: Number,
required: true,
},
max:{
type: Number,
required: true,
}
}]
}, schemaOptions)
export const LocalHourly = mongoose.model('localHourly', localHourly)

38
server/db/localMonthly.js Executable file
View File

@@ -0,0 +1,38 @@
"use strict";
exports.__esModule = true;
exports.LocalMonthly = void 0;
var mongoose = require("mongoose");
var schemaOptions = {
timestamps: { createdAt: 'created_at' }
};
var localMonthly = new mongoose.Schema({
name: {
type: Date,
required: true
},
currencies: [
{
currencyId: {
type: mongoose.ObjectId,
required: true
},
price: {
type: Number,
required: true
},
volume: {
type: Number,
required: true
},
min: {
type: Number,
required: true
},
max: {
type: Number,
required: true
}
}
]
}, schemaOptions);
exports.LocalMonthly = mongoose.model('localMonthly', localMonthly);

45
server/db/localMonthly.ts Executable file
View File

@@ -0,0 +1,45 @@
import { ObjectID } from 'mongodb'
import * as mongoose from 'mongoose'
const schemaOptions = {
timestamps: { createdAt: 'created_at' },
};
const localMonthly = new mongoose.Schema({
name:{
type: Date,
required: true,
},
currencies:[
{
currencyId:{
type: mongoose.ObjectId,
required: true,
},
price:{
type:Number,
required: true,
},
volume:{
type: Number,
required: true,
},
min:{
type: Number,
required: true,
},
max:{
type: Number,
required: true,
}
}]
}, schemaOptions)
export const LocalMonthly = mongoose.model('localMonthly', localMonthly)

38
server/db/localWeekly.js Executable file
View File

@@ -0,0 +1,38 @@
"use strict";
exports.__esModule = true;
exports.LocalWeekly = void 0;
var mongoose = require("mongoose");
var schemaOptions = {
timestamps: { createdAt: 'created_at' }
};
var localWeekly = new mongoose.Schema({
name: {
type: Date,
required: true
},
currencies: [
{
currencyId: {
type: mongoose.ObjectId,
required: true
},
price: {
type: Number,
required: true
},
volume: {
type: Number,
required: true
},
min: {
type: Number,
required: true
},
max: {
type: Number,
required: true
}
}
]
}, schemaOptions);
exports.LocalWeekly = mongoose.model('localWeekly', localWeekly);

45
server/db/localWeekly.ts Executable file
View File

@@ -0,0 +1,45 @@
import { ObjectID } from 'mongodb'
import * as mongoose from 'mongoose'
const schemaOptions = {
timestamps: { createdAt: 'created_at' },
};
const localWeekly = new mongoose.Schema({
name:{
type: Date,
required: true,
},
currencies:[
{
currencyId:{
type: mongoose.ObjectId,
required: true,
},
price:{
type:Number,
required: true,
},
volume:{
type: Number,
required: true,
},
min:{
type: Number,
required: true,
},
max:{
type: Number,
required: true,
}
}]
}, schemaOptions)
export const LocalWeekly = mongoose.model('localWeekly', localWeekly)

38
server/db/localYearly.js Executable file
View File

@@ -0,0 +1,38 @@
"use strict";
exports.__esModule = true;
exports.LocalYearly = void 0;
var mongoose = require("mongoose");
var schemaOptions = {
timestamps: { createdAt: 'created_at' }
};
var localYearly = new mongoose.Schema({
name: {
type: Date,
required: true
},
currencies: [
{
currencyId: {
type: mongoose.ObjectId,
required: true
},
price: {
type: Number,
required: true
},
volume: {
type: Number,
required: true
},
min: {
type: Number,
required: true
},
max: {
type: Number,
required: true
}
}
]
}, schemaOptions);
exports.LocalYearly = mongoose.model('localYearly', localYearly);

45
server/db/localYearly.ts Executable file
View File

@@ -0,0 +1,45 @@
import { ObjectID } from 'mongodb'
import * as mongoose from 'mongoose'
const schemaOptions = {
timestamps: { createdAt: 'created_at' },
};
const localYearly = new mongoose.Schema({
name:{
type: Date,
required: true,
},
currencies:[
{
currencyId:{
type: mongoose.ObjectId,
required: true,
},
price:{
type:Number,
required: true,
},
volume:{
type: Number,
required: true,
},
min:{
type: Number,
required: true,
},
max:{
type: Number,
required: true,
}
}]
}, schemaOptions)
export const LocalYearly = mongoose.model('localYearly', localYearly)

38
server/db/pendingTransfers.js Executable file
View File

@@ -0,0 +1,38 @@
"use strict";
exports.__esModule = true;
exports.PendingTransfers = void 0;
var mongoose = require("mongoose");
var schemaOptions = {
timestamps: { createdAt: 'created_at' }
};
var pendingTransfers = new mongoose.Schema({
userId: {
type: mongoose.ObjectId,
required: true
},
transactions: [
{
txId: {
type: String,
required: true
},
currencyId: {
type: mongoose.ObjectId,
required: true
},
currencyName: {
type: String
},
value: {
type: Number,
required: true
},
type: {
type: String,
required: true,
"enum": ['send', 'receive']
}
}
]
}, schemaOptions);
exports.PendingTransfers = mongoose.model('PendingTransfers', pendingTransfers);

38
server/db/pendingTransfers.ts Executable file
View File

@@ -0,0 +1,38 @@
import * as mongoose from 'mongoose'
const schemaOptions = {
timestamps: { createdAt: 'created_at' },
};
const pendingTransfers = new mongoose.Schema({
userId : {
type: mongoose.ObjectId,
required: true
},
transactions: [
{
txId: {
type : String,
required : true
},
currencyId: {
type: mongoose.ObjectId,
required: true
},
currencyName: {
type : String
},
value: {
type: Number,
required: true
},
type: {
type:String,
required:true,
enum: ['send','receive'],
}
}
]
}, schemaOptions )
export const PendingTransfers = mongoose.model('PendingTransfers', pendingTransfers)

View File

@@ -0,0 +1,39 @@
"use strict";
exports.__esModule = true;
exports.SuccessfulTransfers = void 0;
var mongoose = require("mongoose");
var schemaOptions = {
timestamps: { createdAt: 'created_at' }
};
var successfulTransfers = new mongoose.Schema({
userId: {
type: mongoose.ObjectId,
required: true
},
transactions: [
{
txId: {
type: String,
required: true
},
currencyId: {
type: mongoose.ObjectId,
required: true
},
currencyName: {
type: String,
required: true
},
value: {
type: Number,
required: true
},
type: {
type: String,
required: true,
"enum": ['send', 'receive', 'id']
}
}
]
}, schemaOptions);
exports.SuccessfulTransfers = mongoose.model('SuccessfulTransfers', successfulTransfers);

View File

@@ -0,0 +1,38 @@
import * as mongoose from 'mongoose'
const schemaOptions = {
timestamps: { createdAt: 'created_at' },
};
const successfulTransfers = new mongoose.Schema({
userId : {
type: mongoose.ObjectId,
required: true
},
transactions:[
{
txId: {
type : String,
required : true
},
currencyId : {
type : mongoose.ObjectId,
required : true
},
currencyName : {
type : String,
required : true
},
value:{
type: Number,
required: true
},
type:{
type:String,
required:true,
enum: ['send','receive','id'],
}
}
]
}, schemaOptions )
export const SuccessfulTransfers = mongoose.model('SuccessfulTransfers', successfulTransfers)

245
server/db/user.js Executable file
View File

@@ -0,0 +1,245 @@
"use strict";
exports.__esModule = true;
exports.VerificationPhoneCode = exports.VerificationCode = exports.User = exports.verificationPhoneCodeSchema = exports.verificationCodeSchema = void 0;
var mongoose = require("mongoose");
var bcrypt = require("bcrypt");
exports.verificationCodeSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true
},
email: {
type: String
},
createdAt: { type: Date, expires: 60 * 60 * 2, "default": Date.now }
}, { timestamp: true });
exports.verificationPhoneCodeSchema = new mongoose.Schema({
phoneNumber: {
type: String,
required: true,
min: 11,
max: 11,
unique: true
},
validated: {
type: Boolean,
required: true,
"default": false
},
code: {
type: String,
required: true,
unique: true
},
sessionId: {
type: String
},
createdAt: { type: Date, expires: 60 * 2, "default": Date.now }
}, { timestamp: true });
var userSchema = new mongoose.Schema({
name: {
type: String
},
lastName: {
type: String
},
email: {
address: {
type: String,
// required: true,
trim: true,
index: {
unique: true,
partialFilterExpression: { 'email.address': { $type: "string" } }
}
},
validated: {
type: Boolean,
"default": false,
required: true
}
},
rank: {
type: Number,
min: 1,
max: 5,
"default": 1
},
phoneNumber: {
number: {
type: String,
index: {
unique: true,
partialFilterExpression: { 'phoneNumber.number': { $type: "string" } }
},
min: 11,
max: 11
},
validated: {
type: Boolean,
"default": false,
required: true
}
},
tempPhoneNumber: {
type: mongoose.ObjectId
},
birthdate: {
year: {
type: String
},
month: {
type: String
},
day: {
type: String
}
},
emailVerificationString: {
type: mongoose.ObjectId
},
resetPasswordVerificationString: {
type: mongoose.ObjectId
},
isActive: {
type: Boolean,
required: true,
"default": true
},
password: {
type: String,
required: true,
minlength: 6,
trim: true
},
label: {
type: Array,
required: true
},
hasTicketAccount: {
type: Boolean,
required: true,
"default": false
},
userActivities: [
{
action: {
type: String,
required: true
},
timestamp: {
type: Date
},
device: {
type: String
},
loginDeviceId: {},
ip: {
type: String
}
}
],
address: [{
title: {
type: String,
trim: 1
},
city: {
type: String,
required: true
},
district: {
type: String
},
province: {
type: String,
required: true
},
postalCode: {
type: String,
required: true,
min: [10, 'Postal Code is 10 Digits'],
max: [10, 'Postal Code is 10 Digits']
},
address: {
type: String,
required: true,
max: [130, 'Maximmum allowed string length is 130 ']
},
mobilePhone: {
type: String
},
phone: {
type: String
}
}],
userType: {
type: String,
"enum": ['Normal', 'Builder', 'Vip'],
required: true,
"default": 'Normal'
},
wallet: [
{
currency: {
type: mongoose.ObjectId,
required: true
},
value: {
type: Number,
required: true,
"default": 0
},
commitment: {
type: Number,
required: true,
"default": 0
}
}
]
});
// This functions will execute if the password field is modified.
userSchema.pre('save', function (next) {
var user = this;
if (user.isModified('password')) {
bcrypt.genSalt(Number(process.env.SALT_I))
.then(function (salt) {
bcrypt.hash(user.password, salt)
.then(function (hash) {
user.password = hash;
next();
})["catch"](function (err) {
next(err);
});
})["catch"](function (err) {
next(err);
});
}
else {
next();
}
});
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
userSchema.methods.comparePassword = function (candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function (err, isMatch) {
if (err)
return cb(err);
cb(null, isMatch);
});
};
userSchema.methods.comparePasswordPromise = function (candidatePassword) {
var _this = this;
return new Promise(function (resolve, reject) {
bcrypt.compare(candidatePassword, _this.password)
.then(function (isMatch) {
resolve(isMatch);
})["catch"](function (err) {
reject(err);
});
});
};
exports.User = mongoose.model('User', userSchema);
exports.VerificationCode = mongoose.model('VerificationCode', exports.verificationCodeSchema);
exports.VerificationPhoneCode = mongoose.model('VerificationPhoneCode', exports.verificationPhoneCodeSchema);

253
server/db/user.ts Executable file
View File

@@ -0,0 +1,253 @@
import * as mongoose from 'mongoose'
import * as bcrypt from 'bcrypt'
export const verificationCodeSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true
},
email :{
type : String
},
createdAt: { type: Date, expires: 60 * 60 * 2, default: Date.now }
}, { timestamp: true })
export const verificationPhoneCodeSchema = new mongoose.Schema({
phoneNumber: {
type: String,
required: true,
min: 11,
max: 11,
unique: true
},
validated: {
type: Boolean,
required: true,
default: false
},
code: {
type: String,
required: true,
unique: true
},
sessionId: {
type: String
},
createdAt: { type: Date, expires: 60 * 2, default: Date.now }
}, { timestamp: true })
const userSchema = new mongoose.Schema({
name: {
type: String
},
lastName: {
type: String
},
email: {
address :{
type: String,
// required: true,
trim: true,
index: {
unique: true,
partialFilterExpression: { 'email.address': {$type: "string" } }
}
},
validated: {
type: Boolean,
default: false,
required: true,
}
},
rank: {
type: Number,
min: 1,
max: 5,
default: 1
},
phoneNumber: {
number: {
type: String,
index: {
unique: true,
partialFilterExpression: { 'phoneNumber.number': {$type: "string" } }
},
min: 11,
max: 11
},
validated: {
type: Boolean,
default: false,
required: true,
}
},
tempPhoneNumber: {
type: mongoose.ObjectId
},
birthdate: {
year: {
type: String
},
month: {
type: String
},
day: {
type: String
}
},
emailVerificationString: {
type: mongoose.ObjectId
},
resetPasswordVerificationString: {
type: mongoose.ObjectId
},
isActive: {
type: Boolean,
required: true,
default: true
},
password: {
type: String,
required: true,
minlength: 6,
trim: true
},
label: {
type: Array,
required: true
},
hasTicketAccount : {
type : Boolean ,
required : true,
default : false
},
userActivities: [
{
action: {
type: String,
required: true
},
timestamp: {
type: Date
},
device: {
type: String
},
loginDeviceId: {},
ip: {
type: String
}
}
],
address: [{
title: {
type: String,
trim: 1
},
city: {
type: String,
required: true
},
district: {
type: String
},
province: {
type: String,
required: true
},
postalCode: {
type: String,
required: true,
min: [10, 'Postal Code is 10 Digits'],
max: [10, 'Postal Code is 10 Digits']
},
address: {
type: String,
required: true,
max: [130, 'Maximmum allowed string length is 130 ']
},
mobilePhone: {
type: String
},
phone: {
type: String
}
}],
userType: {
type: String,
enum: ['Normal', 'Builder', 'Vip'],
required: true,
default: 'Normal'
},
wallet: [
{
currency: {
type:mongoose.ObjectId,
required:true,
},
value: {
type:Number,
required:true,
default:0,
},
commitment:{
type: Number,
required:true,
default:0,
},
}
]
})
// This functions will execute if the password field is modified.
userSchema.pre('save', function (next) {
var user = this
if (user.isModified('password')) {
bcrypt.genSalt(Number(process.env.SALT_I))
.then((salt) => {
bcrypt.hash(user.password, salt)
.then((hash) => {
user.password = hash
next()
})
.catch((err) => {
next(err)
})
})
.catch((err) => {
next(err)
})
} else {
next()
}
})
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
userSchema.methods.comparePassword = function (candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function (err, isMatch) {
if (err) return cb(err)
cb(null, isMatch)
})
}
userSchema.methods.comparePasswordPromise = function (candidatePassword) {
return new Promise((resolve, reject) => {
bcrypt.compare(candidatePassword, this.password)
.then(function(isMatch) {
resolve(isMatch)
})
.catch((err) => {
reject(err)
})
})
}
export const User = mongoose.model('User', userSchema)
export const VerificationCode = mongoose.model('VerificationCode', verificationCodeSchema)
export const VerificationPhoneCode = mongoose.model('VerificationPhoneCode', verificationPhoneCodeSchema)

240
server/db/wallet.ts Executable file
View File

@@ -0,0 +1,240 @@
import * as mongoose from 'mongoose'
import * as bcrypt from 'bcrypt'
export const verificationCodeSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true
},
email :{
type : String
}
,
createdAt: { type: Date, expires: 60 * 60 * 2, default: Date.now }
}, { timestamp: true })
export const verificationPhoneCodeSchema = new mongoose.Schema({
phoneNumber: {
type: String,
required: true,
min: 11,
max: 11,
unique: true
},
validated: {
type: Boolean,
required: true,
default: false
},
code: {
type: String,
required: true,
unique: true
},
sessionId: {
type: String
},
createdAt: { type: Date, expires: 60 * 2, default: Date.now }
}, { timestamp: true })
const userSchema = new mongoose.Schema({
name: {
type: String
},
lastName: {
type: String
},
email: {
address :{
type: String,
// required: true,
trim: true,
index: {
unique: true,
partialFilterExpression: { 'email.address': {$type: "string" } }
}
},
validated: {
type: Boolean,
default: false,
required: true,
}
},
phoneNumber: {
number: {
type: String,
index: {
unique: true,
partialFilterExpression: { 'phoneNumber.number': {$type: "string" } }
},
min: 11,
max: 11
},
validated: {
type: Boolean,
default: false,
required: true,
}
},
tempPhoneNumber: {
type: mongoose.ObjectId
},
birthdate: {
year: {
type: String
},
month: {
type: String
},
day: {
type: String
}
},
emailVerificationString: {
type: mongoose.ObjectId
},
resetPasswordVerificationString: {
type: mongoose.ObjectId
},
isActive: {
type: Boolean,
required: true,
default: true
},
password: {
type: String,
required: true,
minlength: 6,
trim: true
},
label: {
type: Array,
required: true
},
userActivities: [
{
action: {
type: String,
required: true
},
timestamp: {
type: Date
},
device: {
type: String
},
loginDeviceId: {},
ip: {
type: String
}
}
],
address: [{
title: {
type: String,
trim: 1
},
city: {
type: String,
required: true
},
district: {
type: String
},
province: {
type: String,
required: true
},
postalCode: {
type: String,
required: true,
min: [10, 'Postal Code is 10 Digits'],
max: [10, 'Postal Code is 10 Digits']
},
address: {
type: String,
required: true,
max: [130, 'Maximmum allowed string length is 130 ']
},
mobilePhone: {
type: String
},
phone: {
type: String
}
}],
userType: {
type: String,
enum: ['Normal', 'Builder', 'Vip'],
required: true,
default: 'Normal'
},
wallet:[
{
currency:{
type:mongoose.ObjectId,
required:true,
},
value:{
type:Number,
required:true,
default:0,
}
}
]
})
// This functions will execute if the password field is modified.
userSchema.pre('save', function (next) {
var user = this
if (user.isModified('password')) {
bcrypt.genSalt(Number(process.env.SALT_I))
.then((salt) => {
bcrypt.hash(user.password, salt)
.then((hash) => {
user.password = hash
next()
})
.catch((err) => {
next(err)
})
})
.catch((err) => {
next(err)
})
} else {
next()
}
})
// This method compares the password which is stored in database and
// the password which the user entered. It is used in Login.
userSchema.methods.comparePassword = function (candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function (err, isMatch) {
if (err) return cb(err)
cb(null, isMatch)
})
}
userSchema.methods.comparePasswordPromise = function (candidatePassword) {
return new Promise((resolve, reject) => {
bcrypt.compare(candidatePassword, this.password)
.then(function(isMatch) {
resolve(isMatch)
})
.catch((err) => {
reject(err)
})
})
}
export const User = mongoose.model('User', userSchema)
export const VerificationCode = mongoose.model('VerificationCode', verificationCodeSchema)
export const VerificationPhoneCode = mongoose.model('VerificationPhoneCode', verificationPhoneCodeSchema)

45
server/db/withdrawOffers.js Executable file
View File

@@ -0,0 +1,45 @@
"use strict";
exports.__esModule = true;
exports.Withdraw_Offers = void 0;
var mongoose = require("mongoose");
var schemaOptions = {
timestamps: { createdAt: 'created_at' }
};
var withdrawnOffers = new mongoose.Schema({
userId: {
type: mongoose.ObjectId,
required: false
},
offers: [{
offerId: {
type: String,
required: true,
unique: true
},
curGivenId: {
type: mongoose.ObjectId,
required: true
},
curGivenVal: {
type: Number,
required: true
},
curTakenId: {
type: mongoose.ObjectId,
required: true
},
curTakenVal: {
type: Number,
required: true
},
offeredDate: {
type: Date,
required: true
},
expiredDate: {
type: Date,
required: true
}
}]
}, schemaOptions);
exports.Withdraw_Offers = mongoose.model('WithdrawnOffers', withdrawnOffers);

73
server/db/withdrawOffers.ts Executable file
View File

@@ -0,0 +1,73 @@
import * as mongoose from 'mongoose'
const schemaOptions = {
timestamps: { createdAt: 'created_at' },
};
const withdrawnOffers = new mongoose.Schema({
userId : {
type: mongoose.ObjectId,
required: false,
},
offers : [{
offerId:{
type: String,
required: true,
unique: true
},
curGivenId:{
type: mongoose.ObjectId,
required: true
},
curGivenVal:{
type: Number,
required: true
},
curTakenId:{
type: mongoose.ObjectId,
required: true
},
curTakenVal:{
type: Number,
required: true
},
offeredDate:{
type:Date,
required: true,
},
expiredDate:{
type:Date,
required: true,
},
//withdrawDate:{
// type: Date,
// required: true,
// default: Date.now,
//}
// bargains:[{
// userId:{
// type: mongoose.ObjectId,
// required: true,
// },
// value:{
// type: Number,
// required: true,
// },
// cur_id:{
// type: mongoose.ObjectId,
// required: true,
// },
// bar_date:{
// type:Date,
// required:true,
// }
// }]
}],
}, schemaOptions)
export const Withdraw_Offers = mongoose.model('WithdrawnOffers', withdrawnOffers)

60
server/db/withdrawnOffers.js Executable file
View File

@@ -0,0 +1,60 @@
"use strict";
exports.__esModule = true;
exports.Withdrawn_Offers = void 0;
var mongoose = require("mongoose");
var withdrawnOffers = new mongoose.Schema({
userId: {
type: mongoose.ObjectId,
required: false
},
offers: [{
curGivenId: {
type: mongoose.ObjectId,
required: true
},
curGivenVal: {
type: Number,
required: true
},
curTakenId: {
type: mongoose.ObjectId,
required: true
},
curTakenVal: {
type: Number,
required: true
},
offeredDate: {
type: Date,
required: true
},
expiredDate: {
type: Date,
required: true
},
withdrawDate: {
type: Date,
required: true,
"default": Date.now
}
// bargains:[{
// userId:{
// type: mongoose.ObjectId,
// required: true,
// },
// value:{
// type: Number,
// required: true,
// },
// cur_id:{
// type: mongoose.ObjectId,
// required: true,
// },
// bar_date:{
// type:Date,
// required:true,
// }
// }]
}]
});
exports.Withdrawn_Offers = mongoose.model('WithdrawnOffers', withdrawnOffers);

Binary file not shown.

View File

@@ -0,0 +1 @@
{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"}],"uuid":"daaa08c4bcf54161b9f06c5fc2d402d1","collectionName":"system.version"}

View File

View File

@@ -0,0 +1 @@
{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"},{"v":{"$numberInt":"2"},"unique":true,"key":{"offers.offerId":{"$numberInt":"1"}},"name":"offers.offerId_1","background":true},{"v":{"$numberInt":"2"},"unique":true,"key":{"offerId":{"$numberInt":"1"}},"name":"offerId_1","background":true}],"uuid":"8703dc2b5f5d4567a568d80817b56afa","collectionName":"acceptedoffers"}

Binary file not shown.

View File

@@ -0,0 +1 @@
{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"},{"v":{"$numberInt":"2"},"unique":true,"key":{"userId":{"$numberInt":"1"}},"name":"userId_1","background":true},{"v":{"$numberInt":"2"},"unique":true,"key":{"offerId":{"$numberInt":"1"}},"name":"offerId_1","background":true}],"uuid":"fc4244e986a5438f87685af69e958898","collectionName":"activeoffers"}

BIN
server/dump/exchange/admins.bson Executable file

Binary file not shown.

View File

@@ -0,0 +1 @@
{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"},{"v":{"$numberInt":"2"},"unique":true,"key":{"email":{"$numberInt":"1"}},"name":"email_1","background":true}],"uuid":"19571896da2b47d98703ab79ffe3d1f5","collectionName":"admins"}

Binary file not shown.

View File

@@ -0,0 +1 @@
{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"},{"v":{"$numberInt":"2"},"unique":true,"key":{"name":{"$numberInt":"1"}},"name":"name_1","background":true},{"v":{"$numberInt":"2"},"unique":true,"key":{"per_name":{"$numberInt":"1"}},"name":"per_name_1","background":true},{"v":{"$numberInt":"2"},"unique":true,"key":{"ab_name":{"$numberInt":"1"}},"name":"ab_name_1","background":true}],"uuid":"17d5a5198d0147478e485f1a6e60cfef","collectionName":"currencies"}

View File

View File

@@ -0,0 +1 @@
{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"},{"v":{"$numberInt":"2"},"key":{"createdAt":{"$numberInt":"1"}},"name":"createdAt_1","expireAfterSeconds":{"$numberInt":"20"},"background":true}],"uuid":"1b7d90c9468e4d4d8ae0d09010c118fd","collectionName":"getprices"}

Binary file not shown.

View File

@@ -0,0 +1 @@
{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"}],"uuid":"1b7b7f5c1c474ab28210a6c0c16725a6","collectionName":"globaldailyprices"}

Binary file not shown.

View File

@@ -0,0 +1 @@
{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"}],"uuid":"d36a7159cd864b2e8ce904964d7c91ff","collectionName":"globalhourlyprices"}

Binary file not shown.

View File

@@ -0,0 +1 @@
{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"}],"uuid":"f804694693924d74bc73518bfffc61e8","collectionName":"globalmonthlyprices"}

Binary file not shown.

View File

@@ -0,0 +1 @@
{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"}],"uuid":"beb258360afa44a39fca27c3ed669858","collectionName":"globalweeklyprices"}

Binary file not shown.

View File

@@ -0,0 +1 @@
{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"}],"uuid":"f9f208ef081748199e70b442bf74143f","collectionName":"globalyearlyprices"}

Some files were not shown because too many files have changed in this diff Show More