removes files from previous app
This commit is contained in:
-36
@@ -1,36 +0,0 @@
|
||||
FROM golang:1.15.2
|
||||
|
||||
# install git
|
||||
RUN apt-get update && \
|
||||
apt-get upgrade -y && \
|
||||
apt-get install -y git
|
||||
|
||||
# install gaiacli
|
||||
RUN git clone -b v2.0.13 https://github.com/cosmos/gaia
|
||||
RUN cd gaia && make install
|
||||
|
||||
# set gaiacli config
|
||||
RUN gaiacli config node https://cosmos.chorus.one:26657
|
||||
RUN gaiacli config chain-id cosmoshub-3
|
||||
|
||||
# install node
|
||||
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
|
||||
RUN apt-get install -y nodejs
|
||||
|
||||
# setup directory
|
||||
RUN mkdir -p /usr/src
|
||||
WORKDIR /usr/src
|
||||
|
||||
# copy source files
|
||||
COPY . /usr/src
|
||||
|
||||
# install dependencies
|
||||
RUN npm install
|
||||
|
||||
# reset database
|
||||
RUN node database/initialize.js
|
||||
|
||||
# start app
|
||||
RUN npm run build
|
||||
EXPOSE 3000
|
||||
CMD npm run start
|
||||
@@ -1,54 +1,9 @@
|
||||
# Gaiacli node.js wrapper and demo app
|
||||
# Cosmoshub Legacy Multisig
|
||||
|
||||
## Reason for Being
|
||||
This app allows for legacy multisig users to create, sign and broadcast transactions on the stargate enabled cosmos hub chain.
|
||||
|
||||
Conducting a simple multi-signature transaction using the [gaiacli](https://hub.cosmos.network/master/gaia-tutorials/what-is-gaia.html) currently requires a couple handfuls of terminal commands, and for the initial multi-sig creator to send files to all the different signers, who must sign and then send back. It's a little arduous.
|
||||
# 🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧
|
||||
|
||||
This app is a little stop gap that makes creating and signing multi-sig transactions a little simpler while we wait for some upcoming developments in the cosmos dev world. It does this by wrapping the gaiacli in its own little [node.js module](https://github.com/samepant/cosmos-multisig-ui/blob/master/lib/gaiaWrap.js), making it available to whatever node.js app we can imagine, and in this case it's a small next.js app that walks through the multi-sig creation and signing process.
|
||||
# UNDER CONSTRUCTION
|
||||
|
||||
At the moment the app reduces the need for direct command line interaction to a single command per signer, and there are [plans to eliminate those as well below](https://github.com/samepant/cosmos-multisig-ui#future-enhancements).
|
||||
|
||||
## Install / Running
|
||||
A demo app is running here: https://cosmos-multi-sig.herokuapp.com/ It's running with `gaiacli tx broadcast --dry-run` on, so none of the transactions will go through, but you'll still see some transaction information returned.
|
||||
|
||||
#### With Docker
|
||||
|
||||
While inside the directory, run `docker build -t multi-sig-wrap .` to build the image. (note that `multi-sig-wrap` can be any string). This builds an image with all the dependencies, including `gaiacli` connected to the node at `https://cosmos.chorus.one:26657` with a chain-id of `cosmoshub-3`. These values are [configured here](https://github.com/samepant/cosmos-multisig-ui/blob/master/Dockerfile#L12).
|
||||
|
||||
Run the container with `docker run --name multi_sig_app -p 0.0.0.0:5000:3000 multi-sig-wrap`
|
||||
|
||||
The app should be live at http://localhost:5000
|
||||
|
||||
#### No Docker
|
||||
|
||||
You must have the `gaiacli` and `node` running on your machine
|
||||
|
||||
Install dependencies with `npm install`
|
||||
|
||||
Run developer mode with `npm run dev`
|
||||
|
||||
Build production with `npm run build`
|
||||
|
||||
If you want to reset the db run `node database/initialize.js`
|
||||
|
||||
#### Notes
|
||||
|
||||
- The `--dry-run` flag is [currently set](https://github.com/samepant/cosmos-multisig-ui/blob/master/lib/gaiaWrap.js#L59) on the wrapped `gaiacli tx broadcast` command, so if you want to run this with real transactions, be sure to remove.
|
||||
|
||||
- Building the docker container resets the sqlite database
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Use wallet providers for signing the contract
|
||||
|
||||
At the moment, the signer of a transaction has to download the transaction json to sign it locally. Many digital asset wallets provide client side libraries for signing with the private keys they store, and we could use this to turn the signing process into a few clicks. At the moment, the ledger wallet has a [cosmos library available](https://github.com/Zondax/ledger-cosmos-js) and based on this [github issue](https://github.com/chainapsis/keplr-extension/issues/23), the kepler wallet will support this soon.
|
||||
|
||||
### Remove the need for the server entirely
|
||||
|
||||
Right now, this app relies on a server running a gaiacli app to create multisig keys and to do the final signing of the transactions. Because the multisig key can be created with public keys, there shouldn't be a security issue with running everything in the browser. In order to accomplish this, we would need a module that ports the multisign components of the cosmos-sdk to run in the browser. Based on this [github issue](https://github.com/CosmWasm/cosmjs/issues/416), it looks like the CosmWasm dev community is thinking through it.
|
||||
|
||||
The server also stores the signatures during the signing process to make it easier to coordinate signing. This could be avoided by storing basic transaction data in the URL (a url-encoded transaction is pretty long, but is still shorter than the standard url length limits ~2000 characters). Another solution would be to store in progress transactions with ipfs, and encode the ipfs url in our app's url.
|
||||
|
||||
### Friendlier UI
|
||||
|
||||
At the moment the UI is pretty technical and doesn't explain a whole lot about what's happening, and doesn't really have any navigation 😪😪😪
|
||||
# 🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
const Database = require("better-sqlite3");
|
||||
const path = require("path");
|
||||
|
||||
const db = new Database(
|
||||
path.join(path.resolve(process.cwd(), "database"), "multisig-db.db"),
|
||||
{
|
||||
verbose: console.log,
|
||||
}
|
||||
);
|
||||
|
||||
const queries = {};
|
||||
// setup queries
|
||||
queries.insertSingleKey = db.prepare(
|
||||
"INSERT INTO keys(nickname, pubkey, key_name) VALUES($nickname, $pubkey, $key_name)"
|
||||
);
|
||||
queries.updateSingleKey = db.prepare(
|
||||
"UPDATE keys SET address = $address WHERE id = $id"
|
||||
);
|
||||
queries.insertMultiKey = db.prepare(
|
||||
"INSERT INTO keys(key_name, address, multi_members, is_multi, multi_threshold) VALUES($key_name, $address, $multi_members, $is_multi, $multi_threshold)"
|
||||
);
|
||||
queries.getAllMulti = db.prepare("SELECT * FROM keys WHERE is_multi = 1");
|
||||
queries.getMultiFromUUID = db.prepare("SELECT * FROM keys WHERE key_name = ?");
|
||||
queries.getMultiFromAddress = db.prepare(
|
||||
"SELECT * FROM keys WHERE address = ?"
|
||||
);
|
||||
queries.getTransactionForUUID = db.prepare(
|
||||
"SELECT * FROM transactions WHERE uuid = ?"
|
||||
);
|
||||
queries.insertTransaction = db.prepare(
|
||||
"INSERT INTO transactions(multi_key_name, unsigned, uuid) VALUES($multi_key_name, $unsigned, $uuid)"
|
||||
);
|
||||
queries.updateTransactionSignatures = db.prepare(
|
||||
"UPDATE transactions SET signatures = $signatures WHERE uuid = $uuid"
|
||||
);
|
||||
queries.updateTransactionSigned = db.prepare(
|
||||
"UPDATE transactions SET signed = $signed WHERE uuid = $uuid"
|
||||
);
|
||||
queries.updateTransactionCompleted = db.prepare(
|
||||
"UPDATE transactions SET completed_tx = $completed_tx WHERE uuid = $uuid"
|
||||
);
|
||||
queries.getTransactionsForMultiKeyName = db.prepare(
|
||||
"SELECT * FROM transactions WHERE multi_key_name = ?"
|
||||
);
|
||||
|
||||
module.exports = {
|
||||
db,
|
||||
queries,
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
const Database = require("better-sqlite3");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const db = new Database(path.join(__dirname, "multisig-db.db"), {
|
||||
verbose: console.log,
|
||||
});
|
||||
|
||||
// initialize db
|
||||
const initialSchema = fs.readFileSync(
|
||||
path.join(__dirname, "./schema.sql"),
|
||||
"utf8"
|
||||
);
|
||||
db.exec(initialSchema);
|
||||
Binary file not shown.
@@ -1,23 +0,0 @@
|
||||
DROP TABLE IF EXISTS keys;
|
||||
DROP TABLE IF EXISTS transactions;
|
||||
|
||||
CREATE TABLE keys (
|
||||
id integer PRIMARY KEY AUTOINCREMENT,
|
||||
key_name text,
|
||||
pubkey text,
|
||||
address text,
|
||||
multi_threshold integer,
|
||||
multi_members text, -- Comma separated UUIDs
|
||||
nickname text,
|
||||
is_multi integer
|
||||
);
|
||||
|
||||
CREATE TABLE transactions (
|
||||
id integer PRIMARY KEY AUTOINCREMENT,
|
||||
uuid text,
|
||||
unsigned text,
|
||||
signatures text,
|
||||
signed text,
|
||||
completed_tx text,
|
||||
multi_key_name text NOT NULL
|
||||
);
|
||||
@@ -1,91 +0,0 @@
|
||||
const exec = require("../utilities/promiseExec");
|
||||
|
||||
// All of the following functions return the string output (if there is any)
|
||||
// from the gaia command line utility.
|
||||
|
||||
// Some Notes
|
||||
//
|
||||
// - gaiacli locks its keystore when writing, so running concurrent commands will fail,
|
||||
// use sequential operators (like for loops) and not async ones (like forEach)
|
||||
//
|
||||
// - There are newline characters in some of the return values. Newline characters get
|
||||
// stripped when the return value is a single line
|
||||
|
||||
// KEY WRAPPERS
|
||||
|
||||
const createKey = (props) => {
|
||||
// props = {
|
||||
// keyName: 'string',
|
||||
// pubkey: 'string',
|
||||
// }
|
||||
|
||||
return exec(`gaiacli keys add ${props.keyName} --pubkey=${props.pubkey}`);
|
||||
};
|
||||
|
||||
const getMultiAddress = async (props) => {
|
||||
// props = {
|
||||
// keyName: 'string',
|
||||
// }
|
||||
|
||||
const rawReturn = await exec(`gaiacli keys show ${props.keyName} -a`);
|
||||
const cleaned = rawReturn.replace(/(\r\n|\n|\r)/gm, "");
|
||||
|
||||
return cleaned;
|
||||
};
|
||||
|
||||
const createMultiSigKey = (props) => {
|
||||
// props = {
|
||||
// multiName: 'string',
|
||||
// commaSepKeyNames: 'string',
|
||||
// threshold: 'string',
|
||||
// }
|
||||
|
||||
return exec(
|
||||
`gaiacli keys add ${props.multiName} --multisig=${props.commaSepKeyNames} --multisig-threshold=${props.threshold}`
|
||||
);
|
||||
};
|
||||
|
||||
const listKeys = () => {
|
||||
return exec("gaiacli keys list");
|
||||
};
|
||||
|
||||
// TRANSACTION WRAPPERS
|
||||
|
||||
const broadcastTX = (props) => {
|
||||
// props = {
|
||||
// txFilename: 'string',
|
||||
// }
|
||||
|
||||
return exec(`gaiacli tx broadcast ${props.txFilename} --dry-run`);
|
||||
};
|
||||
|
||||
const signMulti = (props) => {
|
||||
// props = {
|
||||
// keyName: 'string',
|
||||
// signatureFiles: array of filepaths,
|
||||
// unsignedFile: 'filepath'
|
||||
// }
|
||||
let signatureFileString = "";
|
||||
|
||||
for (var i = 0; i < props.signatureFiles.length; i++) {
|
||||
signatureFileString += props.signatureFiles[i];
|
||||
|
||||
if (i !== props.signatureFiles.length - 1) {
|
||||
// add space
|
||||
signatureFileString += " ";
|
||||
}
|
||||
}
|
||||
|
||||
return exec(
|
||||
`gaiacli tx multisign ${props.unsignedFile} ${props.keyName} ${signatureFileString}`
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
broadcastTX,
|
||||
createMultiSigKey,
|
||||
createKey,
|
||||
getMultiAddress,
|
||||
listKeys,
|
||||
signMulti,
|
||||
};
|
||||
Generated
+1477
-1251
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -6,10 +6,10 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.20.0",
|
||||
"better-sqlite3": "^7.1.1",
|
||||
"js-file-download": "^0.4.12",
|
||||
"next": "^9.5.3",
|
||||
"@cosmjs/proto-signing": "^0.24.0-alpha.26",
|
||||
"@cosmjs/stargate": "^0.24.0-alpha.26",
|
||||
"axios": "^0.21.1",
|
||||
"next": "^9.5.5",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"uuid": "^8.3.0"
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
const execShellCommand = (cmd) => {
|
||||
const exec = require("child_process").exec;
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(cmd, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.warn(error);
|
||||
}
|
||||
resolve(stdout ? stdout : stderr);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = execShellCommand;
|
||||
Reference in New Issue
Block a user