From da242cc68997ce57c103a6ec0864a4ad498b2c3e Mon Sep 17 00:00:00 2001 From: michael1011 Date: Sat, 15 Dec 2018 21:17:01 +0100 Subject: [PATCH] feat: add refunds (#10) * feat: add refunds * feat: add file uploads via file inputs * refactor: style and flow fixes * feat: show loading when waiting for requests * feat: clean state when exiting --- package-lock.json | 23 ++++ package.json | 36 +++--- src/components/dropzone/index.js | 13 ++- src/components/fileupload/index.js | 14 ++- src/components/view/index.js | 1 + src/constants/actions/index.js | 9 +- src/constants/index.js | 1 + src/scripts/utils.js | 30 ++++- src/views/refund/index.js | 17 ++- src/views/refund/refund.js | 170 +++++++++++++++++++---------- src/views/refund/refundActions.js | 121 +++++++++++++++++++- src/views/refund/refundReducer.js | 51 ++++++++- src/views/refund/steps.js | 97 +++++++++------- src/views/swap/steps.js | 19 +++- src/views/swap/swap.js | 15 ++- src/views/swap/swapActions.js | 3 +- src/views/swap/swapReducer.js | 6 + 17 files changed, 486 insertions(+), 140 deletions(-) create mode 100644 src/constants/index.js diff --git a/package-lock.json b/package-lock.json index e480005..1c8a531 100644 --- a/package-lock.json +++ b/package-lock.json @@ -849,6 +849,11 @@ "to-fast-properties": "^2.0.0" } }, + "@boltz/bitcoin-ops": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@boltz/bitcoin-ops/-/bitcoin-ops-2.0.0.tgz", + "integrity": "sha512-AM7vFNwSD7B4XI6yeRKccWbbD/lvwoFr8U3pqhzryBQo4uMkYe5V3/kMVnml4SNuxzyqdIFu4ur3TId02sC33A==" + }, "@csstools/convert-colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", @@ -2244,6 +2249,11 @@ "wif": "^2.0.6" } }, + "bip65": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bip65/-/bip65-1.0.3.tgz", + "integrity": "sha512-RQ1nc7xtnLa5XltnCqkoR2zmhuz498RjMJwrLKQzOE049D1HUqnYfon7cVSbwS5UGm0/EQlC2CH+NY3MyITA4Q==" + }, "bip66": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", @@ -2329,6 +2339,19 @@ } } }, + "boltz-core": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/boltz-core/-/boltz-core-0.0.3.tgz", + "integrity": "sha512-ibEAcHwb5Y1eXzv+yD3J+Ij7WdVotWKc9W6QIst72A/PbMVXQK3Dw6ybV1O9Wha8oZ1TS77IFsu4N3QJE9wTvA==", + "requires": { + "@boltz/bitcoin-ops": "^2.0.0", + "bip65": "^1.0.3", + "bip66": "^1.1.5", + "bitcoinjs-lib": "^4.0.2", + "bn.js": "^4.11.8", + "varuint-bitcoin": "^1.1.0" + } + }, "bonjour": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", diff --git a/package.json b/package.json index 6505912..5bdd95e 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,6 @@ { "name": "boltz-frontend", "version": "1.0.0", - "dependencies": { - "axios": "^0.18.0", - "bitcoinjs-lib": "^4.0.2", - "prop-types": "^15.6.2", - "qrious": "^4.0.2", - "react": "^16.6.3", - "react-dom": "^16.6.3", - "react-icons": "^3.2.2", - "react-jss": "^8.6.1", - "react-redux": "^5.1.1", - "react-scripts": "2.1.1", - "redux": "^4.0.1", - "redux-logger": "^3.0.6", - "redux-thunk": "^2.3.0" - }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", @@ -33,6 +18,27 @@ "not ie <= 11", "not op_mini all" ], + "license": "AGPL-3.0", + "repository": { + "type": "git", + "url": "git+https://github.com/BoltzExchange/boltz-frontend.git" + }, + "dependencies": { + "axios": "^0.18.0", + "bitcoinjs-lib": "^4.0.2", + "boltz-core": "0.0.3", + "prop-types": "^15.6.2", + "qrious": "^4.0.2", + "react": "^16.6.3", + "react-dom": "^16.6.3", + "react-icons": "^3.2.2", + "react-jss": "^8.6.1", + "react-redux": "^5.1.1", + "react-scripts": "2.1.1", + "redux": "^4.0.1", + "redux-logger": "^3.0.6", + "redux-thunk": "^2.3.0" + }, "devDependencies": { "@babel/plugin-syntax-decorators": "^7.1.0", "babel-eslint": "^10.0.1", diff --git a/src/components/dropzone/index.js b/src/components/dropzone/index.js index 8b515b6..778fd79 100644 --- a/src/components/dropzone/index.js +++ b/src/components/dropzone/index.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import View from '../view'; +import { readFile } from '../../scripts/utils'; class DropZone extends React.Component { constructor(props) { @@ -10,12 +11,14 @@ class DropZone extends React.Component { }; this.ref = React.createRef(); } + componentDidMount() { this.ref.current.addEventListener('mouseup', this.onDragLeave); this.ref.current.addEventListener('dragenter', this.onDragEnter); this.ref.current.addEventListener('dragover', this.onDragOver); this.ref.current.addEventListener('drop', this.onDrop); } + componentWillUnmount() { this.ref.current.removeEventListener('mouseup', this.onDragLeave); this.ref.current.removeEventListener('dragenter', this.onDragEnter); @@ -23,11 +26,14 @@ class DropZone extends React.Component { this.ref.current.removeEventListener('drop', this.onDrop); } - // TODO: Extract data from files. onDrop = e => { e.preventDefault(); - const files = e.dataTransfer.files; - window.alert(`Files dropped: ${files}`); + const file = e.dataTransfer.items[0].getAsFile(); + + readFile(file, content => { + this.props.onFileRead(content); + }); + this.setState({ active: false }); return false; }; @@ -80,6 +86,7 @@ DropZone.protoTypes = { style: PropTypes.object, width: PropTypes.number, height: PropTypes.number, + onFileRead: PropTypes.func.isRequired, }; export default DropZone; diff --git a/src/components/fileupload/index.js b/src/components/fileupload/index.js index ec1aae6..e75e3d8 100644 --- a/src/components/fileupload/index.js +++ b/src/components/fileupload/index.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import injectSheet from 'react-jss'; +import { readFile } from '../../scripts/utils'; const fileBtnStyles = theme => ({ wrapper: { @@ -31,16 +32,25 @@ const fileBtnStyles = theme => ({ }, }); -const FileUpload = ({ classes, text }) => ( +const FileUpload = ({ classes, text, onFileRead }) => (
{text} - + { + readFile(event.target.files[0], content => { + onFileRead(content); + }); + }} + type="file" + />
); FileUpload.propTypes = { classes: PropTypes.object.isRequired, text: PropTypes.string.isRequired, + onFileRead: PropTypes.func.isRequired, }; export default injectSheet(fileBtnStyles)(FileUpload); diff --git a/src/components/view/index.js b/src/components/view/index.js index b3c8b1e..d296abc 100644 --- a/src/components/view/index.js +++ b/src/components/view/index.js @@ -8,6 +8,7 @@ const View = ({ children, style, className, inputRef, ...otherProps }) => { if (style !== undefined) { newStyle = { ...newStyle, ...style }; } + return (
{children} diff --git a/src/constants/actions/index.js b/src/constants/actions/index.js index 5c4a9a2..b8cbc54 100644 --- a/src/constants/actions/index.js +++ b/src/constants/actions/index.js @@ -16,4 +16,11 @@ export const SWAP_RESPONSE = 'SWAP_RESPONSE'; /** * Refund actions */ -export const ENTER_REFUND_MODE = 'ENTER_REFUND_MODE'; +export const COMPLETE_REFUND = 'COMPLETE_REFUND'; +export const SET_REFUND_FILE = 'SET_REFUND_FILE'; +export const SET_REFUND_TXHASH = 'SET_REFUND_TXHASH'; +export const SET_REFUND_DESTINATION = 'SET_REFUND_DESTINATION'; +export const SET_REFUND_TRANSACTION = 'SET_REFUND_TRANSACTION'; +export const SET_REFUND_TRANSACTION_HASH = 'SET_REFUND_TRANSACTION_HASH'; +export const REFUND_REQUEST = 'REFUND_REQUEST'; +export const REFUND_RESPONSE = 'REFUND_RESPONSE'; diff --git a/src/constants/index.js b/src/constants/index.js new file mode 100644 index 0000000..793b15f --- /dev/null +++ b/src/constants/index.js @@ -0,0 +1 @@ +export const boltzApi = 'http://localhost:9001'; diff --git a/src/scripts/utils.js b/src/scripts/utils.js index ae22c03..f675444 100644 --- a/src/scripts/utils.js +++ b/src/scripts/utils.js @@ -9,11 +9,37 @@ export const getHexString = input => { }; /** - * Convert BTC to Satoshi. + * Convert BTC to satoshi * * @param btc btc - * @returns satoshi + * @returns amount in satoshi */ export const toSatoshi = btc => { return btc * 100000000; }; + +/** + * Get a hex encoded Buffer from a string + * + * @param input {string} input + * @returns a hex encoded Buffer + */ +export const getHexBuffer = input => { + return Buffer.from(input, 'hex'); +}; + +/** + * Read the content of a file + * + * @param file file that should be read + * @param cb callback that will be called once the file is read + */ +export const readFile = (file, cb) => { + const reader = new window.FileReader(); + + reader.onload = () => { + cb(reader.result); + }; + + reader.readAsText(file); +}; diff --git a/src/views/refund/index.js b/src/views/refund/index.js index 4143db9..16f1ed4 100644 --- a/src/views/refund/index.js +++ b/src/views/refund/index.js @@ -4,12 +4,25 @@ import * as actions from './refundActions'; import { nav } from '../../action'; const mapStateToProps = state => ({ - inRefundMode: state.refundReducer.inRefundMode, + refundFile: state.refundReducer.refundFile, + transactionHash: state.refundReducer.transactionHash, + destinationAddress: state.refundReducer.destinationAddress, + refundTransaction: state.refundReducer.refundTransaction, + refundTransactionHash: state.refundReducer.refundTransactionHash, + isFetching: state.refundReducer.isFetching, }); const mapDispatchToProps = dispatch => ({ - toggleRefundMode: () => dispatch(actions.toggleRefundMode()), goHome: () => dispatch(nav.goHome()), + setRefundFile: file => dispatch(actions.setRefundFile(file)), + setTransactionHash: hash => dispatch(actions.setTransactionHash(hash)), + setDestinationAddress: address => + dispatch(actions.setDestinationAddress(address)), + startRefund: (refundFile, transactionHash, destinationAddress, cb) => + dispatch( + actions.startRefund(refundFile, transactionHash, destinationAddress, cb) + ), + completeRefund: () => dispatch(actions.completeRefund()), }); export default connect( diff --git a/src/views/refund/refund.js b/src/views/refund/refund.js index bfd2782..a3ddd7a 100644 --- a/src/views/refund/refund.js +++ b/src/views/refund/refund.js @@ -6,7 +6,7 @@ import Background from '../../components/background'; import StepsWizard from '../../components/stepswizard'; import Prompt from '../../components/prompt'; import View from '../../components/view'; -import { StepOne, StepTwo, StepFour } from './steps'; +import { StepOne, StepTwo, StepThree } from './steps'; const styles = () => ({ wrapper: { @@ -16,68 +16,122 @@ const styles = () => ({ }, }); -class Refund extends React.Component { - UNSAFE_componentWillMount() { - this.props.toggleRefundMode(); - } - - componentWillUnmount() { - this.props.toggleRefundMode(); - } - - render() { - const { classes, inRefundMode, goHome } = this.props; - return ( - - - - { +const Refund = ({ + classes, + goHome, + refundFile, + setRefundFile, + transactionHash, + setTransactionHash, + destinationAddress, + setDestinationAddress, + startRefund, + completeRefund, + refundTransaction, + refundTransactionHash, + isFetching, +}) => { + return ( + + + + { + if (window.confirm('Are you sure you want to exit')) { + completeRefund(); goHome(); - }} - message={'Are you sure?'} - > - - } /> - } /> - } /> - } /> - - - } - /> - } - /> - } - /> - } - /> - - - - - ); - } -} + } + }} + message={'Are you sure?'} + > + + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + + + ( + props.nextStage()} /> + )} + /> + ( + + startRefund( + refundFile, + transactionHash, + destinationAddress, + props.nextStage + ) + } + /> + )} + /> + ( + { + completeRefund(); + goHome(); + }} + /> + )} + /> + + + + + ); +}; Refund.propTypes = { classes: PropTypes.object, goHome: PropTypes.func.isRequired, - inRefundMode: PropTypes.bool, - toggleRefundMode: PropTypes.func, + nextStage: PropTypes.func, + isFetching: PropTypes.bool, + refundFile: PropTypes.object, + setRefundFile: PropTypes.func.isRequired, + transactionHash: PropTypes.string, + setTransactionHash: PropTypes.func.isRequired, + destinationAddress: PropTypes.string, + setDestinationAddress: PropTypes.func.isRequired, + startRefund: PropTypes.func.isRequired, + completeRefund: PropTypes.func.isRequired, + refundTransaction: PropTypes.string, + refundTransactionHash: PropTypes.string, }; export default injectSheet(styles)(Refund); diff --git a/src/views/refund/refundActions.js b/src/views/refund/refundActions.js index dded834..8981a21 100644 --- a/src/views/refund/refundActions.js +++ b/src/views/refund/refundActions.js @@ -1,5 +1,122 @@ +import axios from 'axios'; +import { ECPair, address, Transaction } from 'bitcoinjs-lib'; +import { Networks, constructRefundTransaction, detectSwap } from 'boltz-core'; import * as actionTypes from '../../constants/actions'; +import { boltzApi } from '../../constants'; +import { getHexBuffer } from '../../scripts/utils'; -export const toggleRefundMode = () => ({ - type: actionTypes.ENTER_REFUND_MODE, +export const completeRefund = () => { + return { + type: actionTypes.COMPLETE_REFUND, + }; +}; + +export const setRefundFile = file => ({ + type: actionTypes.SET_REFUND_FILE, + payload: JSON.parse(file), +}); + +export const setTransactionHash = hash => ({ + type: actionTypes.SET_REFUND_TXHASH, + payload: hash, +}); + +export const setDestinationAddress = address => ({ + type: actionTypes.SET_REFUND_DESTINATION, + payload: address, +}); + +const setRefundTransaction = transaction => ({ + type: actionTypes.SET_REFUND_TRANSACTION, + payload: transaction, +}); + +const setRefundTransactionHash = hash => ({ + type: actionTypes.SET_REFUND_TRANSACTION_HASH, + payload: hash, +}); + +export const refundRequest = () => ({ + type: actionTypes.REFUND_REQUEST, }); + +export const refundResponse = (success, response) => ({ + type: actionTypes.REFUND_RESPONSE, + payload: { + success, + response, + }, +}); + +export const startRefund = ( + refundFile, + transactionHash, + destinationAddress, + cb +) => { + const url = `${boltzApi}/gettransaction`; + const currency = refundFile.currency; + + return dispatch => { + dispatch(refundRequest()); + axios + .post(url, { + currency, + transactionHash, + }) + .then(response => { + const redeemScript = getHexBuffer(refundFile.redeemScript); + const lockupTransaction = Transaction.fromHex( + response.data.transactionHex + ); + + const refundTransaction = constructRefundTransaction( + ECPair.fromPrivateKey(getHexBuffer(refundFile.privateKey)), + redeemScript, + refundFile.timeoutBlockHeight, + // TODO: make sure the provided lockup transaction hash was correct and show more specific error is not + { + txHash: lockupTransaction.getHash(), + ...detectSwap(redeemScript, lockupTransaction), + }, + address.toOutputScript(destinationAddress, Networks.litecoinSimnet) + ); + + const refundTransactionHex = refundTransaction.toHex(); + const refundTransactionHash = refundTransaction.getId(); + + dispatch(setRefundTransaction(refundTransactionHex)); + dispatch(setRefundTransactionHash(refundTransactionHash)); + + broadcastRefund(currency, refundTransactionHex, () => { + dispatch(refundResponse(true, response.data)); + + cb(); + }); + }) + .catch(error => { + window.alert('Failed to refund swap'); + dispatch(refundResponse(false, error.data)); + }); + }; +}; + +const broadcastRefund = (currency, refundTransaction, cb) => { + const url = `${boltzApi}/broadcasttransaction`; + return dispatch => { + dispatch(refundRequest()); + axios + .post(url, { + currency, + transactionHex: refundTransaction, + }) + .then(response => { + dispatch(refundResponse(true, response.data)); + }) + .then(() => cb()) + .catch(error => { + window.alert(`Failed to broadcast refund transaction`); + dispatch(refundResponse(false, error.data)); + }); + }; +}; diff --git a/src/views/refund/refundReducer.js b/src/views/refund/refundReducer.js index 9c9ad32..0dfb35b 100644 --- a/src/views/refund/refundReducer.js +++ b/src/views/refund/refundReducer.js @@ -1,16 +1,61 @@ import * as actionTypes from '../../constants/actions'; const initalState = { - inRefundMode: false, + isFetching: false, + refundFile: {}, + transactionHash: null, + destinationAddress: null, + refundTransaction: null, + refundTransactionHash: null, }; const reducer = (state = initalState, action) => { switch (action.type) { - case actionTypes.ENTER_REFUND_MODE: + case actionTypes.REFUND_REQUEST: return { ...state, - inRefundMode: !state.inRefundMode, + isFetching: true, }; + + case actionTypes.REFUND_RESPONSE: + return { + ...state, + isFetching: false, + }; + + case actionTypes.SET_REFUND_FILE: + return { + ...state, + refundFile: action.payload, + }; + + case actionTypes.SET_REFUND_TXHASH: + return { + ...state, + transactionHash: action.payload, + }; + + case actionTypes.SET_REFUND_DESTINATION: + return { + ...state, + destinationAddress: action.payload, + }; + + case actionTypes.SET_REFUND_TRANSACTION: + return { + ...state, + refundTransaction: action.payload, + }; + + case actionTypes.SET_REFUND_TRANSACTION_HASH: + return { + ...state, + refundTransactionHash: action.payload, + }; + + case actionTypes.COMPLETE_REFUND: + return initalState; + default: return state; } diff --git a/src/views/refund/steps.js b/src/views/refund/steps.js index fe34a51..604947c 100644 --- a/src/views/refund/steps.js +++ b/src/views/refund/steps.js @@ -5,12 +5,15 @@ import View from '../../components/view'; import { FaCheckCircle } from 'react-icons/fa'; import DropZone from '../../components/dropzone'; import FileUpload from '../../components/fileupload'; +import InputArea from '../../components/inputarea'; const stepOneStyles = theme => ({ wrapper: { flex: 1, + flexDirection: 'column', justifyContent: 'center', alignItems: 'center', + paddingBottom: '1vh', backgroundColor: theme.colors.aeroBlue, }, dropZone: { @@ -28,19 +31,30 @@ const stepOneStyles = theme => ({ }, }); -const StyledStepOne = ({ classes }) => ( +const StyledStepOne = ({ classes, setRefundFile, setTransactionHash }) => ( - +

Drag the Refund JSON file here

or - {/*TODO: add ability to upload*/} - +
+ +

Lockup transaction hash

+
); StyledStepOne.propTypes = { classes: PropTypes.object.isRequired, + setRefundFile: PropTypes.func.isRequired, + setTransactionHash: PropTypes.func.isRequired, }; export const StepOne = injectSheet(stepOneStyles)(StyledStepOne); @@ -48,58 +62,38 @@ export const StepOne = injectSheet(stepOneStyles)(StyledStepOne); const stepTwoStyles = theme => ({ wrapper: { flex: 1, + flexDirection: 'column', justifyContent: 'center', alignItems: 'center', + paddingBottom: '1vh', backgroundColor: theme.colors.aeroBlue, }, info: { - height: '200px', - width: 'auto', - flexDirection: 'column', - justifyContent: 'space-between', - }, - title: { - fontSize: '30px', - }, - link: { - fontSize: '18px', - textDecoration: 'none', - }, - description: { fontSize: '30px', + color: theme.colors.tundoraGrey, }, }); -const StyledStepTwo = ({ classes }) => ( +const StyledStepTwo = ({ classes, setDestinationAddress }) => ( - - Your refund transaction is: - - 1F1tAaz5x1HUXrCNLbtMDqcw6o5GNn4xqX - -

- Please wait for Block 549843 to be mined
- and broadcast the transaction to claim
- refund. -

-
+

Destination address

+
); StyledStepTwo.propTypes = { classes: PropTypes.object.isRequired, + setDestinationAddress: PropTypes.func.isRequired, }; export const StepTwo = injectSheet(stepTwoStyles)(StyledStepTwo); -const stepFourStyles = theme => ({ +const stepThreeStyles = theme => ({ wrapper: { flex: 1, justifyContent: 'center', @@ -114,17 +108,40 @@ const stepFourStyles = theme => ({ margin: '15px', fontSize: '30px', }, + transaction: { + wordBreak: 'break-all', + paddingLeft: '1vw', + paddingRight: '1vw', + }, }); -const StyledStepFour = ({ classes }) => ( +const StyledStepThree = ({ + classes, + refundTransaction, + refundTransactionHash, +}) => ( Success! +

Your refund transaction:

+ {refundTransaction} + +

+ + {refundTransactionHash} + +

); -StyledStepFour.propTypes = { +StyledStepThree.propTypes = { classes: PropTypes.object.isRequired, + refundTransaction: PropTypes.string.isRequired, + refundTransactionHash: PropTypes.string.isRequired, }; -export const StepFour = injectSheet(stepFourStyles)(StyledStepFour); +export const StepThree = injectSheet(stepThreeStyles)(StyledStepThree); diff --git a/src/views/swap/steps.js b/src/views/swap/steps.js index e9ad089..ac247f8 100644 --- a/src/views/swap/steps.js +++ b/src/views/swap/steps.js @@ -137,7 +137,7 @@ const StyledStepTwo = ({ classes, value, address, link }) => ( fontSize: '30px', }} > - Send `${toSatoshi(value.received)} Satoshi`
+ Send {toSatoshi(value.received)} Litoshi
on Litecoin
blockchain address:

@@ -189,16 +189,24 @@ class StyledStepThree extends React.Component { } render() { - const { classes, redeemScript, address, currency, privateKey } = this.props; + const { + classes, + address, + currency, + redeemScript, + privateKey, + timeoutBlockHeight, + } = this.props; return (

@@ -214,7 +222,7 @@ class StyledStepThree extends React.Component { {address} @@ -226,10 +234,11 @@ class StyledStepThree extends React.Component { StyledStepThree.propTypes = { classes: PropTypes.object.isRequired, - redeemScript: PropTypes.string.isRequired, address: PropTypes.string.isRequired, currency: PropTypes.string.isRequired, + redeemScript: PropTypes.string.isRequired, privateKey: PropTypes.string.isRequired, + timeoutBlockHeight: PropTypes.number.isRequired, }; export const StepThree = injectSheet(stepThreeStyles)(StyledStepThree); diff --git a/src/views/swap/swap.js b/src/views/swap/swap.js index e01a108..f9099e3 100644 --- a/src/views/swap/swap.js +++ b/src/views/swap/swap.js @@ -37,7 +37,7 @@ const Swap = ({ range={4} stage={1} onExit={() => { - if (window.confirm('Sure you want to exit')) { + if (window.confirm('Are you sure you want to exit')) { completeSwap(); goHome(); } @@ -65,9 +65,10 @@ const Swap = ({ render={() => ( )} /> @@ -100,10 +101,13 @@ const Swap = ({ /> ( + render={() => ( props.onExit()} + onPress={() => { + completeSwap(); + goHome(); + }} /> )} /> @@ -117,7 +121,7 @@ const Swap = ({ Swap.propTypes = { classes: PropTypes.object.isRequired, history: PropTypes.object.isRequired, - inSwapMode: PropTypes.bool.isRequired, + isFetching: PropTypes.bool.isRequired, goHome: PropTypes.func.isRequired, swapInfo: PropTypes.object, swapResponse: PropTypes.object, @@ -126,7 +130,6 @@ Swap.propTypes = { onExit: PropTypes.func, nextStage: PropTypes.func, startSwap: PropTypes.func.isRequired, - isFetching: PropTypes.bool.isRequired, }; export default injectSheet(styles)(Swap); diff --git a/src/views/swap/swapActions.js b/src/views/swap/swapActions.js index d73e743..d602e0a 100644 --- a/src/views/swap/swapActions.js +++ b/src/views/swap/swapActions.js @@ -1,5 +1,6 @@ import axios from 'axios'; import { generateKeys } from '../../action'; +import { boltzApi } from '../../constants'; import * as actionTypes from '../../constants/actions'; export const completeSwap = () => { @@ -48,7 +49,7 @@ export const swapRequest = () => ({ }); export const startSwap = (swapInfo, cb) => { - const url = 'http://localhost:9001/createswap'; + const url = `${boltzApi}/createswap`; return dispatch => { dispatch(swapRequest()); axios diff --git a/src/views/swap/swapReducer.js b/src/views/swap/swapReducer.js index 2b30ffc..01cb020 100644 --- a/src/views/swap/swapReducer.js +++ b/src/views/swap/swapReducer.js @@ -20,12 +20,14 @@ const reducer = (state = initalState, action) => { ...state, isFetching: true, }; + case actionTypes.SWAP_RESPONSE: return { ...state, isFetching: false, swapResponse: action.payload, }; + case actionTypes.SET_SWAP_AMOUNT: return { ...state, @@ -37,6 +39,7 @@ const reducer = (state = initalState, action) => { receivedCurrency: action.payload.receivedCurrency, }, }; + case actionTypes.SET_SWAP_INVOICE: return { ...state, @@ -45,6 +48,7 @@ const reducer = (state = initalState, action) => { invoice: action.payload, }, }; + case actionTypes.NEW_KEYS: return { ...state, @@ -53,8 +57,10 @@ const reducer = (state = initalState, action) => { publicKey: action.payload, }, }; + case actionTypes.COMPLETE_SWAP: return initalState; + default: return state; }