ui updated

This commit is contained in:
“ciscodacunha” 2020-10-20 20:56:31 +02:00
parent 19c7d04a5c
commit 67f936889b
13 changed files with 1247 additions and 147 deletions

View File

@ -6,4 +6,6 @@ DB_NAME="test"
DB_USER="admin"
DB_PASSWORD="password"
DB_HOST="localhost"
DB_PORT="31956"
DB_PORT="31956"
TOKEN_AMOUNT=10
COOLING_PERIOD_IN_HOURS=24

837
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,18 +5,23 @@
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node src/server.js"
"start": "node src/server.js",
"dev": "nodemon src/server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"dotenv": "^8.2.0",
"ejs": "^3.1.5",
"express": "^4.17.1",
"mongodb": "^3.6.2",
"truffle-hdwallet-provider": "^1.0.17",
"url": "^0.11.0",
"uuid": "^8.3.1",
"web3": "^1.2.11"
},
"devDependencies": {
"nodemon": "^2.0.6"
}
}

View File

@ -1,49 +1,51 @@
const MongoClient = require('mongodb').MongoClient;
require('dotenv').config()
var client = null
const MongoClient = require("mongodb").MongoClient;
require("dotenv").config();
var client = null;
// Connection URL
let password = encodeURIComponent(process.env.DB_PASSWORD)
const url = `mongodb://${process.env.DB_USER}:${password}@${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`
console.log("URL - ", url)
let password = encodeURIComponent(process.env.DB_PASSWORD);
const url = `mongodb://${process.env.DB_USER}:${password}@${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}`;
console.log("URL - ", url);
// Use connect method to connect to the server
async function connection() {
try {
client = await MongoClient.connect(url, { useUnifiedTopology: true })
console.log("Connected successfully to server");
return client
} catch (err) {
console.error(err)
}
try {
client = await MongoClient.connect(url, { useUnifiedTopology: true });
console.log("Connected successfully to server");
return client;
} catch (err) {
console.error(err);
}
}
async function insert(records, callback) {
// Get the documents collection
console.log("client - ", client)
let db = client.db(process.env.DB_NAME)
const collection = db.collection('records');
// Insert some documents
try {
await collection.insertOne(records, function (err, result) {
console.log("Inserted into database");
callback(result);
});
} catch (err) {
console.error(err)
}
// Get the documents collection
console.log("client - ", client);
let db = client.db(process.env.DB_NAME);
const collection = db.collection("records");
// Insert some documents
try {
await collection.save(records, function(err, result) {
console.log("Inserted into database");
callback(result);
});
} catch (err) {
console.error(err);
}
}
async function find(query, callback) {
// Get the documents collection
let db = client.db(process.env.DB_NAME)
const collection = db.collection('records');
collection.find(query).toArray(function (err, docs) {
assert.equal(err, null);
console.log("Found the following records");
console.log(docs);
callback(docs);
// Get the documents collection
let db = client.db(process.env.DB_NAME);
const collection = db.collection("records");
collection
.find(query)
.sort({ lastUpdatedOn: -1 })
.toArray(function(err, docs) {
console.log("Found the following records");
console.log(docs);
callback(docs);
});
}
module.exports = { connection, insert }
module.exports = { connection, insert, find };

7
src/public/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

133
src/public/css/index.css Normal file
View File

@ -0,0 +1,133 @@
.page {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
min-height: 100vh;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
#waves {
z-index: 1;
overflow: hidden;
transform: translateZ(0);
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
/* transform: scale(1.2) rotate(-8deg); */
}
@media (max-width: 768px) {
#waves {
top: -100px;
}
}
.section {
position: relative;
padding: 50px 0;
z-index: 2;
background: transparent;
}
.section-sm {
padding: 50px 0;
}
.container {
max-width: 1170px;
}
.container-sm {
max-width: 780px;
}
.center {
max-width: 554px;
margin: 0 auto 50px;
text-align: center;
}
.center-lg {
max-width: 750px;
}
.title {
margin-bottom: 28px;
font-size: 50px;
letter-spacing: -0.31px;
line-height: 1;
}
.title-2 {
margin-bottom: 30px;
font-size: 47px;
}
.subscribe .form-group {
margin: 0 10px 0 0;
-webkit-box-flex: 1;
-ms-flex: 1 0 auto;
flex: 1 0 auto;
}
.subscribe .btn {
width: 100%;
}
.subscribe-form {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.form {
width: 100%;
margin: 50% 50%;
}
.form-group {
margin-bottom: 30px;
}
.form-control {
height: 48px;
padding: 12px 15px;
font-family: "Segoe UI", sans-serif;
font-size: 18px;
font-display: swap;
}
.form-control::-webkit-input-placeholder {
color: rgba(43, 41, 45, 0.6);
}
.form-control::-ms-input-placeholder {
color: rgba(43, 41, 45, 0.6);
}
.form-control::placeholder {
color: rgba(43, 41, 45, 0.6);
}
.form-control:focus {
border-color: #0247e2;
-webkit-box-shadow: 0 0 0 0.2rem rgba(48, 65, 196, 0.25);
box-shadow: 0 0 0 0.2rem rgba(48, 65, 196, 0.25);
}
.notify {
margin-top: 5%;
}
.success {
color: "green";
}
.error {
color: "red";
}

View File

@ -0,0 +1 @@
<svg fill="none" height="352" viewBox="0 0 2050 352" width="2050" xmlns="http://www.w3.org/2000/svg"><g stroke-width="2"><path d="m2049 8.59412c-22.5-6.49994-88-14.49994-182.5 2.99998-134.5 50-164 64.5-257 67.9999-102.5 14.5001-195-25.4999-302-14.5-174.74 47.081-196 150.371-313.5 147s-206-103.465-331-92.5c-85.5 7.5-196 206.5-293.5 206.5-77.274 0-118-26-170-52l-198.5-107.5" stroke="#e2e2e2"/><path d="m1950 2.59412c-19-.00015-77.5 3-113 12.99988-102 42.0001-191 60.9998-283.5 74.9999-77.81 11.7761-233.5-38.8779-302-14.5-170.5 60.6781-196 150.3711-313.5 147.0001s-206-103.465-331-92.5c-85.5 7.5-196 206.5-293.5 206.5-77.274 0-118-26-170-52l-129-77" stroke="#8b98a9"/><path d="m1970 1.09412c-55.5 4.5-88.56 0-177 26.49998-138.5 41.5-206 62.5891-297.5 68.9999-78.5 5.5-233.5-38.8779-302-14.5-170.5 60.678-196 150.371-313.5 147s-206-103.465-331-92.5c-85.5 7.5-196 206.5-293.5 206.5-77.274 0-118-26-170-52l-70-36" stroke="#e000cf"/><path d="m14.5 297.094c52 26 96.226 53.5 173.5 53.5 97.5 0 208-199 293.5-206.5 125-10.965 213.5 89.129 331 92.5s143-86.322 313.5-147c68.5-24.3779 223.5 20 302 14.5 91.5-6.4108 159-27.4999 297.5-68.9999 88.44-26.49998 168-28.49998 223.5-32.99998" stroke="#ff4092"/></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

75
src/public/index.ejs Normal file
View File

@ -0,0 +1,75 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Ocean Rinkeby Test Faucet</title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Test Faucet for OCEAN ">
<meta name="theme-color" content="#1965bf">
<meta name="msapplication-TileColor" content="#1965bf">
<link rel="search" href="open-search.xml" title="Search OCEAN test faucet" type="application/opensearchdescription+xml" />
<link rel="shortcut icon" media="(prefers-color-scheme:light)" href="images/favicon-black.png" type="image/png" />
<link rel="shortcut icon" media="(prefers-color-scheme:dark)" href="images/favicon-white.png" type="image/png" />
<link rel="apple-touch-icon" sizes="180x180" href="images/favicon-white.png">
<link rel="mask-icon" href="images/favicon-white.png" color="#1965bf">
<link rel="preload" href="css/bootstrap.min.css" as="style">
<link rel="preload" href="css/index.css" as="style">
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<div class="page">
<div class="inner" style="overflow: none;"">
<svg id="waves" width="100%" height="500"></svg>
<div class="section">
<div class="container">
<div class="center">
<h4 class="title title-2">Ocean Rinkeby Test Faucet</h4>
</div>
<div class="row align-items-center">
<div class="col-md-6 col-xl-6">
<div class="subscribe">
<form class="form" action="/send">
<div class="form-group">
<label for="address" class="form-label">Enter your wallet address</label>
<input class="form-control" type="text" placeholder="0x12345.....abcde" required="" id="address" name="address"/>
<br/>
</div>
<div class="col-md-12 col-xl-12 text-center">
<button type="submit" class="btn btn-primary skip-dark" id="createBtn">Get 10 OCEAN</button>
</div>
<% if(message && success) { %>
<div class="notify text-center">
<h5 class="success"><%= message %></h5>
<a><%= link %></a>
</div>
<% } else { %>
<div class="notify text-center">
<h5 class="error"><%= message %></h5>
</div>
<% } %>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="js/lib/bootstrap.min.js"></script>
<script src="js/lib/d3.v6.min.js"></script>
<script src="js/index.js"></script>
</body>
</html>

47
src/public/js/index.js Normal file
View File

@ -0,0 +1,47 @@
window.addEventListener("load", async () => {
setupWaves();
function setupWaves() {
const svg = d3.select("#waves"),
width = window.innerWidth,
height = +svg.attr("height"),
x = d3.scaleLinear().range([0, width]);
angles = d3.range(0, 4 * Math.PI, Math.PI / 20);
const path = svg
.append("g")
.attr("transform", `translate(${-width / 24}, ${height / 1.8})`)
.attr("fill", "none")
.attr("stroke-width", 2)
.selectAll("path")
.data(["#5E60CE", "#48BFE3", "#56CFE1", "#72EFDD"])
.enter()
.append("path")
.attr("stroke", d => {
return d;
})
.style("mix-blend-mode", "darken")
.datum((d, i) => {
return d3
.line()
.curve(d3.curveBasisOpen)
.x(angles => {
return x(angles / 4);
})
.y(angles => {
const t = d3.now() / 3000;
return (
Math.cos(angles * 8 - (i * 2 * Math.PI) / 10 + t) *
Math.pow((2 + Math.cos(angles - t)) / 2, 4) *
15
);
});
});
d3.timer(() => {
path.attr("d", d => {
return d(angles);
});
});
}
});

7
src/public/js/lib/bootstrap.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
src/public/js/lib/d3.v6.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,123 +1,97 @@
const express = require('express')
const bodyParser = require('body-parser')
const url = require('url')
const HDWalletProvider = require('truffle-hdwallet-provider')
const Web3 = require('web3')
const abi = require('./abi/token')
const { connection, insert, find } = require('./db')
var client = null
require('dotenv').config()
const express = require("express");
const bodyParser = require("body-parser");
const url = require("url");
const HDWalletProvider = require("truffle-hdwallet-provider");
const Web3 = require("web3");
const path = require("path");
const abi = require("./abi/token");
const { connection, insert, find } = require("./db");
const { isAllowed } = require("./util");
var client = null;
require("dotenv").config();
const infura_apikey = process.env.INFURA_NODE_ID
const infura_apikey = process.env.INFURA_NODE_ID;
const provider = new HDWalletProvider(
process.env.SEED_PHRASE,
'https://rinkeby.infura.io/v3/' + infura_apikey
)
const web3 = new Web3(provider)
"https://rinkeby.infura.io/v3/" + infura_apikey
);
const web3 = new Web3(provider);
const app = express()
app.use(bodyParser.urlencoded({ extended: false }))
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
const template = (err, message, transactionHash) => `
<html>
<head>
<title>Rinkeby OCEAN Faucet</title>
</head>
<body>
<h1>Rinkeby test OCEAN Faucet</h1>
<h4>Give me your address and I'll give you .001 ether!</h4>
<form action="/send">
<label>My Address:</label>
<input name="address" />
<button>Submit</button>
<span style="display: none" class="loader loader--style1" title="0">
<svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="40px" height="40px" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve">
<path opacity="0.2" fill="#000" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946
s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634
c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z"/>
<path fill="#000" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0
C22.32,8.481,24.301,9.057,26.013,10.047z">
<animateTransform attributeType="xml"
attributeName="transform"
type="rotate"
from="0 20 20"
to="360 20 20"
dur="0.5s"
repeatCount="indefinite"/>
</path>
</svg>
</span>
</form>
<h3 style="color: red">${err || ''}</h3>
<h3>${message || ''}</h3>
<p>
${transactionHash
? `If you're curious, here is your transaction id: ${transactionHash}`
: ''}
</p>
</body>
<script>
var button = document.querySelector('button')
button.addEventListener('click', function() {
button.style.display = 'none'
document.querySelector('.loader').style.display = 'inline'
})
</script>
</html>
`
app.get('/', (req, res) => {
res.send(template())
})
app.get('/send', async (req, res) => {
app.get("/", (req, res) => {
//res.send(template());
res.render("index.ejs", { message: null, success: false });
});
app.get("/send", async (req, res) => {
try {
let ipAddress =
req.headers["x-forwarded-for"] || req.connection.remoteAddress;
console.log(`ip address - `, ipAddress);
const url_parts = url.parse(req.url, true);
const query = url_parts.query;
let ipAddress = req.headers['x-forwarded-for'] || req.connection.remoteAddress
console.log(`ip address - `, ipAddress)
const url_parts = url.parse(req.url, true)
const query = url_parts.query
const from = process.env.FROM
const to = query.address
const value = web3.utils.toWei(process.env.TOKEN_AMOUNT, 'ether')
const from = process.env.FROM;
const to = query.address;
const value = web3.utils.toWei(process.env.TOKEN_AMOUNT, "ether");
//check if this user is in cool down period
await find({ $or: [{ "ip": ipAddress }, { "wallet": query.address }] }, shouldTransfer => {
if (shouldTransfer) {
res.send(
template('', "You have to wait 24 hours between faucet requests", undefined)
)
await find(
{
$or: [{ wallet: query.address }]
},
async records => {
console.log(records[0]);
if (records[0] && !isAllowed(records[0].lastUpdatedOn)) {
res.render("index.ejs", {
message: "You have to wait 24 hours between faucet requests",
success: false
});
} else {
//insert ip address into db
await insert(
{ ip: ipAddress, wallet: to, lastUpdatedOn: Date.now() },
result => console.log(result)
);
//create token instance from abi and contract address
const tokenInstance = new web3.eth.Contract(
abi,
process.env.TOKEN_CONTRACT_ADDRESS
);
tokenInstance.methods
.transfer(to, value)
.send({ from }, function(error, txHash) {
if (!error) {
console.log("txHash - ", txHash);
res.render("index.ejs", {
message: `Great!! test OCEANs are on the way - ${txHash}`,
link: `https://rinkeby.etherscan.io/tx/${txHash}`,
success: true
});
} else {
console.error(err);
}
});
}
}
})
//insert ip address into db
await insert({ ip: ipAddress, wallet: to, lastUpdatedOn: Date.now() }, (result) => console.log(result))
//create token instance from abi and contract address
const tokenInstance = new web3.eth.Contract(abi, process.env.TOKEN_CONTRACT_ADDRESS)
tokenInstance.methods.transfer(to, value).send({ from }, function (error, txHash) {
if (!error) {
console.log(txHash)
res.send(
template('', 'Great, test OCEANs are on the way!', txHash)
)
} else {
console.error(err)
}
})
);
} catch (err) {
console.error(err)
console.error(err);
}
})
});
const port = process.env.PORT || 4000;
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "/public"));
app.use(express.static(__dirname + "/public"));
const port = process.env.PORT || 4000
app.listen(port, async () => {
client = await connection()
console.log('Listening on port - ', port)
})
client = await connection();
console.log("Listening on port - ", port);
});

14
src/util.js Normal file
View File

@ -0,0 +1,14 @@
const isAllowed = lastUpdatedOn => {
let currentTime = Date.now();
let threshold = parseInt(process.env.COOLING_PERIOD_IN_HOURS) * 3600000;
console.log("currentTime - ", currentTime);
console.log("Threshold - ", threshold);
console.log("Last Updated - ", lastUpdatedOn);
console.log("Total - ", lastUpdatedOn + threshold);
if (lastUpdatedOn + threshold <= currentTime) {
return true;
}
return false;
};
module.exports = { isAllowed };