add in faunadb and netlify

This commit is contained in:
samepant
2021-03-07 19:58:41 -05:00
parent 46d09219af
commit 06e25887e8
16 changed files with 5783 additions and 345 deletions
+3
View File
@@ -17,3 +17,6 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Local Netlify folder
.netlify
+22 -6
View File
@@ -58,12 +58,28 @@ class MultiSigForm extends React.Component {
handleCreate = async () => {
this.setState({ processing: true });
const res = await axios.post("/api/multiaddress", {
members: this.state.pubkeys,
threshold: this.state.threshold,
const res = await axios.post("/.netlify/functions/create-multisig", {
threshold: 3,
sourceAddresses: [
{
nickname: "samtest",
address: "cosmossam1",
pubkey: "sampubkey",
},
{
nickname: "samtest2",
address: "cosmossam2",
pubkey: "sampubkey",
},
{
nickname: "samtest3",
address: "cosmossam3",
pubkey: "sampubkey",
},
],
});
this.props.router.push(`/multi/${res.data}`);
console.log(res);
// this.props.router.push(`/multi/${res.data}`);
};
render() {
@@ -78,7 +94,7 @@ class MultiSigForm extends React.Component {
</p>
</StackableContainer>
{this.state.pubkeys.map((pubkeyGroup, index) => (
<StackableContainer lessPadding lessMargin>
<StackableContainer lessPadding lessMargin key={index}>
<div className="key-row">
{this.state.pubkeys.length > 2 && (
<button
+37
View File
@@ -0,0 +1,37 @@
type Multisig {
threshold: Int!
sourceAddresses: [SourceAddress]! @relation
address: String
nickname: String
}
type SourceAddress {
nickname: String
address: String!
pubkey: String!
multisig: Multisig @relation
}
type Transaction {
multisigId: Multisig!
signatures: [Signature] @relation
toAddress: String!
fromAddress: String!
amount: Float!
threshold: Int!
txHash: String
broadcastDate: String
gas: Int!
fee: Float
JSON: String
}
type Signature {
transaction: Transaction! @relation
JSON: String!
sourceAddress: SourceAddress @relation
}
type Query {
getMultisig(address: String!): Multisig
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+37
View File
@@ -0,0 +1,37 @@
/* code from functions/todos-create.js */
import faunadb from "faunadb"; /* Import faunaDB sdk */
/* configure faunaDB Client with our secret */
const q = faunadb.query;
const client = new faunadb.Client({
secret: process.env.FAUNADB_SECRET,
});
/* export our lambda function as named "handler" export */
exports.handler = (event, context, callback) => {
/* parse the string body into a useable JS object */
const data = JSON.parse(event.body);
console.log("Function `createMultisig` invoked", data);
const multisig = {
data: data,
};
/* construct the fauna query */
return client
.query(q.Create(q.Collection("Multisig"), multisig))
.then((response) => {
console.log("success", response);
/* Success! return the response with statusCode 200 */
return callback(null, {
statusCode: 200,
body: JSON.stringify(response),
});
})
.catch((error) => {
console.log("error", error);
/* Error! return the error with statusCode 400 */
return callback(null, {
statusCode: 400,
body: JSON.stringify(error),
});
});
};
+21
View File
@@ -0,0 +1,21 @@
# example netlify.toml
[build]
command = "next build"
functions = "lambda-build"
publish = ".next"
## Uncomment to use this redirect for Single Page Applications like create-react-app.
## Not needed for static site generators.
#[[redirects]]
# from = "/*"
# to = "/index.html"
# status = 200
## (optional) Settings for Netlify Dev
## https://github.com/netlify/cli/blob/master/docs/netlify-dev.md#project-detection
#[dev]
# command = "yarn start" # Command to start your dev server
# port = 3000 # Port that the dev server will be listening on
# publish = "dist" # Folder with the static content for _redirect file
## more info on configuring this file: https://www.netlify.com/docs/netlify-toml-reference/
+5578 -19
View File
File diff suppressed because it is too large Load Diff
+22 -2
View File
@@ -2,16 +2,36 @@
"name": "create-next-example-app",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
"build": "npm-run-all --parallel build:**",
"build:app": "next build",
"build:functions": "netlify-lambda build functions",
"start": "npm-run-all --parallel start:app start:server",
"start:app": "PORT=3000 node server.js",
"start:server": "netlify-lambda serve lambda"
},
"dependencies": {
"@cosmjs/proto-signing": "^0.24.0-alpha.26",
"@cosmjs/stargate": "^0.24.0-alpha.26",
"axios": "^0.21.1",
"chalk": "^4.1.0",
"faunadb": "^4.1.1",
"next": "^10.0.7",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"uuid": "^8.3.0"
},
"devDependencies": {
"express": "^4.17.1",
"http-proxy-middleware": "^1.0.6",
"netlify-lambda": "^2.0.3",
"npm-run-all": "^4.1.5"
},
"proxy": {
"/.netlify/functions": {
"target": "http://localhost:9000",
"pathRewrite": {
"^/\\.netlify/functions": ""
}
}
}
}
-26
View File
@@ -1,26 +0,0 @@
const { v4: uuidv4 } = require("uuid");
const { queries } = require("../../../database/connectDatabase");
const get = async (req, res) => {
try {
const {
query: { uuid },
} = req;
const multi = query.getMultiFromUUID.get(uuid);
res.status(200).send(multi);
} catch (err) {
console.log(err);
res.status(500).send(err.message);
}
};
export default (req, res) => {
switch (req.method) {
case "GET":
get(req, res);
break;
default:
res.status(404).send();
}
};
-92
View File
@@ -1,92 +0,0 @@
const gaiaWrap = require("../../../lib/gaiaWrap");
const { v4: uuidv4 } = require("uuid");
const { queries } = require("../../../database/connectDatabase");
const get = async (req, res) => {
const allKeys = await gaiaWrap.listKeys();
res.status(200).send(allKeys);
};
const post = async (req, res) => {
try {
// req.body.members should have array of members:
// members: [{nickname: 'Cyril', pubkey: ''}]
// req.body.threshold should have integer <= members.length
const { members, threshold } = req.body;
// for each member, create key and save to DB
// have to do this sequentially/synchronously to avoid
// locking up gaiacli
const saveProms = [];
let commaSepKeyNames = "";
for (var i = 0; i < members.length; i++) {
const member = members[i];
const keyname = await createAndSaveKey(member);
// combine keyNames into string for creating multisig key
commaSepKeyNames += keyname;
if (i !== members.length - 1) {
// not the last one so add a comma
commaSepKeyNames += ",";
}
}
// create multisig key
const multiName = uuidv4();
await gaiaWrap.createMultiSigKey({
multiName,
commaSepKeyNames,
threshold,
});
let multiAddress = await gaiaWrap.getMultiAddress({ keyName: multiName });
// save multisig
const saveResult = queries.insertMultiKey.run({
key_name: multiName,
address: multiAddress,
multi_threshold: threshold,
multi_members: commaSepKeyNames,
is_multi: 1,
});
res.status(200).send(multiAddress);
} catch (err) {
console.log(err);
res.status(500).send(err.message);
}
};
const createAndSaveKey = async (member) => {
try {
// create gaiacli key
member.key_name = uuidv4();
await gaiaWrap.createKey({
keyName: member.key_name,
pubkey: member.pubkey,
});
// save single key
const saveResult = queries.insertSingleKey.run(member);
return member.key_name;
} catch (err) {
console.log(err);
throw err;
}
};
export default (req, res) => {
switch (req.method) {
case "GET":
get(req, res);
break;
case "POST":
post(req, res);
break;
default:
res.status(404).send();
}
};
-99
View File
@@ -1,99 +0,0 @@
const fs = require("fs");
const gaiaWrap = require("../../../../lib/gaiaWrap");
const path = require("path");
const { v4: uuidv4 } = require("uuid");
const { queries } = require("../../../../database/connectDatabase");
const get = async (req, res) => {
try {
const {
query: { uuid },
} = req;
// get corresponding multi record
const transaction = queries.getTransactionForUUID.get(uuid);
if (!transaction) {
res.status(404).send();
} else {
const multi = queries.getMultiFromUUID.get(transaction.multi_key_name);
const signatures = JSON.parse(transaction.signatures);
if (signatures.length < multi.multi_threshold) {
res.status(400).send("Not enough signatures");
} else {
// create the files and multisign the tx
const unsignedJsonPath = `${transaction.uuid}-unsigned.json`;
fs.writeFileSync(unsignedJsonPath, transaction.unsigned);
const signatureFilePaths = [];
for (var i = 0; i < signatures.length; i++) {
const signature = signatures[i];
const filePath = `${transaction.uuid}-sign${i}.json`;
fs.writeFileSync(filePath, JSON.stringify(signature));
signatureFilePaths.push(filePath);
}
let signedTransaction = await gaiaWrap.signMulti({
keyName: multi.key_name,
signatureFiles: signatureFilePaths,
unsignedFile: unsignedJsonPath,
});
signedTransaction = signedTransaction.replace(/(\r\n|\n|\r)/gm, "");
// save signed tx
queries.updateTransactionSigned.run({
uuid: transaction.uuid,
signed: signedTransaction,
});
// save signed transaction
const signedTxPath = `${transaction.uuid}-signed.json`;
fs.writeFileSync(signedTxPath, signedTransaction);
// broadcast tx
const broadcastRes = await gaiaWrap.broadcastTX({
txFilename: signedTxPath,
});
queries.updateTransactionCompleted.run({
completed_tx: broadcastRes,
uuid: transaction.uuid,
});
const updatedTransaction = queries.getTransactionForUUID.get(uuid);
res.status(200).send(updatedTransaction);
// delete unsigned and signatures
fs.unlink(unsignedJsonPath, (err) => {
if (err) {
throw err;
}
});
for (var i = 0; i < signatureFilePaths.length; i++) {
fs.unlink(signatureFilePaths[i], (err) => {
if (err) {
throw err;
}
});
}
}
}
} catch (err) {
console.log(err);
res.status(500).send(err.message);
}
};
export default (req, res) => {
switch (req.method) {
case "GET":
get(req, res);
break;
default:
res.status(404).send();
}
};
-64
View File
@@ -1,64 +0,0 @@
const { v4: uuidv4 } = require("uuid");
const { queries } = require("../../../../database/connectDatabase");
const get = async (req, res) => {
try {
const {
query: { uuid },
} = req;
const transaction = query.getTransactionForUUID.get(uuid);
res.status(200).send(transaction);
} catch (err) {
console.log(err);
res.status(500).send(err.message);
}
};
const post = async (req, res) => {
try {
const {
query: { uuid },
} = req;
// req.body should have signature, a json object of the
// signature for this transaction
const { signature } = req.body;
// get corresponding transaction record
const transaction = queries.getTransactionForUUID.get(uuid);
if (!transaction) {
res.status(404).send();
} else {
// add signature to existing signatures and save
transaction.signatures = transaction.signatures
? JSON.parse(transaction.signatures)
: [];
transaction.signatures.push(signature);
queries.updateTransactionSignatures.run({
signatures: JSON.stringify(transaction.signatures),
uuid: transaction.uuid,
});
const updatedTransaction = queries.getTransactionForUUID.get(uuid);
res.status(200).send(updatedTransaction);
}
} catch (err) {
console.log(err);
res.status(500).send(err.message);
}
};
export default (req, res) => {
switch (req.method) {
case "POST":
post(req, res);
break;
case "GET":
post(req, res);
break;
default:
res.status(404).send();
}
};
-36
View File
@@ -1,36 +0,0 @@
const { v4: uuidv4 } = require("uuid");
const { queries } = require("../../../database/connectDatabase");
const post = async (req, res) => {
try {
// req.body should have unsignedJson, a json object of the
// cosmos sdk standard send msg, and multiAddress, a string
// with the address of the multisig that the tx is from
const { unsignedJson, multiAddress } = req.body;
// get corresponding multi record
const multi = queries.getMultiFromAddress.get(multiAddress);
const transactionUUID = uuidv4();
const saveResult = queries.insertTransaction.run({
multi_key_name: multi.key_name,
unsigned: unsignedJson,
uuid: transactionUUID,
});
res.status(200).send(transactionUUID);
} catch (err) {
console.log(err);
res.status(500).send(err.message);
}
};
export default (req, res) => {
switch (req.method) {
case "POST":
post(req, res);
break;
default:
res.status(404).send();
}
};
@@ -21,7 +21,7 @@ const transactionPage = ({ transaction, multi }) => {
<Page>
<StackableContainer base>
<StackableContainer>
<h1>Un-broadcast Transaction</h1>
<h1>In Progress Transaction</h1>
</StackableContainer>
<TransactionInfo tx={dummyTX} />
<TransactionSigning />
+50
View File
@@ -0,0 +1,50 @@
// server.js
/* eslint-disable no-console */
const express = require("express");
const next = require("next");
const devProxy = {
"/.netlify": {
target: "http://localhost:9000",
pathRewrite: { "^/.netlify/functions": "" },
},
};
const port = parseInt(process.env.PORT, 10) || 3000;
const env = process.env.NODE_ENV;
const dev = env !== "production";
const app = next({
dir: ".", // base directory where everything is, could move to src later
dev,
});
const handle = app.getRequestHandler();
let server;
app
.prepare()
.then(() => {
server = express();
// Set up the proxy.
if (dev && devProxy) {
const { createProxyMiddleware } = require("http-proxy-middleware");
Object.keys(devProxy).forEach(function (context) {
server.use(createProxyMiddleware(context, devProxy[context]));
});
}
// Default catch-all handler to allow Next.js to handle all other routes
server.all("*", (req, res) => handle(req, res));
server.listen(port, (err) => {
if (err) {
throw err;
}
console.log(`> Ready on port ${port} [${env}]`);
});
})
.catch((err) => {
console.log("An error occurred, unable to start the server");
console.log(err);
});