Skip to content

Commit

Permalink
Merge pull request #136 from liquality/refund_flow
Browse files Browse the repository at this point in the history
Refund flow for swaps
  • Loading branch information
grandsmarquis committed Jun 7, 2019
2 parents d1ee998 + 1b74bae commit f800f52
Show file tree
Hide file tree
Showing 14 changed files with 544 additions and 359 deletions.
628 changes: 297 additions & 331 deletions package-lock.json

Large diffs are not rendered by default.

30 changes: 15 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@
"private": true,
"dependencies": {
"@liquality/cryptoassets": "^0.0.7",
"@liquality/bitcoin-bitcoinjs-lib-swap-provider": "^0.2.2",
"@liquality/bitcoin-bitcore-rpc-provider": "^0.2.2",
"@liquality/bitcoin-ledger-provider": "^0.2.2",
"@liquality/bitcoin-networks": "^0.2.2",
"@liquality/bitcoin-swap-provider": "^0.2.2",
"@liquality/client": "^0.2.2",
"@liquality/crypto": "^0.2.2",
"@liquality/errors": "^0.2.2",
"@liquality/ethereum-erc20-provider": "^0.2.2",
"@liquality/ethereum-erc20-swap-provider": "^0.2.2",
"@liquality/ethereum-ledger-provider": "^0.2.2",
"@liquality/ethereum-metamask-provider": "^0.2.2",
"@liquality/ethereum-networks": "^0.2.2",
"@liquality/ethereum-rpc-provider": "^0.2.2",
"@liquality/ethereum-swap-provider": "^0.2.2",
"@liquality/bitcoin-bitcoinjs-lib-swap-provider": "^0.2.7",
"@liquality/bitcoin-bitcore-rpc-provider": "^0.2.7",
"@liquality/bitcoin-ledger-provider": "^0.2.7",
"@liquality/bitcoin-networks": "^0.2.7",
"@liquality/bitcoin-swap-provider": "^0.2.7",
"@liquality/client": "^0.2.7",
"@liquality/crypto": "^0.2.7",
"@liquality/errors": "^0.2.7",
"@liquality/ethereum-erc20-provider": "^0.2.7",
"@liquality/ethereum-erc20-swap-provider": "^0.2.7",
"@liquality/ethereum-ledger-provider": "^0.2.7",
"@liquality/ethereum-metamask-provider": "^0.2.7",
"@liquality/ethereum-networks": "^0.2.7",
"@liquality/ethereum-rpc-provider": "^0.2.7",
"@liquality/ethereum-swap-provider": "^0.2.7",
"@material-ui/core": "^3.5.1",
"bignumber.js": "^8.0.1",
"bootstrap": "^4.1.3",
Expand Down
23 changes: 22 additions & 1 deletion src/actions/swap.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,24 @@ function waitForSwapClaim () {
}
}

function waitForSwapRefund () {
return async (dispatch, getState) => {
const {
assets,
wallets,
transactions,
counterParty,
secretParams,
expiration,
isPartyB
} = getState().swap
const client = getClient(assets.a.currency, wallets.a.type)
const swapExpiration = getFundExpiration(expiration, isPartyB ? 'a' : 'b').time
const refundTransaction = await client.swap.findRefundSwapTransaction(transactions.a.fund.hash, counterParty.a.address, wallets.a.addresses[0], secretParams.secretHash, swapExpiration.unix())
dispatch(transactionActions.setTransaction('a', 'refund', refundTransaction))
}
}

