Commit 3a1ca9cd authored by Allan Juma's avatar Allan Juma

0.7.8

parent 4c8579a4
......@@ -17474,6 +17474,16 @@
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"python": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/python/-/python-0.0.4.tgz",
"integrity": "sha1-MJTomO8Xozqpw+lzs4SKOOR9GBg="
},
"python-shell": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/python-shell/-/python-shell-3.0.1.tgz",
"integrity": "sha512-TWeotuxe1auhXa5bGRScxnc2J+0r41NBntSa6RYZtMBLtAEsvCboKrEbW6DvASosWQepVkhZZlT3B5Ei766G+Q=="
},
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
......@@ -20646,6 +20656,14 @@
"dev": true,
"optional": true
},
"tinyman-ts-sdk": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tinyman-ts-sdk/-/tinyman-ts-sdk-1.0.1.tgz",
"integrity": "sha512-uaZ5wEptwpPAqNeqOOrI6JmW6BVGi3kaZUR9T5s3ouM6snzzF9LLW8T+lkW4BXXjiy6r1xEAIQO6bQhz/ypUEQ==",
"requires": {
"algosdk": "^1.12.0"
}
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
......@@ -20777,6 +20795,11 @@
"resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.2.tgz",
"integrity": "sha512-f5Knjh7XCyRIzoC/z1Su1yLLRrPrFCgtUAh/9fCSP6NKbATwpOL1+idQVXQokK9GRFURn/jYPGPfegIctwunoA=="
},
"tsc": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/tsc/-/tsc-2.0.4.tgz",
"integrity": "sha512-fzoSieZI5KKJVBYGvwbVZs/J5za84f2lSTLPYf6AGiIf43tZ3GNrI1QzTLcjtyDDP4aLxd46RTZq1nQxe7+k5Q=="
},
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
......@@ -20855,6 +20878,12 @@
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"typescript": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz",
"integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==",
"dev": true
},
"ua-parser-js": {
"version": "0.7.20",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.20.tgz",
......
......@@ -47,6 +47,8 @@
"mobx": "^4.9.4",
"mobx-react": "^5.4.3",
"npm": "^8.1.0",
"python": "0.0.4",
"python-shell": "^3.0.1",
"qr-image": "^3.2.0",
"react": "^16.10.0",
"react-art": "^16.8.6",
......@@ -54,7 +56,9 @@
"react-dom": "17.0.2",
"react-native-web": "^0.11.2",
"react-scripts": "4.0.3",
"svgs": "4.0.0"
"svgs": "4.0.0",
"tinyman-ts-sdk": "^1.0.1",
"tsc": "^2.0.4"
},
"devDependencies": {
"@babel/cli": "^7.2.3",
......@@ -90,7 +94,7 @@
"protobufjs": "^6.8.8",
"react-scripts": "^3.0.0",
"sinon": "^6.0.0",
"typescript": "4.4.2",
"typescript": "^4.4.2",
"unexpected": "^10.37.2",
"unexpected-sinon": "^10.10.1",
"wait-on": "^2.1.0",
......
const { app, BrowserWindow, ipcMain, dialog, Menu } = require('electron');
const { contextBridge, ipcRenderer, app, BrowserWindow, ipcMain, dialog, Menu } = require('electron');
const { autoUpdater } = require('electron-updater');
const os = require('os');
const path = require('path');
......@@ -6,6 +6,7 @@ const url = require('url');
const isDev = require('electron-is-dev');
const log = require('electron-log');
const { startLndProcess, startBtcdProcess } = require('./lnd-child-process');
const { initPythonProcess } = require('./python-child-process');
const grcpClient = require('./grpc-client');
const {
PREFIX_NAME,
......@@ -47,6 +48,7 @@ const lndArgs = process.argv.filter(a =>
let win;
let lndProcess;
let btcdProcess;
let pythonProcess;
log.transports.console.level = 'info';
log.transports.file.level = 'info';
......@@ -99,7 +101,7 @@ console.log(path.join(__dirname, 'preload.js'));
nodeIntegration: true, // is default value after Electron v5
contextIsolation: true, // protect against prototype pollution
enableRemoteModule: false, // turn off remote
allowRunningInsecureContent: true,
//allowRunningInsecureContent: true,
sandbox: false,
preload: path.join(__dirname, 'preload.js'),
},
......@@ -163,9 +165,50 @@ ipcMain.on('lnd-restart-process', async event => {
event.sender.send('lnd-restart-error', { restartError });
});
const startLnd = async () => {
ipcMain.on('pyFace', async function(event, args) {
console.log(args.body);
var ranID = args.body[0];
//args.body = args.body.shift(0);
args.body = args.body.filter(function(v){
console.log(typeof(v));
if(typeof(v) != 'string') return true;
return !(v.includes('pyFace:'));
});
console.log(args.body, ranID);
try {
/*
res = await initPythonProcess({args: args.body,logger: Logger,});
} catch (err) {
console.log(err);
res = err
}
/*
pythonProcess = "{'address': 'TTNTINGI6AKN6JBHCAOXVFZN72BAMDNBTHZ3ZRQC3ILAMWONKN7XRRQ6GM', 'amount': 0, 'amount-without-pending-rewards': 0, 'apps-local-state': [], 'apps-total-schema': {'num-byte-slice': 0, 'num-uint': 0}, 'assets': [], 'created-apps': [], 'created-assets': [], 'pending-rewards': 0, 'reward-base': 27521, 'rewards': 0, 'round': 19891151, 'status': 'Offline'}";
*/
var res = JSON.stringify(res);
event.sender.send(ranID, {response:res});
});
const startLnd = async () => {
try {
/*
pythonProcess = await initPythonProcess({args: ['/data/lightning-bits/src/chains/algo/pools.py',
'',
'',
'',
'',
'',
'TTNTINGI6AKN6JBHCAOXVFZN72BAMDNBTHZ3ZRQC3ILAMWONKN7XRRQ6GM',
],logger: Logger,});
btcdProcess = await startBtcdProcess({
isDev,
logger: Logger,
......@@ -237,6 +280,7 @@ app.on('activate', () => {
app.on('quit', () => {
lndProcess && lndProcess.kill('SIGINT');
btcdProcess && btcdProcess.kill('SIGINT');
pythonProcess && pythonProcess.kill('SIGINT');
});
// Prevent multiple instances of the application.
......
......@@ -51,6 +51,7 @@ function startBlockingProcess(name, args, logger) {
});
}
module.exports.startLndProcess = async function({
isDev,
lndSettingsDir,
......@@ -86,7 +87,7 @@ module.exports.startLndProcess = async function({
];
// set development or production settings
if (!isDev) {
if (isDev) {
args = args.concat([
'--bitcoin.node=neutrino',
......@@ -109,7 +110,7 @@ module.exports.startLndProcess = async function({
// set default production settings if no custom flags
//if (!isDev && !lndArgs.length) {
if (isDev) {
if (!isDev) {
args = args.concat([
'--bitcoin.node=bitcoind',
'--bitcoind.rpchost=btc-p2p.bitsoko.org',
......@@ -160,3 +161,4 @@ module.exports.mineBlocks = async function({ blocks, logger }) {
};
......@@ -6,7 +6,7 @@ var { contextBridge, ipcRenderer } = require("electron");
const filter = event => {
if (
!/^(lnd)|(unlock)|(log)|(locale)|(open-url)[a-zA-Z_-]{0,20}$/.test(event)
!/^(lnd)|(unlock)|(pyFace)|(log)|(locale)|(open-url)[a-zA-Z_-]{0,20}$/.test(event)
) {
throw new Error(`Invalid IPC: ${event}`);
}
......
const os = require('os');
const fs = require('fs');
const path = require('path');
const cp = require('child_process');
var cmdQueue = new Array();
function handleStdout(data) {
var datastr = data.toString('utf8');
var finished = false;
if (datastr.match(/Command Start\n/)) {
datastr = datastr.replace(/Command Start\n/,'');
}
if (datastr.match(/Command End\n/)) {
datastr = datastr.replace(/Command End\n/,'');
finished = true;
}
if (cmdQueue.length > 0) {
cmdQueue[0].data+=datastr;
}
if (finished) {
cmd = cmdQueue.shift();
if (cmd && cmd.command) {
if (undefined != typeof cmd.callback) {
cmd.callback(null, cmd.data);
processQueue();
}
}
}
return datastr;
};
function handleStderr(data) {
processQueue();
};
function processQueue() {
if (cmdQueue.length > 0 && cmdQueue[0].state === 'pending') {
cmdQueue[0].state = 'processing';
child.stdin.write(cmdQueue[0].command, encoding='utf8');
}
};
function handleExit(code) {
console.log('child process exited with code ' + code);
//process.exit();
};
function getProcessName(binName) {
const filename = os.platform() === 'win32' ? `${binName}.exe` : binName;
const filePath = __dirname.includes('asar')
? path.join(__dirname, '..', '..', 'assets', 'bin', os.platform(), filename)
: path.join(__dirname, '..', 'assets', 'bin', os.platform(), filename);
console.log(fs.existsSync(filePath),path.join(__dirname, '..', 'assets', 'bin', os.platform(), filename));
return fs.existsSync(filePath) ? filePath : filename;
}
async function startChildProcess(name, args, logger) {
return new Promise((resolve, reject) => {
const processName = getProcessName(name);
logger.info(`Using ${name} in path ${processName}`);
const childProcess = cp.spawn(processName, args);
childProcess.stdout.on('data', data => {
logger.info(`${name}: ${data}`);
//resolve(childProcess);
resolve(data);
});
childProcess.stderr.on('data', data => {
logger.error(`${name} Error: ${data}`);
reject(new Error(data));
});
childProcess.on('error', reject);
});
}
function startBlockingProcess(name, args, logger) {
return new Promise((resolve, reject) => {
const processName = getProcessName(name);
logger.info(`Using ${name} in path ${processName}`);
const childProcess = cp.spawn(processName, args);
childProcess.stdout.on('data', data => {
logger.info(`${name}: ${data}`);
});
childProcess.stderr.on('data', data => {
logger.error(`${name} Error: ${data}`);
reject(new Error(data));
});
childProcess.on('exit', resolve);
childProcess.on('error', reject);
});
}
module.exports.initPythonProcess = async function({
args,logger
}) {
console.log('RUNNING Python');
//logger.error(`started python`);
const processName = 'python3';
data = await startChildProcess(processName, args, logger);
return handleStdout(data);
//child.stdout.on('data', handleStdout);
//child.stderr.on('data', handleStderr);
//child.on('exit', handleExit);
};
......@@ -17,6 +17,32 @@ class GrpcAction {
// WalletUnlocker grpc client
//
/**
* The first GRPC api that is called to initialize the wallet unlocker.
* Once `unlockerReady` is set to true on the store GRPC calls can be
* made to the client.
* @return {Promise<undefined>}
*/
async initPyface(body) {
log.info('python starting');
try{
var ranID = 'pyFace:'+JSON.stringify(Math.floor(Math.random() * 10000));
body = [ranID].concat(body);
var res = await this._ipc.send('pyFace', ranID, { body });
return res;
}catch(err){
console.log(err);
}
}
//
// WalletUnlocker grpc client
//
/**
* The first GRPC api that is called to initialize the wallet unlocker.
* Once `unlockerReady` is set to true on the store GRPC calls can be
......
......@@ -29,9 +29,8 @@ import PoolRedeemLiqAction from './pool-redeem-liquid';
import InvoiceAction from './invoice';
import SettingAction from './setting';
import AtplAction from './autopilot';
import Algorand from '../chains/algo.js';
import Solana from '../chains/sol.js';
import Algorand from '../chains/algo/algo.js';
import Solana from '../chains/sol/sol.js';
//
// Inject dependencies
......@@ -98,7 +97,7 @@ when(
await grpc.closeUnlocker();
await grpc.initLnd();
await grpc.initAutopilot();
}
}
);
/**
......@@ -173,6 +172,24 @@ when(
console.log('old algo account! '+store.settings.chains.algo.account.address);
}
//var poolStats = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'bootstrap', 70232824, 0, '289:BITS', 'ALGO', 'TTNTINGI6AKN6JBHCAOXVFZN72BAMDNBTHZ3ZRQC3ILAMWONKN7XRRQ6GM' ]);
var poolStats = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'accState', 'TTNTINGI6AKN6JBHCAOXVFZN72BAMDNBTHZ3ZRQC3ILAMWONKN7XRRQ6GM' ]);
poolStats = poolStats.replace(/'/g, '"').replace(/"{/g, "{").slice(0, -3);
console.log(poolStats);
store.settings.chains.algo.account.balance = JSON.parse(poolStats).amount/1000000+' ALGOS'
/*
if(!store.chains.sol.account){
......
......@@ -40,8 +40,9 @@ class IpcAction {
* @return {Promise<Object>}
*/
send(event, listen, payload) {
return new Promise((resolve, reject) => {
return new Promise(async (resolve, reject) => {
this._ipcRenderer.send(event, payload);
if (!listen) return resolve();
this._ipcRenderer.once(listen, (e, arg) => {
if (arg.err) {
......
......@@ -101,6 +101,10 @@ class NavAction {
this._store.route = 'PayLightningConfirm';
}
goPayPoolDone() {
this._store.route = 'PayPoolDone';
}
goPayLightningDone() {
this._store.route = 'PayLightningDone';
}
......
......@@ -338,19 +338,19 @@ class PaymentAction {
this._nav.goWait();
const invoice = this._store.payment.address;
const stream = this._grpc.sendStreamCommand('sendPayment');
await new Promise((resolve, reject) => {
return await new Promise((resolve, reject) => {
stream.on('data', data => {
if (data.paymentError) {
reject(new Error(`Lightning payment error: ${data.paymentError}`));
} else {
resolve();
resolve(data);
}
});
stream.on('error', reject);
stream.write(JSON.stringify({ paymentRequest: invoice }), 'utf8');
});
if (failed) return;
this._nav.goPayLightningDone();
this._notification.display({ msg: 'Lightning sent to swap!' });
} catch (err) {
if (failed) return;
//this._nav.goPayLightningConfirm();
......
......@@ -116,6 +116,8 @@ class PoolAddAction {
this._nav.goPoolAddLiquid();
}
/**
* Set the address input for the payment view. This can either be
* an on-chain bitcoin addres or an encoded lightning invoice.
......@@ -138,10 +140,21 @@ class PoolAddAction {
const { settings } = this._store;
var amount = toSatoshis(amount, settings);
//check if contract has enough balance first
console.log(parseFloat(this._store.settings.chains.algo.account.balance)*100, (amount*1.1));
if(parseFloat(this._store.settings.chains.algo.account.balance)*100 > (amount*1.1)){
console.log('INFO! contract has sufficient balance');
}else{
//get new pool quotation from server
var escrowInvoice = await sendToEscrow(amount, '{"state":"pool", "action":"add", "account":"'+this._store.settings.chains.algo.account.address+'", "pool":"'+this._store.selectedPool.id+'", "type":"float"}');
console.log(escrowInvoice);
this.setAddress({ address: escrowInvoice });
}
}
......@@ -172,10 +185,18 @@ class PoolAddAction {
* @return {Promise<undefined>}
*/
async checkType() {
if (!this._store.payment.address) {
const { settings } = this._store;
var amount = toSatoshis(this._store.payment.amount, settings);
if(parseFloat(this._store.settings.chains.algo.account.balance)*1000000 > (amount*1.01)){
console.log('INFO! sufficient BTC in contract. skipping lightning swap...');
} else if (!this._store.payment.address) {
return this._notification.display({ msg: 'Enter an invoice or address' });
}
/*
//if not enough contract BTC then swap from lightning
//
if (await this.decodeInvoice({ invoice: this._store.payment.address })) {
this._nav.goPayLightningConfirm();
......@@ -184,7 +205,10 @@ class PoolAddAction {
} else {
this._notification.display({ msg: 'Invalid invoice or address' });
}
*/
this._nav.goPayPoolConfirm();
}
......@@ -306,6 +330,8 @@ class PoolAddAction {
});
}
}
/**
* Send the specified amount as an on-chain transaction to the provided
......
......@@ -4,7 +4,9 @@
*/
import * as log from './log';
import { parseDate, toHex, checkHttpStatus } from '../helper';
import { parseDate, toHex, checkHttpStatus, toAmountLabel, addAsaQuote } from '../helper';
var hii;
class PoolAction {
constructor(store, grpc, nav, notification) {
......@@ -12,6 +14,7 @@ class PoolAction {
this._grpc = grpc;
this._nav = nav;
this._notification = notification;
hii = this;
}
/**
......@@ -51,7 +54,32 @@ class PoolAction {
//this.getPayments(),
]);
}
async poolsToPool(pool){
var grpc = hii._grpc;
var store = hii._store;
var ret = {
id: pool.id,
cat: 'micro',
type: 'algorand',
icon: pool.bannerPath,
quote: await addAsaQuote(grpc,store,75685483, 0),
banner: pool.bannerPath,
url: 'https://demo1.bitsoko.org',
title: pool.name,
desc: pool.description,
amount: 0,
fee: 0,
confirmations: 5,
status: pool.active ? 'open' : 'closed',
date: parseDate(1604646525),
};
return ret;
}
/**
* List the on-chain transactions by calling the respective grpc api and updating
* the transactions array in the global store.
......@@ -68,23 +96,9 @@ class PoolAction {
var pools = svs.services;
//const pools = (await response.json()).tickers;
//const rate = tickers.find(t => t.ticker.toLowerCase() === fiat).rate;
var quote = await this.addQuote;
this._store.pools = pools.map(pool => ({
id: pool.id,
cat: 'micro',
type: 'algorand',
icon: pool.bannerPath,
banner: pool.bannerPath,
url: 'https://demo1.bitsoko.org',
title: pool.name,
desc: pool.description,
amount: 0,
fee: 0,
confirmations: 5,
status: pool.active ? 'open' : 'closed',
date: parseDate(1604646525),
}));
this._store.pools = await Promise.all(pools.map(await this.poolsToPool));
} catch (err) {
log.error('Listing transactions failed', err);
......
import React from 'react';
import Svg, { Path } from '../../component/svg';
const Bits = props => (
<Svg viewBox="0 0 512 512" width="1em" height="1em" {...props}><Path d="M252.2 10.2c-.5 1.8-4.4 17.6-8.8 35.1l-7.9 31.8-3-.7c-1.6-.3-20.9-5-42.7-10.5-21.8-5.4-40.1-9.9-40.6-9.9-1 0-12.5 46-11.7 46.8.2.2 8.3 2.4 18 4.8 19.6 4.8 25.1 7.3 29.2 13.5 5.2 7.9 5.7 5.2-20.6 111.4-18.1 72.5-24.7 97.9-26.5 100.6-2.4 3.6-7.8 6.9-11.3 6.9-1.1 0-10-2-19.7-4.4l-17.8-4.4-1.3 3.2c-.7 1.7-5.6 13-10.9 25.1-5.2 12.1-9.4 22-9.3 22.2.1.1 19.4 5 42.7 10.8 23.4 5.8 42.8 10.9 43.2 11.3.4.4-3.3 16.6-8.2 36-5.9 23.9-8.4 35.5-7.6 35.7 2 .8 41.5 10.5 42.3 10.5.5 0 4.7-15.3 9.3-34.1 4.7-18.7 8.8-34.6 9.2-35.2.4-.7 5.8.3 16.3 3.1 8.7 2.2 16 4.3 16.2 4.6.3.3-3.3 16.1-8.1 35.2s-8.5 34.8-8.4 35c.8.7 41.3 10.5 42.6 10.2 1.2-.2 3.8-9.3 10.3-35.1 4.8-19.2 8.8-35 9-35.1.2-.2 6.9.7 14.9 2 18.2 3 46.7 4.2 59.5 2.5 34.9-4.6 56.7-19.4 71.3-48.6 15.1-30.3 17.5-63.2 6.2-84.3-6.5-12.2-18.8-24.5-32-31.9-2.7-1.5-5-3-5-3.4 0-.3 3-1.5 6.8-2.7 28.2-9.1 46.2-37.4 46.4-72.7.1-13.8-1.4-21.2-6.8-32-9.7-19.8-31.5-36.6-64.7-50.1-7.3-3-13.7-5.4-14.3-5.4-.7 0 2.2-13.6 7.7-35.3 4.8-19.3 8.5-35.5 8.1-35.8-.9-.8-43.2-11.3-43.5-10.8-.2.2-4 15.7-8.7 34.4l-8.4 34.1-16.5-3.9c-9.1-2.1-16.7-4-16.8-4.1-.1-.1 3.6-15.2 8.2-33.6 4.7-18.4 8.5-34 8.5-34.6 0-1-38.7-11.4-42.4-11.4-.8 0-1.9 1.5-2.4 3.2zm55.4 189.9c-5.7 26.6-10.4 48.5-10.3 48.6.1 0 14.5 3.2 31.9 7 17.5 3.7 31.8 7.1 31.8 7.5 0 .4-27 25.7-60 56.3-33 30.5-60 54.9-60 54.2 0-.8 4.5-22.2 10-47.7 5.5-25.4 10-46.9 10-47.8 0-1.4-5.4-2.8-30.3-8.1-16.6-3.6-31-6.7-32-7.1-1.5-.5 10.8-12.3 58.3-56.4 33.1-30.6 60.4-55.5 60.6-55.3.3.2-4.3 22.2-10 48.8z" fill="#FFF"/></Svg>
);
export default Bits;
......@@ -3,6 +3,8 @@ import * as algosdk from "algosdk";
import * as config from "./algo-config.js";
import store from '../store';
const Algorand = {
status: {
PENDING: 0,
......@@ -135,6 +137,37 @@ const Algorand = {
} catch (err) {
return await Algorand.checkTxStatus(network, txId);
}
},
checkPoolStatus: async (network, txId, aID1, aID2, addr) => {
try {
var poolObject = await Algorand.getClient(network).pendingTransactionInformation(
txId
);
console.log(poolObject);
return poolObject;
} catch (err) {
return await Algorand.checkTxStatus(network, txId);
}
},
checkAccountStatus: async (network, txId, aID1, aID2, addr) => {
try {
var poolObject = await Algorand.getClient(network).pendingTransactionInformation(
txId
);
console.log(poolObject);
return poolObject;
} catch (err) {
return await Algorand.checkTxStatus(network, txId);
}
}
};
......
import * as algosdk from "algosdk";
import * as config from "./algo-config.js";
import store from '../../store';
const Algorand = {
status: {
PENDING: 0,
SUCCESS: 1,
FAILED: 2
},
isValidAddress: address => {
return algosdk.isValidAddress(address);
},
getClient: network => {
let token = {
"X-Algo-API-Token": store.chains.algo.rpc[network].key
};
if (store.chains.algo.rpc[network].server.search("purestake") >= 0) {
token = {
"X-API-Key": store.chains.algo.rpc[network].key
};
}
return new algosdk.Algod(
token,
store.chains.algo.rpc[network].server,
store.chains.algo.rpc[network].port
);
},
getClientForTx: network => {
let token = {
"X-API-Key": store.chains.algo.rpc[network].key,
"Content-Type": "application/x-binary"
};
return new algosdk.Algod(
token,
store.chains.algo.rpc[network].server,
store.chains.algo.rpc[network].port
);
},
createWallet: () => {
const key = algosdk.generateAccount();
const mnemonic = algosdk.secretKeyToMnemonic(key.sk);
return { address: key.addr, mnemonic, sk: key.sk };
},
getWallet: mnemonic => {
const key = algosdk.mnemonicToSecretKey(mnemonic);
if (!algosdk.isValidAddress(key.addr)) {
throw new Error("Invalid wallet mnemonic!");
}
return { address: key.addr, mnemonic, sk: key.sk };
},
getAccount: async (network, address) => {
return await Algorand.getClient(network).accountInformation(address);
},
createTransaction: async (network, { to, amount, memo, date }) => {
let tx = await Algorand.getClient(network).getTransactionParams();
tx.to = to;
tx.amount = Number(amount) * Math.pow(10, 6); // convert to micro-algos.
tx.genesisHash = tx.genesishashb64;
const now = new Date().getTime();
let lastRound = tx.lastRound;
// Transaction to be processed in the future.
if (date.getTime() > now) {
// 1 block per 4.5s.
const seconds = (date.getTime() - now) / 1000;
const blocks = Math.ceil(seconds / 4.5);
tx.firstRound = lastRound + blocks;
tx.lastRound = lastRound + blocks + parseInt(1000);
console.log(`Need to wait for ${blocks} blocks`);
} else {
tx.firstRound = lastRound;
tx.lastRound = lastRound + parseInt(1000);
}
if (memo !== undefined) {
tx.note = algosdk.encodeObj(memo);
}
return tx;
},
sendTransaction: async (network, tx, secretKey) => {
try {
let txParams = await Algorand.getClient(network).getTransactionParams();
let lastRound = txParams.lastRound;
if (tx.firstRound <= lastRound && lastRound <= tx.lastRound) {
const signedTx = algosdk.signTransaction(tx, secretKey);
const txResponse = await Algorand.getClientForTx(
network
).sendRawTransaction(signedTx.blob);
console.log(`Sent the transaction: ${txResponse.txId}`);
await Algorand.checkTxStatus(network, txResponse.txId);
return txResponse.txId;
}
// wait for atleast 4.5 seconds and try again.
await Algorand.sleep(4500);
} catch (err) {
console.log(err);
console.log("Failed to make an algorand transaction!");
}
return await Algorand.sendTransaction(network, tx, secretKey);
},
sleep: ms => {
return new Promise(resolve => setTimeout(resolve, ms));
},
checkTxStatus: async (network, txId) => {
try {
return await Algorand.getClient(network).pendingTransactionInformation(
txId
);
} catch (err) {
return await Algorand.checkTxStatus(network, txId);
}
},
checkPoolStatus: async (network, txId, aID1, aID2, addr) => {
try {
var poolObject = await Algorand.getClient(network).pendingTransactionInformation(
txId
);
console.log(poolObject);
return poolObject;
} catch (err) {
return await Algorand.checkTxStatus(network, txId);
}
}
};
export default Algorand;
import base64
from os import name
import algosdk
from algosdk.future.transaction import ApplicationOptInTxn, PaymentTxn, AssetCreateTxn, AssetOptInTxn
from algosdk.v2client.algod import AlgodClient
from tinyman.utils import int_to_bytes, TransactionGroup
from contracts import get_pool_logicsig
import sys
def prepare_bootstrap_transactions(validator_app_id, asset1_id, asset2_id, asset1_unit_name, asset2_unit_name, sender, suggested_params):
pool_logicsig = get_pool_logicsig(validator_app_id, asset1_id, asset2_id)
pool_address = pool_logicsig.address()
assert(asset1_id > asset2_id)
if asset2_id == 0:
asset2_unit_name = 'ALGO'
txns = [
PaymentTxn(
sender=sender,
sp=suggested_params,
receiver=pool_address,
amt=961000 if asset2_id > 0 else 860000,
note='fee',
),
ApplicationOptInTxn(
sender=pool_address,
sp=suggested_params,
index=validator_app_id,
app_args=['bootstrap', int_to_bytes(asset1_id), int_to_bytes(asset2_id)],
foreign_assets=[asset1_id] if asset2_id == 0 else [asset1_id, asset2_id],
),
AssetCreateTxn(
sender=pool_address,
sp=suggested_params,
total=0xFFFFFFFFFFFFFFFF,
decimals=6,
unit_name='TMPOOL11',
asset_name=f'TinymanPool1.1 {asset1_unit_name}-{asset2_unit_name}',
url='https://tinyman.org',
default_frozen=False,
),
AssetOptInTxn(
sender=pool_address,
sp=suggested_params,
index=asset1_id,
),
]
if asset2_id > 0:
txns += [
AssetOptInTxn(
sender=pool_address,
sp=suggested_params,
index=asset2_id,
)
]
txn_group = TransactionGroup(txns)
txn_group.sign_with_logicisg(pool_logicsig)
return txn_group
import base64
from os import name
import algosdk
from algosdk.future.transaction import ApplicationNoOpTxn, PaymentTxn, AssetTransferTxn
from tinyman.utils import TransactionGroup
from contracts import get_pool_logicsig
def prepare_burn_transactions(validator_app_id, asset1_id, asset2_id, liquidity_asset_id, asset1_amount, asset2_amount, liquidity_asset_amount, sender, suggested_params):
pool_logicsig = get_pool_logicsig(validator_app_id, asset1_id, asset2_id)
pool_address = pool_logicsig.address()
txns = [
PaymentTxn(
sender=sender,
sp=suggested_params,
receiver=pool_address,
amt=3000,
note='fee',
),
ApplicationNoOpTxn(
sender=pool_address,
sp=suggested_params,
index=validator_app_id,
app_args=['burn'],
accounts=[sender],
foreign_assets=[asset1_id, liquidity_asset_id] if asset2_id == 0 else [asset1_id, asset2_id, liquidity_asset_id],
),
AssetTransferTxn(
sender=pool_address,
sp=suggested_params,
receiver=sender,
amt=int(asset1_amount),
index=asset1_id,
),
AssetTransferTxn(
sender=pool_address,
sp=suggested_params,
receiver=sender,
amt=int(asset2_amount),
index=asset2_id,
) if asset2_id != 0 else PaymentTxn(
sender=pool_address,
sp=suggested_params,
receiver=sender,
amt=int(asset2_amount),
),
AssetTransferTxn(
sender=sender,
sp=suggested_params,
receiver=pool_address,
amt=int(liquidity_asset_amount),
index=liquidity_asset_id,
),
]
txn_group = TransactionGroup(txns)
txn_group.sign_with_logicisg(pool_logicsig)
return txn_group
import json
from base64 import b64decode
from algosdk.v2client.algod import AlgodClient
from algosdk.error import AlgodHTTPError
from algosdk.encoding import encode_address
from tinyman.utils import wait_for_confirmation
from tinyman.assets import Asset, AssetAmount
from optin import prepare_app_optin_transactions,prepare_asset_optin_transactions
from constants import TESTNET_VALIDATOR_APP_ID, MAINNET_VALIDATOR_APP_ID
class TinymanClient:
def __init__(self, algod_client: AlgodClient, validator_app_id: int, user_address=None):
self.algod = algod_client
self.validator_app_id = validator_app_id
self.assets_cache = {}
self.user_address = user_address
def fetch_pool(self, asset1, asset2, fetch=True):
from .pools import Pool
return Pool(self, asset1, asset2, fetch=fetch)
def fetch_asset(self, asset_id):
return Asset(asset_id)
if asset_id not in self.assets_cache:
asset = Asset(asset_id)
asset.fetch(self.algod)
self.assets_cache[asset_id] = asset
return self.assets_cache[asset_id]
def submit(self, transaction_group, wait=False):
txid = self.algod.send_transactions(transaction_group.signed_transactions)
if wait:
return wait_for_confirmation(self.algod, txid)
return {'txid': txid}
def prepare_app_optin_transactions(self, user_address=None):
user_address = user_address or self.user_address
suggested_params = self.algod.suggested_params()
txn_group = prepare_app_optin_transactions(
validator_app_id=self.validator_app_id,
sender=user_address,
suggested_params=suggested_params,
)
return txn_group
def prepare_asset_optin_transactions(self, asset_id, user_address=None):
user_address = user_address or self.user_address
suggested_params = self.algod.suggested_params()
txn_group = prepare_asset_optin_transactions(
asset_id=asset_id,
sender=user_address,
suggested_params=suggested_params,
)
return txn_group
def fetch_excess_amounts(self, user_address=None):
user_address = user_address or self.user_address
account_info = self.algod.account_info(user_address)
try:
validator_app = [a for a in account_info['apps-local-state'] if a['id'] == self.validator_app_id][0]
except IndexError:
return {}
try:
validator_app_state = {x['key']: x['value'] for x in validator_app['key-value']}
except KeyError:
return {}
pools = {}
for key in validator_app_state:
b = b64decode(key.encode())
if b[-9:-8] == b'e':
value = validator_app_state[key]['uint']
pool_address = encode_address(b[:-9])
pools[pool_address] = pools.get(pool_address, {})
asset_id = int.from_bytes(b[-8:], 'big')
asset = self.fetch_asset(asset_id)
pools[pool_address][asset] = AssetAmount(asset, value)
return pools
def is_opted_in(self, user_address=None):
user_address = user_address or self.user_address
account_info = self.algod.account_info(user_address)
for a in account_info.get('apps-local-state', []):
if a['id'] == self.validator_app_id:
return True
return False
def asset_is_opted_in(self, asset_id, user_address=None):
user_address = user_address or self.user_address
account_info = self.algod.account_info(user_address)
for a in account_info.get('assets', []):
if a['asset-id']==asset_id:
return True
return False
class TinymanTestnetClient(TinymanClient):
def __init__(self, algod_client=None, user_address=None):
if algod_client is None:
algod_client = AlgodClient('', 'https://api.testnet.algoexplorer.io', headers={'User-Agent': 'algosdk'})
super().__init__(algod_client, validator_app_id=TESTNET_VALIDATOR_APP_ID, user_address=user_address)
class TinymanMainnetClient(TinymanClient):
def __init__(self, algod_client=None, user_address=None):
if algod_client is None:
algod_client = AlgodClient('', 'https://api.algoexplorer.io', headers={'User-Agent': 'algosdk'})
super().__init__(algod_client, validator_app_id=MAINNET_VALIDATOR_APP_ID, user_address=user_address)
BOOTSTRAP_APP_ARGUMENT = "Ym9vdHN0cmFw"
BURN_APP_ARGUMENT = "YnVybg=="
MINT_APP_ARGUMENT = "bWludA=="
REDEEM_APP_ARGUMENT = "cmVkZWVt"
SWAP_APP_ARGUMENT = "c3dhcA=="
TESTNET_VALIDATOR_APP_ID_V1_0 = 21580889
TESTNET_VALIDATOR_APP_ID_V1_1 = 62368684
MAINNET_VALIDATOR_APP_ID_V1_0 = 350338509
MAINNET_VALIDATOR_APP_ID_V1_1 = 552635992
TESTNET_VALIDATOR_APP_ID = TESTNET_VALIDATOR_APP_ID_V1_1
MAINNET_VALIDATOR_APP_ID = MAINNET_VALIDATOR_APP_ID_V1_1
import json
import importlib.resources
from algosdk.future.transaction import LogicSig
import tinyman.v1
from tinyman.utils import get_program
_contracts = json.loads(importlib.resources.read_text(tinyman.v1, 'asc.json'))
pool_logicsig_def = _contracts['contracts']['pool_logicsig']['logic']
validator_app_def = _contracts['contracts']['validator_app']
def get_pool_logicsig(validator_app_id, asset1_id, asset2_id):
assets = [asset1_id, asset2_id]
asset_id_1 = max(assets)
asset_id_2 = min(assets)
program_bytes = get_program(pool_logicsig_def, variables=dict(
validator_app_id=validator_app_id,
asset_id_1=asset_id_1,
asset_id_2=asset_id_2,
))
return LogicSig(program=program_bytes)
import base64
from os import name
import algosdk
from algosdk.future.transaction import ApplicationNoOpTxn, PaymentTxn, AssetTransferTxn
from tinyman.utils import TransactionGroup
from contracts import get_pool_logicsig
def prepare_redeem_fees_transactions(validator_app_id, asset1_id, asset2_id, liquidity_asset_id, amount, creator, sender, suggested_params):
pool_logicsig = get_pool_logicsig(validator_app_id, asset1_id, asset2_id)
pool_address = pool_logicsig.address()
txns = [
PaymentTxn(
sender=sender,
sp=suggested_params,
receiver=pool_address,
amt=2000,
note='fee',
),
ApplicationNoOpTxn(
sender=pool_address,
sp=suggested_params,
index=validator_app_id,
app_args=['fees'],
foreign_assets=[asset1_id, liquidity_asset_id] if asset2_id == 0 else [asset1_id, asset2_id, liquidity_asset_id],
),
AssetTransferTxn(
sender=pool_address,
sp=suggested_params,
receiver=creator,
amt=int(amount),
index=liquidity_asset_id,
)
]
txn_group = TransactionGroup(txns)
txn_group.sign_with_logicisg(pool_logicsig)
return txn_group
import base64
from os import name
import algosdk
from algosdk.future.transaction import ApplicationNoOpTxn, PaymentTxn, AssetTransferTxn
from tinyman.utils import TransactionGroup
from contracts import get_pool_logicsig
def prepare_mint_transactions(validator_app_id, asset1_id, asset2_id, liquidity_asset_id, asset1_amount, asset2_amount, liquidity_asset_amount, sender, suggested_params):
pool_logicsig = get_pool_logicsig(validator_app_id, asset1_id, asset2_id)
pool_address = pool_logicsig.address()
txns = [
PaymentTxn(
sender=sender,
sp=suggested_params,
receiver=pool_address,
amt=2000,
note='fee',
),
ApplicationNoOpTxn(
sender=pool_address,
sp=suggested_params,
index=validator_app_id,
app_args=['mint'],
accounts=[sender],
foreign_assets=[asset1_id, liquidity_asset_id] if asset2_id == 0 else [asset1_id, asset2_id, liquidity_asset_id],
),
AssetTransferTxn(
sender=sender,
sp=suggested_params,
receiver=pool_address,
amt=int(asset1_amount),
index=asset1_id,
),
AssetTransferTxn(
sender=sender,
sp=suggested_params,
receiver=pool_address,
amt=int(asset2_amount),
index=asset2_id,
) if asset2_id != 0 else PaymentTxn(
sender=sender,
sp=suggested_params,
receiver=pool_address,
amt=int(asset2_amount),
),
AssetTransferTxn(
sender=pool_address,
sp=suggested_params,
receiver=sender,
amt=int(liquidity_asset_amount),
index=liquidity_asset_id,
),
]
txn_group = TransactionGroup(txns)
txn_group.sign_with_logicisg(pool_logicsig)
return txn_group
import base64
import algosdk
from algosdk.future.transaction import ApplicationOptInTxn, AssetOptInTxn
from algosdk.v2client.algod import AlgodClient
from tinyman.utils import TransactionGroup
def prepare_app_optin_transactions(validator_app_id, sender, suggested_params):
txn = ApplicationOptInTxn(
sender=sender,
sp=suggested_params,
index=validator_app_id,
)
txn_group = TransactionGroup([txn])
return txn_group
def prepare_asset_optin_transactions(asset_id, sender, suggested_params):
txn = AssetOptInTxn(
sender=sender,
sp=suggested_params,
index=asset_id,
)
txn_group = TransactionGroup([txn])
return txn_group
from tinyman.v1.client import TinymanTestnetClient
from algosdk import mnemonic
import logging
logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.debug(mnemonic)
import sys
import re
#split string by single space
#mnem = re.split(' +', mnemonic)
# Hardcoding account keys is not a great practice. This is for demonstration purposes only.
# See the README & Docs for alternative signing methods.
account = {
# 'address': sys.argv[1],
'address': 'TTNTINGI6AKN6JBHCAOXVFZN72BAMDNBTHZ3ZRQC3ILAMWONKN7XRRQ6GM',
# 'private_key': mnem.split(' ').to_private_key(sys.argv[1]),
}
client = TinymanTestnetClient(user_address=account['address'])
# By default all subsequent operations are on behalf of user_address
# Fetch our two assets of interest
#ASA = client.fetch_asset(int(sys.argv[3]))
ASA = client.fetch_asset(69855411)
ALGO = client.fetch_asset(0)
# Fetch the pool we will work with
pool = client.fetch_pool(ASA, ALGO)
info = pool.fetch_pool_position()
share = info['share'] * 100
print(f'Pool Tokens: {info[pool.liquidity_asset]}')
print(f'Assets: {info[ASA]}, {info[ALGO]}')
print(f'Share of pool: {share:.3f}%')
This diff is collapsed.
import base64
from os import name
import algosdk
from algosdk.future.transaction import ApplicationNoOpTxn, PaymentTxn, AssetTransferTxn
from tinyman.utils import TransactionGroup
from contracts import get_pool_logicsig
def prepare_redeem_transactions(validator_app_id, asset1_id, asset2_id, liquidity_asset_id, asset_id, asset_amount, sender, suggested_params):
pool_logicsig = get_pool_logicsig(validator_app_id, asset1_id, asset2_id)
pool_address = pool_logicsig.address()
txns = [
PaymentTxn(
sender=sender,
sp=suggested_params,
receiver=pool_address,
amt=2000,
note='fee',
),
ApplicationNoOpTxn(
sender=pool_address,
sp=suggested_params,
index=validator_app_id,
app_args=['redeem'],
accounts=[sender],
foreign_assets=[asset1_id, liquidity_asset_id] if asset2_id == 0 else [asset1_id, asset2_id, liquidity_asset_id],
),
AssetTransferTxn(
sender=pool_address,
sp=suggested_params,
receiver=sender,
amt=int(asset_amount),
index=asset_id,
) if asset_id != 0 else PaymentTxn(
sender=pool_address,
sp=suggested_params,
receiver=sender,
amt=int(asset_amount),
),
]
txn_group = TransactionGroup(txns)
txn_group.sign_with_logicisg(pool_logicsig)
return txn_group
import base64
from os import name
import algosdk
from algosdk.future.transaction import ApplicationNoOpTxn, PaymentTxn, AssetTransferTxn
from tinyman.utils import TransactionGroup
from contracts import get_pool_logicsig
def prepare_swap_transactions(validator_app_id, asset1_id, asset2_id, liquidity_asset_id, asset_in_id, asset_in_amount, asset_out_amount, swap_type, sender, suggested_params):
pool_logicsig = get_pool_logicsig(validator_app_id, asset1_id, asset2_id)
pool_address = pool_logicsig.address()
swap_types = {
'fixed-input': 'fi',
'fixed-output': 'fo',
}
asset_out_id = asset2_id if asset_in_id == asset1_id else asset1_id
txns = [
PaymentTxn(
sender=sender,
sp=suggested_params,
receiver=pool_address,
amt=2000,
note='fee',
),
ApplicationNoOpTxn(
sender=pool_address,
sp=suggested_params,
index=validator_app_id,
app_args=['swap', swap_types[swap_type]],
accounts=[sender],
foreign_assets=[asset1_id, liquidity_asset_id] if asset2_id == 0 else [asset1_id, asset2_id, liquidity_asset_id],
),
AssetTransferTxn(
sender=sender,
sp=suggested_params,
receiver=pool_address,
amt=int(asset_in_amount),
index=asset_in_id,
) if asset_in_id != 0 else PaymentTxn(
sender=sender,
sp=suggested_params,
receiver=pool_address,
amt=int(asset_in_amount),
),
AssetTransferTxn(
sender=pool_address,
sp=suggested_params,
receiver=sender,
amt=int(asset_out_amount),
index=asset_out_id,
) if asset_out_id != 0 else PaymentTxn(
sender=pool_address,
sp=suggested_params,
receiver=sender,
amt=int(asset_out_amount),
),
]
txn_group = TransactionGroup(txns)
txn_group.sign_with_logicisg(pool_logicsig)
return txn_group
......@@ -27,8 +27,8 @@ import * as solana from '@solana/web3.js';
*/
import * as config from "./algo-config.js";
import store from '../store';
//import * as config from "./../algo-config.js";
import store from '../../store';
const Solana = {
status: {
......
......@@ -7,7 +7,7 @@ import {
} from 'react-native';
import PropTypes from 'prop-types';
import { color, font } from './style';
import BitcoinIcon from '../../src/asset/icon/bitcoin';
import BitsIcon from '../../src/asset/icon/bits';
import Text from './text';
import Svg, { Path, Circle, Defs, Stop, LinearGradient } from './svg';
import { generateArc } from '../helper';
......@@ -54,7 +54,7 @@ export const LoadNetworkSpinner = ({ continuous, percentage, msg, style }) => (
gradient="loadNetworkGrad"
>
<BitcoinIcon height={38} width={25} />
<BitsIcon height={38} width={25} />
</ResizeableSpinner>
<Text style={loadNetworkStyles.copy}>{msg}</Text>
</View>
......
......@@ -3,7 +3,8 @@
*/
import { extendObservable } from 'mobx';
import { toAmountLabel, toCaps } from '../helper';
import { toAmountLabel, toCaps, parseDate } from '../helper';
const ComputedPool = store => {
extendObservable(store, {
......@@ -17,14 +18,16 @@ const ComputedPool = store => {
all.forEach((t, i) => {
t.key = String(i);
//t.idName = t.type === 'algorand' ? '209:BITS:dooca-net' : 'Ethereum';
t.idName = t.id+':BITS:dooca.net | '+t.title;
t.idName = t.id+':BITS:MSM-1:POOL | '+t.title;
t.icon = t.icon;
t.typeLabel = toCaps(t.type);
t.statusLabel = toCaps(t.status);
t.merchantLabel = t.title;
//t.quote = addQuote(t.aID, 0);
t.dateLabel = t.date.toLocaleDateString();
t.dateTimeLabel = t.date.toLocaleString();
t.amountLabel = toAmountLabel(t.amount, settings);
t.amountLabel = JSON.stringify(t.quote);
t.share = toAmountLabel(t.amount, settings);
t.raised = toAmountLabel(0, settings);
if (Number.isInteger(t.confirmations)) {
t.confirmationsLabel = t.confirmations.toString();
......
......@@ -140,6 +140,17 @@ export const toAmountLabel = (satoshis, settings) => {
: formatNumber(toAmount(satoshis, settings));
};
export const addAsaQuote = async (grpc, store, aID1, aID2) => {
var quote = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'quote', aID1, aID2 ]);
var q = quote.split("'")[1].split("'")[0];
var ql = toAmountLabel(parseInt((1/parseInt(q))*1000000),store.settings);
return ql;
}
/**
* Convert a string formatted btc/fiat amount either to fiat or the selected BTC unit.
* The output should be used throughout the UI for value labels.
......
......@@ -93,7 +93,7 @@ export class Store {
closedChannels: [],
selectedChannel: null,
channel: {
pubkeyAtHost: '03fc96e4e90cbc3f3b57548b0693b77c34ac696a125fe1158aaa9cf3752498fe63@170.75.163.101:9735',
pubkeyAtHost: '035e4ff418fc8b5554c5d9eea66396c227bd429a3251c8cbc711002ba215bfc226@170.75.163.209:9735',
amount: '20000',
},
paymentRequest: null,
......
......@@ -271,7 +271,7 @@ const HomeHeader = ({ isTestnet, goDeposit, goSettings, goGovern }) => (
<Button onPress={goGovern}>
<View>
{isTestnet ? (
<Title style={headerStyles.testnet} title="BETA v0.6.2" />
<Title style={headerStyles.testnet} title="BETA v0.7.8" />
) : null}
<Title title="Bits" />
</View></Button>
......
......@@ -26,6 +26,7 @@ import PoolAddLiquid from './pool-add-liquid';
import PayPoolConfirm from './pay-pool-confirm';
import PayLightningConfirm from './pay-lightning-confirm';
import PayLightningDone from './pay-lightning-done';
import PayPoolDone from './pay-pool-done';
import PaymentFailed from './payment-failed';
import PayBitcoin from './pay-bitcoin';
import PayBitcoinConfirm from './pay-bitcoin-confirm';
......@@ -54,6 +55,7 @@ import TransactionDetail from './transaction-detail';
import PoolDetail from './pool-detail';
import PromotionDetail from './promotion-detail';
import {
grpc,
nav,
wallet,
payment,
......@@ -153,13 +155,13 @@ class MainView extends Component {
<Payment store={store} payment={payment} nav={nav} />
)}
{route === 'PoolAddLiquid' && (
<PoolAddLiquid store={store} pooladdliq={pooladdliq} nav={nav} />
<PoolAddLiquid grpc={grpc} store={store} pooladdliq={pooladdliq} nav={nav} />
)}
{route === 'PoolRemoveLiquid' && (
<PoolRemoveLiquid store={store} poolremoveliq={poolremoveliq} nav={nav} />
)}
{route === 'PayPoolConfirm' && (
<PayPoolConfirm store={store} payment={payment} nav={nav} />
<PayPoolConfirm grpc={grpc} store={store} payment={payment} nav={nav} />
)}
{route === 'PayLightningConfirm' && (
<PayLightningConfirm store={store} payment={payment} nav={nav} />
......@@ -167,6 +169,9 @@ class MainView extends Component {
{route === 'PayLightningDone' && (
<PayLightningDone payment={payment} nav={nav} />
)}
{route === 'PayPoolDone' && (
<PayPoolDone pool={pool} payment={payment} nav={nav} />
)}
{route === 'PaymentFailed' && (
<PaymentFailed channel={channel} nav={nav} />
)}
......@@ -214,7 +219,7 @@ class MainView extends Component {
<Promotion store={store} promotion={promotion} nav={nav} />
)}
{route === 'Pools' && (
<Pool store={store} pool={pool} nav={nav} />
<Pool grpc={grpc} store={store} pool={pool} nav={nav} />
)}
{route === 'Dao' && (
<Dao store={store} dao={dao} nav={nav} />
......@@ -223,7 +228,7 @@ class MainView extends Component {
<TransactionDetail store={store} nav={nav} />
)}
{route === 'PoolDetail' && (
<PoolDetail store={store} nav={nav} invoice={invoice} pooladdliq={pooladdliq} poolremoveliq={poolremoveliq} />
<PoolDetail store={store} grpc={grpc} nav={nav} invoice={invoice} pooladdliq={pooladdliq} poolremoveliq={poolremoveliq} />
)}
{route === 'PromotionDetail' && (
<PromotionDetail store={store} nav={nav} poolredeemliq={poolredeemliq} />
......
......@@ -18,11 +18,77 @@ import {
BalanceLabelUnit,
} from '../component/label';
import { color } from '../component/style';
import { toSatoshis, toAmount } from '../helper';
ChartJS.register(ArcElement, Tooltip, Legend);
/**
*send BTC to Pool
*
*
*/
async function addToPool(grpc,store,pay,nav) {
const { settings } = store;
var amount = toSatoshis(store.payment.amount, settings);
if(parseFloat(store.settings.chains.algo.account.balance)*100 > (amount*1.01)){
console.log('INFO! sufficient BTC in contract. skipping lightning swap...');
var poolStats = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'swap', 75685483 , 0, 10, store.settings.chains.algo.account.address, store.settings.chains.algo.account.mnemonic, 'add' ]);
console.log(poolStats);
nav.goPayPoolDone();
return true;
} else if ( store.payment.address != '' ) {
//return this._notification.display({ msg: 'INFO! swapping lightning BTC to contract BTC' });
const { payment, settings } = store;
try{
const request = await grpc.sendCommand('decodePayReq', {
payReq: store.payment.address,
});
payment.amount = toAmount(request.numSatoshis, settings);
payment.note = request.description;
/* */
try{
const { routes } = await grpc.sendCommand('queryRoutes', {
pubKey: request.destination,
amt: request.numSatoshis,
numRoutes: 1,
});
payment.fee = toAmount(routes[0].totalFees, settings);
}catch(er){console.error(er)}
payment.fee = 2;
console.log(payment);
var paymentHash = await pay.payLightning();
console.log(paymentHash);
// then add converted contract satoshis to merchant pool
var poolStats = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'swap', 75685483 , 0, 10, store.settings.chains.algo.account.address, store.settings.chains.algo.account.mnemonic, 'add' ]);
console.log(poolStats);
//this._notification.display({ msg: 'Swap completed!' });
nav.goPayPoolDone();
return true;
}catch(err){
console.error(err);
nav.goPaymentFailed();
}
}
}
const shareData = {
labels: ['Locked', 'Allocated', 'Rewards', 'Others'],
datasets: [
......@@ -74,7 +140,7 @@ const styles = StyleSheet.create({
},
});
const PayPoolConfirmView = ({ store, nav, payment }) => (
const PayPoolConfirmView = ({ grpc, store, nav, payment }) => (
<Background image="purple-gradient-bg">
<Header shadow color={color.purple}>
<BackButton onPress={() => nav.goPoolDetail()} />
......@@ -115,7 +181,9 @@ const PayPoolConfirmView = ({ store, nav, payment }) => (
</FormStretcher>
<PillButton
style={styles.confirmBtn}
onPress={() => payment.payLightning()}
onPress={async function(){
await addToPool(grpc,store,payment,nav);
}}
>
Confirm
</PillButton>
......
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { observer } from 'mobx-react';
import PropTypes from 'prop-types';
import Background from '../component/background';
import MainContent from '../component/main-content';
import { H1Text } from '../component/text';
import { Circle } from '../component/loader';
import { Button, ButtonText, PillButton } from '../component/button';
import { FormStretcher } from '../component/form';
import LightningBoltIcon from '../asset/icon/lightning-bolt';
import BitsIcon from '../../src/asset/icon/bits';
import { color } from '../component/style';
const styles = StyleSheet.create({
circle: {
marginTop: 30,
},
iconWrapper: {
marginRight: 5,
},
doneBtn: {
alignSelf: 'center',
backgroundColor: color.glas,
width: 400,
},
anotherBtn: {
marginTop: 5,
marginBottom: 25,
},
});
const PayPoolDoneView = ({ nav, payment, pool }) => (
<Background image="purple-gradient-bg">
<MainContent>
<FormStretcher>
<H1Text>Payment Sent!</H1Text>
<Circle style={styles.circle}>
<View style={styles.iconWrapper}>
<BitsIcon height={126 * 0.9} width={64 * 0.9} />
</View>
</Circle>
</FormStretcher>
<PillButton onPress={() => nav.goHome()} style={styles.doneBtn}>
Done
</PillButton>
<Button onPress={() => pool.init()} style={styles.anotherBtn}>
<ButtonText>ANOTHER PAYMENT</ButtonText>
</Button>
</MainContent>
</Background>
);
PayPoolDoneView.propTypes = {
nav: PropTypes.object.isRequired,
payment: PropTypes.object.isRequired,
};
export default observer(PayPoolDoneView);
......@@ -67,7 +67,7 @@ const PoolAddLiqView = ({ store, nav, pooladdliq }) => (
Investments will be locked for a minimum lock time as shown on the pool contract. So make sure you are investing in the right merchant.
</FormSubText>
</FormStretcher>
<PillButton onPress={() => pooladdliq.checkType()}>Next</PillButton>
<PillButton onPress={() => pooladdliq.checkType()}>Verify Shares</PillButton>
</Card>
</MainContent>
</Background>
......
......@@ -15,9 +15,14 @@ import { GlasButton, ChannelButton } from '../component/button';
import store from '../store';
import { DEFAULT_FIAT } from '../config';
import Algorand from '../chains/algo/algo.js';
import Icon from '../component/icon';
//import algosdk from "algosdk";
//import { Asset,TinymanMainnetClient } from 'tinyman-ts-sdk';
ChartJS.register(ArcElement, Tooltip, Legend,
CategoryScale,
......@@ -30,7 +35,45 @@ ChartJS.register(ArcElement, Tooltip, Legend,
const labels = ['30', '29', '28', '27', '26', '25', '24', '23', '22', '21', '20', '19', '18', '17', '16', '15', '14', '13', '12', '11', '10', '9', '8', '7', '6', '5', '4', '3', '2', '1'];
/*
async function doSwap(mne){
const MNEMONIC = mne;
const ACCOUNT = algosdk.mnemonicToSecretKey(MNEMONIC);
const WALLET_ADDRESS = ACCOUNT.addr;
const SECRET_KEY = ACCOUNT.sk;
const client = new algosdk.Algodv2('','https://api.algoexplorer.io','',{'user-agent':'algo-sdk'});
//Initialize Tinyman's Mainnet Client
const TinymanClient = new TinymanMainnetClient(client,WALLET_ADDRESS);
//Fetch the Assets from the network
const A1 = await new Asset(0).fetch(client); //ALGO
const A2 = await new Asset(31566704).fetch(client); //USDC
//Get the Pool for this Asset pair
const POOL = await TinymanClient.fetch_pool(A1,A2,true);
//Get a Fixed Input Swap Quote
const FIXED_INPUT_SWAP = await POOL.fetch_fixed_input_swap_quote(A1.AssetAmount(1000000),0.01);
//Prepare the Swap Transactions
const TXNS = await POOL.prepare_swap_transactions(
FIXED_INPUT_SWAP.amount_in_with_slippage(),
FIXED_INPUT_SWAP.amount_out_with_slippage(),
'fixed-input',
WALLET_ADDRESS
);
//Sign the Transactions
TXNS.sign_with_private_key(WALLET_ADDRESS,SECRET_KEY);
//Submit the transactions and wait for confirmation
await TXNS.submit(client,true);
}
*/
function newPoolSize(day){
var size = (faker.datatype.number({ min: 1000, max: 1500 })/(Math.log(10+parseInt(day))*faker.datatype.number({ min: 0.65, max: 0.95 })));
......@@ -55,7 +98,7 @@ export const perfData = {
backgroundColor: 'rgba(255, 99, 132, 0.4)',
},
{
label: 'pool (,000)',
label: 'pool (,00)',
data: labels.map(newPoolSize),
borderColor: 'rgb(53, 162, 235)',
backgroundColor: 'rgba(53, 162, 235, 0.5)',
......@@ -110,7 +153,13 @@ const iconType = t => {
return require('../asset/icon/'+t+'.png');
};
function dataGen(store, options) {
function getPoolShare(type, aID1, aID2, address) {
Algorand.checkPoolStatus()
}
async function dataGen(store, options, grpc) {
perfData.datasets[0].data = labels.map(() => faker.datatype.number({ min: 400, max: 1000 }));
......@@ -121,8 +170,48 @@ const iconType = t => {
options.plugins.title.text = '30d Volume ('+store.settings.fiat.toLowerCase()+')';
/*
var poolStats = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'bootstrap', 70653745, 0, '289:BITS', 'ALGO', 'TTNTINGI6AKN6JBHCAOXVFZN72BAMDNBTHZ3ZRQC3ILAMWONKN7XRRQ6GM' ]);
//poolStats = poolStats.replace(/'/g, '"').replace(/"{/g, "{").slice(0, -3);
console.log(poolStats);
store.selectedPool.stats=JSON.parse(poolStats);
console.log(store.settings.chains.algo.account.address);
var poolStats = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'poolState', 70232824, 0, 'TTNTINGI6AKN6JBHCAOXVFZN72BAMDNBTHZ3ZRQC3ILAMWONKN7XRRQ6GM' ]);
console.log(poolStats);
var poolStats = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'quote', 70232824, 0 ]);
console.log(poolStats);
var poolStats = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'addLiq', 21582668, 0 , store.settings.chains.algo.account.address, store.settings.chains.algo.account.mnemonic, 1]);
console.log(poolStats);
var poolStats = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'swap', 70653745, 0, 1, store.settings.chains.algo.account.address, store.settings.chains.algo.account.mnemonic, 1 ]);
var poolStats = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'addLiq', 70653745, 0 , store.settings.chains.algo.account.address, store.settings.chains.algo.account.mnemonic, 1]);
var poolStats = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'addLiq', 70653745, 0 , store.settings.chains.algo.account.address, store.settings.chains.algo.account.mnemonic, 1]);
*/
// doSwap(store.settings.chains.algo.account.mnemonic);
var poolStats = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'pooling', 75685483 , 0, store.settings.chains.algo.account.address, store.settings.chains.algo.account.mnemonic ]);
console.log(poolStats);
var poolStats = await grpc.initPyface(['/data/lightning-bits/src/chains/algo/pools.py', 'swap', 75685483 , 0, 10, store.settings.chains.algo.account.address, store.settings.chains.algo.account.mnemonic, 'remove' ]);
console.log(poolStats);
}
const options = {
......@@ -137,18 +226,18 @@ const options = {
},
},
};
const PoolDetailView = ({ store, nav, pooladdliq, poolremoveliq}) => (
const PoolDetailView = ({ store, grpc, nav, pooladdliq, poolremoveliq}) => (
<Background color={color.blackDark}>
<MainContent style={styles.content}>
<Modal title={store.selectedPool.idName} onClose={() => nav.goPools()}>
<Line meta={ dataGen(store, options) } options={options} data={perfData} />
<Line meta={ dataGen(store, options, grpc) } options={options} data={perfData} />
<DetailField name={store.selectedPool.title}>
{store.selectedPool.desc}
</DetailField>
<DetailField name="Performance">
VALUATION: 0{DEFAULT_FIAT} | PRICE: 0{DEFAULT_FIAT} | ROI: 0%
VALUATION: {store.selectedPool.quote*1000} | PRICE: {store.selectedPool.quote} | ROI: 0%
</DetailField>
{store.selectedPool.memo ? (
<DetailField name="Note">
......@@ -163,15 +252,7 @@ const PoolDetailView = ({ store, nav, pooladdliq, poolremoveliq}) => (
</DetailField>
{store.selectedPool.confirmationsLabel ? (
<DetailField name="Contract">
POOLERS: {store.selectedPool.confirmationsLabel} | CHAIN: {store.selectedPool.typeLabel}
</DetailField>
) : null}
<DetailField name="Status">
{store.selectedPool.statusLabel}
</DetailField>
{store.selectedPool.preimage ? (
<DetailField name="Proof of Payment">
{store.selectedPool.preimage}
POOLERS: {store.selectedPool.confirmationsLabel} | CHAIN: {store.selectedPool.typeLabel} | Lock Time: 30 Days
</DetailField>
) : null}
......
......@@ -170,7 +170,7 @@ const poolStyles = StyleSheet.create({
margin: 10,
},
});
const PoolView = ({ store, nav, pool, goPoolAdd }) => {
const PoolView = ({ store, nav, pool, grpc, goPoolAdd }) => {
const { computedPools: pools,
poolBalanceOpenLabel,
poolBalanceClosingLabel,
......@@ -223,6 +223,7 @@ PoolView.propTypes = {
store: PropTypes.object.isRequired,
nav: PropTypes.object.isRequired,
pool: PropTypes.object.isRequired,
grpc: PropTypes.object.isRequired,
goPoolAdd: PropTypes.object.isRequired,
};
......@@ -303,11 +304,13 @@ const PoolListItem = ({ tx, onSelect }) => (
<Text style={iStyles.txt}>{tx.statusLabel}</Text>
</View>
<Text style={[iStyles.m, iStyles.txt]}>{tx.Label}</Text>
<View style={iStyles.l}>
<Text style={[iStyles.txt, iStyles.wrap]} numberOfLines={1}>
{tx.merchantLabel}
</Text>
</View>
<Text style={[iStyles.m, iStyles.txt]}>{tx.share}</Text>
<Text style={[iStyles.m, iStyles.txt]}>{tx.amountLabel}</Text>
<Text style={[iStyles.s, iStyles.txt]}>{tx.raised}</Text>
</ListItem>
......@@ -338,8 +341,9 @@ const PoolListHeader = () => (
<Text style={[iStyles.m, hStyles.txt]}>STATUS</Text>
<Text style={[iStyles.m, hStyles.txt]}>CAP</Text>
<Text style={[iStyles.l, hStyles.txt]}>MERCHANT</Text>
<Text style={[iStyles.m, hStyles.txt]}>% SHARE</Text>
<Text style={[iStyles.s, hStyles.txt]}>REWARDS</Text>
<Text style={[iStyles.l, hStyles.txt]}>SHARE</Text>
<Text style={[iStyles.m, hStyles.txt]}>PRICE</Text>
<Text style={[iStyles.s, hStyles.txt]}>% CHANGE</Text>
</ListHeader>
);
......
......@@ -13,6 +13,7 @@ import Text from '../component/text';
import LightningBoltIcon from '../../src/asset/icon/lightning-bolt';
import CopyDarkIcon from '../../src/asset/icon/copy-dark';
import BitcoinIcon from '../../src/asset/icon/bitcoin';
import BitsIcon from '../../src/asset/icon/bits';
import Icon from '../component/icon';
......@@ -98,9 +99,9 @@ const ContractSummary = ({
<View style={summaryStyles.wrapper}>
<View style={summaryStyles.box}>
<Alert type="success" style={summaryStyles.alert} />
<Text style={summaryStyles.txt}>Uptime</Text>
<Text style={summaryStyles.txt}>Gas fees</Text>
<Text style={[summaryStyles.txt, summaryStyles.total]}>
365 Days
0.001 (low)
</Text>
</View>
<View style={summaryStyles.box}>
......@@ -108,9 +109,9 @@ const ContractSummary = ({
<BitcoinIcon />
</View>
<Text style={summaryStyles.txt}> ID</Text>
<Text style={summaryStyles.txt}>ID</Text>
<Text style={[summaryStyles.txt, summaryStyles.total]}>
1456789
1942776
</Text>
</View>
</View>
......@@ -159,17 +160,32 @@ const SetContractView = ({ store, nav, setting, invoice }) => {
<Button style={summaryStyles.topBtn}>
<Title style={summaryStyles.poolInfo, summaryStyles.topPad} title="Algorand" />
<Icon
image={require('../asset/icon/algorand.png')}
style={summaryStyles.topIcon}
/>
<Title style={summaryStyles.poolInfo} title="Algorand" />
<Title style={summaryStyles.poolInfo} title="https://algorand.org" />
<Title style={summaryStyles.poolInfo} title="https://algorand.com" />
<CopyText style={summaryStyles.copyTxtX}>
A world where everyone creates and exchanges value efficiently, transparently, and securely.
</CopyText>
<View style={summaryStyles.wrapper}>
<View style={summaryStyles.box}>
<View style={summaryStyles.alert}>
<Alert type="success" style={summaryStyles.alert} />
</View>
<Text style={summaryStyles.txt}> Balance</Text>
<Text style={[summaryStyles.txt, summaryStyles.total]}>
{store.settings.chains.algo.account.balance}
</Text>
</View>
</View>
<ContractSummary style={summaryStyles.btnWrapper}
poolBalanceOpenLabel=""
poolBalanceClosingLabel=""
......@@ -182,6 +198,7 @@ const SetContractView = ({ store, nav, setting, invoice }) => {
unitLabel={store.settings.chains.algo.account.address}
/>
<View style={summaryStyles.wrapper}>
<View style={summaryStyles.box}>
<View style={summaryStyles.alert}>
......@@ -193,11 +210,21 @@ const SetContractView = ({ store, nav, setting, invoice }) => {
0.00001
</Text>
</View>
</View>
<ContractBalances style={summaryStyles.btnWrapper}
balanceLabel="Assets"
unitLabel="0"
/>
<View style={summaryStyles.wrapper}>
<View style={summaryStyles.box}>
<View style={summaryStyles.alert}>
<BitsIcon />
</View>
<Text style={summaryStyles.txt}>Assets</Text>
<Text style={[summaryStyles.txt, summaryStyles.total]}>
0
</Text>
</View>
</View>
<CopyText style={summaryStyles.copyTxtX}>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment