Created
March 18, 2019 16:30
-
-
Save mqklin/a791ea57e3da9beb999e329e521c2395 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { | |
useEffect, | |
} from 'react'; | |
import styled, {css} from 'styled-components'; | |
import {forbidExtraProps} from 'airbnb-prop-types'; | |
import {ButtonContainer, SelectAssetModal} from 'App/dumb'; | |
import {func, string, object} from 'prop-types'; | |
import {withContext} from 'withContext'; | |
import Values from './Values'; | |
import payFeeAssetsRaw from './payFeeAssetsRaw'; | |
import { | |
useInterval, | |
useStateReducer, | |
FetchTokenaryService, | |
} from 'App/utils'; | |
import {cdpPortalProxy} from 'src/Root/methods/node/services/cdp/contracts'; | |
const Wr = styled.div` | |
background: #2D368A; | |
border-radius: 0px 8px 8px 0px; | |
height: 100%; | |
padding: 24px 16px 0; | |
position: relative; | |
@media (max-width: 768px) { | |
border-radius: 0; | |
} | |
`; | |
const Header = styled.div` | |
line-height: 24px; | |
font-size: 20px; | |
color: #FFFFFF; | |
position: relative; | |
`; | |
const CrossButton = styled(ButtonContainer)` | |
position: absolute; | |
width: 24px; | |
height: 24px; | |
background-image: url(${require('./images/cross.svg')}); | |
top: -16px; | |
right: 0; | |
transform: translateX(50%); | |
@media (max-width: 768px) { | |
top: 0; | |
right: 20px; | |
transform: none; | |
} | |
`; | |
const CancelButton = styled(ButtonContainer)` | |
position: absolute; | |
top: 0; | |
right: 0; | |
line-height: 24px; | |
font-size: 14px; | |
color: #EB5757; | |
width: auto; | |
`; | |
const InputPlace = styled.div` | |
height: 66px; | |
position: relative; | |
width: 100%; | |
margin-top: ${props => props.theSecondOne ? 24 : 32}px; | |
`; | |
const InputWr = styled.div` | |
position: absolute; | |
width: 100%; | |
`; | |
const InputLabel = styled.div` | |
line-height: 16px; | |
font-size: 12px; | |
color: #FFFFFF; | |
position: relative; | |
`; | |
const InputActionButton = styled( | |
({withCheck, isChecked, isDisabled, ...props}) => <ButtonContainer {...props}/>, | |
)` | |
${css` | |
width: auto; | |
line-height: 16px; | |
font-size: 12px; | |
text-align: right; | |
text-decoration-line: underline; | |
color: #31B5FF; | |
position: absolute; | |
right: 0; | |
${props => props.isDisabled && css` | |
pointer-events: none; | |
opacity: 0.5; | |
`}; | |
${props => props.withCheck && css` | |
padding-right: 24px; | |
&::before, &::after { | |
content: ''; | |
position: absolute; | |
} | |
&::before { | |
background-image: url(${require('./images/check-placeholder.svg')}); | |
width: 16px; | |
height: 16px; | |
right: 0; | |
} | |
&::after { | |
display: ${props => !props.isChecked && 'none'}; | |
background-image: url(${require('./images/check.svg')}); | |
width: 12px; | |
height: 9px; | |
right: 2px; | |
top: 50%; | |
transform: translateY(-50%); | |
} | |
`}; | |
`} | |
`; | |
const Input = styled.input` | |
background: #FFFFFF; | |
border: 1px solid #DFE4E8; | |
border-radius: 4px; | |
font-family: Roboto !important; | |
font-weight: 500; | |
line-height: 24px; | |
font-size: 16px; | |
color: #232F55; | |
padding: 7px 16px; | |
width: 100%; | |
margin-top: 8px; | |
outline: none; | |
${props => props.isDisabled && css` | |
pointer-events: none; | |
color: rgba(35, 47, 85, 0.6); | |
`}; | |
${props => props.withTokenSelect && css` | |
border-top-left-radius: 0; | |
border-bottom-left-radius: 0; | |
margin-left: 73px; | |
padding-left: 12px; | |
width: calc(100% - 74px); | |
`}; | |
`; | |
const InputTokenSelectButton = styled( | |
({icon_url, ...props}) => <ButtonContainer {...props}/>, | |
)` | |
${css` | |
position: absolute; | |
line-height: 24px; | |
font-size: 14px; | |
color: #010101; | |
background: #EFF0F9; | |
border: 1px solid rgba(223, 228, 232, 0.6); | |
box-sizing: border-box; | |
border-top-left-radius: 4px; | |
border-bottom-left-radius: 4px; | |
bottom: 0; | |
left: 0; | |
height: 40px; | |
width: 74px; | |
padding-left: 28px; | |
padding-right: 17px; | |
&::before, &::after { | |
content: ''; | |
position: absolute; | |
} | |
&::before { | |
left: 5px; | |
top: 50%; | |
transform: translateY(-50%); | |
width: 18px; | |
height: 18px; | |
background-image: url(${props => props.icon_url}); | |
background-size: cover; | |
} | |
&::after { | |
right: 4px; | |
top: 50%; | |
transform: translateY(-50%); | |
width: 9px; | |
height: 5px; | |
background-image: url(${require('./images/select-token-arrow.svg')}); | |
} | |
`} | |
`; | |
const EnableButton = styled( | |
({showSpinner, ...props}) => <ButtonContainer {...props}/>, | |
)` | |
${css` | |
position: absolute; | |
bottom: 8px; | |
right: 8px; | |
background: #f0f1fa; | |
border: 1px solid rgba(45, 54, 138, 0.1); | |
box-sizing: border-box; | |
border-radius: 16px; | |
width: 76px; | |
height: 24px; | |
&::before, &::after { | |
position: absolute; | |
} | |
&::before { | |
content: ''; | |
background-image: url(${require('./images/lock.svg')}); | |
width: 8px; | |
height: 10px; | |
left: 14px; | |
top: 6px; | |
${props => props.showSpinner && css` | |
left: 13px; | |
top: 5px; | |
width: 12px; | |
height: 12px; | |
background: url(${require('./images/spinner.png')}) no-repeat; | |
background-size: cover; | |
@keyframes spinner { | |
from { | |
transform: rotate(0); | |
} | |
to { | |
transform: rotate(360deg); | |
} | |
} | |
animation: spinner .6s linear infinite; | |
`}; | |
} | |
&::after { | |
content: 'Enable'; | |
font-weight: 500; | |
line-height: 16px; | |
font-size: 11px; | |
color: #2D368A; | |
top: 4px; | |
right: 11px; | |
} | |
`} | |
`; | |
const ValuesWr = styled.div` | |
margin-top: 28px; | |
`; | |
const SubmitButton = styled( | |
({showSpinner, ...props}) => <ButtonContainer {...props}/>, | |
)` | |
${css` | |
background: #31B5FF; | |
border-radius: 6px; | |
text-align: center; | |
padding: 8px 0; | |
margin-top: 24px; | |
&:disabled { | |
opacity: 0.8; | |
} | |
span { | |
line-height: 24px; | |
font-size: 18px; | |
color: #FFFFFF; | |
position: relative; | |
&::before { | |
display: ${props => !props.showSpinner && 'none'}; | |
content: ''; | |
position: absolute; | |
top: 50%; | |
margin-top: -8px; | |
left: -28px; | |
width: 16px; | |
height: 16px; | |
background: url(${require('./images/spinner.png')}) no-repeat; | |
background-size: cover; | |
@keyframes spinner { | |
from { | |
transform: rotate(0); | |
} | |
to { | |
transform: rotate(360deg); | |
} | |
} | |
animation: spinner .6s linear infinite; | |
} | |
} | |
`}; | |
`; | |
const TransactionFee = styled.div` | |
margin-top: 16px; | |
text-align: center; | |
.label { | |
line-height: 16px; | |
font-size: 14px; | |
color: #C0C3DC; | |
} | |
.value { | |
margin-left: 9px; | |
font-family: Roboto !important; | |
font-weight: 500; | |
line-height: 16px; | |
font-size: 14px; | |
color: #FFFFFF; | |
} | |
`; | |
const BottomError = styled.div` | |
background: #F27D6D; | |
border-radius: 4px; | |
line-height: 16px; | |
font-size: 12px; | |
padding: 4px 0 4px 33px; | |
color: #FFFFFF; | |
position: relative; | |
margin-top: 16px; | |
&::before { | |
content: ''; | |
position: absolute; | |
width: 12px; | |
height: 12px; | |
top: 50%; | |
transform: translateY(-50%); | |
left: 17px; | |
background-image: url(${require('./images/error.svg')}); | |
} | |
`; | |
const FIRST_TIME_BORROWING_ERROR = 'first-time-borrowing-error'; | |
export default withContext( | |
Form, | |
[ | |
'swCdpId', | |
'selectedWalletAssets', | |
'assetsPrices', | |
'swDsProxyAddress', | |
'cdpService', | |
'sendTransaction', | |
'swCdpInfo', | |
'getAverageGasPrice', | |
'estimateGas', | |
'setSwCdpTx', | |
'swCdpTx', | |
'setSwCdpUnlockTx', | |
'swCdpUnlockTxs', | |
'getTxReceipt', | |
'showNotification', | |
'erc20Service', | |
'getNonce', | |
], | |
); | |
Form.propTypes = forbidExtraProps({ | |
onClose: func.isRequired, | |
sendTransaction: func.isRequired, | |
swCdpId: string, | |
selectedWalletAssets: object, | |
assetsPrices: object.isRequired, | |
selectedButtonName: string, | |
swDsProxyAddress: string, | |
cdpService: object.isRequired, | |
swCdpInfo: object, | |
getAverageGasPrice: func.isRequired, | |
estimateGas: func.isRequired, | |
setSwCdpUnlockTx: func.isRequired, | |
getTxReceipt: func.isRequired, | |
getNonce: func.isRequired, | |
showNotification: func.isRequired, | |
setSwCdpTx: func.isRequired, | |
swCdpTx: object, | |
swCdpUnlockTxs: object, | |
erc20Service: object.isRequired, | |
}); | |
const estimatingTimesRef = {value: 0}; | |
function Form({ | |
getTxReceipt, | |
onClose, | |
swCdpId, | |
selectedWalletAssets, | |
assetsPrices, | |
swDsProxyAddress, | |
selectedButtonName, | |
sendTransaction, | |
swCdpInfo, | |
getAverageGasPrice, | |
estimateGas, | |
showNotification, | |
setSwCdpTx, | |
swCdpTx, | |
setSwCdpUnlockTx, | |
swCdpUnlockTxs, | |
getNonce, | |
cdpService: { | |
createOpen, | |
createOpenDeposit, | |
createOpenDepositBorrow, | |
open, | |
openDeposit, | |
openDepositBorrow, | |
deposit, | |
borrow, | |
repay, | |
close, | |
withdraw, | |
repay_feeDAI, | |
close_feeDAI, | |
}, | |
erc20Service, | |
}) { | |
const [{ | |
isAllowancesFetched = false, | |
tokensAllowances = Object.keys(payFeeAssetsRaw).reduce( | |
(acc, code) => { | |
acc[code] = false; | |
return acc; | |
}, | |
{[w.DAI_CODE]: false}, | |
), | |
tokensPendingAllowances = Object.keys(swCdpUnlockTxs), | |
isCloseCdpChecked = swCdpTx ? swCdpTx.isCloseCdpChecked : false, | |
fInputValue = swCdpTx ? swCdpTx.fInputValue : '0', | |
sInputValue = swCdpTx ? swCdpTx.sInputValue : '0', | |
isSelectAssetModalShown = false, | |
selectedAssetCode = Object.keys(payFeeAssetsRaw)[0], | |
tokensAreFetched = false, | |
cannotEstimateGasError = false, | |
isGasEstimating = false, | |
gasEstimation = swCdpTx ? swCdpTx.gasEstimation : 0, | |
gasPrice = swCdpTx ? swCdpTx.gasPrice : 0, | |
throwFetchError = null, | |
payFeeAssets = {}, | |
}, ss] = useStateReducer(); | |
selectedButtonName = swCdpTx ? swCdpTx.selectedButtonName : selectedButtonName; | |
const isFormSubmitting = Boolean(swCdpTx); | |
if (throwFetchError) { | |
throw throwFetchError; | |
} | |
const CREATING_FOR_THE_FIRST_TIME = Number(swDsProxyAddress) === 0; | |
const USER_HAS_NO_CDP = swCdpId === null; | |
const USER_HAS_CDP = !USER_HAS_NO_CDP; | |
const [DEPOSIT, WITHDRAW, BORROW] = ['deposit', 'withdraw', 'borrow'].map(s => s === selectedButtonName); | |
const [REPAY, CLOSE] = [!isCloseCdpChecked, isCloseCdpChecked].map(b => selectedButtonName === 'repay' && b); | |
const getTxParams = async () => { | |
try { | |
const [value, jam, wad] = (() => { | |
if (USER_HAS_NO_CDP) { | |
return [fInputValue, undefined, sInputValue]; | |
} | |
return { | |
[DEPOSIT]: [fInputValue], | |
[WITHDRAW]: [undefined, fInputValue], | |
[BORROW || REPAY || CLOSE]: [undefined, undefined, fInputValue], | |
}[true]; | |
})(); | |
const data = (() => { | |
const inputsType = [Number(fInputValue) !== 0, Number(sInputValue) !== 0].join('|'); | |
if (CREATING_FOR_THE_FIRST_TIME) { | |
if (inputsType === 'false|true') { | |
throw FIRST_TIME_BORROWING_ERROR; | |
} | |
return { | |
'false|false': createOpen(), | |
'true|false': createOpenDeposit(), | |
'true|true': createOpenDepositBorrow(wad), | |
}[inputsType]; | |
} | |
if (USER_HAS_NO_CDP) { | |
if (inputsType === 'false|true') { | |
throw FIRST_TIME_BORROWING_ERROR; | |
} | |
return { | |
'false|false': open(), | |
'true|false': openDeposit(), | |
'true|true': openDepositBorrow(wad), | |
}[inputsType]; | |
} | |
return { | |
[DEPOSIT]: deposit(), | |
[BORROW]: borrow(wad), | |
[REPAY]: repay(wad), | |
[CLOSE]: close(), | |
[REPAY && selectedAssetCode === w.DAI_CODE]: repay_feeDAI(wad), | |
[CLOSE && selectedAssetCode === w.DAI_CODE]: close_feeDAI(), | |
[WITHDRAW]: withdraw(jam), | |
}[true]; | |
})(); | |
const params = { | |
to: CREATING_FOR_THE_FIRST_TIME ? cdpPortalProxy.address : swDsProxyAddress, | |
value: web3Utils.toWei(value), | |
data, | |
}; | |
return params; | |
} | |
catch (e) { | |
if (e === FIRST_TIME_BORROWING_ERROR) { | |
ss({cannotEstimateGasError: true}); | |
} | |
else { | |
console.error(e); // eslint-disable-line no-console | |
} | |
throw e; | |
} | |
}; | |
const handleInputChange = (inputNumber, {target: {value}}) => { | |
if (!/^$|^\d+\.?\d{0,18}$/g.test(value)) { | |
return; | |
} | |
if (/^0+$/.test(value)) { | |
value = '0'; | |
} | |
else if (/^0\d+$/.test(value)) { | |
value = value.slice(1); | |
} | |
ss({[`${inputNumber}InputValue`]: value}); | |
}; | |
const handleSubmitButtonClick = async () => { | |
try { | |
const params = await getTxParams(); | |
params.gas = web3Utils.toWei(gasEstimation); | |
params.gasPrice = gasPrice; | |
const txHash = await sendTransaction(params); | |
const nonce = await getNonce(); | |
setSwCdpTx({ | |
hash: txHash, | |
nonce, | |
selectedButtonName, | |
isCloseCdpChecked, | |
fInputValue, | |
sInputValue, | |
gasEstimation, | |
gasPrice, | |
}); | |
} | |
catch (e) { | |
if (e === 'USER_CANCELLED_CONNECTING_SELECTED_WALLET' || e.message === 'Error: MetaMask Tx Signature: User denied transaction signature.') { | |
return; | |
} | |
console.error(e); // eslint-disable-line no-console | |
ss({throwFetchError: e}); | |
} | |
}; | |
const formHeader = !swCdpId | |
? 'Open CDP' | |
: { | |
borrow: 'Borrow DAI', | |
repay: 'Repay DAI', | |
deposit: 'Deposit ETH', | |
withdraw: 'Withdraw ETH', | |
}[selectedButtonName] | |
; | |
const { | |
header, | |
fInput, | |
sInput, | |
} = { | |
header: formHeader, | |
fInput: (() => { | |
const label = ( | |
<InputLabel> | |
{(() => { | |
if (USER_HAS_NO_CDP) { | |
return 'Deposit ETH'; | |
} | |
return formHeader; | |
})()} | |
<InputActionButton | |
isDisabled={isFormSubmitting} | |
{...(() => { | |
if (REPAY || CLOSE) { | |
return { | |
children: 'Close CDP', | |
onClick: () => ss({ | |
isCloseCdpChecked: !isCloseCdpChecked, | |
fInputValue: isCloseCdpChecked ? '0' : String(web3Utils.fromWei(swCdpInfo.debt)), | |
sInputValue: '0', | |
gasEstimation: 0, | |
gasPrice: 0, | |
cannotEstimateGasError: false, | |
}), | |
isChecked: isCloseCdpChecked, | |
withCheck: true, | |
}; | |
} | |
return { | |
children: null, | |
}; | |
})()} | |
/> | |
</InputLabel> | |
); | |
return { | |
label, | |
isDisabled: CLOSE || isFormSubmitting, | |
}; | |
})(), | |
sInput: (() => { | |
if (USER_HAS_NO_CDP) { | |
return { | |
label: ( | |
<InputLabel> | |
Borrow DAI | |
</InputLabel> | |
), | |
isDisabled: isFormSubmitting, | |
}; | |
} | |
if (REPAY || CLOSE) { | |
return { | |
label: ( | |
<InputLabel> | |
Stability Fee | |
</InputLabel> | |
), | |
isDisabled: true, | |
}; | |
} | |
return null; | |
})(), | |
}; | |
const handleUnlockClick = async code => { | |
try { | |
ss({tokensPendingAllowances: [...tokensPendingAllowances, code]}); | |
const params = erc20Service.getApproveParams(code, swDsProxyAddress); | |
const gas = await estimateGas(params); | |
const gasPrice = await getAverageGasPrice(); | |
params.gas = gas; | |
params.gasPrice = gasPrice; | |
const txHash = await sendTransaction(params); | |
const nonce = await getNonce(); | |
setSwCdpUnlockTx(code, { | |
hash: txHash, | |
nonce, | |
}); | |
} | |
catch (e) { | |
ss({tokensPendingAllowances: tokensPendingAllowances.filter(_code => _code !== code)}); | |
if (e === 'USER_CANCELLED_CONNECTING_SELECTED_WALLET' || e.message === 'Error: MetaMask Tx Signature: User denied transaction signature.') { | |
return; | |
} | |
console.error(e); // eslint-disable-line no-console | |
ss({throwFetchError: e}); | |
} | |
}; | |
const fetchAllowances = async () => { | |
try { | |
const codes = Object.keys(payFeeAssetsRaw); | |
const promises = codes.map(code => erc20Service.getIsAllowed(code, swDsProxyAddress)); | |
const allowances = await Promise.all(promises); | |
const isDaiAllowed = await erc20Service.getIsAllowed(w.DAI_CODE, swDsProxyAddress); | |
ss({ | |
tokensAllowances: allowances.reduce( | |
(acc, isAllowed, idx) => { | |
acc[codes[idx]] = isAllowed; | |
return acc; | |
}, | |
{[w.DAI_CODE]: isDaiAllowed}, | |
), | |
isAllowancesFetched: true, | |
}); | |
} | |
catch (e) { | |
console.error(e); // eslint-disable-line no-console | |
ss({throwFetchError: e}); | |
} | |
}; | |
useInterval( | |
() => { | |
Object.entries(swCdpUnlockTxs).forEach( | |
async ([code, txHash]) => { | |
try { | |
const tx = await getTxReceipt(txHash); | |
if (!tx) { | |
const currentNonce = await getNonce(); | |
if (currentNonce > swCdpTx.nonce) { | |
setSwCdpUnlockTx(code, null); | |
ss({tokensPendingAllowances: tokensPendingAllowances.filter(_code => _code !== code)}); | |
fetchAllowances(); | |
} | |
return; | |
} | |
const {status} = tx; | |
if (status === '0x0') { | |
showNotification({status: 'error', message: 'CDP unlock tx failed. Please, try again.'}); | |
} | |
if (status === '0x1') { | |
setSwCdpUnlockTx(code, null); | |
ss({tokensPendingAllowances: tokensPendingAllowances.filter(_code => _code !== code)}); | |
ss({tokensAllowances: {...tokensAllowances, [code]: true}}); | |
} | |
} | |
catch (e) { | |
console.error(e); // eslint-disable-line no-console | |
if (e.message.includes('JsonRpcEngine - response has no error or result for request')) { | |
return; | |
} | |
ss({throwFetchError: e}); | |
} | |
}, | |
); | |
}, | |
3000, | |
); | |
useEffect(() => { | |
fetchAllowances(); | |
}, []); | |
useEffect(() => { | |
if (swCdpTx) { | |
return; | |
} | |
ss({ | |
fInputValue: '0', | |
sInputValue: '0', | |
isCloseCdpChecked: false, | |
gasEstimation: 0, | |
gasPrice: 0, | |
cannotEstimateGasError: false, | |
}); | |
}, [selectedButtonName]); | |
useEffect(() => { | |
if (swCdpTx) { | |
return; | |
} | |
estimatingTimesRef.value++; | |
if (USER_HAS_CDP && !CLOSE && Number(fInputValue) === 0) { | |
ss({ | |
cannotEstimateGasError: false, | |
isGasEstimating: false, | |
gasEstimation: 0, | |
gasPrice: 0, | |
}); | |
return; | |
} | |
(async () => { | |
try { | |
ss({isGasEstimating: true}); | |
const params = await getTxParams(); | |
const estimatingTimes = estimatingTimesRef.value; | |
try { | |
const gas = await estimateGas(params); | |
const gasPrice = await getAverageGasPrice(); | |
if (estimatingTimes === estimatingTimesRef.value) { | |
ss({ | |
gasEstimation: web3Utils.fromWei((gas * 1.2).toFixed(0)), | |
gasPrice: (gasPrice * 1.2).toFixed(0), | |
cannotEstimateGasError: false, | |
isGasEstimating: false, | |
}); | |
} | |
} | |
catch (e) { | |
if (estimatingTimes === estimatingTimesRef.value) { | |
ss({ | |
cannotEstimateGasError: true, | |
isGasEstimating: false, | |
}); | |
} | |
} | |
} | |
catch (e) { | |
if (e !== FIRST_TIME_BORROWING_ERROR) { | |
console.error(e); // eslint-disable-line no-console | |
} | |
} | |
})(); | |
}, [fInputValue, sInputValue, isCloseCdpChecked, tokensAllowances]); | |
useEffect(() => { | |
if (selectedWalletAssets !== undefined && assetsPrices.eth !== undefined && !tokensAreFetched ) { | |
ss({tokensAreFetched: true}); | |
FetchTokenaryService.tokens(Object.keys(payFeeAssetsRaw)) | |
.then(tokens => { | |
ss({ | |
payFeeAssets: Object.keys(tokens).reduce( | |
(acc, code) => { | |
acc[code] = { | |
decimals: tokens[code].decimals, | |
icon_url: payFeeAssetsRaw[code].icon_url, | |
price_usd: tokens[code].price_usd, | |
symbol: payFeeAssetsRaw[code].symbol, | |
name: tokens[code].title, | |
quantity: selectedWalletAssets[code] && selectedWalletAssets[code].quantity || 0, | |
}; | |
acc[code].decimaledQuantity = web3Utils.toBigNumber(10 ** -acc[code].decimals).mul(String(acc[code].quantity)); | |
return acc; | |
}, | |
{...payFeeAssets}, | |
), | |
}); | |
}) | |
.catch(e => { | |
console.error(e); // eslint-disable-line no-console | |
ss({throwFetchError: e}); | |
}) | |
; | |
} | |
}); | |
return ( | |
<> | |
{isSelectAssetModalShown && | |
<SelectAssetModal | |
title="Pay with" | |
onClose={() => ss({isSelectAssetModalShown: false})} | |
assets={payFeeAssets} | |
onSelect={code => ss({selectedAssetCode: code, isSelectAssetModalShown: false})} | |
selectedAssetCode={selectedAssetCode} | |
/> | |
} | |
<Wr> | |
<Header> | |
{header} | |
{swCdpTx | |
? null | |
: USER_HAS_NO_CDP | |
? <CancelButton onClick={onClose}>Cancel</CancelButton> | |
: <CrossButton onClick={onClose}/> | |
} | |
</Header> | |
<InputPlace> | |
<InputWr> | |
{fInput.label} | |
<Input | |
value={swCdpTx ? swCdpTx.fInputValue : fInputValue} | |
onChange={(...args) => handleInputChange('f', ...args)} | |
isDisabled={fInput.isDisabled} | |
onBlur={() => fInputValue === '' && ss({fInputValue: '0'})} | |
/> | |
{(REPAY || CLOSE) && Number(fInputValue) !== 0 && isAllowancesFetched && !tokensAllowances[w.DAI_CODE] && | |
<EnableButton | |
disabled={tokensPendingAllowances.includes(w.DAI_CODE)} | |
showSpinner={tokensPendingAllowances.includes(w.DAI_CODE)} | |
onClick={() => handleUnlockClick(w.DAI_CODE)} | |
/> | |
} | |
</InputWr> | |
</InputPlace> | |
<InputPlace theSecondOne> | |
{sInput && ( | |
<InputWr> | |
{sInput.label} | |
{(REPAY || CLOSE) && tokensAreFetched && | |
<InputTokenSelectButton | |
onClick={() => ss({isSelectAssetModalShown: true})} | |
icon_url={payFeeAssetsRaw[selectedAssetCode].icon_url} | |
> | |
{payFeeAssetsRaw[selectedAssetCode].symbol} | |
</InputTokenSelectButton> | |
} | |
<Input | |
value={(REPAY || CLOSE) ? '3.5%' : swCdpTx ? swCdpTx.sInputValue : sInputValue} | |
onChange={(...args) => handleInputChange('s', ...args)} | |
isDisabled={sInput.isDisabled} | |
onBlur={() => sInputValue === '' && ss({sInputValue: '0'})} | |
withTokenSelect={REPAY || CLOSE} | |
/> | |
{(REPAY || CLOSE) && isAllowancesFetched && !tokensAllowances[selectedAssetCode] && | |
<EnableButton | |
disabled={tokensPendingAllowances.includes(selectedAssetCode)} | |
showSpinner={tokensPendingAllowances.includes(selectedAssetCode)} | |
onClick={() => handleUnlockClick(selectedAssetCode)} | |
/> | |
} | |
</InputWr> | |
)} | |
</InputPlace> | |
<ValuesWr> | |
<Values | |
debt={ | |
USER_HAS_NO_CDP | |
? sInputValue || 0 | |
: { | |
[true]: String(web3Utils.fromWei(swCdpInfo.debt)), | |
[BORROW]: String(web3Utils.toBigNumber(web3Utils.fromWei(swCdpInfo.debt)).add(fInputValue || 0)), | |
[REPAY]: String(web3Utils.toBigNumber(web3Utils.fromWei(swCdpInfo.debt)).sub(fInputValue || 0)), | |
}[true] | |
} | |
collateral={ | |
USER_HAS_NO_CDP | |
? fInputValue || 0 | |
: { | |
[true]: String(web3Utils.fromWei(swCdpInfo.collateral.mul(String(swCdpInfo.makerPer)))), | |
[DEPOSIT]: String(web3Utils.toBigNumber(web3Utils.fromWei(swCdpInfo.collateral.mul(String(swCdpInfo.makerPer)))).add(fInputValue || 0)), | |
[WITHDRAW]: String(web3Utils.toBigNumber(web3Utils.fromWei(swCdpInfo.collateral.mul(String(swCdpInfo.makerPer)))).sub(fInputValue || 0)), | |
}[true] | |
} | |
/> | |
</ValuesWr> | |
<SubmitButton | |
onClick={handleSubmitButtonClick} | |
showSpinner={isFormSubmitting} | |
disabled={swCdpId && (!isAllowancesFetched || !tokensAllowances[selectedAssetCode]) || isFormSubmitting || gasEstimation === 0 || isGasEstimating || cannotEstimateGasError || (USER_HAS_CDP && !CLOSE && Number(fInputValue) === 0)} | |
> | |
<span>{CLOSE ? 'Close CDP' : formHeader}</span> | |
</SubmitButton> | |
{!cannotEstimateGasError && | |
<TransactionFee> | |
<span className="label"> | |
Transaction fee | |
</span> | |
<span className="value"> | |
{gasEstimation * gasPrice} ETH (${(gasEstimation * gasPrice * assetsPrices.eth.value.usd ).toFixed(2)}) | |
</span> | |
</TransactionFee> | |
} | |
{cannotEstimateGasError && | |
<BottomError> | |
Cannot estimate gas | |
</BottomError> | |
} | |
</Wr> | |
</> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment