Skip to content
This repository was archived by the owner on Apr 28, 2023. It is now read-only.

Commit

Permalink
feat: support new hold reverse swaps
Browse files Browse the repository at this point in the history
  • Loading branch information
michael1011 committed Jan 2, 2020
1 parent 3c66e4e commit e6e5ce6
Show file tree
Hide file tree
Showing 16 changed files with 229 additions and 158 deletions.
47 changes: 27 additions & 20 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "boltz-frontend",
"version": "1.1.0-beta",
"version": "1.2.0-beta",
"scripts": {
"start": "BROWSER=none react-scripts start",
"build": "react-scripts build",
Expand Down Expand Up @@ -28,8 +28,8 @@
"dependencies": {
"axios": "^0.19.0",
"bignumber.js": "^9.0.0",
"bitcoinjs-lib": "^5.1.3",
"boltz-core": "^0.0.7",
"bitcoinjs-lib": "^5.1.6",
"boltz-core": "^0.0.10",
"eventsource": "^1.0.7",
"lodash.throttle": "^4.1.1",
"prop-types": "^15.7.2",
Expand Down
4 changes: 3 additions & 1 deletion src/__test__/unit/reducers/ReverseReducer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ describe('reverse swap reducer', () => {
const action = {
type: actions.REVERSE_SWAP_RESPONSE,
payload: {
response: 'response',
response: {
test: 'response',
},
success: false,
},
};
Expand Down
12 changes: 10 additions & 2 deletions src/actions/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import Navigation from './navigation';
import { generateKeys } from './keys';
import history from '../constants/history';
import Navigation from './navigation';

const randomBytes = size => {
const bytes = Buffer.allocUnsafe(size);
global.crypto.getRandomValues(bytes);

return bytes;
};

const navigation = new Navigation(history);
export { generateKeys, navigation };

export { navigation, randomBytes, generateKeys };
119 changes: 72 additions & 47 deletions src/actions/reverseActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export const initReverseSwap = state => ({
quoteAmount: state.quoteAmount,
keys: state.keys,
pair: state.pair,
preimage: state.preimage,
preimageHash: state.preimageHash,
},
});

Expand Down Expand Up @@ -61,7 +63,7 @@ export const setIsReconnecting = isReconnecting => ({
});

export const startReverseSwap = (swapInfo, nextStage, timelockExpired) => {
const url = `${boltzApi}/createreverseswap`;
const url = `${boltzApi}/createswap`;
const { pair, keys, baseAmount } = swapInfo;

const amount = toSatoshi(Number.parseFloat(baseAmount));
Expand All @@ -70,10 +72,12 @@ export const startReverseSwap = (swapInfo, nextStage, timelockExpired) => {
dispatch(reverseSwapRequest());
axios
.post(url, {
type: 'reversesubmarine',
pairId: pair.id,
invoiceAmount: amount,
orderSide: pair.orderSide,
claimPublicKey: keys.publicKey,
preimageHash: swapInfo.preimageHash,
})
.then(response => {
dispatch(reverseSwapResponse(true, response.data));
Expand All @@ -95,17 +99,40 @@ export const startReverseSwap = (swapInfo, nextStage, timelockExpired) => {
};
};

const getClaimTransaction = (swapInfo, response, preimage, feeEstimation) => {
export const claimSwap = (dispatch, nextStage, swapInfo, swapResponse) => {
dispatch(
getFeeEstimation(feeEstimation => {
const claimTransaction = getClaimTransaction(
swapInfo,
swapResponse,
feeEstimation
);

dispatch(
broadcastClaimTransaction(
swapInfo.quote,
claimTransaction.toHex(),
() => {
dispatch(reverseSwapResponse(true, swapResponse));
nextStage();
}
)
);
})
);
};

const getClaimTransaction = (swapInfo, response, feeEstimation) => {
const redeemScript = getHexBuffer(response.redeemScript);
const lockupTransaction = Transaction.fromHex(response.lockupTransaction);
const lockupTransaction = Transaction.fromHex(response.transactionHex);

return constructClaimTransaction(
[
{
...detectSwap(redeemScript, lockupTransaction),
redeemScript,
preimage: Buffer.from(preimage, 'hex'),
txHash: lockupTransaction.getHash(),
preimage: getHexBuffer(swapInfo.preimage),
keys: ECPair.fromPrivateKey(getHexBuffer(swapInfo.keys.privateKey)),
},
],
Expand All @@ -115,6 +142,24 @@ const getClaimTransaction = (swapInfo, response, preimage, feeEstimation) => {
);
};

const broadcastClaimTransaction = (currency, claimTransaction, cb) => {
const url = `${boltzApi}/broadcasttransaction`;
return dispatch => {
axios
.post(url, {
currency,
transactionHex: claimTransaction,
})
.then(() => cb())
.catch(error => {
const message = error.response.data.error;

window.alert(`Failed to broadcast claim transaction: ${message}`);
dispatch(reverseSwapResponse(false, message));
});
};
};

const handleReverseSwapStatus = (
data,
source,
Expand All @@ -134,42 +179,40 @@ const handleReverseSwapStatus = (
latestSwapEvent = status;
}

// TODO: handle transaction failed
switch (status) {
case SwapUpdateEvent.TransactionMempool:
dispatch(
reverseSwapResponse(true, {
transactionId: data.transactionId,
transactionHex: data.transactionHex,
})
);

nextStage();
break;

case SwapUpdateEvent.TransactionConfirmed:
dispatch(setReverseSwapStatus('Waiting for invoice to be paid...'));
nextStage(true);
source.close();

claimSwap(dispatch, nextStage, swapInfo, {
...response,
transactionId: data.transactionId,
transactionHex: data.transactionHex,
});
break;

case SwapUpdateEvent.SwapExpired:
case SwapUpdateEvent.TransactionRefunded:
source.close();
dispatch(timelockExpired());

break;

case SwapUpdateEvent.InvoiceSettled:
case SwapUpdateEvent.TransactionFailed:
source.close();

dispatch(
getFeeEstimation(feeEstimation => {
const claimTransaction = getClaimTransaction(
swapInfo,
response,
data.preimage,
feeEstimation
);

dispatch(
broadcastClaimTransaction(
swapInfo.quote,
claimTransaction.toHex(),
() => {
dispatch(reverseSwapResponse(true, response));
nextStage();
}
)
);
})
);
dispatch(setReverseSwapStatus('Could not send onchain coins'));
dispatch(reverseSwapResponse(false, {}));
break;

default:
Expand Down Expand Up @@ -241,21 +284,3 @@ const startListening = (
);
};
};

const broadcastClaimTransaction = (currency, claimTransaction, cb) => {
const url = `${boltzApi}/broadcasttransaction`;
return dispatch => {
axios
.post(url, {
currency,
transactionHex: claimTransaction,
})
.then(() => cb())
.catch(error => {
const message = error.response.data.error;

window.alert(`Failed to broadcast claim transaction: ${message}`);
dispatch(reverseSwapResponse(false, message));
});
};
};
1 change: 1 addition & 0 deletions src/actions/swapActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const startSwap = (swapInfo, cb) => {
dispatch(swapRequest());
axios
.post(url, {
type: 'submarine',
pairId: pair.id,
orderSide: pair.orderSide,
invoice: invoice,
Expand Down
38 changes: 18 additions & 20 deletions src/components/qrcode/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,27 @@ import Qrious from 'qrious';
import PropTypes from 'prop-types';

class QrCode extends React.Component {
id = '';

componentDidMount() {
render() {
const { size, link } = this.props;
const element = document.getElementById(this.id);
this.qr = new Qrious({
element,
});

this.qr.set({
size,
level: 'H',
value: link,
background: 'white',
foreground: 'black',
backgroundAlpha: 1,
foregroundAlpha: 1,
});
}
if (link) {
this.id = `qr-${link.substring(0, 4)}`;

render() {
const { link } = this.props;
this.id = `qr-${link.substring(0, 4)}`;
const element = document.getElementById(this.id);
this.qr = new Qrious({
element,
});

this.qr.set({
size,
level: 'H',
value: link,
background: 'white',
foreground: 'black',
backgroundAlpha: 1,
foregroundAlpha: 1,
});
}

return <canvas id={this.id} />;
}
Expand Down
2 changes: 2 additions & 0 deletions src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export const SwapUpdateEvent = {
InvoiceSettled: 'invoice.settled',
InvoiceFailedToPay: 'invoice.failedToPay',

TransactionFailed: 'transaction.failed',
TransactionMempool: 'transaction.mempool',
TransactionClaimed: 'transaction.claimed',
TransactionRefunded: 'transaction.refunded',
TransactionConfirmed: 'transaction.confirmed',
Expand Down
Loading

0 comments on commit e6e5ce6

Please sign in to comment.