Skip to content

Commit

Permalink
Refactor transaction planning
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterBenc committed Feb 28, 2021
1 parent 6b1effa commit 0729689
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 246 deletions.
42 changes: 23 additions & 19 deletions app/frontend/actions.ts
Expand Up @@ -31,10 +31,8 @@ import ShelleyCryptoProviderFactory from './wallet/shelley/shelley-crypto-provid
import {ShelleyWallet} from './wallet/shelley-wallet'
import {parseUnsignedTx} from './helpers/cliParser/parser'
import {
calculateMinUTxOLovelaceAmount,
TxPlan,
TxPlanResult,
TxPlanResultType,
unsignedPoolTxToTxPlan,
} from './wallet/shelley/shelley-transaction-planner'
import getDonationAddress from './helpers/getDonationAddress'
Expand Down Expand Up @@ -515,8 +513,9 @@ export default ({setState, getState}: {setState: SetStateFn; getState: GetStateF
sendTransactionSummary: {
// TODO: we should reset this to null
type: TxType.SEND_ADA,
sendAddress: {fieldValue: ''},
sendAmount: {assetFamily: AssetFamily.ADA, fieldValue: '', coins: 0 as Lovelace},
address: null,
coins: 0 as Lovelace,
token: null,
minimalLovelaceAmount: 0 as Lovelace,
fee: 0 as Lovelace,
plan: null,
Expand Down Expand Up @@ -592,8 +591,9 @@ export default ({setState, getState}: {setState: SetStateFn; getState: GetStateF
throw e
}
return {
type: TxPlanResultType.FAILURE,
success: false,
estimatedFee: 0 as Lovelace,
minimalLovelaceAmount: 0 as Lovelace,
error: {code: e.name},
}
}
Expand All @@ -617,12 +617,10 @@ export default ({setState, getState}: {setState: SetStateFn; getState: GetStateF
txType: TxType.SEND_ADA,
})
const balance = getSourceAccountInfo(state).balance as Lovelace
const minimalLovelaceAmount = calculateMinUTxOLovelaceAmount(
sendAmount.assetFamily === AssetFamily.ADA ? [] : [sendAmount.token]
)
const coins = sendAmount.assetFamily === AssetFamily.ADA ? sendAmount.coins : (0 as Lovelace)
const token = sendAmount.assetFamily === AssetFamily.TOKEN ? sendAmount.token : null

if (txPlanResult.type === TxPlanResultType.SUCCESS) {
if (txPlanResult.success === true) {
const newState = getState() // if the values changed meanwhile
if (
newState.sendAmount.fieldValue !== state.sendAmount.fieldValue ||
Expand All @@ -633,9 +631,10 @@ export default ({setState, getState}: {setState: SetStateFn; getState: GetStateF
}
const sendTransactionSummary: SendTransactionSummary = {
type: TxType.SEND_ADA,
sendAddress: newState.sendAddress,
sendAmount,
minimalLovelaceAmount,
address: newState.sendAddress.fieldValue as _Address,
coins,
token,
minimalLovelaceAmount: txPlanResult.txPlan.additionalLovelaceAmount,
}
setTransactionSummary(txPlanResult.txPlan, sendTransactionSummary)
setState({
Expand All @@ -645,8 +644,12 @@ export default ({setState, getState}: {setState: SetStateFn; getState: GetStateF
})
} else {
const validationError =
txPlanValidator(coins, minimalLovelaceAmount, balance, txPlanResult.estimatedFee) ||
txPlanResult.error
txPlanValidator(
coins,
txPlanResult.minimalLovelaceAmount,
balance,
txPlanResult.estimatedFee
) || txPlanResult.error
setErrorState('sendAmountValidationError', validationError)
setState({
calculatingFee: false,
Expand Down Expand Up @@ -725,11 +728,12 @@ export default ({setState, getState}: {setState: SetStateFn; getState: GetStateF
})
const balance = getSourceAccountInfo(state).balance as Lovelace

if (txPlanResult.type === TxPlanResultType.SUCCESS) {
if (txPlanResult.success === true) {
const sendTransactionSummary: SendTransactionSummary = {
type: TxType.SEND_ADA,
sendAmount,
sendAddress: {fieldValue: address},
address,
coins,
token: null,
minimalLovelaceAmount: 0 as Lovelace,
}
setTransactionSummary(txPlanResult.txPlan, sendTransactionSummary)
Expand Down Expand Up @@ -761,7 +765,7 @@ export default ({setState, getState}: {setState: SetStateFn; getState: GetStateF
// TODO: balance should be of type Lovelace
const balance = getSourceAccountInfo(state).balance as Lovelace

if (txPlanResult.type === TxPlanResultType.SUCCESS) {
if (txPlanResult.success === true) {
const withdrawTransactionSummary: WithdrawTransactionSummary = {
type: TxType.WITHDRAW,
rewards,
Expand Down Expand Up @@ -834,7 +838,7 @@ export default ({setState, getState}: {setState: SetStateFn; getState: GetStateF
}
const balance = getSourceAccountInfo(state).balance as Lovelace

if (txPlanResult.type === TxPlanResultType.SUCCESS) {
if (txPlanResult.success === true) {
setState({
shelleyDelegation: {
...newState.shelleyDelegation,
Expand Down
190 changes: 17 additions & 173 deletions app/frontend/components/pages/sendAda/confirmTransactionDialog.tsx
Expand Up @@ -37,41 +37,37 @@ const SendAdaReview = ({
transactionSummary: TransactionSummary & SendTransactionSummary
shouldShowAddressVerification: boolean
}) => {
const {sendAddress, sendAmount, fee, minimalLovelaceAmount} = transactionSummary
const summarySendAmount =
sendAmount.assetFamily === AssetFamily.ADA ? sendAmount.coins : (0 as Lovelace)
const total = (summarySendAmount + fee + minimalLovelaceAmount) as Lovelace
const summaryToken = sendAmount.assetFamily === AssetFamily.TOKEN ? sendAmount.token : null
const {address, coins, fee, minimalLovelaceAmount, token} = transactionSummary
const lovelaceAmount = (coins + minimalLovelaceAmount) as Lovelace
const total = (coins + fee) as Lovelace

return (
<Fragment>
<div className="review">
<div className="review-label">Address</div>
<div className="review-address">
{sendAddress.fieldValue}
{shouldShowAddressVerification && (
<AddressVerification address={sendAddress.fieldValue} />
)}
{address}
{shouldShowAddressVerification && <AddressVerification address={address} />}
</div>
{/* TODO: Hide ADA symbol when handling tokens */}
<div className="ada-label">Amount</div>
<div className="review-amount">
{printAda((summarySendAmount + minimalLovelaceAmount) as Lovelace)}
{printAda((lovelaceAmount) as Lovelace)}
</div>
{summaryToken && (
{token && (
<Fragment>
<div className="review-label">Token policy Id</div>
<div className="review-amount">{summaryToken.policyId}</div>
<div className="review-amount">{token.policyId}</div>
<div className="review-label">Token name</div>
<div className="review-amount">{assetNameHex2Readable(summaryToken.assetName)}</div>
<div className="review-amount">{assetNameHex2Readable(token.assetName)}</div>
<div className="review-label">Token amount</div>
<div className="review-amount">{summaryToken.quantity}</div>
<div className="review-amount">{token.quantity}</div>
{/* <div className="ada-label">Minimal Lovelace amount</div>
<div className="review-amount">{printAda(minimalLovelaceAmount)}</div> */}
</Fragment>
)}
<div className="ada-label">Fee</div>
<div className="review-fee">{printAda(transactionSummary.fee as Lovelace)}</div>
<div className="review-fee">{printAda(fee as Lovelace)}</div>
{/* TODO: Hide ADA symbol when handling tokens */}
<div className="ada-label">Total</div>
<div className="review-total">{printAda(total)}</div>
Expand Down Expand Up @@ -160,10 +156,8 @@ const ConvertFundsReview = ({
}: {
transactionSummary: TransactionSummary & SendTransactionSummary
}) => {
const {sendAddress, sendAmount, fee} = transactionSummary
const summarySendAmount =
sendAmount.assetFamily === AssetFamily.ADA ? sendAmount.coins : (0 as Lovelace)
const total = (summarySendAmount + fee) as Lovelace
const {address, coins, fee} = transactionSummary
const total = (coins + fee) as Lovelace
return (
<Fragment>
<div>
Expand All @@ -173,13 +167,13 @@ const ConvertFundsReview = ({
<div className="review">
<div className="review-label">Address</div>
<div className="review-address">
{sendAddress.fieldValue}
<AddressVerification address={sendAddress.fieldValue} />
{address}
<AddressVerification address={address} />
</div>
<div className="ada-label">Amount</div>
<div className="review-amount">{printAda(summarySendAmount)}</div>
<div className="review-amount">{printAda(coins)}</div>
<div className="ada-label">Fee</div>
<div className="review-fee">{printAda(transactionSummary.fee as Lovelace)}</div>
<div className="review-fee">{printAda(fee as Lovelace)}</div>
{/* TODO: Hide ADA symbol when handling tokens */}
<div className="ada-label">Total</div>
<div className="review-total">{printAda(total)}</div>
Expand Down Expand Up @@ -254,156 +248,6 @@ const ConfirmTransactionDialog = ({
)
}

// class ConfirmTransactionDialogClass extends Component<Props, {}> {
// cancelTx: HTMLAnchorElement

// componentDidMount() {
// this.cancelTx.focus()
// }

// render({
// sendAddress,
// summary,
// submitTransaction,
// cancelTransaction,
// setRawTransactionOpen,
// rawTransactionOpen,
// stakePool,
// txConfirmType,
// }: Props) {
// // TODO: refactor all of this
// const summarySendAmount =
// summary.amount?.assetFamily === AssetFamily.ADA ? summary.amount?.coins : (0 as Lovelace)
// const totalAmount = (summarySendAmount + summary.fee + summary.deposit) as Lovelace
// const totalAmounts = {
// convert: summarySendAmount,
// withdraw: (summary.rewards ?? (0 as Lovelace)) - summary.fee,
// }
// const total = (totalAmounts[txConfirmType] as Lovelace) || (totalAmount as Lovelace)
// const titleMap = {
// delegate: 'Delegation review',
// revoke: 'Delegation revocation review',
// send: 'Transaction review',
// convert: 'Stakable balance conversion review',
// withdraw: 'Rewards withdrawal review',
// crossAccount: 'Transaction between accounts review',
// }
// return (
// // TODO: make separate fragments into constants and then build specific types from them
// <Modal onRequestClose={cancelTransaction} title={titleMap[txConfirmType]}>
// {txConfirmType === 'convert' && (
// <div>
// We are creating transaction that will send all funds from your non-staking addresses to
// your first staking address
// </div>
// )}
// {txConfirmType === 'withdraw' && (
// <div>
// We are creating transaction that will withdraw all funds from your rewards account
// balance to your first staking address
// </div>
// )}
// <div className="review">
// {(txConfirmType === 'send' || txConfirmType === 'crossAccount') && (
// <Fragment>
// <div className="review-label">Address</div>
// <div className="review-address">
// {sendAddress}
// {txConfirmType === 'crossAccount' && <AddressVerification address={sendAddress} />}
// </div>
// {/* TODO: Hide ADA symbol when handling tokens */}
// <div className="ada-label">Amount</div>
// <div className="review-amount">{printAda(summarySendAmount)}</div>
// </Fragment>
// )}

// {txConfirmType === 'convert' && (
// <Fragment>
// <div className="review-label">Address</div>
// <div className="review-address">
// {summary.plan.outputs[0].address}
// <AddressVerification address={summary.plan.outputs[0].address} />
// </div>
// <div className="ada-label">Amount</div>
// <div className="review-amount">{printAda(totalAmount)}</div>
// </Fragment>
// )}

// {txConfirmType === 'withdraw' && (
// <Fragment>
// <div className="review-label">Address</div>
// <div className="review-address">
// {summary.plan.change.address}
// <AddressVerification address={summary.plan.change.address} />
// </div>
// <div className="ada-label">Rewards</div>
// <div className="review-amount">{printAda(summary.plan.withdrawals[0].rewards)}</div>
// </Fragment>
// )}

// {txConfirmType === 'delegate' && (
// <Fragment>
// <div className="review-label">Pool ID</div>
// <div className="review-amount">{stakePool.poolHash}</div>
// <div className="review-label">Pool Name</div>
// <div className="review-amount">{stakePool.name}</div>
// <div className="review-label">Ticker</div>
// <div className="review-amount">{stakePool.ticker}</div>
// <div className="review-label">Tax</div>
// <div className="review-amount">{stakePool.margin && stakePool.margin * 100}%</div>
// <div className="review-label">Fixed cost</div>
// <div className="review-amount">
// {stakePool.fixedCost && printAda(stakePool.fixedCost)}
// </div>
// <div className="review-label">Homepage</div>
// <div className="review-amount">{stakePool.homepage}</div>
// <div className="ada-label">Deposit</div>
// <div className="review-fee">
// {printAda(summary.plan.deposit)}
// <a
// {...tooltip(
// 'Required deposit for address stake key registration is 2 ADA. Deposit is made with your first delegation. Further delegations do not require any additional deposits.',
// true
// )}
// >
// <span className="show-info">{''}</span>
// </a>
// </div>
// </Fragment>
// )}
// <div className="ada-label">Fee</div>
// <div className="review-fee">{printAda(summary.fee as Lovelace)}</div>
// {/* TODO: Hide ADA symbol when handling tokens */}
// <div className="ada-label">Total</div>
// <div className="review-total">{printAda(total)}</div>
// </div>

// <div className="review-bottom">
// <button className="button primary" onClick={submitTransaction}>
// Confirm Transaction
// </button>
// <a
// className="review-cancel"
// onClick={cancelTransaction}
// ref={(element) => {
// this.cancelTx = element
// }}
// onKeyDown={(e) => {
// e.key === 'Enter' && (e.target as HTMLAnchorElement).click()
// }}
// >
// Cancel Transaction
// </a>
// </div>
// <a href="#" className="send-raw" onClick={setRawTransactionOpen}>
// Raw unsigned transaction
// </a>
// {rawTransactionOpen && <RawTransactionModal />}
// </Modal>
// )
// }
// }

export default connect(
(state: State) => ({
sendAddress: state.sendAddress.fieldValue,
Expand Down
24 changes: 3 additions & 21 deletions app/frontend/components/pages/sendAda/sendAdaPage.tsx
Expand Up @@ -96,25 +96,6 @@ const showDropdownAssetItem = ({type, star, assetName, policyId, quantity}: Drop
</div>
)

const calculateTotalAmounts = (transactionSummary: TransactionSummary) => {
const zeroTotal = {totalLovelace: 0 as Lovelace, totalTokens: null}
if (!transactionSummary || transactionSummary.type !== TxType.SEND_ADA) return zeroTotal
const {sendAmount, fee, minimalLovelaceAmount} = transactionSummary
if (sendAmount.assetFamily === AssetFamily.ADA) {
return {
totalLovelace: (sendAmount.coins + fee) as Lovelace,
totalTokens: null,
}
}
if (sendAmount.assetFamily === AssetFamily.TOKEN) {
return {
totalLovelace: (minimalLovelaceAmount + fee) as Lovelace,
totalTokens: sendAmount.token,
}
}
return zeroTotal
}

const SendAdaPage = ({
sendResponse,
sendAddress,
Expand Down Expand Up @@ -150,7 +131,8 @@ const SendAdaPage = ({
const enableSubmit = sendAmount.fieldValue && sendAddress && !sendFormValidationError
const isSendAddressValid = !sendAddressValidationError && sendAddress !== ''

const {totalLovelace, totalTokens} = calculateTotalAmounts(summary)
const totalLovelace = (summary.coins + summary.fee + summary.minimalLovelaceAmount) as Lovelace
const totalTokens = summary.token

const adaAsset: DropdownAssetItem = {
type: AssetFamily.ADA,
Expand Down Expand Up @@ -359,7 +341,7 @@ const SendAdaPage = ({
</a>
</div>
{/* TODO: Connect to state when this values is calculated */}
<div className="send-fee">{printAda(2000000 as Lovelace)}</div>
<div className="send-fee">{printAda(summary.minimalLovelaceAmount)}</div>
</Fragment>
)}
</div>
Expand Down

0 comments on commit 0729689

Please sign in to comment.