• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

input-output-hk / lace / 8365257172

20 Mar 2024 08:11PM UTC coverage: 53.437% (-0.4%) from 53.839%
8365257172

push

github

9cf76f
pczeglik-iohk
test(extension): tawalletnofunds received some ada by mistake (#968)

2293 of 5275 branches covered (43.47%)

Branch coverage included in aggregate %.

5239 of 8820 relevant lines covered (59.4%)

54.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

21.84
/apps/browser-extension-wallet/src/features/dapp/components/collateral/CreateCollateral.tsx
1
/* eslint-disable react/no-multi-comp */
2
import React, { useCallback, useEffect, useMemo, useState } from 'react';
72✔
3
import { DappCreateCollateralProps } from './types';
4
import { DappInfo, RowContainer, renderAmountInfo, renderLabel } from '@lace/core';
72✔
5
import { APIErrorCode, ApiError } from '@cardano-sdk/dapp-connector';
72✔
6
import { Wallet } from '@lace/cardano';
72✔
7
import { useTranslation } from 'react-i18next';
72✔
8
import { useWalletStore } from '@src/stores';
72✔
9
import { useFetchCoinPrice } from '@hooks';
72✔
10
import { Layout } from '../Layout';
72✔
11
import { Banner, Button, Password, inputProps, useObservable } from '@lace/common';
72✔
12
import { firstValueFrom } from 'rxjs';
72✔
13
import { map, take, filter } from 'rxjs/operators';
72✔
14
import { isNotNil } from '@cardano-sdk/util';
72✔
15
import { useCurrencyStore } from '@providers';
72✔
16
import { cardanoCoin } from '@src/utils/constants';
72✔
17
import { Spin, Typography } from 'antd';
72✔
18
import styles from './styles.module.scss';
72✔
19
import { withSignTxConfirmation } from '@lib/wallet-api-ui';
72✔
20

21
const { Text } = Typography;
72✔
22

23
export const CreateCollateral = ({
72✔
24
  dappInfo,
25
  collateralInfo,
26
  confirm,
27
  reject
28
}: DappCreateCollateralProps): React.ReactElement => {
29
  const { t } = useTranslation();
×
30

31
  const { inMemoryWallet, walletType, isInMemoryWallet } = useWalletStore();
×
32
  const addresses = useObservable(inMemoryWallet.addresses$);
×
33
  const [isSubmitting, setIsSubmitting] = useState(false);
×
34
  const [password, setPassword] = useState('');
×
35
  const [isPasswordValid, setIsPasswordValid] = useState(true);
×
36

37
  const handleChange: inputProps['onChange'] = ({ target: { value } }) => {
×
38
    setIsPasswordValid(true);
×
39
    setPassword(value);
×
40
  };
41
  const { priceResult } = useFetchCoinPrice();
×
42
  const { fiatCurrency } = useCurrencyStore();
×
43
  const [collateralTx, setCollateralTx] = useState<{ fee: bigint; tx: Wallet.UnwitnessedTx }>();
×
44

45
  useEffect(() => {
×
46
    const getTx = async () => {
×
47
      const output: Wallet.Cardano.TxOut = {
×
48
        address: !!addresses && Wallet.Cardano.PaymentAddress(addresses[0].address),
×
49
        value: {
50
          coins: collateralInfo.amount
51
        }
52
      };
53

54
      const builtTx = inMemoryWallet.createTxBuilder().addOutput(output).build();
×
55
      const inspectedTx = await builtTx.inspect();
×
56
      setCollateralTx({ fee: inspectedTx.body.fee, tx: builtTx });
×
57
    };
58

59
    getTx();
×
60
  }, [collateralInfo.amount, inMemoryWallet, addresses]);
61

62
  const createCollateralTx = useCallback(async () => {
×
63
    setIsSubmitting(true);
×
64
    const submitTx = async () => {
×
65
      const signedTx = await collateralTx.tx.sign();
×
66
      await inMemoryWallet.submitTx(signedTx);
×
67
      const utxo = await firstValueFrom(
×
68
        inMemoryWallet.utxo.available$.pipe(
69
          map((utxos) => utxos.find((o) => o[0].txId === signedTx.tx.id && o[1].value.coins === collateralInfo.amount)),
×
70
          filter(isNotNil),
71
          take(1)
72
        )
73
      );
74
      await inMemoryWallet.utxo.setUnspendable([utxo]);
×
75
      confirm([utxo]);
×
76
    };
77

78
    try {
×
79
      await withSignTxConfirmation(submitTx, password);
×
80
    } catch (error) {
81
      if (error instanceof Wallet.KeyManagement.errors.AuthenticationError) {
×
82
        setPassword('');
×
83
        setIsPasswordValid(false);
×
84
      }
85
    }
86
    setIsSubmitting(false);
×
87
  }, [collateralTx, collateralInfo.amount, inMemoryWallet, password, confirm]);
88

89
  const confirmButtonLabel = useMemo(() => {
×
90
    if (isInMemoryWallet) {
×
91
      return t('browserView.settings.wallet.collateral.confirm');
×
92
    }
93
    return t('browserView.settings.wallet.collateral.confirmWithDevice', { hardwareWallet: walletType });
×
94
  }, [isInMemoryWallet, walletType, t]);
95

96
  return (
×
97
    <Layout
98
      pageClassname={styles.spaceBetween}
99
      title={t('dapp.collateral.create.header')}
100
      data-testid="dapp-create-collateral-layout"
101
    >
102
      <div className={styles.container}>
103
        <DappInfo {...dappInfo} />
104
        <div data-testid="collateral-send" className={styles.collateralSend}>
105
          <Text className={styles.collateralDescription} data-testid="collateral-description">
106
            {t('browserView.settings.wallet.collateral.amountDescription')}
107
          </Text>
108
          {isInMemoryWallet && (
×
109
            <div data-testid="collateral-password">
110
              <Spin spinning={false}>
111
                <Password
112
                  onChange={handleChange}
113
                  value={password}
114
                  error={isPasswordValid === false}
115
                  errorMessage={t('browserView.transaction.send.error.invalidPassword')}
116
                  label={t('browserView.transaction.send.password.placeholder')}
117
                  autoFocus
118
                />
119
              </Spin>
120
            </div>
121
          )}
122
          <Banner className={styles.noTopMargin} withIcon message={t('dapp.collateral.amountSeparated')} />
123
          {collateralTx?.fee && (
×
124
            <RowContainer>
125
              {renderLabel({
126
                label: t('staking.confirmation.transactionFee'),
127
                dataTestId: 'sp-confirmation-staking-fee',
128
                tooltipContent: t('send.theAmountYoullBeChargedToProcessYourTransaction')
129
              })}
130
              <div>
131
                {renderAmountInfo(
132
                  Wallet.util.getFormattedAmount({
133
                    amount: collateralTx.fee.toString(),
134
                    cardanoCoin
135
                  }),
136
                  `${Wallet.util.convertAdaToFiat({
137
                    ada: Wallet.util.lovelacesToAdaString(collateralTx.fee.toString()),
138
                    fiat: priceResult?.cardano?.price || 0
×
139
                  })} ${fiatCurrency?.code}`
×
140
                )}
141
              </div>
142
            </RowContainer>
143
          )}
144
        </div>
145
      </div>
146
      <div className={styles.footer} style={{ zIndex: 1000 }}>
147
        <Button
148
          block
149
          data-testid="collateral-confirmation-btn"
150
          disabled={isSubmitting}
151
          loading={isSubmitting}
152
          className={styles.footerBtn}
153
          size="large"
154
          onClick={createCollateralTx}
155
        >
156
          {confirmButtonLabel}
157
        </Button>
158
        <Button
159
          block
160
          className={styles.footerBtn}
161
          color="secondary"
162
          onClick={() => reject(new ApiError(APIErrorCode.Refused, 'user declined to set collateral'))}
×
163
        >
164
          {t('general.button.cancel')}
165
        </Button>
166
      </div>
167
    </Layout>
168
  );
169
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc