Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verification added #27

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
625 changes: 363 additions & 262 deletions client/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"dependencies": {
"axios": "^0.27.2",
"ethereum-cryptography": "^2.1.2",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
Expand Down
38 changes: 35 additions & 3 deletions client/src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ label {
display: flex;
flex-direction: column;
letter-spacing: 0.05rem;
font-size: .8em;
font-size: .9em;
font-weight: 400;
color: #222;
}
Expand Down Expand Up @@ -54,14 +54,27 @@ input {
border-radius: 0.125rem;
padding: 10px 20px;
color: white;
display: inline-flex;
display: inline-block;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: 400;
font-size: .9em;

&:hover {
cursor: pointer;
}

&:disabled {
background-color: #a73030;
border-radius: 0.125rem;
padding: 10px 20px;
color: white;
display: inline-block;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: 400;
font-size: .9em;
}
}

.wallet {
Expand All @@ -83,4 +96,23 @@ input {
.transfer {
display: flex;
flex-direction: column;
}

.transaction {
text-transform: uppercase;
letter-spacing: 1px;
font-weight: 400;
font-size: .9em;
display: inline-flex;
margin-top: 10px;
padding: 0.75rem;
background-color: #f4f6f8;

.low {
text-transform: lowercase;
}

.up {
text-transform: uppercase;
}
}
}
74 changes: 73 additions & 1 deletion client/src/Transfer.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import { getRandomBytesSync } from "ethereum-cryptography/random.js";
import { keccak256 } from "ethereum-cryptography/keccak.js";
import { utf8ToBytes, toHex } from "ethereum-cryptography/utils.js"
import { secp256k1 } from "ethereum-cryptography/secp256k1";
import { useState } from "react";
import server from "./server";

function Transfer({ address, setBalance }) {
const [signature, setSignature] = useState("");
const [sendAmount, setSendAmount] = useState("");
const [recipient, setRecipient] = useState("");
const [isValid, setValid] = useState("");
const [txMessage, setTxMessage] = useState("");
const [txHash, setTxHash] = useState("");

const transferButton = document.getElementById("transferButton");

const setValue = (setter) => (evt) => setter(evt.target.value);

Expand All @@ -17,17 +27,58 @@ function Transfer({ address, setBalance }) {
sender: address,
amount: parseInt(sendAmount),
recipient,
signature,
txHash,
});
setBalance(balance);
} catch (ex) {
alert(ex.response.data.message);
}
}

function CreateTransaction(evt) {
evt.preventDefault();
transferButton.disabled = true;

const salt = toHex(getRandomBytesSync(32));
const txMessage = recipient + ':' + sendAmount + ':' + salt;
const txHash = toHex(keccak256(utf8ToBytes(txMessage)));
setTxMessage(txMessage);
setTxHash(txHash);
}

function verification(evt) {
const signature = evt.target.value;
setSignature(signature);

if (signature) {
try {
const sig = secp256k1.Signature.fromCompact(signature);
for (let i = 0; i < 4; i++) {
let publicKey = sig.addRecoveryBit(i).recoverPublicKey(txHash).toRawBytes();
let publicKeyHash = keccak256(publicKey.slice(1));
let recoveredAddress = toHex(publicKeyHash.slice(publicKeyHash.length - 20));
if (recoveredAddress === address) {
setValid('Approved');
transferButton.disabled = false;
break;
}
}
} catch {
setValid('Signature is not valid');
transferButton.disabled = true;
}
} else {
setValid("Undefined");
transferButton.disabled = true;
}
}

return (
<form className="container transfer" onSubmit={transfer}>
<h1>Send Transaction</h1>


<label>
Send Amount
<input
Expand All @@ -46,7 +97,28 @@ function Transfer({ address, setBalance }) {
></input>
</label>

<input type="submit" className="button" value="Transfer" />
<input type="button" className="button" value="Create Transaction" onClick={CreateTransaction} />
<div className="transaction">
<div className="up">Transaction: </div>
<div className="low">{txMessage}</div>
</div>
<div className="transaction">
<div className="up">Transaction hash: </div>
<div className="low">{txHash}</div>
</div>

<label>
Verify
<input
placeholder="hex signature"
value={signature}
onChange={verification}
></input>
</label>

<div className="Verification">Verification status: {isValid}</div>

<input type="submit" disabled id="transferButton" className="button" value="Transfer" />
</form>
);
}
Expand Down
2 changes: 1 addition & 1 deletion client/src/Wallet.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function Wallet({ address, setAddress, balance, setBalance }) {

<label>
Wallet Address
<input placeholder="Type an address, for example: 0x1" value={address} onChange={onChange}></input>
<input placeholder="Type an address, for example: 8990e147072b8227e0d028630ff4fbf256cae484" value={address} onChange={onChange}></input>
</label>

<div className="balance">Balance: {balance}</div>
Expand Down
44 changes: 39 additions & 5 deletions server/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
const { keccak256 } = require("ethereum-cryptography/keccak");
const { toHex } = require("ethereum-cryptography/utils");
const { secp256k1 } = require("ethereum-cryptography/secp256k1");
const express = require("express");
const app = express();
const cors = require("cors");
Expand All @@ -7,9 +10,11 @@ app.use(cors());
app.use(express.json());

const balances = {
"0x1": 100,
"0x2": 50,
"0x3": 75,
"2c66c985fa79c326a669e1d282737a0ada49cab9": 100,
"87a4bc900a35dfc47df11719045c26dc34fc2df4": 50,
"c0cbb5992f0825f389084400f59f3686bc713822": 75,
"7dd8df87cca8a988fffd302e7c8486e90f4e6695": 1000,
"3777d9a62dbde165d771448a8d9bed685511ec3f": 1000,
};

app.get("/balance/:address", (req, res) => {
Expand All @@ -18,13 +23,25 @@ app.get("/balance/:address", (req, res) => {
res.send({ balance });
});

app.post("/verify", (req, res) => {
const { signature, address } = req.body;

if (verifySignature(signature, address)) {
res.send({ isValid: 'Success!' });
} else {
res.send({ isValid: 'Signature is not valid!' });
}
});

app.post("/send", (req, res) => {
const { sender, recipient, amount } = req.body;
const { sender, recipient, amount, txHash, signature } = req.body;

setInitialBalance(sender);
setInitialBalance(recipient);

if (balances[sender] < amount) {
if (!verifySignature(signature, sender, txHash)) {
res.status(400).send({ message: "Signature is not valid!" });
} else if (balances[sender] < amount) {
res.status(400).send({ message: "Not enough funds!" });
} else {
balances[sender] -= amount;
Expand All @@ -42,3 +59,20 @@ function setInitialBalance(address) {
balances[address] = 0;
}
}

function verifySignature(signature, address, messageHash) {
try {
const sig = secp256k1.Signature.fromCompact(signature);
for (let i = 0; i < 4; i++) {
let publicKey = sig.addRecoveryBit(i).recoverPublicKey(messageHash).toRawBytes();
let publicKeyHash = keccak256(publicKey.slice(1));
let recoveredAddress = toHex(publicKeyHash.slice(publicKeyHash.length - 20));
if (recoveredAddress === address) {
return true;
}
}
return false;
} catch {
return false;
}
}
Loading