Skip to content
This repository has been archived by the owner on Nov 13, 2020. It is now read-only.

Commit

Permalink
Local Mode (#7)
Browse files Browse the repository at this point in the history
* Print SwapRequest msg with --local flag

* Add switch in case of --local for prompt output amount

* Add swap accept command

* Types

* Add swap accept and swap complete commands and test local flow e2e

* Readme
  • Loading branch information
tiero authored Mar 29, 2020
1 parent 05cffd8 commit 8ac5261
Show file tree
Hide file tree
Showing 9 changed files with 368 additions and 51 deletions.
89 changes: 81 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,72 @@ Wallet CLI for making swaps on TDEX

## Usage

* Install
### Install

* Install from NPM
```sh
$ npm install -g tdex-cli
```

* Configure custom directory for data persistence (Default ~/.tdex)

```sh
$ export TDEX_CLI_PATH=/path/to/data/dir
$ tdex-cli help
```
### Network

* Set the network to work against

> NOTICE With the --explorer flag you can set a different electrum REST server (eg. Blockstream/electrs) for connecting to the blockchain
```sh
# Mainnet
$ tdex-cli netwrok liquid
# Public regtest Nigiri
$ tdex-cli netwrok regtest
# Local Nigiri or Electrum REST server
$ tdex-cli network regtest --explorer localhost:3001
```

### Info

* Show current persisted state

```sh
$ tdex-cli info
```

### Provider

* Connect to a liquidity provider

```sh
$ tdex-cli connect https://tdex.vulpem.com
```

### Market

* List all available markets for current provider

```sh
$ tdex-cli market list
```

* Select a market to use for trading

```sh
$ tdex-cli market LBTC-USDT
```

* Get current exchnage rate for selected market

```sh
$ tdex-cli market LBTC-USDT
```

### Wallet

* Create or Restore Wallet

```sh
Expand All @@ -33,7 +81,7 @@ $ tdex-cli wallet
✔ Type your password · ****
```

* Run again to get current pubkey and address
* Run again to print pubkey and address
```sh
$ tdex-cli wallet
```
Expand All @@ -43,28 +91,53 @@ $ tdex-cli wallet
$ tdex-cli wallet balance
```

* Start a swap

### Swap

* Start a swap against the selected provider

> NOTICE With the --local flag you can export manually the SwapRequest message without the need of a connection with the provider.
```sh
$ tdex-cli swap
=========*** Swap ***==========

✔ Which asset do you want to send? · USDT / LBTC
✔ How much do you want to send? · 600
Gotcha! You will send USDT 600 and receive circa LBTC 0.1002 based on current market rate
✔ How much do you want to send? · 0.5
Gotcha! You will send LBTC 0.5 and receive USDT 3000
✔ Are you sure continue? (y/N) · true

Sending Swap Proposal to provider...
Sending SwapRequest to provider...

Swap has been accepted!

Swap succesful!
Signing with private key...
Sending SwapComplete to provider...

Swap completed!
```

* Import manually a SwapRequest and sign a resulting SwapAccept message

```sh
$ tdex-cli swap accept <message>
```

* Import a SwapAccept message and sign a resulting SwapComplete message

> NOTICE With the --push flag you can print the hex encoded extracted transaction and broadcast to the network
```sh
$ tdex-cli swap complete <message>
```

## Development

**Requirements**
### Requirements

* Node/npm or yarn

### Instructions

* Install deps

Expand Down
6 changes: 5 additions & 1 deletion src/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import walletAction from './walletAction';
import walletBalanceAction from './walletBalanceAction';

import swapAction from './swapAction';
import swapAcceptAction from './swapAcceptAction';
import swapCompleteAction from './swapCompleteAction'

export {
connectAction,
Expand All @@ -19,5 +21,7 @@ export {
marketListAction,
walletAction,
walletBalanceAction,
swapAction
swapAction,
swapAcceptAction,
swapCompleteAction
};
88 changes: 88 additions & 0 deletions src/actions/swapAcceptAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { info, log, error, success } from '../logger';
import State from '../state';
import { WalletInterface, fromWIF, fetchUtxos } from '../wallet';
import { decrypt } from '../crypto';
import { makeid } from '../helpers';
const state = new State();

const { Confirm, Password } = require('enquirer');

const confirm = new Confirm({
name: 'question',
message: 'Do you accept the proposed terms?'
});
const password = new Password({
type: 'password',
name: 'key',
message: 'Type your password'
});


export default function (message: string): void {
info('=========*** Swap ***==========\n');

const { wallet, network } = state.get();

if (!wallet.selected)
return error('A wallet is required. Create or restoste with wallet command');

let json: any
try {
json = JSON.parse(message);
} catch (ignore) {
return error('Not a valid SwapRequest message');
}

log(JSON.stringify(json, undefined, 2));
log();

const psbtBase64 = json.transaction;


let walletInstance: WalletInterface;

confirm.run().then((keepGoing: Boolean) => {
if (!keepGoing)
throw "Canceled";

const execute = wallet.keystore.type === "encrypted" ?
() => password.run() :
() => Promise.resolve(wallet.keystore.value);

return execute()
}).then((passwordOrWif: string) => {
const wif = wallet.keystore.type === "encrypted" ?
decrypt(wallet.keystore.value, passwordOrWif) :
passwordOrWif;

walletInstance = fromWIF(wif, network.chain);

return fetchUtxos(walletInstance.address, network.explorer)
}).then((utxos: Array<any>) => {
// Add inputs and putputs to psbt

const unsignedPsbt = walletInstance.updateTx(
psbtBase64,
utxos,
json.amount_r,
json.amount_p,
json.asset_r,
json.asset_p
);

log("\nSigning with private key...");
return walletInstance.sign(unsignedPsbt);
}).then((signedPsbt: string) => {
success("\n√ Done\n");

const TradeReply = {
SwapAccept: {
id: makeid(8),
request_id: json.id,
transaction: signedPsbt
}
};

success(`\nSwapAccept message\n\n${JSON.stringify(TradeReply.SwapAccept)}`);
}).catch(error)
}
45 changes: 30 additions & 15 deletions src/actions/swapAction.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { info, log, error, success } from '../logger';
import { makeid } from '../helpers';
import State from '../state';
import Wallet, { fetchUtxos, WalletInterface, fromWIF } from '../wallet';
import { fetchUtxos, WalletInterface, fromWIF, createTx } from '../wallet';
import { decrypt } from '../crypto';
const state = new State();

Expand All @@ -20,14 +20,14 @@ export default function (cmdObj: any) {

const { wallet, provider, market, network } = state.get();

if (!provider.selected)
if (!cmdObj.local && !provider.selected)
return error('A provider is required. Select one with connect <endpoint> command');

if (!market.selected)
return error('A market is required. Select one with market <pair> command');

if (!wallet.selected)
return error('A wallet is required. Create or restoste with wallet command');
return error('A wallet is required. Create or restore with wallet command');


const [tickerA, tickerB] = Object.keys(market.assets);
Expand All @@ -36,9 +36,9 @@ export default function (cmdObj: any) {
enabled: tickerA,
disabled: tickerB
});
const amount = new NumberPrompt({
const amount = (message:string) => new NumberPrompt({
name: 'number',
message: `How much do you want to send?`
message
});
const confirm = new Confirm({
name: 'question',
Expand All @@ -47,7 +47,7 @@ export default function (cmdObj: any) {
const password = new Password({
type: 'password',
name: 'key',
message: 'Type your private key WIF (Wallet Import Format)'
message: 'Type your password'
});

let walletInstance: WalletInterface,
Expand All @@ -65,28 +65,37 @@ export default function (cmdObj: any) {
toReceive = tickerA;
}

return amount.run();
return amount(`How much do you want to send?`).run()
}).then((inputAmount: number) => {
amountToBeSent = inputAmount;

const execute = cmdObj.local ?
() => amount(`How much do you want to receive?`).run() :
() => Promise.resolve();

return execute()
}).then((outputAmountOrNothing: number) => {
// Fetch market rate from daemon and calulcate prices for each ticker
// client.Balances().then( balances => { })
// client.Balances().then( balances => {})
const OneOfTickerB = 6000;
const OneOfTickerA = 0.000167;
amountToReceive = amountToBeSent * (toBeSent === 'LBTC' ? OneOfTickerB : OneOfTickerA);
amountToReceive = Number(
amountToReceive
let amountToReceiveFromProvider = amountToBeSent * (toBeSent === 'LBTC' ? OneOfTickerB : OneOfTickerA);
amountToReceiveFromProvider = Number(
amountToReceiveFromProvider
.toLocaleString("en-US", { minimumFractionDigits: 0, maximumFractionDigits: 8 })
.replace(',','')
);
log(`Gotcha! You will send ${toBeSent} ${amountToBeSent} and receive circa ${toReceive} ${amountToReceive} based on current market rate`);
amountToReceive = cmdObj.local ? outputAmountOrNothing : amountToReceiveFromProvider;

log(`Gotcha! You will send ${toBeSent} ${amountToBeSent} and receive ${toReceive} ${amountToReceive}`);

return confirm.run()
}).then((keepGoing: Boolean) => {
if (!keepGoing)
throw 'Terminated';
throw 'Canceled';

const execute = wallet.keystore.type === "encrypted" ?
password.run :
() => password.run() :
() => Promise.resolve(wallet.keystore.value);

return execute()
Expand All @@ -104,7 +113,9 @@ export default function (cmdObj: any) {
amountToBeSent = Math.floor(amountToBeSent * Math.pow(10,8));
amountToReceive = Math.floor(amountToReceive * Math.pow(10,8));

return walletInstance.createTx(
const psbtBase64 = createTx();
return walletInstance.updateTx(
psbtBase64,
utxos,
amountToBeSent,
amountToReceive,
Expand All @@ -128,6 +139,10 @@ export default function (cmdObj: any) {

if (cmdObj.verbose)
info(JSON.stringify(TradeRequest, undefined, 2));

if (cmdObj.local)
return success(`\nSwapRequest message\n\n${JSON.stringify(TradeRequest.SwapRequest)}`);

log(`\nSending SwapRequest to provider...\n`)
// client.Trade().then( stream => { })
setTimeout(() => {
Expand Down
Loading

0 comments on commit 8ac5261

Please sign in to comment.