async function unlockFunds (dispatch, getState) {
const {
assets,
Expand Down Expand Up @@ -302,14 +320,16 @@ function refundSwap () {

const client = getClient(assets.a.currency, wallets.a.type)
const swapExpiration = getFundExpiration(expiration, isPartyB ? 'b' : 'a').time
const block = await client.chain.getBlockHeight()
await withLoadingMessage('a', dispatch, getState, async () => {
return client.swap.refundSwap(
const refundTxHash = await client.swap.refundSwap(
transactions.a.fund.hash,
counterParty.a.address,
wallets.a.addresses[0],
secretParams.secretHash,
swapExpiration.unix()
)
dispatch(transactionActions.setTransaction('a', 'refund', { hash: refundTxHash, block }))
})
}
}
Expand All @@ -328,6 +348,7 @@ const actions = {
verifyInitiateSwapTransaction,
waitForSwapConfirmation,
waitForSwapClaim,
waitForSwapRefund,
redeemSwap,
refundSwap
}
Expand Down
16 changes: 14 additions & 2 deletions src/actions/transactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,19 @@ function setStep (transactions, isPartyB, dispatch) {
}

function setLocation (swap, currentLocation, dispatch) {
const canNavigate = currentLocation.pathname !== '/backupLink' && currentLocation.pathname !== '/refund'
const hasRefunded = swap.transactions.a.refund && swap.transactions.a.refund.hash
const canNavigate = currentLocation.pathname !== '/backupLink' && (hasRefunded || currentLocation.pathname !== '/refund')
if (canNavigate) {
const hasInitiated = swap.transactions.a.fund.hash && swap.transactions.a.fund.confirmations > 0
const canRefund = !swap.transactions.b.claim.hash || swap.transactions.b.claim.confirmations === 0
const swapExpiration = getFundExpiration(swap.expiration, swap.isPartyB ? 'b' : 'a').time
const swapExpired = moment().isAfter(swapExpiration)
if (hasInitiated && canRefund && swapExpired) {
dispatch(replace('/refund'))
if (hasRefunded) {
dispatch(replace('/refunded'))
} else {
dispatch(replace('/refund'))
}
} else if (swap.step === steps.AGREEMENT && currentLocation.pathname !== '/waiting') {
if (swap.isPartyB || swap.transactions.b.fund.hash) {
dispatch(replace('/waiting'))
Expand All @@ -72,6 +77,8 @@ async function monitorTransaction (swap, party, kind, tx, dispatch, getState) {
client = getClient(swap.assets[currentParty].currency, swap.wallets[currentParty].type)
} else if (kind === 'fund') {
client = getClient(swap.assets[party].currency, swap.wallets[party].type)
} else if (kind === 'refund') {
client = getClient(swap.assets[party].currency, swap.wallets[party].type)
}
const updatedTransaction = await client.chain.getTransactionByHash(tx.hash)
if (updatedTransaction) {
Expand Down Expand Up @@ -126,6 +133,11 @@ function loadTransactions () {
if (swapState.transactions.a.fund.hash && !swapState.transactions.b.claim.hash) {
dispatch(swapActions.waitForSwapClaim())
}
const swapExpiration = getFundExpiration(swapState.expiration, swapState.isPartyB ? 'b' : 'a').time
const swapExpired = moment().isAfter(swapExpiration)
if (swapState.transactions.a.fund.hash && swapExpired) {
dispatch(swapActions.waitForSwapRefund())
}
}
}
}
Expand Down
24 changes: 24 additions & 0 deletions src/components/HexaDisplay/HexaDisplay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { Component } from 'react'
import { shortenAddress } from '../../utils/address'

import './HexaDisplay.css'

class HexaDisplay extends Component {
onCopyLink () {
const tempInput = document.createElement('input')
tempInput.value = this.props.address
tempInput.style = 'position: absolute; top: -2000px;'
document.body.appendChild(tempInput)
tempInput.select()
document.execCommand('copy')
document.body.removeChild(tempInput)
}

render () {
return <span onClick={() => this.onCopyLink.bind(this)()} className='HexaDisplay'>
{shortenAddress(this.props.address)}
</span>
}
}

export default HexaDisplay
4 changes: 4 additions & 0 deletions src/components/HexaDisplay/HexaDisplay.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.HexaDisplay {
color: #8D46E2;
cursor: pointer;
}
2 changes: 2 additions & 0 deletions src/containers/LiqualitySwap/LiqualitySwap.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import WalletPopups from '../WalletPopups'
import SwapRedemption from '../SwapRedemption'
import SwapCompleted from '../SwapCompleted'
import SwapRefund from '../SwapRefund'
import SwapRefunded from '../SwapRefunded'
import SwapProgressStepper from '../../components/SwapProgressStepper/SwapProgressStepper'
import { generateLink } from '../../utils/app-links'
import config from '../../config'
Expand Down Expand Up @@ -85,6 +86,7 @@ class LiqualitySwap extends Component {
<Route path='/redeem' component={SwapRedemption} />
<Route path='/completed' component={SwapCompleted} />
<Route path='/refund' component={SwapRefund} />
<Route path='/refunded' component={SwapRefunded} />
<WalletPopups />
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/containers/LiqualitySwap/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default withRouter(connect(
{
waitForSwapConfirmation: swapActions.waitForSwapConfirmation,
waitForSwapClaim: swapActions.waitForSwapClaim,
waitForSwapRefund: swapActions.waitForSwapRefund,
clearError: errorActions.clearError,
waitForWallet: walletsActions.waitForWallet,
waitForWalletInitialization: walletsActions.waitForWalletInitialization,
Expand Down
38 changes: 30 additions & 8 deletions src/containers/SwapRefund/SwapRefund.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,37 @@ import './SwapRefund.css'

class SwapRedemption extends Component {
render () {
return <BrandCard className='SwapRefund' title='Refund'>
<div className='SwapRefund_confirmation'>
<p className='SwapRefund_terms'>
{this.props.assets.a.value} {cryptoassets[this.props.assets.a.currency].code}
</p>
<p>Your funds are ready for a refund.</p>
return <div>
<BrandCard className='SwapRefund' title='RECLAIM YOUR ASSETS'>
<div className='SwapRefund_confirmation'>
Refund amount:
<p className='SwapRefund_terms'>
{this.props.assets.a.value} {cryptoassets[this.props.assets.a.currency].code}
</p>
<p>To process this refund, press the reclaim button.</p>
</div>
<p><Button wide primary loadingMessage={this.props.loadingMessage} onClick={this.props.refundSwap}>Reclaim</Button></p>
</BrandCard>
<div className='SwapRefund_expiredFrame'>
<div className='SwapRefund_expiredFrame_content'>

<p className='SwapRefund_expiredFrame_content_title'>
Expired Swap offer
</p>
<hr />
<p>
Receive: <span className='SwapRefund_expiredFrame_content_value'>{this.props.assets.b.value} {cryptoassets[this.props.assets.b.currency].code}</span>
</p>
<p>
For: <span className='SwapRefund_expiredFrame_content_value'>{this.props.assets.a.value} {cryptoassets[this.props.assets.a.currency].code}</span>
</p>
<p>
Expired: <span className='SwapRefund_expiredFrame_content_value'>{this.props.expiration.format('DD/MM/YYYY h:mm a')}</span>
</p>
<hr />
</div>
</div>
<p><Button wide primary loadingMessage={this.props.loadingMessage} onClick={this.props.refundSwap}>Get Refund</Button></p>
</BrandCard>
</div>
}
}

Expand Down
28 changes: 28 additions & 0 deletions src/containers/SwapRefund/SwapRefund.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,32 @@
&_terms {
font-size: $h1-font-size;
}

&_expiredFrame {
text-align: center;
width: 100%;
background-color: #F7F8FA;
color: #A4AAB6;
margin-top: -20px;
border-radius: 0px 0px 22px 22px;
padding: 50px;

&_content {
margin-left: 30%;
width: 40%;
text-align: left;

&_title {
text-align: center;
color: #494949;
}

&_value {
color: #5F5F5F;
}
}

}


}
47 changes: 47 additions & 0 deletions src/containers/SwapRefunded/SwapRefunded.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { Component } from 'react'
import BrandCard from '../../components/BrandCard/BrandCard'
import HexaDisplay from '../../components/HexaDisplay/HexaDisplay'
import Button from '../../components/Button/Button'
import cryptoassets from '@liquality/cryptoassets'
import { APP_BASE_URL } from '../../utils/app-links'

import './SwapRefunded.css'

class SwapRefunded extends Component {
render () {
const title = cryptoassets[this.props.assets.a.currency].code + ' SUCCESFULLY RECLAIMED'
return <div>
<BrandCard className='SwapRefunded' title={title}>
<div className='SwapRefunded_expiredFrame'>
<div className='SwapRefunded_expiredFrame_content'>

<p className='SwapRefunded_expiredFrame_content_title'>
Expired Swap offer
</p>
<hr />
<p>
Receive: <span className='SwapRefunded_expiredFrame_content_value'>{this.props.assets.b.value} {cryptoassets[this.props.assets.b.currency].code}</span>
</p>
<p>
For: <span className='SwapRefunded_expiredFrame_content_value'>{this.props.assets.a.value} {cryptoassets[this.props.assets.a.currency].code}</span>
</p>
<p>
Expired: <span className='SwapRefunded_expiredFrame_content_value'>{this.props.expiration.format('DD/MM/YYYY h:mm a')}</span>
</p>
<hr />
</div>
</div>
<div className='SwapRefunded_confirmation'>
<p className='SwapRefunded_terms'>
{this.props.assets.a.value} {cryptoassets[this.props.assets.a.currency].code} Returned
</p>
<p>Address: <HexaDisplay address={this.props.wallets.a.addresses[0]} /></p>
<p>Transaction: <HexaDisplay address={this.props.refundTransaction.hash} /></p>
</div>
<Button className='SwapRefunded_button' wide primary onClick={() => window.location.replace(APP_BASE_URL)}>Start another Swap</Button>
</BrandCard>
</div>
}
}

export default SwapRefunded
40 changes: 40 additions & 0 deletions src/containers/SwapRefunded/SwapRefunded.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
@import '../../scss/variables.scss';

.SwapRefunded {
text-align: center;

&_terms {
font-size: $h1-font-size;
}

&_button {
margin-top: 50px;
}

&_expiredFrame {
text-align: center;
width: 100%;
color: #A4AAB6;
margin-top: -20px;
border-radius: 0px 0px 22px 22px;
padding: 50px;

&_content {
margin-left: 30%;
width: 40%;
text-align: left;

&_title {
text-align: center;
color: #494949;
}

&_value {
color: #5F5F5F;
}
}

}


}
16 changes: 16 additions & 0 deletions src/containers/SwapRefunded/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { connect } from 'react-redux'
import SwapRefunded from './SwapRefunded'

const mapStateToProps = state => {
return {
assets: state.swap.assets,
wallets: state.swap.wallets,
expiration: state.swap.expiration,
isPartyB: state.swap.isPartyB,
refundTransaction: state.swap.transactions.a.refund
}
}

export default connect(
mapStateToProps
)(SwapRefunded)
6 changes: 4 additions & 2 deletions src/reducers/transactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { getReducerFunction } from './helpers'
const initialState = {
a: {
fund: {},
claim: {}
claim: {},
refund: {}
},
b: {
fund: {},
claim: {}
claim: {},
refund: {}
}
}

Expand Down

0 comments on commit f800f52

Please sign in to comment.