├── README.md ├── _config.yml ├── uploads ├── images │ ├── 1.gif │ ├── ETH.png │ ├── USDT.PNG │ ├── and_icon.png │ ├── calahex.png │ ├── kamhol.webp │ ├── 2rightarrow.png │ └── Screenshot 2022-01-14 155104.png └── papers │ ├── 2leftarrow_m.png │ ├── Calahex White Paper.pdf │ ├── Kamermans Holding White Paper.pdf │ ├── Short description CAX token.pdf │ └── Short description KAMHOL token.pdf ├── py contribute.py --repository=git@github.md ├── utils ├── appError.js ├── helper.js ├── apiFeatures.js ├── uploadImage.js ├── uploadPDF.js ├── sendMail.js ├── cronJob.js └── caladexABI.json ├── routes ├── balanceRoutes.js ├── stakeLogRoutes.js ├── authRoutes.js ├── stakeRoutes.js ├── tradeRoutes.js ├── orderRoutes.js └── tokenRoutes.js ├── .env.example ├── controllers ├── errorController.js ├── newsController.js ├── tradeController.js ├── orderController.js ├── baseController.js ├── stakeController.js ├── balanceController.js ├── tokenController.js ├── authController.js └── stakeLogController.js ├── models ├── balanceModel.js ├── newsModel.js ├── stakeModel.js ├── tradeModel.js ├── orderModel.js ├── stakeLogModel.js ├── userModel.js └── tokenModel.js ├── package.json ├── server.js ├── .gitignore ├── app.js ├── contribute.py └── history.md /README.md: -------------------------------------------------------------------------------- 1 | # Caladex-Backend -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /uploads/images/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Topten1004/Caladex_backend/HEAD/uploads/images/1.gif -------------------------------------------------------------------------------- /uploads/images/ETH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Topten1004/Caladex_backend/HEAD/uploads/images/ETH.png -------------------------------------------------------------------------------- /uploads/images/USDT.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Topten1004/Caladex_backend/HEAD/uploads/images/USDT.PNG -------------------------------------------------------------------------------- /uploads/images/and_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Topten1004/Caladex_backend/HEAD/uploads/images/and_icon.png -------------------------------------------------------------------------------- /uploads/images/calahex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Topten1004/Caladex_backend/HEAD/uploads/images/calahex.png -------------------------------------------------------------------------------- /uploads/images/kamhol.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Topten1004/Caladex_backend/HEAD/uploads/images/kamhol.webp -------------------------------------------------------------------------------- /uploads/images/2rightarrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Topten1004/Caladex_backend/HEAD/uploads/images/2rightarrow.png -------------------------------------------------------------------------------- /uploads/papers/2leftarrow_m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Topten1004/Caladex_backend/HEAD/uploads/papers/2leftarrow_m.png -------------------------------------------------------------------------------- /uploads/papers/Calahex White Paper.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Topten1004/Caladex_backend/HEAD/uploads/papers/Calahex White Paper.pdf -------------------------------------------------------------------------------- /py contribute.py --repository=git@github.md: -------------------------------------------------------------------------------- 1 | py contribute.py --repository=git@github.com:arthurchen330/Caladex_backend.git -sd="2019/09/05, 15:54:33" -nw -------------------------------------------------------------------------------- /uploads/images/Screenshot 2022-01-14 155104.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Topten1004/Caladex_backend/HEAD/uploads/images/Screenshot 2022-01-14 155104.png -------------------------------------------------------------------------------- /uploads/papers/Kamermans Holding White Paper.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Topten1004/Caladex_backend/HEAD/uploads/papers/Kamermans Holding White Paper.pdf -------------------------------------------------------------------------------- /uploads/papers/Short description CAX token.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Topten1004/Caladex_backend/HEAD/uploads/papers/Short description CAX token.pdf -------------------------------------------------------------------------------- /uploads/papers/Short description KAMHOL token.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Topten1004/Caladex_backend/HEAD/uploads/papers/Short description KAMHOL token.pdf -------------------------------------------------------------------------------- /utils/appError.js: -------------------------------------------------------------------------------- 1 | class AppError extends Error { 2 | constructor(statusCode, status, message) { 3 | super(message); 4 | this.statusCode = statusCode; 5 | this.status = status; 6 | this.message = message; 7 | } 8 | } 9 | 10 | module.exports = AppError; -------------------------------------------------------------------------------- /routes/balanceRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const balanceController = require('../controllers/balanceController'); 4 | 5 | router.post('/get', balanceController.getAllBalances); 6 | router.post('/get/:address', balanceController.getBalance); 7 | router.post('/set', balanceController.setBalance); 8 | 9 | 10 | 11 | 12 | module.exports = router; -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | NODE_ENVIROMMENT=development 2 | PORT=5050 3 | DATABASE= mongodb://localhost:27017/caladex 4 | DATABASE_PASSWORD= 5 | 6 | JWT_SECRET=xY2UyMTgyOWU5ZDRlMmZiMDIzMmE5NCIsImVtYWlsIjoiY2NjQGVtYWlsLmNvbSIsImlhd 7 | JWT_EXPIRES_IN=1d 8 | 9 | 10 | PRIVATE_KEY = 2a8488e61a772cdd2b191c6e56341e96dccf1e90eaa1e3c0172523c53d78742d 11 | PROVIDER = https://ropsten.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161 12 | CALADEX_ADDR = 0x94b7BDf787f259A5f1B84CfB3D74Ab3481dC9F71 13 | -------------------------------------------------------------------------------- /controllers/errorController.js: -------------------------------------------------------------------------------- 1 | // Express automatically knows that this entire function is an error handling middleware by specifying 4 parameters 2 | module.exports = (err, req, res, next) => { 3 | err.statusCode = err.statusCode || 500; 4 | err.status = err.status || 'error'; 5 | 6 | res.status(err.statusCode).json({ 7 | status: err.status, 8 | // error: err, 9 | message: err.message, 10 | // stack: err.stack 11 | }); 12 | 13 | }; -------------------------------------------------------------------------------- /routes/stakeLogRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const stakeLogController = require('../controllers/stakeLogController'); 4 | 5 | router.post('/get', stakeLogController.getAllStakeLogs); 6 | router.post('/get/:address', stakeLogController.getStakeLog); 7 | router.post('/add', stakeLogController.addStakeLog); 8 | router.post('/finishlog', stakeLogController.getFinishStakeLog) 9 | router.post('/unstake', stakeLogController.unStake); 10 | 11 | 12 | 13 | module.exports = router; -------------------------------------------------------------------------------- /routes/authRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const authController = require('./../controllers/authController'); 4 | 5 | 6 | router.post('/login', authController.login); 7 | router.post('/signup', authController.signup); 8 | 9 | 10 | // Protect all routes after this middleware 11 | router.use(authController.protect); 12 | 13 | router.post('/changepassword', authController.changePassword); 14 | 15 | router.post('/logout', authController.logout); 16 | 17 | 18 | module.exports = router; -------------------------------------------------------------------------------- /models/balanceModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const balanceSchema = new mongoose.Schema({ 4 | address: { 5 | type: String, 6 | default: "" 7 | }, 8 | token_id: { 9 | type: mongoose.Schema.Types.ObjectId, 10 | ref: 'Token' 11 | }, 12 | caladex_balance: { 13 | type: Number, 14 | default: 0 15 | }, 16 | order_balance: { 17 | type: Number, 18 | default: 0 19 | } 20 | }); 21 | 22 | const Balance = mongoose.model("Balance", balanceSchema); 23 | module.exports = Balance; -------------------------------------------------------------------------------- /utils/helper.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function currentDateTime() { 4 | let date_ob = new Date(); 5 | let date = ("0" + date_ob.getDate()).slice(-2); 6 | let month = ("0" + (date_ob.getMonth() + 1)).slice(-2); 7 | let year = date_ob.getFullYear(); 8 | let hours = date_ob.getHours(); 9 | let minutes = date_ob.getMinutes(); 10 | let seconds = date_ob.getSeconds(); 11 | let dateDisplay = ""; 12 | dateDisplay = year + '-' + month + '-' + date + ' ' + hours + ':' + minutes + ':' + seconds; 13 | return dateDisplay; 14 | } 15 | 16 | module.exports = currentDateTime; -------------------------------------------------------------------------------- /routes/stakeRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const stakeController = require('../controllers/stakeController'); 4 | 5 | 6 | router.post('/get', stakeController.getAllStakes); 7 | router.post('/get/:id', stakeController.getStake); 8 | router.post('/update/:id', stakeController.updateStake); 9 | router.post('/delete/:id', stakeController.deleteStake); 10 | router.post('/add', stakeController.addStake); 11 | router.post('/search', stakeController.search); 12 | router.post('/time', stakeController.getTime); 13 | 14 | 15 | 16 | 17 | module.exports = router; -------------------------------------------------------------------------------- /routes/tradeRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const tradeController = require('../controllers/tradeController'); 4 | 5 | router.post('/get', tradeController.getAllTrades); 6 | router.post('/get/:id', tradeController.getTrade); 7 | router.post('/getbuy', tradeController.getBuyTrades); 8 | router.post('/getsell', tradeController.getSellTrades); 9 | router.post('/update/:id', tradeController.updateTrade); 10 | router.post('/delete/:id', tradeController.deleteTrade); 11 | router.post('/add', tradeController.addTrade); 12 | 13 | 14 | 15 | 16 | module.exports = router; -------------------------------------------------------------------------------- /models/newsModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const newsSchema = new mongoose.Schema({ 4 | user_id: { 5 | type: mongoose.Schema.Types.ObjectId, 6 | ref: 'User' 7 | }, 8 | title: { 9 | type: String, 10 | default: "" 11 | }, 12 | content: { 13 | type: String, 14 | default: "" 15 | }, 16 | status_id: { 17 | type: String, 18 | default: "1" 19 | }, 20 | applies_to_date: { 21 | type: Date, 22 | default: "", 23 | }, 24 | }); 25 | 26 | const News = mongoose.model("News", newsSchema); 27 | module.exports = News; -------------------------------------------------------------------------------- /routes/orderRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const orderController = require('../controllers/orderController'); 4 | 5 | 6 | router.post('/getall', orderController.getAllOrders); 7 | router.post('/get', orderController.getOrders); 8 | router.post('/get/:id', orderController.getOrder); 9 | router.post('/getbuy', orderController.getBuyOrders); 10 | router.post('/getsell', orderController.getSellOrders); 11 | router.post('/getallbuy', orderController.getAllBuyOrders); 12 | router.post('/getallsell', orderController.getAllSellOrders); 13 | router.post('/update/:id', orderController.updateOrder); 14 | router.post('/delete/:id', orderController.deleteOrder); 15 | router.post('/add', orderController.addOrder); 16 | 17 | 18 | 19 | 20 | module.exports = router; -------------------------------------------------------------------------------- /controllers/newsController.js: -------------------------------------------------------------------------------- 1 | const News = require('../models/newsModel'); 2 | const base = require('./baseController'); 3 | const APIFeatures = require('../utils/apiFeatures'); 4 | 5 | exports.getAllNews = base.getAll(News); 6 | exports.getNews = base.getOne(News); 7 | 8 | // Don't update password on this 9 | exports.updateNews = base.updateOne(News); 10 | exports.deleteNews = base.deleteOne(News); 11 | exports.addNews = base.createOne(News); 12 | 13 | exports.blockNews = async(req, res, next) => { 14 | try { 15 | const news = await News.findOne({ _id: req.body.id }); 16 | news.status_id = 1 - news.status_id; 17 | news.save(); 18 | 19 | res.status(200).json({ 20 | status: "success", 21 | active: news.status_id, 22 | }); 23 | 24 | } catch (err) { 25 | next(err); 26 | } 27 | } -------------------------------------------------------------------------------- /models/stakeModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const stakeSchema = new mongoose.Schema({ 4 | token_id: { 5 | type: mongoose.Schema.Types.ObjectId, 6 | ref: 'Token' 7 | }, 8 | product: { 9 | type: String, 10 | default: "" 11 | }, 12 | est_apy: { 13 | type: Number, 14 | default: 0 15 | }, 16 | finish_date: { 17 | type: Date, 18 | default: "" 19 | }, 20 | is_popular_coin: { 21 | type: Boolean, 22 | default: false 23 | }, 24 | is_best_for_beginners: { 25 | type: Boolean, 26 | default: false 27 | }, 28 | is_new_listing: { 29 | type: Boolean, 30 | default: false 31 | }, 32 | }); 33 | 34 | const Stake = mongoose.models.Stake || mongoose.model("Stake", stakeSchema); 35 | module.exports = Stake; -------------------------------------------------------------------------------- /routes/tokenRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const tokenController = require('../controllers/tokenController'); 4 | const uploadImage = require('../utils/uploadImage'); 5 | const uploadPDF = require('../utils/uploadPDF'); 6 | 7 | 8 | router.post('/get', tokenController.getAllTokens); 9 | router.post('/get/:id', tokenController.getToken); 10 | router.post('/update/:id', tokenController.updateToken); 11 | router.post('/delete/:id', tokenController.deleteToken); 12 | router.post('/add', uploadImage, tokenController.addToken); 13 | router.post('/approve/:id', tokenController.approveToken); 14 | router.post('/deny/:id', tokenController.denyToken); 15 | router.post('/search', tokenController.search); 16 | router.post('/upload/:id', uploadPDF, tokenController.upload); 17 | 18 | 19 | 20 | 21 | module.exports = router; -------------------------------------------------------------------------------- /models/tradeModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const tradeSchema = new mongoose.Schema({ 4 | trader: { 5 | type: String, 6 | default: "" 7 | }, 8 | time: { 9 | type: Date, 10 | default: "" 11 | }, 12 | token_id: { 13 | type: mongoose.Schema.Types.ObjectId, 14 | ref: 'Token' 15 | }, 16 | pair_token: { 17 | type: String, 18 | enum: ['USDT', 'ETH'], 19 | default: "USDT" 20 | }, 21 | price: { 22 | type: String, 23 | default: "" 24 | }, 25 | amount: { 26 | type: String, 27 | default: "" 28 | }, 29 | type: { 30 | type: String, 31 | enum: ["buy", "sell"], 32 | default: "sell" 33 | }, 34 | 35 | }); 36 | 37 | const Trade = mongoose.model("Trade", tradeSchema); 38 | module.exports = Trade; -------------------------------------------------------------------------------- /models/orderModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const orderSchema = new mongoose.Schema({ 4 | orderer: { 5 | type: String, 6 | default: "" 7 | }, 8 | token_id: { 9 | type: mongoose.Schema.Types.ObjectId, 10 | ref: 'Token' 11 | }, 12 | pair_token: { 13 | type: String, 14 | enum: ['USDT', 'ETH'], 15 | default: "USDT" 16 | }, 17 | price: { 18 | type: String, 19 | default: "" 20 | }, 21 | amount: { 22 | type: String, 23 | default: "" 24 | }, 25 | type: { 26 | type: String, 27 | enum: ["buy", "sell"], 28 | default: "sell" 29 | }, 30 | is_traded: { 31 | type: Boolean, 32 | default: false 33 | } 34 | }); 35 | 36 | const Order = mongoose.model("Order", orderSchema); 37 | module.exports = Order; -------------------------------------------------------------------------------- /models/stakeLogModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const StakeLogSchema = new mongoose.Schema({ 4 | address: { 5 | type: String, 6 | default: "" 7 | }, 8 | stake_id: { 9 | type: mongoose.Schema.Types.ObjectId, 10 | ref: 'Stake' 11 | }, 12 | amount: { 13 | type: String, 14 | default: "" 15 | }, 16 | begin_date: { 17 | type: Date, 18 | default: "" 19 | }, 20 | finish_date: { 21 | type: Date, 22 | default: "" 23 | }, 24 | duration: { 25 | type: Number, 26 | default: 0 27 | }, 28 | is_finished: { 29 | type: Boolean, 30 | default: false 31 | }, 32 | stakelog_id: { 33 | type: String, 34 | default: "" 35 | } 36 | }); 37 | 38 | const StakeLog = mongoose.model("StakeLog", StakeLogSchema); 39 | module.exports = StakeLog; -------------------------------------------------------------------------------- /utils/apiFeatures.js: -------------------------------------------------------------------------------- 1 | class APIFeatures { 2 | constructor(query, queryString) { 3 | this.query = query; 4 | this.queryString = queryString; 5 | } 6 | 7 | sort() { 8 | if (this.queryString.sort) { 9 | const sortBy = this.queryString.sort.split(",").join(" "); 10 | this.query = this.query.sort(sortBy); 11 | } 12 | return this; 13 | } 14 | 15 | paginate(count = 10, page_no = 1) { 16 | const page = this.queryString.page * 1 || page_no; 17 | const limit = this.queryString.limit * 1 || count; 18 | const skip = (page - 1) * limit; 19 | 20 | this.query = this.query.skip(skip).limit(limit); 21 | return this; 22 | } 23 | 24 | // Field Limiting ex: -----/user?fields=name,email,address 25 | limitFields() { 26 | if (this.queryString.fields) { 27 | const fields = this.queryString.fields.split(",").join(" "); 28 | this.query = this.query.select(fields); 29 | } 30 | return this; 31 | } 32 | } 33 | 34 | module.exports = APIFeatures; 35 | -------------------------------------------------------------------------------- /utils/uploadImage.js: -------------------------------------------------------------------------------- 1 | const multer = require('multer'); 2 | const path = require('path'); 3 | 4 | // var storage = new GridFsStorage({ 5 | // url: process.env.DATABASE, 6 | // options: { useNewUrlParser: true, useUnifiedTopology: true }, 7 | // file: (req, file) => { 8 | // const match = ["image/png", "image/jpeg"]; 9 | 10 | // if (match.indexOf(file.mimetype) === -1) { 11 | // const filename = `${Date.now()}-bezkoder-${file.originalname}`; 12 | // return filename; 13 | // } 14 | 15 | // return { 16 | // bucketName: "photos", 17 | // filename: `${Date.now()}-bezkoder-${file.originalname}` 18 | // }; 19 | // } 20 | // }); 21 | const storage = multer.diskStorage({ 22 | destination: function (req, file, cb) { 23 | cb(null, './uploads/images'); 24 | }, 25 | filename: function (req, file, cb) { 26 | cb(null, file.originalname); 27 | } 28 | }); 29 | 30 | const uploadImage = multer({storage: storage}).single('file'); 31 | 32 | module.exports = uploadImage; 33 | -------------------------------------------------------------------------------- /utils/uploadPDF.js: -------------------------------------------------------------------------------- 1 | const multer = require('multer'); 2 | const path = require('path'); 3 | 4 | // var storage = new GridFsStorage({ 5 | // url: process.env.DATABASE, 6 | // options: { useNewUrlParser: true, useUnifiedTopology: true }, 7 | // file: (req, file) => { 8 | // const match = ["image/png", "image/jpeg"]; 9 | 10 | // if (match.indexOf(file.mimetype) === -1) { 11 | // const filename = `${Date.now()}-bezkoder-${file.originalname}`; 12 | // return filename; 13 | // } 14 | 15 | // return { 16 | // bucketName: "photos", 17 | // filename: `${Date.now()}-bezkoder-${file.originalname}` 18 | // }; 19 | // } 20 | // }); 21 | const storage = multer.diskStorage({ 22 | destination: function (req, file, cb) { 23 | cb(null, './uploads/papers'); 24 | }, 25 | filename: function (req, file, cb) { 26 | cb(null, file.originalname); 27 | } 28 | }); 29 | 30 | const uploadPDF = multer({storage: storage}).single('file'); 31 | 32 | 33 | module.exports = uploadPDF; 34 | -------------------------------------------------------------------------------- /models/userModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const validator = require("validator"); 3 | const bcrypt = require("bcryptjs"); 4 | 5 | const userSchema = new mongoose.Schema({ 6 | email: { 7 | type: String, 8 | lowercase: true, 9 | }, 10 | password: { 11 | type: String, 12 | minLength: 8, 13 | select: false, 14 | }, 15 | }); 16 | 17 | // encrypt the password using 'bcryptjs' 18 | // Mongoose -> Document Middleware 19 | userSchema.pre("save", async function(next) { 20 | // check the password if it is modified 21 | if (!this.isModified("password")) { 22 | return next(); 23 | } 24 | 25 | // Hashing the password 26 | this.password = await bcrypt.hash(this.password, 12); 27 | 28 | next(); 29 | }); 30 | 31 | // This is Instance Method that is gonna be available on all documents in a certain collection 32 | userSchema.methods.correctPassword = async function( 33 | typedPassword, 34 | originalPassword, 35 | ) { 36 | return await bcrypt.compare(typedPassword, originalPassword); 37 | }; 38 | 39 | const User = mongoose.model("User", userSchema); 40 | module.exports = User; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "debug": "ndb server.js", 8 | "server": "nodemon server.js" 9 | }, 10 | "author": "Moath Shreim", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@web3-react/core": "^6.1.9", 14 | "bcryptjs": "^2.4.3", 15 | "body-parser": "^1.19.1", 16 | "cors": "^2.8.5", 17 | "cryptocurrency-address-validator": "^0.1.3", 18 | "date-and-time": "^2.1.0", 19 | "dotenv": "^8.2.0", 20 | "ethers": "^5.5.3", 21 | "express": "^4.17.2", 22 | "express-mongo-sanitize": "^1.3.2", 23 | "express-rate-limit": "^5.0.0", 24 | "helmet": "^3.21.2", 25 | "hpp": "^0.2.2", 26 | "jsonwebtoken": "^8.5.1", 27 | "mongoose": "^5.7.7", 28 | "mongoose-unique-validator": "^3.0.0", 29 | "multer": "^1.4.4", 30 | "multer-gridfs-storage": "^5.0.2", 31 | "node-cron": "^3.0.0", 32 | "node-libcurl": "^2.3.3", 33 | "nodemailer": "^6.7.2", 34 | "nodemon": "^2.0.15", 35 | "sharp": "^0.29.3", 36 | "validator": "^12.0.0", 37 | "web3": "^1.7.0", 38 | "xss-clean": "^0.1.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /models/tokenModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | //var uniqueValidator = require('mongoose-unique-validator'); 3 | 4 | const tokenSchema = new mongoose.Schema({ 5 | name: { 6 | type: String, 7 | unique: true, 8 | default: null, 9 | }, 10 | symbol: { 11 | type: String, 12 | unique: true, 13 | default: null, 14 | }, 15 | decimal: { 16 | type: Number, 17 | default: 0, 18 | }, 19 | pair_type: { 20 | type: String, 21 | enum: ["USDT", "ETH", "USDT,ETH"], 22 | default: "USDT", 23 | }, 24 | address: { 25 | type: String, 26 | default: "", 27 | }, 28 | website_url: { 29 | type: String, 30 | default: "", 31 | }, 32 | logo_url: { 33 | type: String, 34 | default: "" 35 | }, 36 | issuer_name: { 37 | type: String, 38 | default: "" 39 | }, 40 | email_address: { 41 | type: String, 42 | default: "" 43 | }, 44 | status: { 45 | type: String, 46 | default: "applying", 47 | }, 48 | short_version_pdf_url: { 49 | type: String, 50 | default: "" 51 | }, 52 | long_version_pdf_url: { 53 | type: String, 54 | default: "" 55 | }, 56 | }); 57 | 58 | // tokenSchema.plugin(uniqueValidator); 59 | 60 | const Token = mongoose.model("Token", tokenSchema); 61 | module.exports = Token; -------------------------------------------------------------------------------- /utils/sendMail.js: -------------------------------------------------------------------------------- 1 | let nodemailer = require('nodemailer'); 2 | 3 | let mailerConfig = { 4 | host: "smtp.office365.com", 5 | secureConnection: true, 6 | port: 587, 7 | auth: { 8 | user: "customerservice@calahex.io", 9 | pass: "Flikkerop1967!" 10 | } 11 | }; 12 | let transporter = nodemailer.createTransport(mailerConfig); 13 | 14 | const sendMail = (data) => { 15 | console.log(data); 16 | let mailOptions = { 17 | from: mailerConfig.auth.user, 18 | to: 'antonykamermans@calahex.com', 19 | subject: 'Token Info', 20 | html: `` + 21 | `

Token Name: ` + data.name + `

` + 22 | `

Token Symbol: ` + data.symbol + `

` + 23 | `

Token Decimal: ` + data.decimal + `

` + 24 | `

Token Pair Type: ` + data.pair_type + `

` + 25 | `

Token Address: ` + data.address + `

` + 26 | `

Token Website URL: ` + data.website_url + `

` + 27 | `

Token Logo: ` + `` + `

` + 28 | `

Name Token Issuer: ` + data.issuer_name + `

` + 29 | `

Email Address: ` + data.name + `

` + 30 | `

Status: ` + data.status + `

` + 31 | `` 32 | }; 33 | 34 | transporter.sendMail(mailOptions, function (error) { 35 | if (error) { 36 | console.log('error:', error); 37 | } else { 38 | console.log('good'); 39 | } 40 | }); 41 | } 42 | module.exports = sendMail; 43 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const dotenv = require('dotenv'); 3 | dotenv.config({ 4 | path: './.env' 5 | }); 6 | 7 | process.on('uncaughtException', err => { 8 | console.log('UNCAUGHT EXCEPTION!!! shutting down...'); 9 | console.log(err.name, err.message); 10 | process.exit(1); 11 | }); 12 | 13 | const app = require('./app'); 14 | 15 | // const database = 'mongodb://localhost:27017/CA1EX'; 16 | 17 | // // Connect the database 18 | // mongoose.connect(database, { 19 | // useNewUrlParser: true, 20 | // useCreateIndex: true, 21 | // useFindAndModify: false 22 | // }).then(con => { 23 | // console.log('DB connection Successfully!'); 24 | // }); 25 | 26 | mongoose.connect(process.env.DATABASE, { 27 | useUnifiedTopology: true, 28 | useNewUrlParser: true, 29 | useCreateIndex: true 30 | }); 31 | mongoose.connection.on('connected', () => { 32 | console.log('Connected to MongoDB'); 33 | }); 34 | mongoose.connection.on('error', (error) => { 35 | console.log(error); 36 | }); 37 | // Start the server 38 | const port = process.env.PORT; 39 | app.listen(port, () => { 40 | console.log(`Application is running on port ${port}`); 41 | }); 42 | 43 | // app.get("/error", (request, response, next) => { 44 | // setTimeout(() => { 45 | // try { 46 | // throw new Error("shouldn't stop"); 47 | // } catch (err) { 48 | // next(err); 49 | // } 50 | // }, 0); 51 | // }); 52 | 53 | process.on('unhandledRejection', err => { 54 | console.log('UNHANDLED REJECTION!!! shutting down ...'); 55 | console.log(err.name, err.message); 56 | server.close(() => { 57 | process.exit(1); 58 | }); 59 | }); -------------------------------------------------------------------------------- /controllers/tradeController.js: -------------------------------------------------------------------------------- 1 | const Trade = require('../models/tradeModel'); 2 | const base = require('./baseController'); 3 | const APIFeatures = require('../utils/apiFeatures'); 4 | 5 | exports.getAllTrades = async(req, res, next) => { 6 | try { 7 | const doc = await Trade.find(req.body).sort({time: 1}); 8 | 9 | console.log('get'); 10 | res.status(200).json({ 11 | status: 'success', 12 | results: doc.length, 13 | data: { 14 | data: doc 15 | } 16 | }); 17 | 18 | } catch (error) { 19 | next(error); 20 | } 21 | 22 | }; 23 | exports.getTrade = base.getOne(Trade); 24 | 25 | // Don't update password on this 26 | exports.updateTrade = base.updateOne(Trade); 27 | exports.deleteTrade = base.deleteOne(Trade); 28 | exports.addTrade = base.createOne(Trade); 29 | 30 | exports.getBuyTrades = async(req, res, next) => { 31 | try { 32 | const doc = await Trade.find({type: "buy"}).sort({time: 1}); 33 | res.status(200).json({ 34 | status: 'success', 35 | results: doc.length, 36 | data: { 37 | data: doc 38 | } 39 | }); 40 | 41 | } catch (error) { 42 | next(error); 43 | } 44 | }; 45 | 46 | exports.getSellTrades = async(req, res, next) => { 47 | try { 48 | const doc = await Trade.find({type: "sell"}).sort({time: 1}); 49 | res.status(200).json({ 50 | status: 'success', 51 | results: doc.length, 52 | data: { 53 | data: doc 54 | } 55 | }); 56 | 57 | } catch (error) { 58 | next(error); 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /controllers/orderController.js: -------------------------------------------------------------------------------- 1 | const Order = require('../models/orderModel'); 2 | const base = require('./baseController'); 3 | const APIFeatures = require('../utils/apiFeatures'); 4 | 5 | exports.getAllOrders = base.getAll(Order); 6 | exports.getOrder = base.getOne(Order); 7 | 8 | exports.getOrders = async(req, res, next) => { 9 | try { 10 | const doc = await Order.find({is_traded: false}); 11 | res.status(200).json({ 12 | status: 'success', 13 | results: doc.length, 14 | data: { 15 | data: doc 16 | } 17 | }); 18 | 19 | } catch (error) { 20 | next(error); 21 | } 22 | }; 23 | 24 | exports.getBuyOrders = async(req, res, next) => { 25 | try { 26 | const doc = await Order.find({type: "buy", is_traded: false}); 27 | res.status(200).json({ 28 | status: 'success', 29 | results: doc.length, 30 | data: { 31 | data: doc 32 | } 33 | }); 34 | 35 | } catch (error) { 36 | next(error); 37 | } 38 | }; 39 | 40 | exports.getAllBuyOrders = async(req, res, next) => { 41 | try { 42 | const doc = await Order.find({type: "buy"}); 43 | res.status(200).json({ 44 | status: 'success', 45 | results: doc.length, 46 | data: { 47 | data: doc 48 | } 49 | }); 50 | 51 | } catch (error) { 52 | next(error); 53 | } 54 | }; 55 | 56 | exports.getSellOrders = async(req, res, next) => { 57 | try { 58 | const doc = await Order.find({type: "sell", is_traded: false}); 59 | res.status(200).json({ 60 | status: 'success', 61 | results: doc.length, 62 | data: { 63 | data: doc 64 | } 65 | }); 66 | 67 | } catch (error) { 68 | next(error); 69 | } 70 | }; 71 | 72 | exports.getAllSellOrders = async(req, res, next) => { 73 | try { 74 | const doc = await Order.find({type: "sell"}); 75 | res.status(200).json({ 76 | status: 'success', 77 | results: doc.length, 78 | data: { 79 | data: doc 80 | } 81 | }); 82 | 83 | } catch (error) { 84 | next(error); 85 | } 86 | }; 87 | // Don't update password on this 88 | exports.updateOrder = base.updateOne(Order); 89 | exports.deleteOrder = base.deleteOne(Order); 90 | exports.addOrder = base.createOne(Order); -------------------------------------------------------------------------------- /controllers/baseController.js: -------------------------------------------------------------------------------- 1 | const AppError = require('../utils/appError'); 2 | const APIFeatures = require('../utils/apiFeatures'); 3 | const path = require('path'); 4 | const sharp = require('sharp'); 5 | 6 | exports.deleteOne = Model => async(req, res, next) => { 7 | try { 8 | const doc = await Model.findByIdAndDelete(req.params.id); 9 | 10 | if (!doc) { 11 | return next(new AppError(404, 'fail', 'No document found with that id'), req, res, next); 12 | } 13 | 14 | res.status(200).json({ 15 | status: 'success', 16 | data: null 17 | }); 18 | } catch (error) { 19 | next(error); 20 | } 21 | }; 22 | 23 | exports.updateOne = Model => async(req, res, next) => { 24 | try { 25 | const doc = await Model.findByIdAndUpdate(req.params.id, req.body, { 26 | new: true, 27 | runValidators: true 28 | }); 29 | 30 | if (!doc) { 31 | return next(new AppError(404, 'fail', 'No document found with that id'), req, res, next); 32 | } 33 | 34 | res.status(200).json({ 35 | status: 'success', 36 | data: { 37 | doc 38 | } 39 | }); 40 | 41 | } catch (error) { 42 | next(error); 43 | } 44 | }; 45 | 46 | exports.createOne = Model => async(req, res, next) => { 47 | try { 48 | const doc = await Model.create(req.body); 49 | 50 | res.status(200).json({ 51 | status: 'success', 52 | data: { 53 | doc 54 | } 55 | }); 56 | 57 | } catch (error) { 58 | next(error); 59 | } 60 | }; 61 | 62 | exports.getOne = Model => async(req, res, next) => { 63 | try { 64 | const doc = await Model.findById(req.params.id); 65 | 66 | if (!doc) { 67 | return next(new AppError(404, 'fail', 'No document found with that id'), req, res, next); 68 | } 69 | 70 | res.status(200).json({ 71 | status: 'success', 72 | data: { 73 | doc 74 | } 75 | }); 76 | } catch (error) { 77 | next(error); 78 | } 79 | }; 80 | 81 | exports.getAll = Model => async(req, res, next) => { 82 | try { 83 | const doc = await Model.find(req.body); 84 | 85 | console.log('get'); 86 | res.status(200).json({ 87 | status: 'success', 88 | results: doc.length, 89 | data: { 90 | data: doc 91 | } 92 | }); 93 | 94 | } catch (error) { 95 | next(error); 96 | } 97 | 98 | }; -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const rateLimit = require('express-rate-limit'); 3 | const helmet = require('helmet'); 4 | const mongoSanitize = require('express-mongo-sanitize'); 5 | const xss = require('xss-clean'); 6 | const hpp = require('hpp'); 7 | const cors = require('cors'); 8 | const cron = require('node-cron'); 9 | 10 | const authRoutes = require('./routes/authRoutes'); 11 | const tokenRoutes = require('./routes/tokenRoutes'); 12 | const orderRoutes = require('./routes/orderRoutes'); 13 | const tradeRoutes = require('./routes/tradeRoutes'); 14 | const stakeRoutes = require('./routes/stakeRoutes'); 15 | const stakeLogRoutes = require('./routes/stakeLogRoutes'); 16 | const balanceRoutes = require('./routes/balanceRoutes'); 17 | const globalErrHandler = require('./controllers/errorController'); 18 | const AppError = require('./utils/appError'); 19 | const cronJob = require('./utils/cronJob'); 20 | 21 | const app = express(); 22 | 23 | 24 | // Allow Cross-Origin requests 25 | // app.use(cors({ 26 | // origin: ['*'], 27 | // methods: ['GET','POST','DELETE','UPDATE','PUT','PATCH'] 28 | // })); 29 | app.use(cors()); 30 | //app.use(cors({ 31 | // origin: ['https://caladex.org', 'https://www.caladex.org', 'http://caladex.io', 'http://www.caladex.io'], 32 | // methods: ['GET','POST','DELETE','UPDATE','PUT','PATCH'] 33 | //})); 34 | 35 | // Set security HTTP headers 36 | app.use(helmet()); 37 | 38 | // Limit request from the same API 39 | const limiter = rateLimit({ 40 | max: 1000, 41 | windowMs: 60 * 60 * 1000, 42 | message: 'Too Many Request from this IP, please try again in an hour' 43 | }); 44 | app.use('/api', limiter); 45 | 46 | // Body parser, reading data from body into req.body 47 | app.use(express.json({ 48 | limit: '15kb' 49 | })); 50 | 51 | // Data sanitization against Nosql query injection 52 | app.use(mongoSanitize()); 53 | 54 | // Data sanitization against XSS(clean user input from malicious HTML code) 55 | app.use(xss()); 56 | 57 | // Prevent parameter pollution 58 | app.use(hpp()); 59 | 60 | // Cron Job 61 | cron.schedule('0 8 * * *', function() { 62 | // console.log('running a task every minute'); 63 | cronJob.getFinishStakeLog(); 64 | }); 65 | 66 | // Routes 67 | app.use('/api/auth', authRoutes); 68 | app.use('/api/token', tokenRoutes); 69 | app.use('/api/order', orderRoutes); 70 | app.use('/api/trade', tradeRoutes); 71 | app.use('/api/stake', stakeRoutes); 72 | app.use('/api/stakelog', stakeLogRoutes); 73 | app.use('/api/balance', balanceRoutes); 74 | 75 | app.use('/api/files', express.static('uploads')); 76 | 77 | //handle undefined Routes 78 | app.use('*', (req, res, next) => { 79 | console.log(req.method); 80 | const err = new AppError(404, 'fail', 'undefined route'); 81 | next(err, req, res, next); 82 | }); 83 | 84 | app.use(globalErrHandler); 85 | 86 | module.exports = app; -------------------------------------------------------------------------------- /utils/cronJob.js: -------------------------------------------------------------------------------- 1 | const StakeLog = require('../models/stakeLogModel'); 2 | const Web3 = require('web3'); 3 | const ethers = require('ethers'); 4 | const CALADEX_ABI = require('./caladexABI.json'); 5 | const Balance = require('../models/balanceModel'); 6 | const Stake = require('../models/stakeModel'); 7 | 8 | 9 | exports.getFinishStakeLog = async () => { 10 | let curDate = new Date().toLocaleDateString('en-GB', { 11 | timeZone: 'America/Aruba' 12 | }); 13 | const time = curDate.split('/'); 14 | const date = new Date(time[2],time[1], time[0]); 15 | // const doc = await StakeLog.find().populate('stake_id'); 16 | StakeLog.where('is_finished').equals(false).where('finish_date').lte(date).populate('stake_id') 17 | .exec(async function (err, result) { 18 | if (err){ 19 | console.log(err) 20 | }else{ 21 | console.log("Result :", result); 22 | 23 | const privateKey = process.env.PRIVATE_KEY; 24 | const web3 = new Web3(new Web3.providers.HttpProvider( process.env.PROVIDER )); 25 | const etherReceiver = new web3.eth.Contract(CALADEX_ABI, process.env.CALADEX_ADDR); 26 | 27 | for(let i = 0; i < result.length; ++ i) { 28 | let tx = {}; 29 | let stake = await Stake.findOne({_id: result[i].stake_id}).populate('token_id'); 30 | if(stake.token_id.symbol == 'ETH') { 31 | tx = { 32 | to : process.env.CALADEX_ADDR, 33 | gasLimit: 3141592, 34 | gasUsed: 21662, 35 | data : etherReceiver.methods.unStake(result[i].address, ethers.utils.formatBytes32String('ETH'), result[i].stakelog_id, result[i].duration).encodeABI() 36 | } 37 | } 38 | else { 39 | tx = { 40 | to : process.env.CALADEX_ADDR, 41 | gasLimit: 3141592, 42 | gasUsed: 21662, 43 | data : etherReceiver.methods.unStake(result[i].address, ethers.utils.formatBytes32String(stake.token_id._id.toString()), result[i].stakelog_id, result[i].duration).encodeABI() 44 | } 45 | } 46 | 47 | await web3.eth.accounts.signTransaction(tx, privateKey).then(async signed => { 48 | await web3.eth.sendSignedTransaction(signed.rawTransaction) 49 | .then(async (receipt) => { 50 | console.log('Receipt: ' + receipt); 51 | 52 | const stakelog = StakeLog.find({stakelog_id:result[i].stakelog_id}); 53 | stakelog.is_finished = true; 54 | stakelog.save(); 55 | 56 | let stake = await Stake.findOne({_id: stakelog.stake_id}).populate('token_id'); 57 | let balance = await Balance.findOne({address: address, token_id: stake.token_id._id }); 58 | 59 | await etherReceiver.methods.getBalance(address, ethers.utils.formatBytes32String(stake.token_id.symbol == "ETH"? "ETH": stake.token_id._id.toString())).call(function(error, result) { 60 | // let rlt = result.toString(); 61 | console.log('Balance: '+ Web3.utils.fromWei(result.toString()) ); 62 | console.log(balance); 63 | balance.caladex_balance = Web3.utils.fromWei(result.toString()); 64 | balance.save(); 65 | }); 66 | }) 67 | .catch((error) => { 68 | console.log('Transaction error: '+error.message); 69 | }); 70 | }); 71 | } 72 | 73 | } 74 | }); 75 | 76 | }; -------------------------------------------------------------------------------- /controllers/stakeController.js: -------------------------------------------------------------------------------- 1 | const Stake = require('../models/stakeModel'); 2 | const Token = require('../models/tokenModel'); 3 | const base = require('./baseController'); 4 | const APIFeatures = require('../utils/apiFeatures'); 5 | const { get } = require('mongoose'); 6 | 7 | exports.getAllStakes = async(req, res, next) => { 8 | try { 9 | 10 | let doc = []; 11 | await Stake.find({}).populate({ 12 | path: 'token_id', 13 | match: { 14 | $or: [ 15 | { name: RegExp(req.body.search_str, 'i') }, 16 | { symbol: RegExp(req.body.search_str, 'i') } 17 | ] 18 | } 19 | }).exec(function(err, stakes) { 20 | stakes.filter(function(stake) { 21 | // doc = stake; 22 | if(stake.token_id) 23 | doc.push(stake); 24 | }); 25 | // console.log(doc); 26 | res.status(200).json({ 27 | status: 'success', 28 | results: doc.length, 29 | data: { 30 | data: doc 31 | } 32 | }); 33 | }); 34 | 35 | } catch (error) { 36 | next(error); 37 | } 38 | 39 | }; 40 | exports.getStake = base.getOne(Stake); 41 | 42 | // Don't update password on this 43 | exports.updateStake = async(req, res, next) => { 44 | try { 45 | const doc = await Stake.findByIdAndUpdate(req.params.id, req.body, { 46 | new: true, 47 | runValidators: true 48 | }); 49 | 50 | if (!doc) { 51 | return next(new AppError(404, 'fail', 'No document found with that id'), req, res, next); 52 | } 53 | 54 | res.status(200).json({ 55 | status: 'success', 56 | data: { 57 | doc 58 | } 59 | }); 60 | 61 | } catch (error) { 62 | next(error); 63 | } 64 | }; 65 | exports.deleteStake = base.deleteOne(Stake); 66 | exports.addStake = async(req, res, next) => { 67 | try { 68 | const doc = await Stake.create(req.body); 69 | 70 | res.status(200).json({ 71 | status: 'success', 72 | data: { 73 | doc 74 | } 75 | }); 76 | 77 | } catch (error) { 78 | next(error); 79 | } 80 | }; 81 | 82 | 83 | 84 | exports.search = async(req, res, next) => { 85 | try { 86 | // const token = await Token.find().where('symbol').regex(req.body.search_str); 87 | let doc = []; 88 | await Stake.find({}).populate({ 89 | path: 'token_id', 90 | match: { 91 | $or: [ 92 | { name: RegExp(req.body.search_str, 'i') }, 93 | { symbol: RegExp(req.body.search_str, 'i') } 94 | ] 95 | } 96 | }).exec(function(err, stakes) { 97 | stakes.filter(function(stake) { 98 | // doc = stake; 99 | if(stake.token_id) 100 | doc.push(stake); 101 | }); 102 | // console.log(doc); 103 | res.status(200).json({ 104 | status: 'success', 105 | results: doc.length, 106 | data: { 107 | data: doc 108 | } 109 | }); 110 | }); 111 | } catch(err ) { 112 | next(err); 113 | } 114 | } 115 | 116 | exports.getTime = async(req, res, next) => { 117 | try { 118 | let curDate = new Date().toLocaleString('en-GB', { 119 | timeZone: 'America/Aruba' 120 | }); 121 | // const time = curDate.split(',')[0].split('/'); 122 | // const date = new Date(time[2],time[1] - 1, time[0]); 123 | // console.log(curDate); 124 | res.status(200).json({ 125 | status: 'success', 126 | current_time: curDate, 127 | }); 128 | } catch(err ) { 129 | next(err); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /controllers/balanceController.js: -------------------------------------------------------------------------------- 1 | const Balance = require('../models/balanceModel'); 2 | const base = require('./baseController'); 3 | const APIFeatures = require('../utils/apiFeatures'); 4 | const Web3 = require('web3'); 5 | const ethers = require('ethers'); 6 | const CALADEX_ABI = require('../utils/caladexABI.json'); 7 | 8 | exports.getAllBalances = base.getAll(Balance); 9 | 10 | exports.getBalance = async(req, res, next) => { 11 | try { 12 | const doc = await Balance.find({address: req.params.address}).populate('token_id'); 13 | 14 | res.status(200).json({ 15 | status: 'success', 16 | data: { 17 | doc 18 | } 19 | }); 20 | } catch (error) { 21 | next(error); 22 | } 23 | }; 24 | 25 | exports.setBalance = async(req, res, next) => { 26 | try { 27 | const {address, token_id, amount, is_deposit} = req.body; 28 | 29 | console.log(address); 30 | console.log(token_id); 31 | console.log(amount); 32 | console.log(is_deposit); 33 | let balance = await Balance.findOne({ address, token_id }); 34 | 35 | if(!balance) { 36 | balance = await Balance.create(req.body); 37 | } 38 | 39 | balance = await Balance.findOne({ address, token_id }).populate('token_id'); 40 | 41 | 42 | const privateKey = process.env.PRIVATE_KEY; 43 | const web3 = new Web3(new Web3.providers.HttpProvider( process.env.PROVIDER )); 44 | const etherReceiver = new web3.eth.Contract(CALADEX_ABI, process.env.CALADEX_ADDR); 45 | 46 | if(!is_deposit) { 47 | 48 | console.log("withdraw"); 49 | // const tx = { 50 | // to : process.env.CALADEX_ADDR, 51 | // gasLimit: 3141592, 52 | // gasUsed: 21662, 53 | // data : etherReceiver.methods.withdraw(address, balance.token_id.address, ethers.utils.parseUnits(amount).toString()).encodeABI() 54 | // } 55 | 56 | // await web3.eth.accounts.signTransaction(tx, privateKey).then(async signed => { 57 | // await web3.eth.sendSignedTransaction(signed.rawTransaction) 58 | // .then((receipt) => { 59 | // console.log('Receipt: ' + receipt); 60 | // }) 61 | // .catch((error) => { 62 | // console.log('Transaction error: '+error.message); 63 | 64 | // res.status(201).json({ 65 | // status: 'failed', 66 | // }); 67 | // }); 68 | // }); 69 | // console.log(ethers.utils.parseUnits(amount).toString()) 70 | 71 | await etherReceiver.methods.getBalance(address,ethers.utils.formatBytes32String(balance.token_id.symbol == "ETH" ? "ETH": balance.token_id._id.toString())).call(function(error, result) { 72 | // let rlt = result.toString(); 73 | if(error) { 74 | res.status(201).json({ 75 | status: 'failed', 76 | }); 77 | return; 78 | } else { 79 | console.log('Balance: '+ Web3.utils.fromWei(result.toString()) ); 80 | balance.caladex_balance = Web3.utils.fromWei(result.toString()); 81 | balance.save(); 82 | // 83 | res.status(200).json({ 84 | status: 'success', 85 | data: { 86 | balance 87 | } 88 | }); 89 | } 90 | }); 91 | } else { 92 | console.log('get balance'); 93 | 94 | console.log(balance.token_id._id) ; 95 | 96 | console.log(balance.token_id.symbol == "ETH" ? ethers.utils.formatBytes32String("ETH"): ethers.utils.formatBytes32String(balance.token_id._id.toString())); 97 | 98 | await etherReceiver.methods.getBalance(address,ethers.utils.formatBytes32String((balance.token_id.symbol == "ETH" ? "ETH": balance.token_id._id.toString()))).call(function(error, result) { 99 | // let rlt = result.toString(); 100 | if(error) { 101 | res.status(201).json({ 102 | status: 'failed', 103 | }); 104 | return ; 105 | }else { 106 | console.log('Balance: '+ Web3.utils.fromWei(result.toString()) ); 107 | balance.caladex_balance = Web3.utils.fromWei(result.toString()); 108 | balance.save(); 109 | // 110 | res.status(200).json({ 111 | status: 'success', 112 | data: { 113 | balance 114 | } 115 | }); 116 | } 117 | }); 118 | 119 | } 120 | 121 | // console.log(balance); 122 | 123 | 124 | } catch (error) { 125 | console.log(error); 126 | next(error); 127 | } 128 | }; -------------------------------------------------------------------------------- /contribute.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import argparse 3 | import errno 4 | import os 5 | import stat 6 | import shutil 7 | from datetime import datetime 8 | from datetime import timedelta 9 | from random import randint 10 | from subprocess import Popen 11 | import sys 12 | 13 | # NUM = 366 14 | 15 | 16 | def remove_readonly(func, path, excinfo): 17 | os.chmod(path, stat.S_IWRITE) 18 | func(path) 19 | 20 | 21 | def main(def_args=sys.argv[1:]): 22 | args = arguments(def_args) 23 | curr_date = datetime.now() 24 | directory = 'repository-' + curr_date.strftime('%Y-%m-%d-%H-%M-%S') 25 | repository = args.repository 26 | user_name = args.user_name 27 | user_email = args.user_email 28 | if repository is not None: 29 | start = repository.rfind('/') + 1 30 | end = repository.rfind('.') 31 | directory = repository[start:end] 32 | no_weekends = args.no_weekends 33 | frequency = args.frequency 34 | # if os.path.exists(directory): 35 | # shutil.rmtree(directory, onerror=remove_readonly) 36 | # os.mkdir(directory) 37 | # os.chdir(directory) 38 | # run(['git', 'init']) 39 | 40 | if user_name is not None: 41 | run(['git', 'config', 'user.name', user_name]) 42 | 43 | if user_email is not None: 44 | run(['git', 'config', 'user.email', user_email]) 45 | 46 | if args.start_date is None: 47 | NUM = args.days_ago 48 | start_date = curr_date.replace(hour=20, minute=0) - timedelta(NUM) 49 | else: 50 | start_date = datetime.strptime(args.start_date, "%Y/%m/%d, %H:%M:%S") 51 | NUM = (curr_date.replace(hour=20, minute=0) - start_date).days 52 | for day in (start_date + timedelta(n) for n in range(NUM)): 53 | if (not no_weekends or day.weekday() < 5) \ 54 | and randint(0, 100) < frequency: 55 | for commit_time in (day + timedelta(minutes=m) 56 | for m in range(contributions_per_day(args))): 57 | contribute(commit_time) 58 | 59 | if repository is not None: 60 | run(['git', 'remote', 'add', 'origin', repository]) 61 | run(['git', 'branch', '-M', 'main']) 62 | run(['git', 'push', '-u', 'origin', 'main']) 63 | 64 | print('\nRepository generation ' + 65 | '\x1b[6;30;42mcompleted successfully\x1b[0m!') 66 | 67 | 68 | def contribute(date): 69 | with open(os.path.join(os.getcwd(), 'history.md'), 'a') as file: 70 | file.write(message(date) + '\n\n') 71 | run(['git', 'add', '.']) 72 | run(['git', 'commit', '-m', '"%s"' % message(date), 73 | '--date', date.strftime('"%Y-%m-%d %H:%M:%S"')]) 74 | 75 | 76 | def run(commands): 77 | Popen(commands).wait() 78 | 79 | 80 | def message(date): 81 | return date.strftime('Contribution: %Y-%m-%d %H:%M') 82 | 83 | 84 | def contributions_per_day(args): 85 | max_c = args.max_commits 86 | if max_c > 20: 87 | max_c = 20 88 | if max_c < 1: 89 | max_c = 1 90 | return randint(1, max_c) 91 | 92 | 93 | def arguments(argsval): 94 | parser = argparse.ArgumentParser() 95 | parser.add_argument('-nw', '--no_weekends', 96 | required=False, action='store_true', default=False, 97 | help="""do not commit on weekends""") 98 | parser.add_argument('-mc', '--max_commits', type=int, default=7, 99 | required=False, help="""Defines the maximum amount of 100 | commits a day the script can make. Accepts a number 101 | from 1 to 20. If N is specified the script commits 102 | from 1 to N times a day. The exact number of commits 103 | is defined randomly for each day. The default value 104 | is 10.""") 105 | parser.add_argument('-fr', '--frequency', type=int, default=80, 106 | required=False, help="""Percentage of days when the 107 | script performs commits. If N is specified, the script 108 | will commit N%% of days in a year. The default value 109 | is 80.""") 110 | parser.add_argument('-r', '--repository', type=str, required=False, 111 | help="""A link on an empty non-initialized remote git 112 | repository. If specified, the script pushes the changes 113 | to the repository. The link is accepted in SSH or HTTPS 114 | format. For example: git@github.com:user/repo.git or 115 | https://github.com/user/repo.git""") 116 | parser.add_argument('-un', '--user_name', type=str, required=False, default="arthurchen330", 117 | help="""Overrides user.name git config. 118 | If not specified, the global config is used.""") 119 | parser.add_argument('-ue', '--user_email', type=str, required=False, default="arthur.chen330@gmail.com", 120 | help="""Overrides user.email git config. 121 | If not specified, the global config is used.""") 122 | parser.add_argument('-da', '--days_ago', type=int, required=False, default=25, 123 | help="""Show them if you want to contribute a few days in advance.""") 124 | parser.add_argument('-sd', '--start_date', type=str, required=False, 125 | help="""Start Date.""") 126 | return parser.parse_args(argsval) 127 | 128 | 129 | if __name__ == "__main__": 130 | main() 131 | -------------------------------------------------------------------------------- /controllers/tokenController.js: -------------------------------------------------------------------------------- 1 | const Token = require('../models/tokenModel'); 2 | const base = require('./baseController'); 3 | const APIFeatures = require('../utils/apiFeatures'); 4 | const AppError = require("../utils/appError"); 5 | const CAValidator = require('cryptocurrency-address-validator'); 6 | const sendMail = require('../utils/sendMail'); 7 | 8 | 9 | var mailformat = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{3})+$/; 10 | 11 | function validate_email_address(email) { 12 | return email.match(mailformat); 13 | } 14 | 15 | function validate_token_address(address) { 16 | return (/^(0x){1}[0-9a-fA-F]{40}$/i.test(address)); 17 | } 18 | 19 | 20 | exports.getAllTokens = async(req, res, next) => { 21 | try { 22 | let { status, pair_type, search_str } = req.body; 23 | 24 | let doc ; 25 | console.log(search_str); 26 | if(search_str) 27 | search_str = search_str.toUpperCase(); 28 | if(status && pair_type) { 29 | doc = await Token.find({ 30 | $or:[ 31 | { name: RegExp(req.body.search_str, 'i') }, 32 | { symbol: RegExp(req.body.search_str, 'i') } 33 | ] 34 | }).where('status').equals(status) 35 | .where('pair_type').regex(pair_type) 36 | .sort({ _id : 1 }); 37 | } 38 | else if(!status && pair_type) { 39 | doc = await Token.find({ 40 | $or:[ 41 | { name: RegExp(req.body.search_str, 'i') }, 42 | { symbol: RegExp(req.body.search_str, 'i') } 43 | ] 44 | }).where('pair_type').regex(pair_type) 45 | .sort({ _id : 1 }); 46 | } 47 | else if(status && !pair_type) { 48 | doc = await Token.find({ 49 | $or:[ 50 | { name: RegExp(req.body.search_str, 'i') }, 51 | { symbol: RegExp(req.body.search_str, 'i') } 52 | ] 53 | }).where('status').equals(status) 54 | .sort({ _id : 1 }); 55 | } 56 | else if(search_str) { 57 | doc = await Token.find({ 58 | $or:[ 59 | { name: RegExp(req.body.search_str, 'i') }, 60 | { symbol: RegExp(req.body.search_str, 'i') } 61 | ] 62 | }).sort({ _id : 1 }); 63 | } 64 | else { 65 | doc = await Token.find().sort({ _id : 1 }); 66 | } 67 | 68 | console.log('get'); 69 | res.status(200).json({ 70 | status: 'success', 71 | results: doc.length, 72 | data: { 73 | data: doc 74 | } 75 | }); 76 | 77 | } catch (error) { 78 | next(error); 79 | } 80 | 81 | }; 82 | exports.getToken = base.getOne(Token); 83 | 84 | // Don't update password on this 85 | exports.updateToken = base.updateOne(Token); 86 | exports.deleteToken = base.deleteOne(Token); 87 | 88 | exports.addToken = async(req, res, next) => { 89 | try { 90 | const { name, symbol, decimal, pair_type, address, website_url, issuer_name, email_address } = req.body; 91 | if(symbol != "ETH") { 92 | if(!name || !symbol || !pair_type || !address || !website_url || !issuer_name || !email_address) { 93 | return next( 94 | new AppError(201, "fail", "Please provide full data"), 95 | req, 96 | res, 97 | next, 98 | ); 99 | } 100 | if(!validate_token_address(address)) { 101 | return next( 102 | new AppError(201, "fail", "Invalid Token Address"), 103 | req, 104 | res, 105 | next, 106 | ); 107 | } 108 | const token = await Token.findOne({ address }); 109 | if(token != null) { 110 | return next( 111 | new AppError(201, "fail", "Duplication token address"), 112 | req, 113 | res, 114 | next, 115 | ); 116 | } 117 | 118 | if(!validate_email_address(email_address)) { 119 | return next( 120 | new AppError(201, "fail", "Invalid Email"), 121 | req, 122 | res, 123 | next, 124 | ); 125 | } 126 | } 127 | 128 | // console.log('token'); 129 | // let token = await Token.findOne({ name }); 130 | // if(token != null) { 131 | // return next( 132 | // new AppError(201, "fail", "Duplication token name"), 133 | // req, 134 | // res, 135 | // next, 136 | // ); 137 | // } 138 | 139 | // token = await Token.findOne({ symbol }); 140 | // if(token != null) { 141 | // return next( 142 | // new AppError(201, "fail", "Duplication token symbol"), 143 | // req, 144 | // res, 145 | // next, 146 | // ); 147 | // } 148 | 149 | // console.log(address); 150 | 151 | 152 | 153 | 154 | const doc = new Token; 155 | 156 | doc.name = name; 157 | doc.symbol = symbol; 158 | doc.decimal = decimal; 159 | doc.pair_type = pair_type; 160 | doc.address = address; 161 | doc.website_url = website_url; 162 | doc.logo_url = '/images/' + req.file.originalname; 163 | doc.issuer_name = issuer_name; 164 | doc.email_address = email_address; 165 | 166 | if(symbol == "ETH") { 167 | doc.status = "approved"; 168 | } 169 | doc.save(); 170 | 171 | sendMail(doc); 172 | 173 | res.status(200).json({ 174 | status: 'success', 175 | data: { 176 | doc 177 | } 178 | }); 179 | 180 | } catch (error) { 181 | next(error); 182 | } 183 | }; 184 | 185 | exports.approveToken = async(req, res, next) => { 186 | try { 187 | const token = await Token.findOne({ _id: req.params.id }); 188 | 189 | if(!token) { 190 | return next( 191 | new AppError(201, "fail", "token does not exist"), 192 | req, 193 | res, 194 | next, 195 | ); 196 | } 197 | 198 | token.status = "approved"; 199 | token.save(); 200 | 201 | sendMail(token); 202 | 203 | res.status(200).json({ 204 | status: "success", 205 | block: token.status, 206 | }); 207 | 208 | } catch (err) { 209 | next(err); 210 | } 211 | } 212 | 213 | exports.denyToken = async(req, res, next) => { 214 | try { 215 | const token = await Token.findOne({ _id: req.params.id }); 216 | 217 | if(!token) { 218 | return next( 219 | new AppError(201, "fail", "token does not exist"), 220 | req, 221 | res, 222 | next, 223 | ); 224 | } 225 | 226 | token.status = "denied"; 227 | token.save(); 228 | 229 | res.status(200).json({ 230 | status: "success", 231 | block: token.status, 232 | }); 233 | 234 | } catch (err) { 235 | next(err); 236 | } 237 | } 238 | 239 | exports.search = async(req, res, next) => { 240 | try { 241 | // const token = await Token.find().where('symbol').regex(req.body.search_str); 242 | const token = await Token.find({ 243 | $or:[ 244 | { name: RegExp(req.body.search_str, 'i') }, 245 | { symbol: RegExp(req.body.search_str, 'i') } 246 | ] 247 | }).sort({ _id : 1 }); 248 | //.regex(new RegExp(req.body.search_str, 'i')); 249 | res.status(200).json({ 250 | status: 'success', 251 | results: token.length, 252 | data: { 253 | data: token 254 | }, 255 | }); 256 | } catch(err ) { 257 | next(err); 258 | } 259 | } 260 | 261 | exports.upload = async(req, res, next) => { 262 | try { 263 | const token = await Token.findOne({ _id: req.params.id }); 264 | const type = req.body.type; 265 | console.log(type); 266 | console.log(req.file.originalname); 267 | if(type == 'long_version') { 268 | token.long_version_pdf_url = '/papers/' + req.file.originalname; 269 | } else { 270 | token.short_version_pdf_url = '/papers/' + req.file.originalname; 271 | } 272 | token.save(); 273 | 274 | res.status(200).json({ 275 | status: 'success', 276 | results: token, 277 | }); 278 | } catch (error) { 279 | next(error); 280 | } 281 | } -------------------------------------------------------------------------------- /controllers/authController.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require("util"); 2 | const jwt = require("jsonwebtoken"); 3 | const User = require("../models/userModel"); 4 | const AppError = require("../utils/appError"); 5 | const base = require('./baseController'); 6 | const { KeyObject } = require("crypto"); 7 | 8 | const createToken = (id, email) => { 9 | return jwt.sign({ 10 | id: id, 11 | email: email 12 | }, 13 | process.env.JWT_SECRET, { 14 | expiresIn: process.env.JWT_EXPIRES_IN, 15 | }, 16 | ); 17 | }; 18 | 19 | var mailformat = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{3})+$/; 20 | 21 | /** 22 | * Login user and create token 23 | * 24 | * @param [string] email 25 | * @param [string] password 26 | * @param [boolean] remember_me 27 | * @return [string] access_token 28 | * @return [string] token_type 29 | * @return [string] expires_at 30 | */ 31 | exports.login = async(req, res, next) => { 32 | try { 33 | const { email, password } = req.body; 34 | 35 | // 1) check if email and password exist 36 | if (!email || !password) { 37 | return next( 38 | new AppError(201, "fail", "Please provide email or password"), 39 | req, 40 | res, 41 | next, 42 | ); 43 | } 44 | 45 | if(!email.match(mailformat)) { 46 | return next( 47 | new AppError(201, "fail", "Invalid Email"), 48 | req, 49 | res, 50 | next, 51 | ); 52 | } 53 | 54 | if(password.length < 8 ) { 55 | return next( 56 | new AppError(201, "fail", "Your password must be longer than 8 characters."), 57 | req, 58 | res, 59 | next, 60 | ); 61 | } 62 | // 2) check if user exist and password is correct 63 | const user = await User.findOne({ 64 | email, 65 | }).select("+password"); 66 | 67 | if (!user || !(await user.correctPassword(password, user.password))) { 68 | return next( 69 | new AppError(201, "fail", "Email or Password is wrong"), 70 | req, 71 | res, 72 | next, 73 | ); 74 | } 75 | 76 | // if (user.active == false) { 77 | // return next( 78 | // new AppError(201, "fail", "Not allowed yet!"), 79 | // req, 80 | // res, 81 | // next, 82 | // ); 83 | // } 84 | 85 | // if(is_admin == true && !user.menuroles.includes("admin")) { 86 | // return next( 87 | // new AppError(201, "fail", "You are not admin"), 88 | // req, 89 | // res, 90 | // next, 91 | // ); 92 | // } 93 | 94 | // 3) All correct, send jwt to client g 95 | const token = createToken(user.id, user.email); 96 | 97 | // Remove the password from the output 98 | user.password = undefined; 99 | 100 | res.status(200).json({ 101 | status: "success", 102 | token, 103 | data: { 104 | user, 105 | }, 106 | }); 107 | } catch (err) { 108 | next(err); 109 | } 110 | }; 111 | 112 | exports.signup = async(req, res, next) => { 113 | try { 114 | 115 | const {email, password, password_confirmation} = req.body; 116 | 117 | if (!email || !password || !password_confirmation) { 118 | return next( 119 | new AppError(201, "fail", "Please provide email or password"), 120 | req, 121 | res, 122 | next, 123 | ); 124 | } 125 | 126 | if(!email.match(mailformat)) { 127 | return next( 128 | new AppError(201, "fail", "Invalid Email"), 129 | req, 130 | res, 131 | next, 132 | ); 133 | } 134 | 135 | const finduser = await User.findOne({ email }); 136 | if(finduser) { 137 | return next( 138 | new AppError(201, "fail", "E11000 duplicate key error"), 139 | req, 140 | res, 141 | next, 142 | ); 143 | } 144 | 145 | if(password.length < 8 ) { 146 | return next( 147 | new AppError(201, "fail", "Your password must be longer than 8 characters."), 148 | req, 149 | res, 150 | next, 151 | ); 152 | } 153 | 154 | if (password != password_confirmation) { 155 | return next( 156 | new AppError(201, "fail", "Your password and confirmation password are not the same."), 157 | req, 158 | res, 159 | next, 160 | ); 161 | } 162 | 163 | const user = await User.create({ 164 | email: email, 165 | password: password, 166 | }); 167 | 168 | const token = createToken(user.id, user.email); 169 | 170 | // user.email_verify_code = undefined; 171 | 172 | user.password = undefined; 173 | 174 | res.status(200).json({ 175 | status: "success", 176 | token, 177 | data: { 178 | user, 179 | }, 180 | }); 181 | } catch (err) { 182 | next(err); 183 | } 184 | }; 185 | 186 | exports.changePassword = async(req, res, next) => { 187 | try { 188 | 189 | const { _id } = req.body; 190 | 191 | console.log(req.body); 192 | 193 | const user = await User.findOne({ 194 | _id, 195 | }).select("+password"); 196 | 197 | if(!user) { 198 | return next( 199 | new AppError(201, "fail", "User not exists"), 200 | req, 201 | res, 202 | next, 203 | ); 204 | } 205 | 206 | console.log(user); 207 | if (!(await user.correctPassword(req.body.old_password, user.password))) { 208 | return next( 209 | new AppError(201, "fail", "Wrong old Paasword!"), 210 | req, 211 | res, 212 | next, 213 | ); 214 | } 215 | 216 | console.log("1"); 217 | 218 | if (req.body.password != req.body.password_confirmation) { 219 | return next( 220 | new AppError(201, "fail", "Wrong Confirm!"), 221 | req, 222 | res, 223 | next, 224 | ); 225 | } 226 | console.log("2"); 227 | 228 | user.password = req.body.password; 229 | console.log(user.password); 230 | user.save(); 231 | 232 | res.status(200).json({ 233 | status: "Successfully changed!", 234 | }); 235 | } catch (err) { 236 | next(err); 237 | } 238 | }; 239 | 240 | 241 | exports.logout = async(req, res, next) => { 242 | res.status(200).json({ 243 | status: "success", 244 | }); 245 | }; 246 | 247 | 248 | exports.protect = async(req, res, next) => { 249 | try { 250 | // 1) check if the token is there 251 | let token; 252 | if ( 253 | req.headers.authorization && 254 | req.headers.authorization.startsWith("Bearer") 255 | ) { 256 | token = req.headers.authorization.split(" ")[1]; 257 | } 258 | if (!token) { 259 | return next( 260 | new AppError( 261 | 201, 262 | "fail", 263 | "You are not logged in! Please login in to continue", 264 | ), 265 | req, 266 | res, 267 | next, 268 | ); 269 | } 270 | 271 | // 2) Verify token 272 | const decode = await promisify(jwt.verify)(token, process.env.JWT_SECRET); 273 | 274 | // 3) check if the user is exist (not deleted) 275 | const user = await User.findById(decode.id); 276 | if (!user) { 277 | return next( 278 | new AppError(201, "fail", "This user is no longer exist"), 279 | req, 280 | res, 281 | next, 282 | ); 283 | } 284 | 285 | req.user = user; 286 | next(); 287 | } catch (err) { 288 | next(err); 289 | } 290 | }; 291 | 292 | // Authorization check if the user have rights to do this action 293 | exports.restrictTo = (...roles) => { 294 | return (req, res, next) => { 295 | if (!roles.includes(req.user.menuroles)) { 296 | return next( 297 | new AppError(201, "fail", "You are not allowed to do this action"), 298 | req, 299 | res, 300 | next, 301 | ); 302 | } 303 | next(); 304 | }; 305 | }; -------------------------------------------------------------------------------- /utils/caladexABI.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "previousOwner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "newOwner", 15 | "type": "address" 16 | } 17 | ], 18 | "name": "OwnershipTransferred", 19 | "type": "event" 20 | }, 21 | { 22 | "anonymous": false, 23 | "inputs": [ 24 | { 25 | "indexed": false, 26 | "internalType": "uint256", 27 | "name": "count", 28 | "type": "uint256" 29 | } 30 | ], 31 | "name": "StakeCount", 32 | "type": "event" 33 | }, 34 | { 35 | "inputs": [ 36 | { 37 | "internalType": "uint256", 38 | "name": "", 39 | "type": "uint256" 40 | } 41 | ], 42 | "name": "_stakes", 43 | "outputs": [ 44 | { 45 | "internalType": "uint256", 46 | "name": "id", 47 | "type": "uint256" 48 | }, 49 | { 50 | "internalType": "address", 51 | "name": "staker", 52 | "type": "address" 53 | }, 54 | { 55 | "internalType": "address", 56 | "name": "token", 57 | "type": "address" 58 | }, 59 | { 60 | "internalType": "uint256", 61 | "name": "amount", 62 | "type": "uint256" 63 | }, 64 | { 65 | "internalType": "string", 66 | "name": "created_at", 67 | "type": "string" 68 | }, 69 | { 70 | "internalType": "uint256", 71 | "name": "expiration", 72 | "type": "uint256" 73 | }, 74 | { 75 | "internalType": "uint256", 76 | "name": "estApy", 77 | "type": "uint256" 78 | }, 79 | { 80 | "internalType": "bool", 81 | "name": "isCommitted", 82 | "type": "bool" 83 | } 84 | ], 85 | "stateMutability": "view", 86 | "type": "function" 87 | }, 88 | { 89 | "inputs": [ 90 | { 91 | "internalType": "address", 92 | "name": "", 93 | "type": "address" 94 | } 95 | ], 96 | "name": "_tokenlist", 97 | "outputs": [ 98 | { 99 | "internalType": "string", 100 | "name": "name", 101 | "type": "string" 102 | }, 103 | { 104 | "internalType": "string", 105 | "name": "symbol", 106 | "type": "string" 107 | }, 108 | { 109 | "internalType": "uint256", 110 | "name": "decimal", 111 | "type": "uint256" 112 | }, 113 | { 114 | "internalType": "string", 115 | "name": "pair_type", 116 | "type": "string" 117 | }, 118 | { 119 | "internalType": "address", 120 | "name": "token_address", 121 | "type": "address" 122 | }, 123 | { 124 | "internalType": "string", 125 | "name": "website_url", 126 | "type": "string" 127 | }, 128 | { 129 | "internalType": "string", 130 | "name": "logo_url", 131 | "type": "string" 132 | }, 133 | { 134 | "internalType": "string", 135 | "name": "issuer_name", 136 | "type": "string" 137 | }, 138 | { 139 | "internalType": "string", 140 | "name": "email_address", 141 | "type": "string" 142 | }, 143 | { 144 | "internalType": "bool", 145 | "name": "is_deleted", 146 | "type": "bool" 147 | } 148 | ], 149 | "stateMutability": "view", 150 | "type": "function" 151 | }, 152 | { 153 | "inputs": [ 154 | { 155 | "internalType": "address", 156 | "name": "_staker", 157 | "type": "address" 158 | }, 159 | { 160 | "internalType": "address", 161 | "name": "_token", 162 | "type": "address" 163 | }, 164 | { 165 | "internalType": "bytes32", 166 | "name": "symbol", 167 | "type": "bytes32" 168 | }, 169 | { 170 | "internalType": "uint256", 171 | "name": "_amount", 172 | "type": "uint256" 173 | }, 174 | { 175 | "internalType": "string", 176 | "name": "_created_at", 177 | "type": "string" 178 | }, 179 | { 180 | "internalType": "uint256", 181 | "name": "_expiration", 182 | "type": "uint256" 183 | }, 184 | { 185 | "internalType": "uint256", 186 | "name": "_estApy", 187 | "type": "uint256" 188 | } 189 | ], 190 | "name": "addStake", 191 | "outputs": [], 192 | "stateMutability": "nonpayable", 193 | "type": "function" 194 | }, 195 | { 196 | "inputs": [ 197 | { 198 | "internalType": "string", 199 | "name": "name", 200 | "type": "string" 201 | }, 202 | { 203 | "internalType": "string", 204 | "name": "symbol", 205 | "type": "string" 206 | }, 207 | { 208 | "internalType": "uint256", 209 | "name": "decimal", 210 | "type": "uint256" 211 | }, 212 | { 213 | "internalType": "string", 214 | "name": "pair_type", 215 | "type": "string" 216 | }, 217 | { 218 | "internalType": "address", 219 | "name": "token_address", 220 | "type": "address" 221 | }, 222 | { 223 | "internalType": "string", 224 | "name": "website_url", 225 | "type": "string" 226 | }, 227 | { 228 | "internalType": "string", 229 | "name": "logo_url", 230 | "type": "string" 231 | }, 232 | { 233 | "internalType": "string", 234 | "name": "issuer_name", 235 | "type": "string" 236 | }, 237 | { 238 | "internalType": "string", 239 | "name": "email_address", 240 | "type": "string" 241 | } 242 | ], 243 | "name": "approve", 244 | "outputs": [ 245 | { 246 | "internalType": "uint256", 247 | "name": "", 248 | "type": "uint256" 249 | } 250 | ], 251 | "stateMutability": "nonpayable", 252 | "type": "function" 253 | }, 254 | { 255 | "inputs": [ 256 | { 257 | "internalType": "address", 258 | "name": "_token", 259 | "type": "address" 260 | }, 261 | { 262 | "internalType": "bytes32", 263 | "name": "symbol", 264 | "type": "bytes32" 265 | }, 266 | { 267 | "internalType": "uint256", 268 | "name": "amount", 269 | "type": "uint256" 270 | } 271 | ], 272 | "name": "deposit", 273 | "outputs": [], 274 | "stateMutability": "payable", 275 | "type": "function" 276 | }, 277 | { 278 | "inputs": [], 279 | "name": "dexCount", 280 | "outputs": [ 281 | { 282 | "internalType": "uint256", 283 | "name": "", 284 | "type": "uint256" 285 | } 286 | ], 287 | "stateMutability": "view", 288 | "type": "function" 289 | }, 290 | { 291 | "inputs": [ 292 | { 293 | "internalType": "address", 294 | "name": "", 295 | "type": "address" 296 | }, 297 | { 298 | "internalType": "bytes32", 299 | "name": "", 300 | "type": "bytes32" 301 | } 302 | ], 303 | "name": "dex_balances", 304 | "outputs": [ 305 | { 306 | "internalType": "uint256", 307 | "name": "", 308 | "type": "uint256" 309 | } 310 | ], 311 | "stateMutability": "view", 312 | "type": "function" 313 | }, 314 | { 315 | "inputs": [ 316 | { 317 | "internalType": "address", 318 | "name": "_address", 319 | "type": "address" 320 | }, 321 | { 322 | "internalType": "bytes32", 323 | "name": "symbol", 324 | "type": "bytes32" 325 | } 326 | ], 327 | "name": "getBalance", 328 | "outputs": [ 329 | { 330 | "internalType": "uint256", 331 | "name": "", 332 | "type": "uint256" 333 | } 334 | ], 335 | "stateMutability": "view", 336 | "type": "function" 337 | }, 338 | { 339 | "inputs": [], 340 | "name": "owner", 341 | "outputs": [ 342 | { 343 | "internalType": "address", 344 | "name": "", 345 | "type": "address" 346 | } 347 | ], 348 | "stateMutability": "view", 349 | "type": "function" 350 | }, 351 | { 352 | "inputs": [ 353 | { 354 | "internalType": "address", 355 | "name": "token_address", 356 | "type": "address" 357 | } 358 | ], 359 | "name": "removeItem", 360 | "outputs": [], 361 | "stateMutability": "nonpayable", 362 | "type": "function" 363 | }, 364 | { 365 | "inputs": [], 366 | "name": "renounceOwnership", 367 | "outputs": [], 368 | "stateMutability": "nonpayable", 369 | "type": "function" 370 | }, 371 | { 372 | "inputs": [], 373 | "name": "stakeCount", 374 | "outputs": [ 375 | { 376 | "internalType": "uint256", 377 | "name": "", 378 | "type": "uint256" 379 | } 380 | ], 381 | "stateMutability": "view", 382 | "type": "function" 383 | }, 384 | { 385 | "inputs": [ 386 | { 387 | "internalType": "uint256", 388 | "name": "", 389 | "type": "uint256" 390 | } 391 | ], 392 | "name": "stake_balances", 393 | "outputs": [ 394 | { 395 | "internalType": "uint256", 396 | "name": "", 397 | "type": "uint256" 398 | } 399 | ], 400 | "stateMutability": "view", 401 | "type": "function" 402 | }, 403 | { 404 | "inputs": [ 405 | { 406 | "internalType": "address", 407 | "name": "newOwner", 408 | "type": "address" 409 | } 410 | ], 411 | "name": "transferOwnership", 412 | "outputs": [], 413 | "stateMutability": "nonpayable", 414 | "type": "function" 415 | }, 416 | { 417 | "inputs": [ 418 | { 419 | "internalType": "address", 420 | "name": "_address", 421 | "type": "address" 422 | }, 423 | { 424 | "internalType": "bytes32", 425 | "name": "symbol", 426 | "type": "bytes32" 427 | }, 428 | { 429 | "internalType": "uint256", 430 | "name": "index", 431 | "type": "uint256" 432 | }, 433 | { 434 | "internalType": "uint256", 435 | "name": "expired", 436 | "type": "uint256" 437 | } 438 | ], 439 | "name": "unStake", 440 | "outputs": [], 441 | "stateMutability": "nonpayable", 442 | "type": "function" 443 | }, 444 | { 445 | "inputs": [ 446 | { 447 | "internalType": "address", 448 | "name": "_address", 449 | "type": "address" 450 | }, 451 | { 452 | "internalType": "address", 453 | "name": "token_address", 454 | "type": "address" 455 | }, 456 | { 457 | "internalType": "bytes32", 458 | "name": "symbol", 459 | "type": "bytes32" 460 | }, 461 | { 462 | "internalType": "uint256", 463 | "name": "amount", 464 | "type": "uint256" 465 | } 466 | ], 467 | "name": "withdraw", 468 | "outputs": [], 469 | "stateMutability": "payable", 470 | "type": "function" 471 | } 472 | ] -------------------------------------------------------------------------------- /controllers/stakeLogController.js: -------------------------------------------------------------------------------- 1 | const StakeLog = require('../models/stakeLogModel'); 2 | const base = require('./baseController'); 3 | const APIFeatures = require('../utils/apiFeatures'); 4 | const Web3 = require('web3'); 5 | const ethers = require('ethers'); 6 | const CALADEX_ABI = require('../utils/caladexABI.json'); 7 | const Balance = require('../models/balanceModel'); 8 | const Stake = require('../models/stakeModel'); 9 | const Token = require('../models/tokenModel'); 10 | 11 | exports.getAllStakeLogs = base.getAll(StakeLog); 12 | 13 | exports.getStakeLog = async(req, res, next) => { 14 | try { 15 | let doc = await StakeLog.find({address: req.params.address}).where('is_finished').equals(false).populate('stake_id'); 16 | 17 | let curDate = new Date().toLocaleDateString('en-GB', { 18 | timeZone: 'America/Aruba' 19 | }); 20 | const time = curDate.split('/'); 21 | const date = new Date(time[2],time[1] -1, time[0]); 22 | 23 | for(let element of doc) { 24 | const finish_date= new Date(element.finish_date); 25 | element.duration = Math.floor((finish_date.getTime() - date.getTime()) / 1000 / 24 / 60 / 60); 26 | } 27 | res.status(200).json({ 28 | status: 'success', 29 | data: { 30 | doc 31 | } 32 | }); 33 | } catch (error) { 34 | next(error); 35 | } 36 | }; 37 | 38 | 39 | exports.getFinishStakeLog = async(req, res, next) => { 40 | try { 41 | let curDate = new Date().toLocaleDateString('en-GB', { 42 | timeZone: 'America/Aruba' 43 | }); 44 | const time = curDate.split('/'); 45 | const date = new Date(time[2],time[1], time[0]); 46 | // const doc = await StakeLog.find().populate('stake_id'); 47 | StakeLog.where('finish_date').gte(date).populate('stake_id') 48 | .exec(function (err, result) { 49 | if (err){ 50 | console.log(err) 51 | }else{ 52 | console.log("Result :", result); 53 | const doc = result; 54 | 55 | res.status(200).json({ 56 | status: 'success', 57 | data: { 58 | doc 59 | } 60 | }); 61 | } 62 | }); 63 | 64 | } catch (error) { 65 | next(error); 66 | } 67 | }; 68 | 69 | 70 | exports.addStakeLog = async(req, res, next) => { 71 | try { 72 | let {address, duration, amount, stake_id} = req.body; 73 | 74 | console.log('add stake'); 75 | 76 | // const date = new Date(begin_date.getTime() + duration ); 77 | let curDate = new Date().toLocaleDateString('en-GB', { 78 | timeZone: 'America/Aruba' 79 | }); 80 | const time = curDate.split(',')[0].split('/'); 81 | const date = new Date(time[2],time[1] - 1, time[0]); 82 | let finish_date = new Date(date); 83 | finish_date.setDate(finish_date.getDate() + duration); 84 | 85 | req.body.begin_date = date; 86 | req.body.finish_date = finish_date; 87 | 88 | let stake = await Stake.findOne({_id: stake_id}).populate('token_id'); 89 | let balance = await Balance.findOne({address: address, token_id: stake.token_id._id }); 90 | 91 | const privateKey = process.env.PRIVATE_KEY; 92 | const web3 = new Web3(new Web3.providers.HttpProvider( process.env.PROVIDER )); 93 | const etherReceiver = new web3.eth.Contract(CALADEX_ABI, process.env.CALADEX_ADDR); 94 | 95 | let tx = {}; 96 | 97 | if(stake.token_id.symbol == "ETH") { 98 | tx = { 99 | to : process.env.CALADEX_ADDR, 100 | gasLimit: 3141592, 101 | gasUsed: 21662, 102 | data : etherReceiver.methods.addStake(address, "0xD76b5c2A23ef78368d8E34288B5b65D616B746aE", ethers.utils.formatBytes32String("ETH"), ethers.utils.parseEther(amount).toString(), curDate, duration, stake.est_apy * 100).encodeABI() 103 | } 104 | } else { 105 | tx = { 106 | to : process.env.CALADEX_ADDR, 107 | gasLimit: 3141592, 108 | gasUsed: 21662, 109 | data : etherReceiver.methods.addStake(address, stake.token_id.address, ethers.utils.formatBytes32String(stake.token_id._id.toString()), ethers.utils.parseUnits(amount).toString(), curDate, duration, stake.est_apy * 100).encodeABI() 110 | } 111 | } 112 | console.log('staking...'); 113 | await web3.eth.accounts.signTransaction(tx, privateKey).then(async signed => { 114 | await web3.eth.sendSignedTransaction(signed.rawTransaction) 115 | .then(async (receipt) => { 116 | console.log('Receipt: ' + receipt); 117 | console.log('Log ID: ' + parseInt(receipt.logs[0].data, 16)); 118 | 119 | let stakelog = await StakeLog.create(req.body); 120 | stakelog.stakelog_id = parseInt(receipt.logs[0].data, 16); 121 | stakelog.save(); 122 | 123 | console.log('getting balance...'); 124 | await etherReceiver.methods.getBalance(address,ethers.utils.formatBytes32String(stake.token_id.symbol == "ETH"? "ETH": stake.token_id._id.toString())).call(function(error, result) { 125 | // let rlt = result.toString(); 126 | if(error) { 127 | res.status(201).json({ 128 | status: 'failed', 129 | }); 130 | } 131 | else { 132 | console.log('Balance: '+ Web3.utils.fromWei(result.toString()) ); 133 | console.log(balance); 134 | if(balance) { 135 | balance.caladex_balance = Web3.utils.fromWei(result.toString()); 136 | balance.save(); 137 | res.status(200).json({ 138 | status: 'success', 139 | data: { 140 | stakelog 141 | } 142 | }); 143 | } 144 | } 145 | }); 146 | }).catch((error) => { 147 | console.log('Transaction error: '+error.message); 148 | res.status(201).json({ 149 | status: 'failed', 150 | }); 151 | }); 152 | }); 153 | 154 | console.log(balance); 155 | 156 | } catch (error) { 157 | next(error); 158 | } 159 | }; 160 | 161 | exports.unStake = async(req, res, next) => { 162 | try { 163 | const {address, stakelog_id} = req.body; 164 | 165 | let stakelog = await StakeLog.findOne({ stakelog_id : stakelog_id, is_finished : false }); 166 | 167 | if(!stakelog) { 168 | res.status(201).json({ 169 | status: 'failed', 170 | message: 'stake log not found' 171 | }); 172 | return; 173 | } 174 | 175 | let stake = await Stake.findOne({_id: stakelog.stake_id}).populate('token_id'); 176 | let balance = await Balance.findOne({address: address, token_id: stake.token_id._id }); 177 | 178 | let curDate = new Date().toLocaleDateString('en-GB', { 179 | timeZone: 'America/Aruba' 180 | }); 181 | const time = curDate.split('/'); 182 | const date = new Date(time[2],time[1] -1, time[0]); 183 | 184 | const privateKey = process.env.PRIVATE_KEY; 185 | const web3 = new Web3(new Web3.providers.HttpProvider( process.env.PROVIDER )); 186 | const etherReceiver = new web3.eth.Contract(CALADEX_ABI, process.env.CALADEX_ADDR); 187 | 188 | let tx = {}; 189 | 190 | if(stake.token_id.symbol == 'ETH') { 191 | tx = { 192 | to : process.env.CALADEX_ADDR, 193 | gasLimit: 3141592, 194 | gasUsed: 21662, 195 | data : etherReceiver.methods.unStake(address, ethers.utils.formatBytes32String('ETH'), stakelog_id, Math.floor((date.getTime() - stakelog.begin_date.getTime()) / 1000 / 24 / 60 / 60)).encodeABI() 196 | } 197 | 198 | } else { 199 | tx = { 200 | to : process.env.CALADEX_ADDR, 201 | gasLimit: 3141592, 202 | gasUsed: 21662, 203 | data : etherReceiver.methods.unStake(address, ethers.utils.formatBytes32String(stake.token_id._id.toString()), stakelog_id, Math.floor((date.getTime() - stakelog.begin_date.getTime()) / 1000 / 24 / 60 / 60)).encodeABI() 204 | } 205 | } 206 | 207 | 208 | console.log("unstaking..."); 209 | await web3.eth.accounts.signTransaction(tx, privateKey).then(async signed => { 210 | await web3.eth.sendSignedTransaction(signed.rawTransaction) 211 | .then(async (receipt) => { 212 | console.log('Receipt: ' + receipt); 213 | 214 | stakelog.is_finished = true; 215 | stakelog.save(); 216 | 217 | console.log("getting balance..."); 218 | await etherReceiver.methods.getBalance(address, ethers.utils.formatBytes32String(stake.token_id.symbol == "ETH"? "ETH": stake.token_id._id.toString())).call(function(error, result) { 219 | // let rlt = result.toString(); 220 | if(error) { 221 | res.status(201).json({ 222 | status: 'failed', 223 | }); 224 | } 225 | else { 226 | console.log('Balance: '+ Web3.utils.fromWei(result.toString()) ); 227 | console.log(balance); 228 | if(balance) { 229 | balance.caladex_balance = Web3.utils.fromWei(result.toString()); 230 | balance.save(); 231 | } 232 | res.status(200).json({ 233 | status: 'success', 234 | }); 235 | } 236 | }); 237 | }) 238 | .catch((error) => { 239 | console.log('Transaction error: '+error.message); 240 | res.status(201).json({ 241 | status: 'failed', 242 | }); 243 | }); 244 | }); 245 | 246 | console.log(balance); 247 | 248 | } catch (error) { 249 | next(error); 250 | } 251 | }; -------------------------------------------------------------------------------- /history.md: -------------------------------------------------------------------------------- 1 | Contribution: 2018-07-05 15:54 2 | 3 | Contribution: 2018-07-05 15:55 4 | 5 | Contribution: 2018-07-05 15:56 6 | 7 | Contribution: 2018-07-05 15:57 8 | 9 | Contribution: 2018-07-06 15:54 10 | 11 | Contribution: 2018-07-06 15:55 12 | 13 | Contribution: 2018-07-06 15:56 14 | 15 | Contribution: 2018-07-09 15:54 16 | 17 | Contribution: 2018-07-10 15:54 18 | 19 | Contribution: 2018-07-11 15:54 20 | 21 | Contribution: 2018-07-12 15:54 22 | 23 | Contribution: 2018-07-12 15:55 24 | 25 | Contribution: 2018-07-12 15:56 26 | 27 | Contribution: 2018-07-12 15:57 28 | 29 | Contribution: 2018-07-12 15:58 30 | 31 | Contribution: 2018-07-12 15:59 32 | 33 | Contribution: 2018-07-13 15:54 34 | 35 | Contribution: 2018-07-13 15:55 36 | 37 | Contribution: 2018-07-13 15:56 38 | 39 | Contribution: 2018-07-16 15:54 40 | 41 | Contribution: 2018-07-16 15:55 42 | 43 | Contribution: 2018-07-17 15:54 44 | 45 | Contribution: 2018-07-17 15:55 46 | 47 | Contribution: 2018-07-17 15:56 48 | 49 | Contribution: 2018-07-17 15:57 50 | 51 | Contribution: 2018-07-17 15:58 52 | 53 | Contribution: 2018-07-19 15:54 54 | 55 | Contribution: 2018-07-19 15:55 56 | 57 | Contribution: 2018-07-19 15:56 58 | 59 | Contribution: 2018-07-19 15:57 60 | 61 | Contribution: 2018-07-19 15:58 62 | 63 | Contribution: 2018-07-19 15:59 64 | 65 | Contribution: 2018-07-19 16:00 66 | 67 | Contribution: 2018-07-20 15:54 68 | 69 | Contribution: 2018-07-20 15:55 70 | 71 | Contribution: 2018-07-20 15:56 72 | 73 | Contribution: 2018-07-23 15:54 74 | 75 | Contribution: 2018-07-24 15:54 76 | 77 | Contribution: 2018-07-25 15:54 78 | 79 | Contribution: 2018-07-26 15:54 80 | 81 | Contribution: 2018-07-26 15:55 82 | 83 | Contribution: 2018-07-26 15:56 84 | 85 | Contribution: 2018-07-26 15:57 86 | 87 | Contribution: 2018-07-26 15:58 88 | 89 | Contribution: 2018-07-27 15:54 90 | 91 | Contribution: 2018-07-27 15:55 92 | 93 | Contribution: 2018-07-27 15:56 94 | 95 | Contribution: 2018-07-30 15:54 96 | 97 | Contribution: 2018-07-30 15:55 98 | 99 | Contribution: 2018-07-30 15:56 100 | 101 | Contribution: 2018-07-31 15:54 102 | 103 | Contribution: 2018-07-31 15:55 104 | 105 | Contribution: 2018-07-31 15:56 106 | 107 | Contribution: 2018-07-31 15:57 108 | 109 | Contribution: 2018-07-31 15:58 110 | 111 | Contribution: 2018-07-31 15:59 112 | 113 | Contribution: 2018-08-01 15:54 114 | 115 | Contribution: 2018-08-01 15:55 116 | 117 | Contribution: 2018-08-01 15:56 118 | 119 | Contribution: 2018-08-01 15:57 120 | 121 | Contribution: 2018-08-02 15:54 122 | 123 | Contribution: 2018-08-02 15:55 124 | 125 | Contribution: 2018-08-02 15:56 126 | 127 | Contribution: 2018-08-02 15:57 128 | 129 | Contribution: 2018-08-02 15:58 130 | 131 | Contribution: 2018-08-02 15:59 132 | 133 | Contribution: 2018-08-06 15:54 134 | 135 | Contribution: 2018-08-06 15:55 136 | 137 | Contribution: 2018-08-06 15:56 138 | 139 | Contribution: 2018-08-06 15:57 140 | 141 | Contribution: 2018-08-06 15:58 142 | 143 | Contribution: 2018-08-07 15:54 144 | 145 | Contribution: 2018-08-07 15:55 146 | 147 | Contribution: 2018-08-07 15:56 148 | 149 | Contribution: 2018-08-08 15:54 150 | 151 | Contribution: 2018-08-10 15:54 152 | 153 | Contribution: 2018-08-13 15:54 154 | 155 | Contribution: 2018-08-13 15:55 156 | 157 | Contribution: 2018-08-13 15:56 158 | 159 | Contribution: 2018-08-13 15:57 160 | 161 | Contribution: 2018-08-13 15:58 162 | 163 | Contribution: 2018-08-13 15:59 164 | 165 | Contribution: 2018-08-14 15:54 166 | 167 | Contribution: 2018-08-14 15:55 168 | 169 | Contribution: 2018-08-14 15:56 170 | 171 | Contribution: 2018-08-14 15:57 172 | 173 | Contribution: 2018-08-14 15:58 174 | 175 | Contribution: 2018-08-14 15:59 176 | 177 | Contribution: 2018-08-15 15:54 178 | 179 | Contribution: 2018-08-15 15:55 180 | 181 | Contribution: 2018-08-15 15:56 182 | 183 | Contribution: 2018-08-15 15:57 184 | 185 | Contribution: 2018-08-15 15:58 186 | 187 | Contribution: 2018-08-15 15:59 188 | 189 | Contribution: 2018-08-15 16:00 190 | 191 | Contribution: 2018-08-16 15:54 192 | 193 | Contribution: 2018-08-20 15:54 194 | 195 | Contribution: 2018-08-20 15:55 196 | 197 | Contribution: 2018-08-20 15:56 198 | 199 | Contribution: 2018-08-20 15:57 200 | 201 | Contribution: 2018-08-20 15:58 202 | 203 | Contribution: 2018-08-20 15:59 204 | 205 | Contribution: 2018-08-22 15:54 206 | 207 | Contribution: 2018-08-22 15:55 208 | 209 | Contribution: 2018-08-22 15:56 210 | 211 | Contribution: 2018-08-23 15:54 212 | 213 | Contribution: 2018-08-23 15:55 214 | 215 | Contribution: 2018-08-28 15:54 216 | 217 | Contribution: 2018-08-28 15:55 218 | 219 | Contribution: 2018-08-28 15:56 220 | 221 | Contribution: 2018-08-28 15:57 222 | 223 | Contribution: 2018-08-28 15:58 224 | 225 | Contribution: 2018-08-28 15:59 226 | 227 | Contribution: 2018-08-29 15:54 228 | 229 | Contribution: 2018-08-30 15:54 230 | 231 | Contribution: 2018-08-30 15:55 232 | 233 | Contribution: 2018-08-30 15:56 234 | 235 | Contribution: 2018-09-03 15:54 236 | 237 | Contribution: 2018-09-04 15:54 238 | 239 | Contribution: 2018-09-04 15:55 240 | 241 | Contribution: 2018-09-05 15:54 242 | 243 | Contribution: 2018-09-05 15:55 244 | 245 | Contribution: 2018-09-05 15:56 246 | 247 | Contribution: 2018-09-05 15:57 248 | 249 | Contribution: 2018-09-06 15:54 250 | 251 | Contribution: 2018-09-06 15:55 252 | 253 | Contribution: 2018-09-07 15:54 254 | 255 | Contribution: 2018-09-07 15:55 256 | 257 | Contribution: 2018-09-07 15:56 258 | 259 | Contribution: 2018-09-07 15:57 260 | 261 | Contribution: 2018-09-10 15:54 262 | 263 | Contribution: 2018-09-10 15:55 264 | 265 | Contribution: 2018-09-10 15:56 266 | 267 | Contribution: 2018-09-10 15:57 268 | 269 | Contribution: 2018-09-10 15:58 270 | 271 | Contribution: 2018-09-11 15:54 272 | 273 | Contribution: 2018-09-11 15:55 274 | 275 | Contribution: 2018-09-11 15:56 276 | 277 | Contribution: 2018-09-11 15:57 278 | 279 | Contribution: 2018-09-11 15:58 280 | 281 | Contribution: 2018-09-11 15:59 282 | 283 | Contribution: 2018-09-11 16:00 284 | 285 | Contribution: 2018-09-12 15:54 286 | 287 | Contribution: 2018-09-12 15:55 288 | 289 | Contribution: 2018-09-13 15:54 290 | 291 | Contribution: 2018-09-17 15:54 292 | 293 | Contribution: 2018-09-17 15:55 294 | 295 | Contribution: 2018-09-17 15:56 296 | 297 | Contribution: 2018-09-17 15:57 298 | 299 | Contribution: 2018-09-17 15:58 300 | 301 | Contribution: 2018-09-17 15:59 302 | 303 | Contribution: 2018-09-17 16:00 304 | 305 | Contribution: 2018-09-18 15:54 306 | 307 | Contribution: 2018-09-18 15:55 308 | 309 | Contribution: 2018-09-18 15:56 310 | 311 | Contribution: 2018-09-18 15:57 312 | 313 | Contribution: 2018-09-18 15:58 314 | 315 | Contribution: 2018-09-18 15:59 316 | 317 | Contribution: 2018-09-19 15:54 318 | 319 | Contribution: 2018-09-20 15:54 320 | 321 | Contribution: 2018-09-21 15:54 322 | 323 | Contribution: 2018-09-21 15:55 324 | 325 | Contribution: 2018-09-21 15:56 326 | 327 | Contribution: 2018-09-21 15:57 328 | 329 | Contribution: 2018-09-21 15:58 330 | 331 | Contribution: 2018-09-24 15:54 332 | 333 | Contribution: 2018-09-24 15:55 334 | 335 | Contribution: 2018-09-24 15:56 336 | 337 | Contribution: 2018-09-24 15:57 338 | 339 | Contribution: 2018-09-24 15:58 340 | 341 | Contribution: 2018-09-24 15:59 342 | 343 | Contribution: 2018-09-24 16:00 344 | 345 | Contribution: 2018-09-25 15:54 346 | 347 | Contribution: 2018-09-25 15:55 348 | 349 | Contribution: 2018-09-25 15:56 350 | 351 | Contribution: 2018-09-25 15:57 352 | 353 | Contribution: 2018-09-27 15:54 354 | 355 | Contribution: 2018-09-28 15:54 356 | 357 | Contribution: 2018-09-28 15:55 358 | 359 | Contribution: 2018-10-01 15:54 360 | 361 | Contribution: 2018-10-01 15:55 362 | 363 | Contribution: 2018-10-03 15:54 364 | 365 | Contribution: 2018-10-03 15:55 366 | 367 | Contribution: 2018-10-04 15:54 368 | 369 | Contribution: 2018-10-04 15:55 370 | 371 | Contribution: 2018-10-04 15:56 372 | 373 | Contribution: 2018-10-04 15:57 374 | 375 | Contribution: 2018-10-04 15:58 376 | 377 | Contribution: 2018-10-04 15:59 378 | 379 | Contribution: 2018-10-04 16:00 380 | 381 | Contribution: 2018-10-05 15:54 382 | 383 | Contribution: 2018-10-05 15:55 384 | 385 | Contribution: 2018-10-05 15:56 386 | 387 | Contribution: 2018-10-05 15:57 388 | 389 | Contribution: 2018-10-08 15:54 390 | 391 | Contribution: 2018-10-08 15:55 392 | 393 | Contribution: 2018-10-08 15:56 394 | 395 | Contribution: 2018-10-09 15:54 396 | 397 | Contribution: 2018-10-09 15:55 398 | 399 | Contribution: 2018-10-09 15:56 400 | 401 | Contribution: 2018-10-09 15:57 402 | 403 | Contribution: 2018-10-09 15:58 404 | 405 | Contribution: 2018-10-09 15:59 406 | 407 | Contribution: 2018-10-09 16:00 408 | 409 | Contribution: 2018-10-10 15:54 410 | 411 | Contribution: 2018-10-10 15:55 412 | 413 | Contribution: 2018-10-10 15:56 414 | 415 | Contribution: 2018-10-10 15:57 416 | 417 | Contribution: 2018-10-11 15:54 418 | 419 | Contribution: 2018-10-12 15:54 420 | 421 | Contribution: 2018-10-12 15:55 422 | 423 | Contribution: 2018-10-12 15:56 424 | 425 | Contribution: 2018-10-12 15:57 426 | 427 | Contribution: 2018-10-12 15:58 428 | 429 | Contribution: 2018-10-12 15:59 430 | 431 | Contribution: 2018-10-12 16:00 432 | 433 | Contribution: 2018-10-16 15:54 434 | 435 | Contribution: 2018-10-16 15:55 436 | 437 | Contribution: 2018-10-16 15:56 438 | 439 | Contribution: 2018-10-16 15:57 440 | 441 | Contribution: 2018-10-16 15:58 442 | 443 | Contribution: 2018-10-16 15:59 444 | 445 | Contribution: 2018-10-16 16:00 446 | 447 | Contribution: 2018-10-17 15:54 448 | 449 | Contribution: 2018-10-18 15:54 450 | 451 | Contribution: 2018-10-18 15:55 452 | 453 | Contribution: 2018-10-18 15:56 454 | 455 | Contribution: 2018-10-18 15:57 456 | 457 | Contribution: 2018-10-22 15:54 458 | 459 | Contribution: 2018-10-22 15:55 460 | 461 | Contribution: 2018-10-22 15:56 462 | 463 | Contribution: 2018-10-22 15:57 464 | 465 | Contribution: 2018-10-23 15:54 466 | 467 | Contribution: 2018-10-23 15:55 468 | 469 | Contribution: 2018-10-24 15:54 470 | 471 | Contribution: 2018-10-24 15:55 472 | 473 | Contribution: 2018-10-24 15:56 474 | 475 | Contribution: 2018-10-24 15:57 476 | 477 | Contribution: 2018-10-24 15:58 478 | 479 | Contribution: 2018-10-25 15:54 480 | 481 | Contribution: 2018-10-25 15:55 482 | 483 | Contribution: 2018-10-30 15:54 484 | 485 | Contribution: 2018-10-30 15:55 486 | 487 | Contribution: 2018-10-30 15:56 488 | 489 | Contribution: 2018-10-30 15:57 490 | 491 | Contribution: 2018-10-30 15:58 492 | 493 | Contribution: 2018-10-30 15:59 494 | 495 | Contribution: 2018-10-31 15:54 496 | 497 | Contribution: 2018-10-31 15:55 498 | 499 | Contribution: 2018-10-31 15:56 500 | 501 | Contribution: 2018-10-31 15:57 502 | 503 | Contribution: 2018-10-31 15:58 504 | 505 | Contribution: 2018-10-31 15:59 506 | 507 | Contribution: 2018-10-31 16:00 508 | 509 | Contribution: 2018-11-02 15:54 510 | 511 | Contribution: 2018-11-02 15:55 512 | 513 | Contribution: 2018-11-02 15:56 514 | 515 | Contribution: 2018-11-02 15:57 516 | 517 | Contribution: 2018-11-02 15:58 518 | 519 | Contribution: 2018-11-05 15:54 520 | 521 | Contribution: 2018-11-05 15:55 522 | 523 | Contribution: 2018-11-05 15:56 524 | 525 | Contribution: 2018-11-05 15:57 526 | 527 | Contribution: 2018-11-05 15:58 528 | 529 | Contribution: 2018-11-06 15:54 530 | 531 | Contribution: 2018-11-06 15:55 532 | 533 | Contribution: 2018-11-07 15:54 534 | 535 | Contribution: 2018-11-07 15:55 536 | 537 | Contribution: 2018-11-07 15:56 538 | 539 | Contribution: 2018-11-07 15:57 540 | 541 | Contribution: 2018-11-07 15:58 542 | 543 | Contribution: 2018-11-08 15:54 544 | 545 | Contribution: 2018-11-08 15:55 546 | 547 | Contribution: 2018-11-08 15:56 548 | 549 | Contribution: 2018-11-08 15:57 550 | 551 | Contribution: 2018-11-08 15:58 552 | 553 | Contribution: 2018-11-08 15:59 554 | 555 | Contribution: 2018-11-08 16:00 556 | 557 | Contribution: 2018-11-13 15:54 558 | 559 | Contribution: 2018-11-13 15:55 560 | 561 | Contribution: 2018-11-13 15:56 562 | 563 | Contribution: 2018-11-13 15:57 564 | 565 | Contribution: 2018-11-13 15:58 566 | 567 | Contribution: 2018-11-13 15:59 568 | 569 | Contribution: 2018-11-15 15:54 570 | 571 | Contribution: 2018-11-15 15:55 572 | 573 | Contribution: 2018-11-15 15:56 574 | 575 | Contribution: 2018-11-15 15:57 576 | 577 | Contribution: 2018-11-16 15:54 578 | 579 | Contribution: 2018-11-16 15:55 580 | 581 | Contribution: 2018-11-16 15:56 582 | 583 | Contribution: 2018-11-16 15:57 584 | 585 | Contribution: 2018-11-16 15:58 586 | 587 | Contribution: 2018-11-20 15:54 588 | 589 | Contribution: 2018-11-20 15:55 590 | 591 | Contribution: 2018-11-20 15:56 592 | 593 | Contribution: 2018-11-20 15:57 594 | 595 | Contribution: 2018-11-20 15:58 596 | 597 | Contribution: 2018-11-20 15:59 598 | 599 | Contribution: 2018-11-20 16:00 600 | 601 | Contribution: 2018-11-21 15:54 602 | 603 | Contribution: 2018-11-21 15:55 604 | 605 | Contribution: 2018-11-21 15:56 606 | 607 | Contribution: 2018-11-22 15:54 608 | 609 | Contribution: 2018-11-22 15:55 610 | 611 | Contribution: 2018-11-22 15:56 612 | 613 | Contribution: 2018-11-22 15:57 614 | 615 | Contribution: 2018-11-22 15:58 616 | 617 | Contribution: 2018-11-23 15:54 618 | 619 | Contribution: 2018-11-23 15:55 620 | 621 | Contribution: 2018-11-26 15:54 622 | 623 | Contribution: 2018-11-26 15:55 624 | 625 | Contribution: 2018-11-26 15:56 626 | 627 | Contribution: 2018-11-26 15:57 628 | 629 | Contribution: 2018-11-26 15:58 630 | 631 | Contribution: 2018-11-26 15:59 632 | 633 | Contribution: 2018-11-27 15:54 634 | 635 | Contribution: 2018-11-27 15:55 636 | 637 | Contribution: 2018-11-27 15:56 638 | 639 | Contribution: 2018-11-27 15:57 640 | 641 | Contribution: 2018-11-27 15:58 642 | 643 | Contribution: 2018-11-27 15:59 644 | 645 | Contribution: 2018-11-27 16:00 646 | 647 | Contribution: 2018-11-28 15:54 648 | 649 | Contribution: 2018-11-28 15:55 650 | 651 | Contribution: 2018-11-28 15:56 652 | 653 | Contribution: 2018-11-28 15:57 654 | 655 | Contribution: 2018-11-28 15:58 656 | 657 | Contribution: 2018-11-29 15:54 658 | 659 | Contribution: 2018-11-29 15:55 660 | 661 | Contribution: 2018-11-29 15:56 662 | 663 | Contribution: 2018-11-29 15:57 664 | 665 | Contribution: 2018-11-29 15:58 666 | 667 | Contribution: 2018-11-29 15:59 668 | 669 | Contribution: 2018-11-29 16:00 670 | 671 | Contribution: 2018-11-30 15:54 672 | 673 | Contribution: 2018-12-03 15:54 674 | 675 | Contribution: 2018-12-03 15:55 676 | 677 | Contribution: 2018-12-03 15:56 678 | 679 | Contribution: 2018-12-03 15:57 680 | 681 | Contribution: 2018-12-03 15:58 682 | 683 | Contribution: 2018-12-04 15:54 684 | 685 | Contribution: 2018-12-04 15:55 686 | 687 | Contribution: 2018-12-04 15:56 688 | 689 | Contribution: 2018-12-04 15:57 690 | 691 | Contribution: 2018-12-05 15:54 692 | 693 | Contribution: 2018-12-06 15:54 694 | 695 | Contribution: 2018-12-06 15:55 696 | 697 | Contribution: 2018-12-06 15:56 698 | 699 | Contribution: 2018-12-06 15:57 700 | 701 | Contribution: 2018-12-06 15:58 702 | 703 | Contribution: 2018-12-07 15:54 704 | 705 | Contribution: 2018-12-07 15:55 706 | 707 | Contribution: 2018-12-07 15:56 708 | 709 | Contribution: 2018-12-07 15:57 710 | 711 | Contribution: 2018-12-10 15:54 712 | 713 | Contribution: 2018-12-10 15:55 714 | 715 | Contribution: 2018-12-10 15:56 716 | 717 | Contribution: 2018-12-10 15:57 718 | 719 | Contribution: 2018-12-13 15:54 720 | 721 | Contribution: 2018-12-13 15:55 722 | 723 | Contribution: 2018-12-13 15:56 724 | 725 | Contribution: 2018-12-13 15:57 726 | 727 | Contribution: 2018-12-13 15:58 728 | 729 | Contribution: 2018-12-17 15:54 730 | 731 | Contribution: 2018-12-17 15:55 732 | 733 | Contribution: 2018-12-17 15:56 734 | 735 | Contribution: 2018-12-17 15:57 736 | 737 | Contribution: 2018-12-20 15:54 738 | 739 | Contribution: 2018-12-20 15:55 740 | 741 | Contribution: 2018-12-20 15:56 742 | 743 | Contribution: 2018-12-21 15:54 744 | 745 | Contribution: 2018-12-21 15:55 746 | 747 | Contribution: 2018-12-21 15:56 748 | 749 | Contribution: 2018-12-21 15:57 750 | 751 | Contribution: 2018-12-24 15:54 752 | 753 | Contribution: 2018-12-24 15:55 754 | 755 | Contribution: 2018-12-24 15:56 756 | 757 | Contribution: 2018-12-24 15:57 758 | 759 | Contribution: 2018-12-24 15:58 760 | 761 | Contribution: 2018-12-24 15:59 762 | 763 | Contribution: 2018-12-24 16:00 764 | 765 | Contribution: 2018-12-25 15:54 766 | 767 | Contribution: 2018-12-25 15:55 768 | 769 | Contribution: 2018-12-25 15:56 770 | 771 | Contribution: 2018-12-27 15:54 772 | 773 | Contribution: 2018-12-27 15:55 774 | 775 | Contribution: 2018-12-27 15:56 776 | 777 | Contribution: 2018-12-27 15:57 778 | 779 | Contribution: 2018-12-27 15:58 780 | 781 | Contribution: 2018-12-27 15:59 782 | 783 | Contribution: 2018-12-28 15:54 784 | 785 | Contribution: 2018-12-31 15:54 786 | 787 | Contribution: 2018-12-31 15:55 788 | 789 | Contribution: 2018-12-31 15:56 790 | 791 | Contribution: 2018-12-31 15:57 792 | 793 | Contribution: 2018-12-31 15:58 794 | 795 | Contribution: 2018-12-31 15:59 796 | 797 | Contribution: 2018-12-31 16:00 798 | 799 | Contribution: 2019-01-01 15:54 800 | 801 | Contribution: 2019-01-01 15:55 802 | 803 | Contribution: 2019-01-01 15:56 804 | 805 | Contribution: 2019-01-01 15:57 806 | 807 | Contribution: 2019-01-01 15:58 808 | 809 | Contribution: 2019-01-01 15:59 810 | 811 | Contribution: 2019-01-01 16:00 812 | 813 | Contribution: 2019-01-02 15:54 814 | 815 | Contribution: 2019-01-02 15:55 816 | 817 | Contribution: 2019-01-02 15:56 818 | 819 | Contribution: 2019-01-02 15:57 820 | 821 | Contribution: 2019-01-02 15:58 822 | 823 | Contribution: 2019-01-02 15:59 824 | 825 | Contribution: 2019-01-03 15:54 826 | 827 | Contribution: 2019-01-03 15:55 828 | 829 | Contribution: 2019-01-03 15:56 830 | 831 | Contribution: 2019-01-03 15:57 832 | 833 | Contribution: 2019-01-04 15:54 834 | 835 | Contribution: 2019-01-04 15:55 836 | 837 | Contribution: 2019-01-04 15:56 838 | 839 | Contribution: 2019-01-04 15:57 840 | 841 | Contribution: 2019-01-04 15:58 842 | 843 | Contribution: 2019-01-04 15:59 844 | 845 | Contribution: 2019-01-08 15:54 846 | 847 | Contribution: 2019-01-10 15:54 848 | 849 | Contribution: 2019-01-10 15:55 850 | 851 | Contribution: 2019-01-10 15:56 852 | 853 | Contribution: 2019-01-10 15:57 854 | 855 | Contribution: 2019-01-11 15:54 856 | 857 | Contribution: 2019-01-11 15:55 858 | 859 | Contribution: 2019-01-11 15:56 860 | 861 | Contribution: 2019-01-14 15:54 862 | 863 | Contribution: 2019-01-14 15:55 864 | 865 | Contribution: 2019-01-14 15:56 866 | 867 | Contribution: 2019-01-14 15:57 868 | 869 | Contribution: 2019-01-14 15:58 870 | 871 | Contribution: 2019-01-16 15:54 872 | 873 | Contribution: 2019-01-16 15:55 874 | 875 | Contribution: 2019-01-16 15:56 876 | 877 | Contribution: 2019-01-16 15:57 878 | 879 | Contribution: 2019-01-16 15:58 880 | 881 | Contribution: 2019-01-16 15:59 882 | 883 | Contribution: 2019-01-16 16:00 884 | 885 | Contribution: 2019-01-17 15:54 886 | 887 | Contribution: 2019-01-18 15:54 888 | 889 | Contribution: 2019-01-18 15:55 890 | 891 | Contribution: 2019-01-18 15:56 892 | 893 | Contribution: 2019-01-18 15:57 894 | 895 | Contribution: 2019-01-18 15:58 896 | 897 | Contribution: 2019-01-18 15:59 898 | 899 | Contribution: 2019-01-21 15:54 900 | 901 | Contribution: 2019-01-21 15:55 902 | 903 | Contribution: 2019-01-21 15:56 904 | 905 | Contribution: 2019-01-21 15:57 906 | 907 | Contribution: 2019-01-22 15:54 908 | 909 | Contribution: 2019-01-22 15:55 910 | 911 | Contribution: 2019-01-22 15:56 912 | 913 | Contribution: 2019-01-22 15:57 914 | 915 | Contribution: 2019-01-22 15:58 916 | 917 | Contribution: 2019-01-22 15:59 918 | 919 | Contribution: 2019-01-22 16:00 920 | 921 | Contribution: 2019-01-23 15:54 922 | 923 | Contribution: 2019-01-23 15:55 924 | 925 | Contribution: 2019-01-23 15:56 926 | 927 | Contribution: 2019-01-23 15:57 928 | 929 | Contribution: 2019-01-23 15:58 930 | 931 | Contribution: 2019-01-23 15:59 932 | 933 | Contribution: 2019-01-25 15:54 934 | 935 | Contribution: 2019-01-25 15:55 936 | 937 | Contribution: 2019-01-28 15:54 938 | 939 | Contribution: 2019-01-28 15:55 940 | 941 | Contribution: 2019-01-28 15:56 942 | 943 | Contribution: 2019-01-29 15:54 944 | 945 | Contribution: 2019-01-29 15:55 946 | 947 | Contribution: 2019-01-30 15:54 948 | 949 | Contribution: 2019-01-30 15:55 950 | 951 | Contribution: 2019-01-30 15:56 952 | 953 | Contribution: 2019-01-31 15:54 954 | 955 | Contribution: 2019-01-31 15:55 956 | 957 | Contribution: 2019-01-31 15:56 958 | 959 | Contribution: 2019-02-01 15:54 960 | 961 | Contribution: 2019-02-04 15:54 962 | 963 | Contribution: 2019-02-04 15:55 964 | 965 | Contribution: 2019-02-04 15:56 966 | 967 | Contribution: 2019-02-04 15:57 968 | 969 | Contribution: 2019-02-04 15:58 970 | 971 | Contribution: 2019-02-04 15:59 972 | 973 | Contribution: 2019-02-05 15:54 974 | 975 | Contribution: 2019-02-05 15:55 976 | 977 | Contribution: 2019-02-06 15:54 978 | 979 | Contribution: 2019-02-07 15:54 980 | 981 | Contribution: 2019-02-07 15:55 982 | 983 | Contribution: 2019-02-07 15:56 984 | 985 | Contribution: 2019-02-11 15:54 986 | 987 | Contribution: 2019-02-11 15:55 988 | 989 | Contribution: 2019-02-11 15:56 990 | 991 | Contribution: 2019-02-11 15:57 992 | 993 | Contribution: 2019-02-12 15:54 994 | 995 | Contribution: 2019-02-12 15:55 996 | 997 | Contribution: 2019-02-12 15:56 998 | 999 | Contribution: 2019-02-12 15:57 1000 | 1001 | Contribution: 2019-02-12 15:58 1002 | 1003 | Contribution: 2019-02-13 15:54 1004 | 1005 | Contribution: 2019-02-13 15:55 1006 | 1007 | Contribution: 2019-02-13 15:56 1008 | 1009 | Contribution: 2019-02-13 15:57 1010 | 1011 | Contribution: 2019-02-13 15:58 1012 | 1013 | Contribution: 2019-02-14 15:54 1014 | 1015 | Contribution: 2019-02-14 15:55 1016 | 1017 | Contribution: 2019-02-14 15:56 1018 | 1019 | Contribution: 2019-02-14 15:57 1020 | 1021 | Contribution: 2019-02-14 15:58 1022 | 1023 | Contribution: 2019-02-14 15:59 1024 | 1025 | Contribution: 2019-02-14 16:00 1026 | 1027 | Contribution: 2019-02-15 15:54 1028 | 1029 | Contribution: 2019-02-15 15:55 1030 | 1031 | Contribution: 2019-02-15 15:56 1032 | 1033 | Contribution: 2019-02-15 15:57 1034 | 1035 | Contribution: 2019-02-15 15:58 1036 | 1037 | Contribution: 2019-02-18 15:54 1038 | 1039 | Contribution: 2019-02-18 15:55 1040 | 1041 | Contribution: 2019-02-18 15:56 1042 | 1043 | Contribution: 2019-02-18 15:57 1044 | 1045 | Contribution: 2019-02-18 15:58 1046 | 1047 | Contribution: 2019-02-18 15:59 1048 | 1049 | Contribution: 2019-02-18 16:00 1050 | 1051 | Contribution: 2019-02-20 15:54 1052 | 1053 | Contribution: 2019-02-20 15:55 1054 | 1055 | Contribution: 2019-02-20 15:56 1056 | 1057 | Contribution: 2019-02-21 15:54 1058 | 1059 | Contribution: 2019-02-21 15:55 1060 | 1061 | Contribution: 2019-02-21 15:56 1062 | 1063 | Contribution: 2019-02-21 15:57 1064 | 1065 | Contribution: 2019-02-21 15:58 1066 | 1067 | Contribution: 2019-02-21 15:59 1068 | 1069 | Contribution: 2019-02-21 16:00 1070 | 1071 | Contribution: 2019-02-25 15:54 1072 | 1073 | Contribution: 2019-02-25 15:55 1074 | 1075 | Contribution: 2019-02-25 15:56 1076 | 1077 | Contribution: 2019-02-25 15:57 1078 | 1079 | Contribution: 2019-02-26 15:54 1080 | 1081 | Contribution: 2019-02-26 15:55 1082 | 1083 | Contribution: 2019-02-26 15:56 1084 | 1085 | Contribution: 2019-02-26 15:57 1086 | 1087 | Contribution: 2019-02-26 15:58 1088 | 1089 | Contribution: 2019-02-26 15:59 1090 | 1091 | Contribution: 2019-02-26 16:00 1092 | 1093 | Contribution: 2019-02-27 15:54 1094 | 1095 | Contribution: 2019-02-28 15:54 1096 | 1097 | Contribution: 2019-02-28 15:55 1098 | 1099 | Contribution: 2019-02-28 15:56 1100 | 1101 | Contribution: 2019-02-28 15:57 1102 | 1103 | Contribution: 2019-02-28 15:58 1104 | 1105 | Contribution: 2019-03-04 15:54 1106 | 1107 | Contribution: 2019-03-04 15:55 1108 | 1109 | Contribution: 2019-03-04 15:56 1110 | 1111 | Contribution: 2019-03-04 15:57 1112 | 1113 | Contribution: 2019-03-04 15:58 1114 | 1115 | Contribution: 2019-03-05 15:54 1116 | 1117 | Contribution: 2019-03-05 15:55 1118 | 1119 | Contribution: 2019-03-05 15:56 1120 | 1121 | Contribution: 2019-03-05 15:57 1122 | 1123 | Contribution: 2019-03-06 15:54 1124 | 1125 | Contribution: 2019-03-06 15:55 1126 | 1127 | Contribution: 2019-03-06 15:56 1128 | 1129 | Contribution: 2019-03-06 15:57 1130 | 1131 | Contribution: 2019-03-07 15:54 1132 | 1133 | Contribution: 2019-03-07 15:55 1134 | 1135 | Contribution: 2019-03-07 15:56 1136 | 1137 | Contribution: 2019-03-07 15:57 1138 | 1139 | Contribution: 2019-03-07 15:58 1140 | 1141 | Contribution: 2019-03-08 15:54 1142 | 1143 | Contribution: 2019-03-08 15:55 1144 | 1145 | Contribution: 2019-03-08 15:56 1146 | 1147 | Contribution: 2019-03-08 15:57 1148 | 1149 | Contribution: 2019-03-08 15:58 1150 | 1151 | Contribution: 2019-03-08 15:59 1152 | 1153 | Contribution: 2019-03-08 16:00 1154 | 1155 | Contribution: 2019-03-11 15:54 1156 | 1157 | Contribution: 2019-03-12 15:54 1158 | 1159 | Contribution: 2019-03-12 15:55 1160 | 1161 | Contribution: 2019-03-12 15:56 1162 | 1163 | Contribution: 2019-03-12 15:57 1164 | 1165 | Contribution: 2019-03-12 15:58 1166 | 1167 | Contribution: 2019-03-12 15:59 1168 | 1169 | Contribution: 2019-03-12 16:00 1170 | 1171 | Contribution: 2019-03-13 15:54 1172 | 1173 | Contribution: 2019-03-13 15:55 1174 | 1175 | Contribution: 2019-03-13 15:56 1176 | 1177 | Contribution: 2019-03-13 15:57 1178 | 1179 | Contribution: 2019-03-13 15:58 1180 | 1181 | Contribution: 2019-03-13 15:59 1182 | 1183 | Contribution: 2019-03-13 16:00 1184 | 1185 | Contribution: 2019-03-14 15:54 1186 | 1187 | Contribution: 2019-03-14 15:55 1188 | 1189 | Contribution: 2019-03-14 15:56 1190 | 1191 | Contribution: 2019-03-15 15:54 1192 | 1193 | Contribution: 2019-03-15 15:55 1194 | 1195 | Contribution: 2019-03-19 15:54 1196 | 1197 | Contribution: 2019-03-19 15:55 1198 | 1199 | Contribution: 2019-03-19 15:56 1200 | 1201 | Contribution: 2019-03-19 15:57 1202 | 1203 | Contribution: 2019-03-19 15:58 1204 | 1205 | Contribution: 2019-03-19 15:59 1206 | 1207 | Contribution: 2019-03-21 15:54 1208 | 1209 | Contribution: 2019-03-21 15:55 1210 | 1211 | Contribution: 2019-03-21 15:56 1212 | 1213 | Contribution: 2019-03-21 15:57 1214 | 1215 | Contribution: 2019-03-21 15:58 1216 | 1217 | Contribution: 2019-03-21 15:59 1218 | 1219 | Contribution: 2019-03-22 15:54 1220 | 1221 | Contribution: 2019-03-25 15:54 1222 | 1223 | Contribution: 2019-03-26 15:54 1224 | 1225 | Contribution: 2019-03-26 15:55 1226 | 1227 | Contribution: 2019-03-26 15:56 1228 | 1229 | Contribution: 2019-03-27 15:54 1230 | 1231 | Contribution: 2019-03-27 15:55 1232 | 1233 | Contribution: 2019-03-27 15:56 1234 | 1235 | Contribution: 2019-03-27 15:57 1236 | 1237 | Contribution: 2019-03-27 15:58 1238 | 1239 | Contribution: 2019-03-27 15:59 1240 | 1241 | Contribution: 2019-03-28 15:54 1242 | 1243 | Contribution: 2019-03-28 15:55 1244 | 1245 | Contribution: 2019-03-29 15:54 1246 | 1247 | Contribution: 2019-03-29 15:55 1248 | 1249 | Contribution: 2019-04-01 15:54 1250 | 1251 | Contribution: 2019-04-01 15:55 1252 | 1253 | Contribution: 2019-04-01 15:56 1254 | 1255 | Contribution: 2019-04-01 15:57 1256 | 1257 | Contribution: 2019-04-01 15:58 1258 | 1259 | Contribution: 2019-04-01 15:59 1260 | 1261 | Contribution: 2019-04-02 15:54 1262 | 1263 | Contribution: 2019-04-02 15:55 1264 | 1265 | Contribution: 2019-04-02 15:56 1266 | 1267 | Contribution: 2019-04-02 15:57 1268 | 1269 | Contribution: 2019-04-04 15:54 1270 | 1271 | Contribution: 2019-04-04 15:55 1272 | 1273 | Contribution: 2019-04-04 15:56 1274 | 1275 | Contribution: 2019-04-04 15:57 1276 | 1277 | Contribution: 2019-04-04 15:58 1278 | 1279 | Contribution: 2019-04-04 15:59 1280 | 1281 | Contribution: 2019-04-04 16:00 1282 | 1283 | Contribution: 2019-04-05 15:54 1284 | 1285 | Contribution: 2019-04-05 15:55 1286 | 1287 | Contribution: 2019-04-09 15:54 1288 | 1289 | Contribution: 2019-04-09 15:55 1290 | 1291 | Contribution: 2019-04-09 15:56 1292 | 1293 | Contribution: 2019-04-09 15:57 1294 | 1295 | Contribution: 2019-04-09 15:58 1296 | 1297 | Contribution: 2019-04-09 15:59 1298 | 1299 | Contribution: 2019-04-11 15:54 1300 | 1301 | Contribution: 2019-04-11 15:55 1302 | 1303 | Contribution: 2019-04-12 15:54 1304 | 1305 | Contribution: 2019-04-12 15:55 1306 | 1307 | Contribution: 2019-04-12 15:56 1308 | 1309 | Contribution: 2019-04-12 15:57 1310 | 1311 | Contribution: 2019-04-12 15:58 1312 | 1313 | Contribution: 2019-04-12 15:59 1314 | 1315 | Contribution: 2019-04-15 15:54 1316 | 1317 | Contribution: 2019-04-15 15:55 1318 | 1319 | Contribution: 2019-04-15 15:56 1320 | 1321 | Contribution: 2019-04-15 15:57 1322 | 1323 | Contribution: 2019-04-15 15:58 1324 | 1325 | Contribution: 2019-04-16 15:54 1326 | 1327 | Contribution: 2019-04-16 15:55 1328 | 1329 | Contribution: 2019-04-16 15:56 1330 | 1331 | Contribution: 2019-04-16 15:57 1332 | 1333 | Contribution: 2019-04-16 15:58 1334 | 1335 | Contribution: 2019-04-16 15:59 1336 | 1337 | Contribution: 2019-04-16 16:00 1338 | 1339 | Contribution: 2019-04-23 15:54 1340 | 1341 | Contribution: 2019-04-23 15:55 1342 | 1343 | Contribution: 2019-04-23 15:56 1344 | 1345 | Contribution: 2019-04-23 15:57 1346 | 1347 | Contribution: 2019-04-23 15:58 1348 | 1349 | Contribution: 2019-04-23 15:59 1350 | 1351 | Contribution: 2019-04-25 15:54 1352 | 1353 | Contribution: 2019-04-25 15:55 1354 | 1355 | Contribution: 2019-04-25 15:56 1356 | 1357 | Contribution: 2019-04-25 15:57 1358 | 1359 | Contribution: 2019-04-29 15:54 1360 | 1361 | Contribution: 2019-04-29 15:55 1362 | 1363 | Contribution: 2019-05-01 15:54 1364 | 1365 | Contribution: 2019-05-01 15:55 1366 | 1367 | Contribution: 2019-05-01 15:56 1368 | 1369 | Contribution: 2019-05-01 15:57 1370 | 1371 | Contribution: 2019-05-02 15:54 1372 | 1373 | Contribution: 2019-05-02 15:55 1374 | 1375 | Contribution: 2019-05-02 15:56 1376 | 1377 | Contribution: 2019-05-02 15:57 1378 | 1379 | Contribution: 2019-05-02 15:58 1380 | 1381 | Contribution: 2019-05-02 15:59 1382 | 1383 | Contribution: 2019-05-03 15:54 1384 | 1385 | Contribution: 2019-05-03 15:55 1386 | 1387 | Contribution: 2019-05-03 15:56 1388 | 1389 | Contribution: 2019-05-06 15:54 1390 | 1391 | Contribution: 2019-05-06 15:55 1392 | 1393 | Contribution: 2019-05-07 15:54 1394 | 1395 | Contribution: 2019-05-07 15:55 1396 | 1397 | Contribution: 2019-05-07 15:56 1398 | 1399 | Contribution: 2019-05-07 15:57 1400 | 1401 | Contribution: 2019-05-07 15:58 1402 | 1403 | Contribution: 2019-05-07 15:59 1404 | 1405 | Contribution: 2019-05-07 16:00 1406 | 1407 | Contribution: 2019-05-09 15:54 1408 | 1409 | Contribution: 2019-05-09 15:55 1410 | 1411 | Contribution: 2019-05-09 15:56 1412 | 1413 | Contribution: 2019-05-09 15:57 1414 | 1415 | Contribution: 2019-05-10 15:54 1416 | 1417 | Contribution: 2019-05-10 15:55 1418 | 1419 | Contribution: 2019-05-10 15:56 1420 | 1421 | Contribution: 2019-05-10 15:57 1422 | 1423 | Contribution: 2019-05-13 15:54 1424 | 1425 | Contribution: 2019-05-13 15:55 1426 | 1427 | Contribution: 2019-05-13 15:56 1428 | 1429 | Contribution: 2019-05-14 15:54 1430 | 1431 | Contribution: 2019-05-14 15:55 1432 | 1433 | Contribution: 2019-05-15 15:54 1434 | 1435 | Contribution: 2019-05-15 15:55 1436 | 1437 | Contribution: 2019-05-15 15:56 1438 | 1439 | Contribution: 2019-05-15 15:57 1440 | 1441 | Contribution: 2019-05-15 15:58 1442 | 1443 | Contribution: 2019-05-15 15:59 1444 | 1445 | Contribution: 2019-05-16 15:54 1446 | 1447 | Contribution: 2019-05-16 15:55 1448 | 1449 | Contribution: 2019-05-16 15:56 1450 | 1451 | Contribution: 2019-05-16 15:57 1452 | 1453 | Contribution: 2019-05-21 15:54 1454 | 1455 | Contribution: 2019-05-21 15:55 1456 | 1457 | Contribution: 2019-05-21 15:56 1458 | 1459 | Contribution: 2019-05-21 15:57 1460 | 1461 | Contribution: 2019-05-21 15:58 1462 | 1463 | Contribution: 2019-05-21 15:59 1464 | 1465 | Contribution: 2019-05-21 16:00 1466 | 1467 | Contribution: 2019-05-22 15:54 1468 | 1469 | Contribution: 2019-05-22 15:55 1470 | 1471 | Contribution: 2019-05-22 15:56 1472 | 1473 | Contribution: 2019-05-23 15:54 1474 | 1475 | Contribution: 2019-05-23 15:55 1476 | 1477 | Contribution: 2019-05-23 15:56 1478 | 1479 | Contribution: 2019-05-23 15:57 1480 | 1481 | Contribution: 2019-05-23 15:58 1482 | 1483 | Contribution: 2019-05-24 15:54 1484 | 1485 | Contribution: 2019-05-27 15:54 1486 | 1487 | Contribution: 2019-05-27 15:55 1488 | 1489 | Contribution: 2019-05-27 15:56 1490 | 1491 | Contribution: 2019-05-27 15:57 1492 | 1493 | Contribution: 2019-05-28 15:54 1494 | 1495 | Contribution: 2019-05-28 15:55 1496 | 1497 | Contribution: 2019-05-28 15:56 1498 | 1499 | Contribution: 2019-05-29 15:54 1500 | 1501 | Contribution: 2019-05-29 15:55 1502 | 1503 | Contribution: 2019-05-29 15:56 1504 | 1505 | Contribution: 2019-05-29 15:57 1506 | 1507 | Contribution: 2019-05-29 15:58 1508 | 1509 | Contribution: 2019-05-30 15:54 1510 | 1511 | Contribution: 2019-05-30 15:55 1512 | 1513 | Contribution: 2019-06-03 15:54 1514 | 1515 | Contribution: 2019-06-03 15:55 1516 | 1517 | Contribution: 2019-06-03 15:56 1518 | 1519 | Contribution: 2019-06-03 15:57 1520 | 1521 | Contribution: 2019-06-03 15:58 1522 | 1523 | Contribution: 2019-06-04 15:54 1524 | 1525 | Contribution: 2019-06-04 15:55 1526 | 1527 | Contribution: 2019-06-04 15:56 1528 | 1529 | Contribution: 2019-06-04 15:57 1530 | 1531 | Contribution: 2019-06-04 15:58 1532 | 1533 | Contribution: 2019-06-05 15:54 1534 | 1535 | Contribution: 2019-06-06 15:54 1536 | 1537 | Contribution: 2019-06-07 15:54 1538 | 1539 | Contribution: 2019-06-07 15:55 1540 | 1541 | Contribution: 2019-06-07 15:56 1542 | 1543 | Contribution: 2019-06-07 15:57 1544 | 1545 | Contribution: 2019-06-07 15:58 1546 | 1547 | Contribution: 2019-06-12 15:54 1548 | 1549 | Contribution: 2019-06-12 15:55 1550 | 1551 | Contribution: 2019-06-12 15:56 1552 | 1553 | Contribution: 2019-06-12 15:57 1554 | 1555 | Contribution: 2019-06-12 15:58 1556 | 1557 | Contribution: 2019-06-13 15:54 1558 | 1559 | Contribution: 2019-06-13 15:55 1560 | 1561 | Contribution: 2019-06-14 15:54 1562 | 1563 | Contribution: 2019-06-14 15:55 1564 | 1565 | Contribution: 2019-06-14 15:56 1566 | 1567 | Contribution: 2019-06-14 15:57 1568 | 1569 | Contribution: 2019-06-20 15:54 1570 | 1571 | Contribution: 2019-06-20 15:55 1572 | 1573 | Contribution: 2019-06-20 15:56 1574 | 1575 | Contribution: 2019-06-20 15:57 1576 | 1577 | Contribution: 2019-06-21 15:54 1578 | 1579 | Contribution: 2019-06-21 15:55 1580 | 1581 | Contribution: 2019-06-24 15:54 1582 | 1583 | Contribution: 2019-06-24 15:55 1584 | 1585 | Contribution: 2019-06-25 15:54 1586 | 1587 | Contribution: 2019-06-25 15:55 1588 | 1589 | Contribution: 2019-06-25 15:56 1590 | 1591 | Contribution: 2019-06-25 15:57 1592 | 1593 | Contribution: 2019-06-25 15:58 1594 | 1595 | Contribution: 2019-06-26 15:54 1596 | 1597 | Contribution: 2019-06-26 15:55 1598 | 1599 | Contribution: 2019-06-27 15:54 1600 | 1601 | Contribution: 2019-06-27 15:55 1602 | 1603 | Contribution: 2019-06-27 15:56 1604 | 1605 | Contribution: 2019-06-27 15:57 1606 | 1607 | Contribution: 2019-06-27 15:58 1608 | 1609 | Contribution: 2019-06-28 15:54 1610 | 1611 | Contribution: 2019-06-28 15:55 1612 | 1613 | Contribution: 2019-06-28 15:56 1614 | 1615 | Contribution: 2019-06-28 15:57 1616 | 1617 | Contribution: 2019-06-28 15:58 1618 | 1619 | Contribution: 2019-07-01 15:54 1620 | 1621 | Contribution: 2019-07-01 15:55 1622 | 1623 | Contribution: 2019-07-01 15:56 1624 | 1625 | Contribution: 2019-07-01 15:57 1626 | 1627 | Contribution: 2019-07-02 15:54 1628 | 1629 | Contribution: 2019-07-02 15:55 1630 | 1631 | Contribution: 2019-07-02 15:56 1632 | 1633 | Contribution: 2019-07-02 15:57 1634 | 1635 | Contribution: 2019-07-02 15:58 1636 | 1637 | Contribution: 2019-07-02 15:59 1638 | 1639 | Contribution: 2019-07-04 15:54 1640 | 1641 | Contribution: 2019-07-04 15:55 1642 | 1643 | Contribution: 2019-07-05 15:54 1644 | 1645 | Contribution: 2019-07-05 15:55 1646 | 1647 | Contribution: 2019-07-05 15:56 1648 | 1649 | Contribution: 2019-07-05 15:57 1650 | 1651 | Contribution: 2019-07-05 15:58 1652 | 1653 | Contribution: 2019-07-08 15:54 1654 | 1655 | Contribution: 2019-07-08 15:55 1656 | 1657 | Contribution: 2019-07-08 15:56 1658 | 1659 | Contribution: 2019-07-08 15:57 1660 | 1661 | Contribution: 2019-07-09 15:54 1662 | 1663 | Contribution: 2019-07-09 15:55 1664 | 1665 | Contribution: 2019-07-09 15:56 1666 | 1667 | Contribution: 2019-07-09 15:57 1668 | 1669 | Contribution: 2019-07-09 15:58 1670 | 1671 | Contribution: 2019-07-10 15:54 1672 | 1673 | Contribution: 2019-07-10 15:55 1674 | 1675 | Contribution: 2019-07-10 15:56 1676 | 1677 | Contribution: 2019-07-10 15:57 1678 | 1679 | Contribution: 2019-07-15 15:54 1680 | 1681 | Contribution: 2019-07-16 15:54 1682 | 1683 | Contribution: 2019-07-16 15:55 1684 | 1685 | Contribution: 2019-07-16 15:56 1686 | 1687 | Contribution: 2019-07-18 15:54 1688 | 1689 | Contribution: 2019-07-18 15:55 1690 | 1691 | Contribution: 2019-07-18 15:56 1692 | 1693 | Contribution: 2019-07-18 15:57 1694 | 1695 | Contribution: 2019-07-19 15:54 1696 | 1697 | Contribution: 2019-07-19 15:55 1698 | 1699 | Contribution: 2019-07-22 15:54 1700 | 1701 | Contribution: 2019-07-23 15:54 1702 | 1703 | Contribution: 2019-07-23 15:55 1704 | 1705 | Contribution: 2019-07-23 15:56 1706 | 1707 | Contribution: 2019-07-23 15:57 1708 | 1709 | Contribution: 2019-07-23 15:58 1710 | 1711 | Contribution: 2019-07-23 15:59 1712 | 1713 | Contribution: 2019-07-23 16:00 1714 | 1715 | Contribution: 2019-07-25 15:54 1716 | 1717 | Contribution: 2019-07-25 15:55 1718 | 1719 | Contribution: 2019-07-25 15:56 1720 | 1721 | Contribution: 2019-07-25 15:57 1722 | 1723 | Contribution: 2019-07-25 15:58 1724 | 1725 | Contribution: 2019-07-25 15:59 1726 | 1727 | Contribution: 2019-07-30 15:54 1728 | 1729 | Contribution: 2019-07-30 15:55 1730 | 1731 | Contribution: 2019-07-30 15:56 1732 | 1733 | Contribution: 2019-07-30 15:57 1734 | 1735 | Contribution: 2019-07-30 15:58 1736 | 1737 | Contribution: 2019-07-30 15:59 1738 | 1739 | Contribution: 2019-07-30 16:00 1740 | 1741 | Contribution: 2019-07-31 15:54 1742 | 1743 | Contribution: 2019-07-31 15:55 1744 | 1745 | Contribution: 2019-07-31 15:56 1746 | 1747 | Contribution: 2019-07-31 15:57 1748 | 1749 | Contribution: 2019-07-31 15:58 1750 | 1751 | Contribution: 2019-07-31 15:59 1752 | 1753 | Contribution: 2019-07-31 16:00 1754 | 1755 | Contribution: 2019-08-01 15:54 1756 | 1757 | Contribution: 2019-08-01 15:55 1758 | 1759 | Contribution: 2019-08-01 15:56 1760 | 1761 | Contribution: 2019-08-02 15:54 1762 | 1763 | Contribution: 2019-08-02 15:55 1764 | 1765 | Contribution: 2019-08-02 15:56 1766 | 1767 | Contribution: 2019-08-02 15:57 1768 | 1769 | Contribution: 2019-08-02 15:58 1770 | 1771 | Contribution: 2019-08-02 15:59 1772 | 1773 | Contribution: 2019-08-02 16:00 1774 | 1775 | Contribution: 2019-08-05 15:54 1776 | 1777 | Contribution: 2019-08-05 15:55 1778 | 1779 | Contribution: 2019-08-05 15:56 1780 | 1781 | Contribution: 2019-08-05 15:57 1782 | 1783 | Contribution: 2019-08-06 15:54 1784 | 1785 | Contribution: 2019-08-06 15:55 1786 | 1787 | Contribution: 2019-08-06 15:56 1788 | 1789 | Contribution: 2019-08-06 15:57 1790 | 1791 | Contribution: 2019-08-06 15:58 1792 | 1793 | Contribution: 2019-08-06 15:59 1794 | 1795 | Contribution: 2019-08-06 16:00 1796 | 1797 | Contribution: 2019-08-07 15:54 1798 | 1799 | Contribution: 2019-08-07 15:55 1800 | 1801 | Contribution: 2019-08-07 15:56 1802 | 1803 | Contribution: 2019-08-07 15:57 1804 | 1805 | Contribution: 2019-08-07 15:58 1806 | 1807 | Contribution: 2019-08-07 15:59 1808 | 1809 | Contribution: 2019-08-08 15:54 1810 | 1811 | Contribution: 2019-08-08 15:55 1812 | 1813 | Contribution: 2019-08-08 15:56 1814 | 1815 | Contribution: 2019-08-08 15:57 1816 | 1817 | Contribution: 2019-08-08 15:58 1818 | 1819 | Contribution: 2019-08-08 15:59 1820 | 1821 | Contribution: 2019-08-08 16:00 1822 | 1823 | Contribution: 2019-08-09 15:54 1824 | 1825 | Contribution: 2019-08-09 15:55 1826 | 1827 | Contribution: 2019-08-09 15:56 1828 | 1829 | Contribution: 2019-08-09 15:57 1830 | 1831 | Contribution: 2019-08-12 15:54 1832 | 1833 | Contribution: 2019-08-12 15:55 1834 | 1835 | Contribution: 2019-08-12 15:56 1836 | 1837 | Contribution: 2019-08-12 15:57 1838 | 1839 | Contribution: 2019-08-15 15:54 1840 | 1841 | Contribution: 2019-08-15 15:55 1842 | 1843 | Contribution: 2019-08-15 15:56 1844 | 1845 | Contribution: 2019-08-15 15:57 1846 | 1847 | Contribution: 2019-08-20 15:54 1848 | 1849 | Contribution: 2019-08-20 15:55 1850 | 1851 | Contribution: 2019-08-20 15:56 1852 | 1853 | Contribution: 2019-08-20 15:57 1854 | 1855 | Contribution: 2019-08-20 15:58 1856 | 1857 | Contribution: 2019-08-21 15:54 1858 | 1859 | Contribution: 2019-08-21 15:55 1860 | 1861 | Contribution: 2019-08-21 15:56 1862 | 1863 | Contribution: 2019-08-21 15:57 1864 | 1865 | Contribution: 2019-08-21 15:58 1866 | 1867 | Contribution: 2019-08-22 15:54 1868 | 1869 | Contribution: 2019-08-22 15:55 1870 | 1871 | Contribution: 2019-08-23 15:54 1872 | 1873 | Contribution: 2019-08-23 15:55 1874 | 1875 | Contribution: 2019-08-23 15:56 1876 | 1877 | Contribution: 2019-08-23 15:57 1878 | 1879 | Contribution: 2019-08-23 15:58 1880 | 1881 | Contribution: 2019-08-23 15:59 1882 | 1883 | Contribution: 2019-08-26 15:54 1884 | 1885 | Contribution: 2019-08-26 15:55 1886 | 1887 | Contribution: 2019-08-26 15:56 1888 | 1889 | Contribution: 2019-08-26 15:57 1890 | 1891 | Contribution: 2019-08-27 15:54 1892 | 1893 | Contribution: 2019-08-27 15:55 1894 | 1895 | Contribution: 2019-08-28 15:54 1896 | 1897 | Contribution: 2019-08-28 15:55 1898 | 1899 | Contribution: 2019-08-28 15:56 1900 | 1901 | Contribution: 2019-08-30 15:54 1902 | 1903 | Contribution: 2019-08-30 15:55 1904 | 1905 | Contribution: 2019-08-30 15:56 1906 | 1907 | Contribution: 2019-08-30 15:57 1908 | 1909 | Contribution: 2019-09-02 15:54 1910 | 1911 | Contribution: 2019-09-02 15:55 1912 | 1913 | Contribution: 2019-09-02 15:56 1914 | 1915 | Contribution: 2019-09-02 15:57 1916 | 1917 | Contribution: 2019-09-02 15:58 1918 | 1919 | Contribution: 2019-09-02 15:59 1920 | 1921 | Contribution: 2019-09-05 15:54 1922 | 1923 | Contribution: 2019-09-05 15:55 1924 | 1925 | Contribution: 2019-09-05 15:56 1926 | 1927 | Contribution: 2019-09-05 15:57 1928 | 1929 | Contribution: 2019-09-05 15:58 1930 | 1931 | Contribution: 2019-09-05 15:59 1932 | 1933 | Contribution: 2019-09-06 15:54 1934 | 1935 | Contribution: 2019-09-06 15:55 1936 | 1937 | Contribution: 2019-09-06 15:56 1938 | 1939 | Contribution: 2019-09-06 15:57 1940 | 1941 | Contribution: 2019-09-06 15:58 1942 | 1943 | Contribution: 2019-09-06 15:59 1944 | 1945 | Contribution: 2019-09-06 16:00 1946 | 1947 | Contribution: 2019-09-09 15:54 1948 | 1949 | Contribution: 2019-09-09 15:55 1950 | 1951 | Contribution: 2019-09-09 15:56 1952 | 1953 | Contribution: 2019-09-09 15:57 1954 | 1955 | Contribution: 2019-09-09 15:58 1956 | 1957 | Contribution: 2019-09-09 15:59 1958 | 1959 | Contribution: 2019-09-10 15:54 1960 | 1961 | Contribution: 2019-09-10 15:55 1962 | 1963 | Contribution: 2019-09-10 15:56 1964 | 1965 | Contribution: 2019-09-10 15:57 1966 | 1967 | Contribution: 2019-09-10 15:58 1968 | 1969 | Contribution: 2019-09-11 15:54 1970 | 1971 | Contribution: 2019-09-11 15:55 1972 | 1973 | Contribution: 2019-09-11 15:56 1974 | 1975 | Contribution: 2019-09-11 15:57 1976 | 1977 | Contribution: 2019-09-13 15:54 1978 | 1979 | Contribution: 2019-09-16 15:54 1980 | 1981 | Contribution: 2019-09-16 15:55 1982 | 1983 | Contribution: 2019-09-16 15:56 1984 | 1985 | Contribution: 2019-09-16 15:57 1986 | 1987 | Contribution: 2019-09-17 15:54 1988 | 1989 | Contribution: 2019-09-18 15:54 1990 | 1991 | Contribution: 2019-09-18 15:55 1992 | 1993 | Contribution: 2019-09-18 15:56 1994 | 1995 | Contribution: 2019-09-18 15:57 1996 | 1997 | Contribution: 2019-09-18 15:58 1998 | 1999 | Contribution: 2019-09-18 15:59 2000 | 2001 | Contribution: 2019-09-19 15:54 2002 | 2003 | Contribution: 2019-09-19 15:55 2004 | 2005 | Contribution: 2019-09-19 15:56 2006 | 2007 | Contribution: 2019-09-19 15:57 2008 | 2009 | Contribution: 2019-09-19 15:58 2010 | 2011 | Contribution: 2019-09-19 15:59 2012 | 2013 | Contribution: 2019-09-19 16:00 2014 | 2015 | Contribution: 2019-09-23 15:54 2016 | 2017 | Contribution: 2019-09-24 15:54 2018 | 2019 | Contribution: 2019-09-24 15:55 2020 | 2021 | Contribution: 2019-09-24 15:56 2022 | 2023 | Contribution: 2019-09-24 15:57 2024 | 2025 | Contribution: 2019-09-24 15:58 2026 | 2027 | Contribution: 2019-09-24 15:59 2028 | 2029 | Contribution: 2019-09-24 16:00 2030 | 2031 | Contribution: 2019-09-25 15:54 2032 | 2033 | Contribution: 2019-09-25 15:55 2034 | 2035 | Contribution: 2019-09-25 15:56 2036 | 2037 | Contribution: 2019-09-25 15:57 2038 | 2039 | Contribution: 2019-09-26 15:54 2040 | 2041 | Contribution: 2019-09-26 15:55 2042 | 2043 | Contribution: 2019-09-26 15:56 2044 | 2045 | Contribution: 2019-09-26 15:57 2046 | 2047 | Contribution: 2019-09-26 15:58 2048 | 2049 | Contribution: 2019-09-27 15:54 2050 | 2051 | Contribution: 2019-09-27 15:55 2052 | 2053 | Contribution: 2019-09-27 15:56 2054 | 2055 | Contribution: 2019-09-27 15:57 2056 | 2057 | Contribution: 2019-10-01 15:54 2058 | 2059 | Contribution: 2019-10-01 15:55 2060 | 2061 | Contribution: 2019-10-01 15:56 2062 | 2063 | Contribution: 2019-10-01 15:57 2064 | 2065 | Contribution: 2019-10-01 15:58 2066 | 2067 | Contribution: 2019-10-02 15:54 2068 | 2069 | Contribution: 2019-10-02 15:55 2070 | 2071 | Contribution: 2019-10-02 15:56 2072 | 2073 | Contribution: 2019-10-03 15:54 2074 | 2075 | Contribution: 2019-10-03 15:55 2076 | 2077 | Contribution: 2019-10-03 15:56 2078 | 2079 | Contribution: 2019-10-03 15:57 2080 | 2081 | Contribution: 2019-10-03 15:58 2082 | 2083 | Contribution: 2019-10-03 15:59 2084 | 2085 | Contribution: 2019-10-04 15:54 2086 | 2087 | Contribution: 2019-10-04 15:55 2088 | 2089 | Contribution: 2019-10-04 15:56 2090 | 2091 | Contribution: 2019-10-04 15:57 2092 | 2093 | Contribution: 2019-10-04 15:58 2094 | 2095 | Contribution: 2019-10-04 15:59 2096 | 2097 | Contribution: 2019-10-04 16:00 2098 | 2099 | Contribution: 2019-10-07 15:54 2100 | 2101 | Contribution: 2019-10-07 15:55 2102 | 2103 | Contribution: 2019-10-09 15:54 2104 | 2105 | Contribution: 2019-10-09 15:55 2106 | 2107 | Contribution: 2019-10-09 15:56 2108 | 2109 | Contribution: 2019-10-09 15:57 2110 | 2111 | Contribution: 2019-10-09 15:58 2112 | 2113 | Contribution: 2019-10-10 15:54 2114 | 2115 | Contribution: 2019-10-10 15:55 2116 | 2117 | Contribution: 2019-10-10 15:56 2118 | 2119 | Contribution: 2019-10-11 15:54 2120 | 2121 | Contribution: 2019-10-11 15:55 2122 | 2123 | Contribution: 2019-10-11 15:56 2124 | 2125 | Contribution: 2019-10-11 15:57 2126 | 2127 | Contribution: 2019-10-14 15:54 2128 | 2129 | Contribution: 2019-10-14 15:55 2130 | 2131 | Contribution: 2019-10-14 15:56 2132 | 2133 | Contribution: 2019-10-14 15:57 2134 | 2135 | Contribution: 2019-10-14 15:58 2136 | 2137 | Contribution: 2019-10-14 15:59 2138 | 2139 | Contribution: 2019-10-14 16:00 2140 | 2141 | Contribution: 2019-10-15 15:54 2142 | 2143 | Contribution: 2019-10-15 15:55 2144 | 2145 | Contribution: 2019-10-15 15:56 2146 | 2147 | Contribution: 2019-10-15 15:57 2148 | 2149 | Contribution: 2019-10-16 15:54 2150 | 2151 | Contribution: 2019-10-16 15:55 2152 | 2153 | Contribution: 2019-10-16 15:56 2154 | 2155 | Contribution: 2019-10-16 15:57 2156 | 2157 | Contribution: 2019-10-16 15:58 2158 | 2159 | Contribution: 2019-10-17 15:54 2160 | 2161 | Contribution: 2019-10-17 15:55 2162 | 2163 | Contribution: 2019-10-17 15:56 2164 | 2165 | Contribution: 2019-10-17 15:57 2166 | 2167 | Contribution: 2019-10-17 15:58 2168 | 2169 | Contribution: 2019-10-21 15:54 2170 | 2171 | Contribution: 2019-10-21 15:55 2172 | 2173 | Contribution: 2019-10-22 15:54 2174 | 2175 | Contribution: 2019-10-22 15:55 2176 | 2177 | Contribution: 2019-10-22 15:56 2178 | 2179 | Contribution: 2019-10-22 15:57 2180 | 2181 | Contribution: 2019-10-22 15:58 2182 | 2183 | Contribution: 2019-10-22 15:59 2184 | 2185 | Contribution: 2019-10-24 15:54 2186 | 2187 | Contribution: 2019-10-24 15:55 2188 | 2189 | Contribution: 2019-10-24 15:56 2190 | 2191 | Contribution: 2019-10-25 15:54 2192 | 2193 | Contribution: 2019-10-28 15:54 2194 | 2195 | Contribution: 2019-10-28 15:55 2196 | 2197 | Contribution: 2019-10-28 15:56 2198 | 2199 | Contribution: 2019-10-28 15:57 2200 | 2201 | Contribution: 2019-10-29 15:54 2202 | 2203 | Contribution: 2019-10-29 15:55 2204 | 2205 | Contribution: 2019-10-29 15:56 2206 | 2207 | Contribution: 2019-10-29 15:57 2208 | 2209 | Contribution: 2019-10-29 15:58 2210 | 2211 | Contribution: 2019-10-29 15:59 2212 | 2213 | Contribution: 2019-10-29 16:00 2214 | 2215 | Contribution: 2019-10-31 15:54 2216 | 2217 | Contribution: 2019-10-31 15:55 2218 | 2219 | Contribution: 2019-10-31 15:56 2220 | 2221 | Contribution: 2019-11-01 15:54 2222 | 2223 | Contribution: 2019-11-01 15:55 2224 | 2225 | Contribution: 2019-11-01 15:56 2226 | 2227 | Contribution: 2019-11-01 15:57 2228 | 2229 | Contribution: 2019-11-01 15:58 2230 | 2231 | Contribution: 2019-11-01 15:59 2232 | 2233 | Contribution: 2019-11-04 15:54 2234 | 2235 | Contribution: 2019-11-04 15:55 2236 | 2237 | Contribution: 2019-11-04 15:56 2238 | 2239 | Contribution: 2019-11-04 15:57 2240 | 2241 | Contribution: 2019-11-05 15:54 2242 | 2243 | Contribution: 2019-11-05 15:55 2244 | 2245 | Contribution: 2019-11-05 15:56 2246 | 2247 | Contribution: 2019-11-06 15:54 2248 | 2249 | Contribution: 2019-11-06 15:55 2250 | 2251 | Contribution: 2019-11-06 15:56 2252 | 2253 | Contribution: 2019-11-06 15:57 2254 | 2255 | Contribution: 2019-11-06 15:58 2256 | 2257 | Contribution: 2019-11-06 15:59 2258 | 2259 | Contribution: 2019-11-06 16:00 2260 | 2261 | Contribution: 2019-11-11 15:54 2262 | 2263 | Contribution: 2019-11-11 15:55 2264 | 2265 | Contribution: 2019-11-11 15:56 2266 | 2267 | Contribution: 2019-11-11 15:57 2268 | 2269 | Contribution: 2019-11-11 15:58 2270 | 2271 | Contribution: 2019-11-11 15:59 2272 | 2273 | Contribution: 2019-11-11 16:00 2274 | 2275 | Contribution: 2019-11-12 15:54 2276 | 2277 | Contribution: 2019-11-12 15:55 2278 | 2279 | Contribution: 2019-11-12 15:56 2280 | 2281 | Contribution: 2019-11-12 15:57 2282 | 2283 | Contribution: 2019-11-12 15:58 2284 | 2285 | Contribution: 2019-11-12 15:59 2286 | 2287 | Contribution: 2019-11-12 16:00 2288 | 2289 | Contribution: 2019-11-14 15:54 2290 | 2291 | Contribution: 2019-11-14 15:55 2292 | 2293 | Contribution: 2019-11-14 15:56 2294 | 2295 | Contribution: 2019-11-14 15:57 2296 | 2297 | Contribution: 2019-11-18 15:54 2298 | 2299 | Contribution: 2019-11-18 15:55 2300 | 2301 | Contribution: 2019-11-18 15:56 2302 | 2303 | Contribution: 2019-11-18 15:57 2304 | 2305 | Contribution: 2019-11-18 15:58 2306 | 2307 | Contribution: 2019-11-21 15:54 2308 | 2309 | Contribution: 2019-11-21 15:55 2310 | 2311 | Contribution: 2019-11-21 15:56 2312 | 2313 | Contribution: 2019-11-22 15:54 2314 | 2315 | Contribution: 2019-11-22 15:55 2316 | 2317 | Contribution: 2019-11-22 15:56 2318 | 2319 | Contribution: 2019-11-22 15:57 2320 | 2321 | Contribution: 2019-11-25 15:54 2322 | 2323 | Contribution: 2019-11-25 15:55 2324 | 2325 | Contribution: 2019-11-26 15:54 2326 | 2327 | Contribution: 2019-11-26 15:55 2328 | 2329 | Contribution: 2019-11-27 15:54 2330 | 2331 | Contribution: 2019-11-27 15:55 2332 | 2333 | Contribution: 2019-11-27 15:56 2334 | 2335 | Contribution: 2019-11-29 15:54 2336 | 2337 | Contribution: 2019-12-02 15:54 2338 | 2339 | Contribution: 2019-12-03 15:54 2340 | 2341 | Contribution: 2019-12-03 15:55 2342 | 2343 | Contribution: 2019-12-03 15:56 2344 | 2345 | Contribution: 2019-12-03 15:57 2346 | 2347 | Contribution: 2019-12-04 15:54 2348 | 2349 | Contribution: 2019-12-04 15:55 2350 | 2351 | Contribution: 2019-12-04 15:56 2352 | 2353 | Contribution: 2019-12-05 15:54 2354 | 2355 | Contribution: 2019-12-05 15:55 2356 | 2357 | Contribution: 2019-12-05 15:56 2358 | 2359 | Contribution: 2019-12-06 15:54 2360 | 2361 | Contribution: 2019-12-06 15:55 2362 | 2363 | Contribution: 2019-12-10 15:54 2364 | 2365 | Contribution: 2019-12-10 15:55 2366 | 2367 | Contribution: 2019-12-10 15:56 2368 | 2369 | Contribution: 2019-12-10 15:57 2370 | 2371 | Contribution: 2019-12-10 15:58 2372 | 2373 | Contribution: 2019-12-10 15:59 2374 | 2375 | Contribution: 2019-12-10 16:00 2376 | 2377 | Contribution: 2019-12-11 15:54 2378 | 2379 | Contribution: 2019-12-11 15:55 2380 | 2381 | Contribution: 2019-12-11 15:56 2382 | 2383 | Contribution: 2019-12-11 15:57 2384 | 2385 | Contribution: 2019-12-11 15:58 2386 | 2387 | Contribution: 2019-12-11 15:59 2388 | 2389 | Contribution: 2019-12-12 15:54 2390 | 2391 | Contribution: 2019-12-13 15:54 2392 | 2393 | Contribution: 2019-12-17 15:54 2394 | 2395 | Contribution: 2019-12-17 15:55 2396 | 2397 | Contribution: 2019-12-18 15:54 2398 | 2399 | Contribution: 2019-12-19 15:54 2400 | 2401 | Contribution: 2019-12-19 15:55 2402 | 2403 | Contribution: 2019-12-19 15:56 2404 | 2405 | Contribution: 2019-12-19 15:57 2406 | 2407 | Contribution: 2019-12-19 15:58 2408 | 2409 | Contribution: 2019-12-19 15:59 2410 | 2411 | Contribution: 2019-12-20 15:54 2412 | 2413 | Contribution: 2019-12-20 15:55 2414 | 2415 | Contribution: 2019-12-20 15:56 2416 | 2417 | Contribution: 2019-12-20 15:57 2418 | 2419 | Contribution: 2019-12-20 15:58 2420 | 2421 | Contribution: 2019-12-23 15:54 2422 | 2423 | Contribution: 2019-12-23 15:55 2424 | 2425 | Contribution: 2019-12-23 15:56 2426 | 2427 | Contribution: 2019-12-24 15:54 2428 | 2429 | Contribution: 2019-12-24 15:55 2430 | 2431 | Contribution: 2019-12-24 15:56 2432 | 2433 | Contribution: 2019-12-24 15:57 2434 | 2435 | Contribution: 2019-12-24 15:58 2436 | 2437 | Contribution: 2019-12-24 15:59 2438 | 2439 | Contribution: 2019-12-24 16:00 2440 | 2441 | Contribution: 2019-12-25 15:54 2442 | 2443 | Contribution: 2019-12-26 15:54 2444 | 2445 | Contribution: 2019-12-26 15:55 2446 | 2447 | Contribution: 2019-12-26 15:56 2448 | 2449 | Contribution: 2019-12-26 15:57 2450 | 2451 | Contribution: 2019-12-27 15:54 2452 | 2453 | Contribution: 2019-12-27 15:55 2454 | 2455 | Contribution: 2019-12-27 15:56 2456 | 2457 | Contribution: 2019-12-30 15:54 2458 | 2459 | Contribution: 2019-12-30 15:55 2460 | 2461 | --------------------------------------------------------------------------------