cosmos-fundraiser-cli
Version:
CLI tool for purchasing Atoms in the Cosmos Fundraiser
484 lines (385 loc) • 16.3 kB
JavaScript
'use strict';
var _stringify = require('babel-runtime/core-js/json/stringify');
var _stringify2 = _interopRequireDefault(_stringify);
var _regenerator = require('babel-runtime/regenerator');
var _regenerator2 = _interopRequireDefault(_regenerator);
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
var main = function () {
var _ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee() {
var wallet, currency, tx;
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
console.log(cyan('\n .d8888b. .d88888b. .d8888b. 888b d888 .d88888b. .d8888b.\nd88P Y88b d88P" "Y88b d88P Y88b 8888b d8888 d88P" "Y88b d88P Y88b\n888 888 888 888 Y88b. 88888b.d88888 888 888 Y88b.\n888 888 888 "Y888b. 888Y88888P888 888 888 "Y888b.\n888 888 888 "Y88b. 888 Y888P 888 888 888 "Y88b.\n888 888 888 888 "888 888 Y8P 888 888 888 "888\nY88b d88P Y88b. .d88P Y88b d88P 888 " 888 Y88b. .d88P Y88b d88P\n "Y8888P" "Y88888P" "Y8888P" 888 888 "Y88888P" "Y8888P"\n'), '\n\nWelcome to the Cosmos Fundraiser!\n\nThank you for your interest in donating funds for the development of The Cosmos Network.\nLet\'s get started!\n ');
_context.next = 3;
return checkFundraiserStatus();
case 3:
_context.next = 5;
return createOrInputWallet();
case 5:
wallet = _context.sent;
_context.next = 8;
return promptForCurrency();
case 8:
currency = _context.sent;
if (!(currency === 'BTC')) {
_context.next = 17;
break;
}
_context.next = 12;
return waitForBtcTx(wallet.addresses.bitcoin);
case 12:
tx = _context.sent;
_context.next = 15;
return finalizeBtcDonation(wallet, tx);
case 15:
_context.next = 19;
break;
case 17:
_context.next = 19;
return makeEthDonation(wallet);
case 19:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}));
return function main() {
return _ref.apply(this, arguments);
};
}();
var checkFundraiserStatus = function () {
var _ref2 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2() {
var spinner, status, _ref3, donateAnyway;
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
spinner = createSpinner('Checking fundraiser status...');
_context2.next = 3;
return cfr.fetchStatus();
case 3:
status = _context2.sent;
spinner.stop();
if (status.fundraiserEnded) {
_context2.next = 7;
break;
}
return _context2.abrupt('return');
case 7:
_context2.next = 9;
return prompt({
type: 'confirm',
name: 'donateAnyway',
message: red('NOTICE: The fundraiser has ended or has not yet started.\nYou may still donate, but you will NOT receive Atoms.\nContinue anyway?')
});
case 9:
_ref3 = _context2.sent;
donateAnyway = _ref3.donateAnyway;
if (!donateAnyway) process.exit(0);
console.log();
case 13:
case 'end':
return _context2.stop();
}
}
}, _callee2, this);
}));
return function checkFundraiserStatus() {
return _ref2.apply(this, arguments);
};
}();
var createOrInputWallet = function () {
var _ref4 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee3() {
var choices, _ref5, action, generate;
return _regenerator2.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
choices = ['Generate wallet', 'Input existing wallet'];
_context3.next = 3;
return prompt({
type: 'list',
choices: choices,
name: 'action',
message: 'Generate a new wallet, or use an existing one?'
});
case 3:
_ref5 = _context3.sent;
action = _ref5.action;
generate = choices[0];
if (!(action === generate)) {
_context3.next = 12;
break;
}
_context3.next = 9;
return createWallet();
case 9:
return _context3.abrupt('return', _context3.sent);
case 12:
_context3.next = 14;
return inputWallet();
case 14:
return _context3.abrupt('return', _context3.sent);
case 15:
case 'end':
return _context3.stop();
}
}
}, _callee3, this);
}));
return function createOrInputWallet() {
return _ref4.apply(this, arguments);
};
}();
var createWallet = function () {
var _ref6 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee4() {
var seed, walletString, walletStringLength, _ref7, reinput;
return _regenerator2.default.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
seed = cfr.generateMnemonic();
walletString = '\nLet\'s generate your Cosmos wallet. You will need this in the future to\naccess your Atoms.\n\nHere is your wallet:\n\n' + green(seed.toString('hex')) + '\n\n' + red('WRITE THIS DOWN AND DO NOT LOSE IT!') + '\n\n' + red('IF YOU LOSE THIS WALLET YOU LOSE YOUR ATOMS!') + '\n\n' + red('WARNING: DO NOT LOSE YOUR WALLET!') + '\n' + red('WARNING: DO NOT LOSE YOUR WALLET!') + '\n' + red('WARNING: DO NOT LOSE YOUR WALLET!') + '\n \n';
console.log(walletString);
_context4.next = 5;
return prompt({
name: 'write-wallet',
message: 'Please write down your wallet, then continue.'
});
case 5:
walletStringLength = walletString.split(/\r\n|\r|\n/).length;
readline.moveCursor(process.stdout, 0, -walletStringLength);
readline.clearScreenDown(process.stdout);
case 8:
if (!true) {
_context4.next = 18;
break;
}
_context4.next = 11;
return prompt({
name: 'reinput',
message: 'Please re-enter your 12-word wallet phrase:'
});
case 11:
_ref7 = _context4.sent;
reinput = _ref7.reinput;
if (!(reinput.trim() == seed)) {
_context4.next = 15;
break;
}
return _context4.abrupt('return', cfr.deriveWallet(seed));
case 15:
console.log("Incorrect. Try again or exit and restart");
_context4.next = 8;
break;
case 18:
case 'end':
return _context4.stop();
}
}
}, _callee4, this);
}));
return function createWallet() {
return _ref6.apply(this, arguments);
};
}();
var inputWallet = function () {
var _ref8 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee5() {
var _ref9, seed;
return _regenerator2.default.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
_context5.next = 2;
return prompt({
name: 'seed',
message: 'Please enter your 12-word wallet phrase:'
});
case 2:
_ref9 = _context5.sent;
seed = _ref9.seed;
return _context5.abrupt('return', cfr.deriveWallet(seed));
case 5:
case 'end':
return _context5.stop();
}
}
}, _callee5, this);
}));
return function inputWallet() {
return _ref8.apply(this, arguments);
};
}();
var promptForCurrency = function () {
var _ref10 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee6() {
var _ref11, currency;
return _regenerator2.default.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
_context6.next = 2;
return prompt({
type: 'list',
choices: ['BTC', 'ETH'],
name: 'currency',
message: 'Which currency will you make your donation in?'
});
case 2:
_ref11 = _context6.sent;
currency = _ref11.currency;
return _context6.abrupt('return', currency);
case 5:
case 'end':
return _context6.stop();
}
}
}, _callee6, this);
}));
return function promptForCurrency() {
return _ref10.apply(this, arguments);
};
}();
var waitForBtcTx = function () {
var _ref12 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee7(address) {
var spinner, inputs;
return _regenerator2.default.wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
console.log('\n' + bold('Suggested allocation rate:') + ' 1 BTC : ' + cfr.bitcoin.ATOMS_PER_BTC + ' ATOM\n' + bold('Minimum donation:') + ' ' + cfr.bitcoin.MINIMUM_AMOUNT / 1e8 + ' BTC\n\nYour intermediate Bitcoin address is:\n' + cyan(address) + '\n\nSend BTC to this address to continue with your contribution.\nThis address is owned by you, so you can get the coins back if you\nchange your mind.\n ');
spinner = createSpinner('Waiting for a transaction...').start();
_context7.next = 4;
return cfr.bitcoin.waitForPayment(address);
case 4:
inputs = _context7.sent;
spinner.succeed('Got payment of ' + cyan(inputs.amount / 1e8 + ' BTC'));
return _context7.abrupt('return', inputs);
case 7:
case 'end':
return _context7.stop();
}
}
}, _callee7, this);
}));
return function waitForBtcTx(_x) {
return _ref12.apply(this, arguments);
};
}();
var finalizeBtcDonation = function () {
var _ref13 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee8(wallet, inputs) {
var feeSpinner, feeRate, finalTx, _ref14, agree, _ref15, confirm, signedTx, spinner, txid;
return _regenerator2.default.wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
feeSpinner = createSpinner('Fetching BTC transaction fee rate...');
_context8.next = 3;
return cfr.bitcoin.fetchFeeRate();
case 3:
feeRate = _context8.sent;
feeSpinner.stop();
finalTx = cfr.bitcoin.createFinalTx(inputs.utxos, feeRate);
console.log('\nReady to finalize contribution:\n ' + bold('Donating:') + ' ' + finalTx.paidAmount / 1e8 + ' BTC\n ' + bold('Bitcoin transaction fee:') + ' ' + finalTx.feeAmount / 1e8 + ' BTC\n ' + bold('Suggested Atom Equivalent:') + ' ' + finalTx.atomAmount + ' ATOM\n ' + bold('Cosmos address:') + ' ' + wallet.addresses.cosmos + '\n ');
_context8.next = 9;
return prompt({
type: 'confirm',
name: 'agree',
message: 'Have you read and agreed to the Terms of Service and Donation Agreement?',
default: false
});
case 9:
_ref14 = _context8.sent;
agree = _ref14.agree;
if (agree) {
_context8.next = 14;
break;
}
console.log(red('\nYou can read the Terms of Service and Donation Agreement here:\nhttps://github.com/cosmos/cosmos/blob/master/fundraiser/Interchain%20Cosmos%20Contribution%20Terms%20-%20FINAL.pdf\n '));
return _context8.abrupt('return');
case 14:
_context8.next = 16;
return prompt({
type: 'confirm',
name: 'confirm',
message: 'Finalize contribution? You will NOT be able undo this transaction:',
default: false
});
case 16:
_ref15 = _context8.sent;
confirm = _ref15.confirm;
if (confirm) {
_context8.next = 20;
break;
}
return _context8.abrupt('return');
case 20:
signedTx = cfr.bitcoin.signFinalTx(wallet, finalTx.tx);
spinner = createSpinner('Broadcasting transaction...');
_context8.next = 24;
return cfr.bitcoin.pushTx(signedTx.toHex());
case 24:
spinner.succeed('Transaction sent!');
txid = signedTx.getId();
console.log('Bitcoin TXID: ' + cyan(txid));
console.log('Thank you for participating in the Cosmos fundraiser!');
case 28:
case 'end':
return _context8.stop();
}
}
}, _callee8, this);
}));
return function finalizeBtcDonation(_x2, _x3) {
return _ref13.apply(this, arguments);
};
}();
var makeEthDonation = function () {
var _ref16 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee9(wallet) {
var tx, spinner, weiPerAtom, atomPerEth;
return _regenerator2.default.wrap(function _callee9$(_context9) {
while (1) {
switch (_context9.prev = _context9.next) {
case 0:
tx = cfr.ethereum.getTransaction('' + wallet.addresses.cosmos, wallet.addresses.ethereum);
spinner = createSpinner('Fetching ATOM/ETH exchange rate...');
_context9.next = 4;
return cfr.ethereum.fetchAtomRate(FUNDRAISER_CONTRACT);
case 4:
weiPerAtom = _context9.sent;
atomPerEth = Math.pow(10, 18) / weiPerAtom;
spinner.stop();
console.log('\n ' + bold('Suggested allocation rate:') + ' 1 ETH : ' + atomPerEth + ' ATOM\n ' + bold('Minimum donation:') + ' ' + cfr.ethereum.MIN_DONATION + ' ETH\n ' + bold('Your Cosmos address:') + ' ' + wallet.addresses.cosmos + ' (DO NOT SEND ETHER HERE!)\n\nHere\'s your donation transaction:\n' + cyan(' ' + (0, _stringify2.default)(tx, null, ' ').replace('}', ' }')) + '\n\nTo make your donation, copy and paste this information into a wallet\nsuch as MyEtherWallet or Mist. Be sure to include an amount of ETH to\ndonate! Your Cosmos address is included in the data, and the donation\nwill be recorded for that address in the smart contract.\n\nThank you for participating in the Cosmos Fundraiser!\n ');
case 8:
case 'end':
return _context9.stop();
}
}
}, _callee9, this);
}));
return function makeEthDonation(_x4) {
return _ref16.apply(this, arguments);
};
}();
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var readline = require('readline');
var _require = require('chalk'),
bold = _require.bold,
cyan = _require.cyan,
red = _require.red,
green = _require.green;
var _require2 = require('inquirer'),
prompt = _require2.prompt;
var createSpinner = require('ora');
var promisify = require('bluebird').promisify;
var cfr = require('cosmos-fundraiser');
var FUNDRAISER_CONTRACT = cfr.ethereum.FUNDRAISER_CONTRACT;
cfr.fetchStatus = promisify(cfr.fetchStatus);
cfr.bitcoin.pushTx = promisify(cfr.bitcoin.pushTx);
cfr.bitcoin.fetchFeeRate = promisify(cfr.bitcoin.fetchFeeRate);
cfr.bitcoin.waitForPayment = promisify(cfr.bitcoin.waitForPayment);
cfr.ethereum.fetchAtomRate = promisify(cfr.ethereum.fetchAtomRate);
module.exports = main;