From a9e6c10bb2c5201a3ce62a5487a6d7459f3b2a24 Mon Sep 17 00:00:00 2001 From: Lucas Araujo Date: Tue, 24 Oct 2023 13:17:24 -0300 Subject: [PATCH 01/13] feat(core): setup storybook --- packages/core/.storybook/main.ts | 37 +++++++++++++++++++++++++++++ packages/core/.storybook/preview.ts | 18 ++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 packages/core/.storybook/main.ts create mode 100644 packages/core/.storybook/preview.ts diff --git a/packages/core/.storybook/main.ts b/packages/core/.storybook/main.ts new file mode 100644 index 0000000000..4b4aaa16c7 --- /dev/null +++ b/packages/core/.storybook/main.ts @@ -0,0 +1,37 @@ +import type { StorybookConfig } from '@storybook/react-webpack5'; + +import { join, dirname } from 'path'; + +/** + * This function is used to resolve the absolute path of a package. + * It is needed in projects that use Yarn PnP or are set up within a monorepo. + */ +function getAbsolutePath(value: string): any { + return dirname(require.resolve(join(value, 'package.json'))); +} +const config: StorybookConfig = { + stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + addons: [ + getAbsolutePath('@storybook/addon-links'), + getAbsolutePath('@storybook/addon-essentials'), + getAbsolutePath('@storybook/addon-onboarding'), + getAbsolutePath('@storybook/addon-interactions'), + { + name: '@storybook/addon-styling', + options: { + sass: { + // Require your Sass preprocessor here + implementation: require('sass') + } + } + } + ], + framework: { + name: getAbsolutePath('@storybook/react-webpack5'), + options: {} + }, + docs: { + autodocs: 'tag' + } +}; +export default config; diff --git a/packages/core/.storybook/preview.ts b/packages/core/.storybook/preview.ts new file mode 100644 index 0000000000..3f708890e3 --- /dev/null +++ b/packages/core/.storybook/preview.ts @@ -0,0 +1,18 @@ +import type { Preview } from '@storybook/react'; +import 'antd/dist/antd.css'; +import 'normalize.css'; +import './theme.scss'; + +const preview: Preview = { + parameters: { + actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/ + } + } + } +}; + +export default preview; From e647e8679c1e8a1433bcc5d597e45563c7764400 Mon Sep 17 00:00:00 2001 From: Lucas Araujo Date: Tue, 24 Oct 2023 13:18:14 -0300 Subject: [PATCH 02/13] feat(core): add lace/ui package --- packages/core/.storybook/{preview.ts => preview.tsx} | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) rename packages/core/.storybook/{preview.ts => preview.tsx} (59%) diff --git a/packages/core/.storybook/preview.ts b/packages/core/.storybook/preview.tsx similarity index 59% rename from packages/core/.storybook/preview.ts rename to packages/core/.storybook/preview.tsx index 3f708890e3..397dbf0f0d 100644 --- a/packages/core/.storybook/preview.ts +++ b/packages/core/.storybook/preview.tsx @@ -1,7 +1,9 @@ +import React from 'react'; import type { Preview } from '@storybook/react'; import 'antd/dist/antd.css'; import 'normalize.css'; import './theme.scss'; +import { ThemeColorScheme, ThemeProvider } from '@lace/ui'; const preview: Preview = { parameters: { @@ -12,7 +14,14 @@ const preview: Preview = { date: /Date$/ } } - } + }, + decorators: [ + (Story) => ( + + + + ) + ] }; export default preview; From 8ce5dd3a3624ee32bdbf943a2aff9152d822dd16 Mon Sep 17 00:00:00 2001 From: Lucas Araujo Date: Thu, 21 Sep 2023 22:02:29 -0300 Subject: [PATCH 03/13] feat: check for DRep transaction --- .../DRepRegistrationContainer.tsx | 11 +++ .../confirm-transaction/SendContainer.tsx | 72 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DRepRegistrationContainer.tsx create mode 100644 apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/SendContainer.tsx diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DRepRegistrationContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DRepRegistrationContainer.tsx new file mode 100644 index 0000000000..74f38a9c84 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DRepRegistrationContainer.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +// import { useTranslation } from 'react-i18next'; +import { Skeleton } from 'antd'; +import { SignTxData } from './types'; + +export const DRepRegistrationContent = ({ signTxData }: { signTxData: SignTxData }): React.ReactElement => { + // const { t } = useTranslation(); + const tx = signTxData?.tx; + + return <>{tx ? <> : }; +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/SendContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/SendContainer.tsx new file mode 100644 index 0000000000..e693d69e2b --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/SendContainer.tsx @@ -0,0 +1,72 @@ +import React, { useEffect } from 'react'; +import { useObservable } from '@lace/common'; +import { useTranslation } from 'react-i18next'; +import { DappTransaction } from '@lace/core'; +import { useAddressBookContext, withAddressBookContext } from '@src/features/address-book/context'; +import { useWalletStore } from '@stores'; +import { AddressListType } from '@views/browser/features/activity'; +import { Skeleton } from 'antd'; +import { TokenInfo } from '@src/utils/get-assets-information'; +import { useCreateAssetList, useTxSummary } from './hooks'; +import { SignTxData } from './types'; + +export const SendContent = withAddressBookContext( + ({ + signTxData, + errorMessage, + disableConfirmationBtn + }: { + signTxData: SignTxData; + disableConfirmationBtn: (disable: boolean) => void; + errorMessage?: string; + }): React.ReactElement => { + const { t } = useTranslation(); + const { + walletInfo, + inMemoryWallet, + blockchainProvider: { assetProvider } + } = useWalletStore(); + const { list: addressList } = useAddressBookContext() as { list: AddressListType[] }; + const tx = signTxData.tx; + const outputs = tx.body.outputs; + const assets = useObservable(inMemoryWallet.assetInfo$); + const availableBalance = useObservable(inMemoryWallet.balance.utxo.available$); + const createAssetList = useCreateAssetList({ outputs, assets, assetProvider }); + const { txSummary, hasInsufficientFunds } = useTxSummary({ + addressList, + createAssetList, + availableBalance, + tx, + walletInfo + }); + + useEffect(() => { + disableConfirmationBtn(hasInsufficientFunds); + }, [disableConfirmationBtn, hasInsufficientFunds]); + + const translations = { + transaction: t('core.dappTransaction.transaction'), + amount: t('core.dappTransaction.amount'), + recipient: t('core.dappTransaction.recipient'), + fee: t('core.dappTransaction.fee'), + insufficientFunds: t('core.dappTransaction.insufficientFunds'), + adaFollowingNumericValue: t('general.adaFollowingNumericValue') + }; + + return ( + <> + {txSummary ? ( + + ) : ( + + )} + + ); + } +); From 15cfa69089a74cf0daa4b6e3f502801b45ee3796 Mon Sep 17 00:00:00 2001 From: Lucas Araujo Date: Tue, 24 Oct 2023 13:22:12 -0300 Subject: [PATCH 04/13] feat: integrate confirm drep registration component --- .../DRepRegistrationContainer.tsx | 11 --- .../confirm-transaction/SendContainer.tsx | 72 ------------------- 2 files changed, 83 deletions(-) delete mode 100644 apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DRepRegistrationContainer.tsx delete mode 100644 apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/SendContainer.tsx diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DRepRegistrationContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DRepRegistrationContainer.tsx deleted file mode 100644 index 74f38a9c84..0000000000 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/DRepRegistrationContainer.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -// import { useTranslation } from 'react-i18next'; -import { Skeleton } from 'antd'; -import { SignTxData } from './types'; - -export const DRepRegistrationContent = ({ signTxData }: { signTxData: SignTxData }): React.ReactElement => { - // const { t } = useTranslation(); - const tx = signTxData?.tx; - - return <>{tx ? <> : }; -}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/SendContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/SendContainer.tsx deleted file mode 100644 index e693d69e2b..0000000000 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/SendContainer.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import React, { useEffect } from 'react'; -import { useObservable } from '@lace/common'; -import { useTranslation } from 'react-i18next'; -import { DappTransaction } from '@lace/core'; -import { useAddressBookContext, withAddressBookContext } from '@src/features/address-book/context'; -import { useWalletStore } from '@stores'; -import { AddressListType } from '@views/browser/features/activity'; -import { Skeleton } from 'antd'; -import { TokenInfo } from '@src/utils/get-assets-information'; -import { useCreateAssetList, useTxSummary } from './hooks'; -import { SignTxData } from './types'; - -export const SendContent = withAddressBookContext( - ({ - signTxData, - errorMessage, - disableConfirmationBtn - }: { - signTxData: SignTxData; - disableConfirmationBtn: (disable: boolean) => void; - errorMessage?: string; - }): React.ReactElement => { - const { t } = useTranslation(); - const { - walletInfo, - inMemoryWallet, - blockchainProvider: { assetProvider } - } = useWalletStore(); - const { list: addressList } = useAddressBookContext() as { list: AddressListType[] }; - const tx = signTxData.tx; - const outputs = tx.body.outputs; - const assets = useObservable(inMemoryWallet.assetInfo$); - const availableBalance = useObservable(inMemoryWallet.balance.utxo.available$); - const createAssetList = useCreateAssetList({ outputs, assets, assetProvider }); - const { txSummary, hasInsufficientFunds } = useTxSummary({ - addressList, - createAssetList, - availableBalance, - tx, - walletInfo - }); - - useEffect(() => { - disableConfirmationBtn(hasInsufficientFunds); - }, [disableConfirmationBtn, hasInsufficientFunds]); - - const translations = { - transaction: t('core.dappTransaction.transaction'), - amount: t('core.dappTransaction.amount'), - recipient: t('core.dappTransaction.recipient'), - fee: t('core.dappTransaction.fee'), - insufficientFunds: t('core.dappTransaction.insufficientFunds'), - adaFollowingNumericValue: t('general.adaFollowingNumericValue') - }; - - return ( - <> - {txSummary ? ( - - ) : ( - - )} - - ); - } -); From ae14460158700e41df839becfcae1cc56467243d Mon Sep 17 00:00:00 2001 From: Lucas Araujo Date: Tue, 24 Oct 2023 13:24:23 -0300 Subject: [PATCH 05/13] refactor: remove insufficient funds warning; break down main component --- .../features/dapp/components/confirm-transaction/utils.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts index 6b6611499d..a47dbec0c8 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts @@ -142,3 +142,8 @@ export const getOwnRetirementMessageKey = (isOwnRetirement: boolean | undefined) } return isOwnRetirement ? 'core.drepRetirement.isOwnRetirement' : 'core.drepRetirement.isNotOwnRetirement'; }; + +export const isDRepRegistration = (tx: Wallet.Cardano.Tx | undefined): boolean => + tx?.body.certificates.some( + ({ __typename }) => __typename === Wallet.Cardano.CertificateType.RegisterDelegateRepresentative + ); From 293654b5168d9833594e251445904c41903b81c6 Mon Sep 17 00:00:00 2001 From: Lucas Araujo Date: Tue, 24 Oct 2023 13:24:48 -0300 Subject: [PATCH 06/13] feat: add certificate data --- .../dapp/components/confirm-transaction/utils.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts index a47dbec0c8..657982485e 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts @@ -143,7 +143,15 @@ export const getOwnRetirementMessageKey = (isOwnRetirement: boolean | undefined) return isOwnRetirement ? 'core.drepRetirement.isOwnRetirement' : 'core.drepRetirement.isNotOwnRetirement'; }; +const isDRepRegistrationCertificate = (type: Wallet.Cardano.CertificateType) => + type === Wallet.Cardano.CertificateType.RegisterDelegateRepresentative; + +export const getDRepCertificate = ( + tx: Wallet.Cardano.Tx +): Wallet.Cardano.RegisterDelegateRepresentativeCertificate | undefined => + tx?.body.certificates.find(({ __typename }) => isDRepRegistrationCertificate(__typename)) as + | Wallet.Cardano.RegisterDelegateRepresentativeCertificate + | undefined; + export const isDRepRegistration = (tx: Wallet.Cardano.Tx | undefined): boolean => - tx?.body.certificates.some( - ({ __typename }) => __typename === Wallet.Cardano.CertificateType.RegisterDelegateRepresentative - ); + tx?.body.certificates.some(({ __typename }) => isDRepRegistrationCertificate(__typename)); From 4a0ffdc0f9f37f1ca2814fc4492183a265c441f5 Mon Sep 17 00:00:00 2001 From: Lucas Araujo Date: Tue, 24 Oct 2023 13:28:38 -0300 Subject: [PATCH 07/13] feat: add drep retirement container --- .../dapp/components/confirm-transaction/utils.ts | 13 ------------- .../src/lib/translations/en.json | 6 ++++++ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts index 657982485e..6b6611499d 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts @@ -142,16 +142,3 @@ export const getOwnRetirementMessageKey = (isOwnRetirement: boolean | undefined) } return isOwnRetirement ? 'core.drepRetirement.isOwnRetirement' : 'core.drepRetirement.isNotOwnRetirement'; }; - -const isDRepRegistrationCertificate = (type: Wallet.Cardano.CertificateType) => - type === Wallet.Cardano.CertificateType.RegisterDelegateRepresentative; - -export const getDRepCertificate = ( - tx: Wallet.Cardano.Tx -): Wallet.Cardano.RegisterDelegateRepresentativeCertificate | undefined => - tx?.body.certificates.find(({ __typename }) => isDRepRegistrationCertificate(__typename)) as - | Wallet.Cardano.RegisterDelegateRepresentativeCertificate - | undefined; - -export const isDRepRegistration = (tx: Wallet.Cardano.Tx | undefined): boolean => - tx?.body.certificates.some(({ __typename }) => isDRepRegistrationCertificate(__typename)); diff --git a/apps/browser-extension-wallet/src/lib/translations/en.json b/apps/browser-extension-wallet/src/lib/translations/en.json index 4ecc80854f..2eb729c7d4 100644 --- a/apps/browser-extension-wallet/src/lib/translations/en.json +++ b/apps/browser-extension-wallet/src/lib/translations/en.json @@ -1121,6 +1121,12 @@ "isOwnRetirement": "This is your DRep retirement.", "isNotOwnRetirement": "The presented DRepID does not match your wallet's DRepID." }, + "drepRetirement": { + "title": "Confirm DRep retirement", + "metadata": "Metadata", + "drepId": "Drep ID", + "depositReturned": "Deposit returned" + }, "destinationAddressInput": { "recipientAddress": "Recipient's address or $handle" }, From c258971fc431295fce9a6a500c1d4cb62d7acf5d Mon Sep 17 00:00:00 2001 From: Michael Chappell <7581002+mchappell@users.noreply.github.com> Date: Thu, 12 Oct 2023 10:12:06 +0100 Subject: [PATCH 08/13] feat(extension): use consistent naming of DRep ID --- apps/browser-extension-wallet/src/lib/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/browser-extension-wallet/src/lib/translations/en.json b/apps/browser-extension-wallet/src/lib/translations/en.json index 2eb729c7d4..caef3d43af 100644 --- a/apps/browser-extension-wallet/src/lib/translations/en.json +++ b/apps/browser-extension-wallet/src/lib/translations/en.json @@ -1124,7 +1124,7 @@ "drepRetirement": { "title": "Confirm DRep retirement", "metadata": "Metadata", - "drepId": "Drep ID", + "drepId": "DRep ID", "depositReturned": "Deposit returned" }, "destinationAddressInput": { From d102f7798896007f6a56d273b8ba9ee706a05c3f Mon Sep 17 00:00:00 2001 From: Lucas Araujo Date: Tue, 24 Oct 2023 13:30:24 -0300 Subject: [PATCH 09/13] fix: add cardano symbol to deposit amount --- apps/browser-extension-wallet/src/lib/translations/en.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/browser-extension-wallet/src/lib/translations/en.json b/apps/browser-extension-wallet/src/lib/translations/en.json index caef3d43af..4ecc80854f 100644 --- a/apps/browser-extension-wallet/src/lib/translations/en.json +++ b/apps/browser-extension-wallet/src/lib/translations/en.json @@ -1121,12 +1121,6 @@ "isOwnRetirement": "This is your DRep retirement.", "isNotOwnRetirement": "The presented DRepID does not match your wallet's DRepID." }, - "drepRetirement": { - "title": "Confirm DRep retirement", - "metadata": "Metadata", - "drepId": "DRep ID", - "depositReturned": "Deposit returned" - }, "destinationAddressInput": { "recipientAddress": "Recipient's address or $handle" }, From 09e72ec920f611c9b1d9481755dcdb9da3f31a33 Mon Sep 17 00:00:00 2001 From: Lucas Araujo Date: Tue, 24 Oct 2023 13:31:14 -0300 Subject: [PATCH 10/13] refactor: certificate inspector factory --- .../ConfirmDRepRegistrationContainer.tsx | 9 ++++--- .../ConfirmDRepRetirementContainer.tsx | 9 ++++--- .../components/confirm-transaction/utils.ts | 27 +++++-------------- 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRegistrationContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRegistrationContainer.tsx index f9a32a49c9..3b349e0452 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRegistrationContainer.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRegistrationContainer.tsx @@ -2,10 +2,12 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { ConfirmDRepRegistration } from '@lace/core'; import { SignTxData } from './types'; -import { dRepRegistrationInspector, drepIDasBech32FromHash } from './utils'; +import { certificateInspectorFactory, drepIDasBech32FromHash } from './utils'; import { Wallet } from '@lace/cardano'; import { useWalletStore } from '@src/stores'; +const { CertificateType } = Wallet.Cardano; + interface Props { signTxData: SignTxData; errorMessage?: string; @@ -13,11 +15,12 @@ interface Props { export const ConfirmDRepRegistrationContainer = ({ signTxData, errorMessage }: Props): React.ReactElement => { const { t } = useTranslation(); - const certificate = dRepRegistrationInspector(signTxData.tx); const { walletUI: { cardanoCoin } } = useWalletStore(); - + const certificate = certificateInspectorFactory( + CertificateType.RegisterDelegateRepresentative + )(signTxData.tx); const depositPaidWithCardanoSymbol = `${Wallet.util.lovelacesToAdaString(certificate.deposit.toString())} ${ cardanoCoin.symbol }`; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx index 1bb2cb14ab..dc926c88e3 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmDRepRetirementContainer.tsx @@ -2,11 +2,13 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { ConfirmDRepRetirement } from '@lace/core'; import { SignTxData } from './types'; -import { dRepRetirementInspector, drepIDasBech32FromHash, getOwnRetirementMessageKey } from './utils'; +import { certificateInspectorFactory, drepIDasBech32FromHash, getOwnRetirementMessageKey } from './utils'; import { Wallet } from '@lace/cardano'; import { useWalletStore } from '@src/stores'; import { useIsOwnPubDRepKey } from './hooks'; +const { CertificateType } = Wallet.Cardano; + interface Props { signTxData: SignTxData; errorMessage?: string; @@ -14,12 +16,13 @@ interface Props { export const ConfirmDRepRetirementContainer = ({ signTxData, errorMessage }: Props): React.ReactElement => { const { t } = useTranslation(); - const certificate = dRepRetirementInspector(signTxData.tx); const { walletUI: { cardanoCoin }, inMemoryWallet } = useWalletStore(); - + const certificate = certificateInspectorFactory( + CertificateType.UnregisterDelegateRepresentative + )(signTxData.tx); const depositPaidWithCardanoSymbol = `${Wallet.util.lovelacesToAdaString(certificate.deposit.toString())} ${ cardanoCoin.symbol }`; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts index 6b6611499d..a48f86b70f 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts @@ -74,32 +74,17 @@ export const getTransactionAssetsId = (outputs: CardanoTxOut[]): Wallet.Cardano. return assetIds; }; -const isDRepRegistrationCertificate = (type: Wallet.Cardano.CertificateType) => - type === Wallet.Cardano.CertificateType.RegisterDelegateRepresentative; - -const isDRepRetirementCertificate = (type: Wallet.Cardano.CertificateType) => - type === Wallet.Cardano.CertificateType.UnregisterDelegateRepresentative; - -export const dRepRegistrationInspector = ( - tx: Wallet.Cardano.Tx -): Wallet.Cardano.RegisterDelegateRepresentativeCertificate | undefined => - tx?.body?.certificates?.find(({ __typename }) => isDRepRegistrationCertificate(__typename)) as - | Wallet.Cardano.RegisterDelegateRepresentativeCertificate - | undefined; - -export const dRepRetirementInspector = ( - tx: Wallet.Cardano.Tx -): Wallet.Cardano.UnRegisterDelegateRepresentativeCertificate | undefined => - tx?.body?.certificates?.find(({ __typename }) => isDRepRetirementCertificate(__typename)) as - | Wallet.Cardano.UnRegisterDelegateRepresentativeCertificate - | undefined; +export const certificateInspectorFactory = + (type: Wallet.Cardano.CertificateType) => + (tx: Wallet.Cardano.Tx): T | undefined => + tx?.body?.certificates?.find((certificate) => certificate.__typename === type) as T | undefined; export const getTxType = (tx: Wallet.Cardano.Tx): TxType => { const inspector = createTxInspector({ minted: assetsMintedInspector, burned: assetsBurnedInspector, - dRepRegistration: dRepRegistrationInspector, - dRepRetirement: dRepRetirementInspector + dRepRegistration: certificateInspectorFactory(CertificateType.RegisterDelegateRepresentative), + dRepRetirement: certificateInspectorFactory(CertificateType.UnregisterDelegateRepresentative) }); const { minted, burned, dRepRegistration, dRepRetirement } = inspector(tx as Wallet.Cardano.HydratedTx); From 5825144adcdfd75e96dc07d51010d735ef627535 Mon Sep 17 00:00:00 2001 From: Lucas Araujo Date: Mon, 16 Oct 2023 14:06:40 -0300 Subject: [PATCH 11/13] feat: voting delegation --- .../ConfirmTransactionContent.tsx | 4 ++ .../ConfirmVoteDelegationContainer.tsx | 42 +++++++++++ .../components/confirm-transaction/utils.ts | 20 +++++- .../src/lib/translations/en.json | 8 +++ packages/core/src/index.ts | 1 + .../ConfirmVoteDelegation.stories.ts | 70 +++++++++++++++++++ .../ConfirmVoteDelegation.tsx | 56 +++++++++++++++ .../components/ConfirmVoteDelegation/index.ts | 1 + 8 files changed, 199 insertions(+), 3 deletions(-) create mode 100644 apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmVoteDelegationContainer.tsx create mode 100644 packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.stories.ts create mode 100644 packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.tsx create mode 100644 packages/core/src/ui/components/ConfirmVoteDelegation/index.ts diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionContent.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionContent.tsx index 8cee30714e..e85a7605cd 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionContent.tsx +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmTransactionContent.tsx @@ -5,6 +5,7 @@ import { DappTransactionContainer } from './DappTransactionContainer'; import { TxType } from './utils'; import { SignTxData } from './types'; import { ConfirmDRepRetirementContainer } from './ConfirmDRepRetirementContainer'; +import { ConfirmVoteDelegationContainer } from './ConfirmVoteDelegationContainer'; interface Props { txType?: TxType; @@ -22,6 +23,9 @@ export const ConfirmTransactionContent = ({ txType, signTxData, errorMessage }: if (txType === TxType.DRepRetirement) { return ; } + if (txType === TxType.VoteDelegation) { + return ; + } return ; }; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmVoteDelegationContainer.tsx b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmVoteDelegationContainer.tsx new file mode 100644 index 0000000000..3e578cc900 --- /dev/null +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/ConfirmVoteDelegationContainer.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { ConfirmVoteDelegation } from '@lace/core'; +import { SignTxData } from './types'; +import { certificateInspectorFactory } from './utils'; +import { Wallet } from '@lace/cardano'; + +const { CertificateType } = Wallet.Cardano; + +interface Props { + signTxData: SignTxData; + errorMessage?: string; +} + +export const ConfirmVoteDelegationContainer = ({ signTxData, errorMessage }: Props): React.ReactElement => { + const { t } = useTranslation(); + const certificate = certificateInspectorFactory( + CertificateType.VoteDelegation + )(signTxData.tx); + const dRep = certificate.dRep; + + return ( + + ); +}; diff --git a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts index a48f86b70f..4432ae8a10 100644 --- a/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts +++ b/apps/browser-extension-wallet/src/features/dapp/components/confirm-transaction/utils.ts @@ -8,6 +8,8 @@ import { runtime } from 'webextension-polyfill'; import { of } from 'rxjs'; import { sectionTitle, DAPP_VIEWS } from '../../config'; +const { CertificateType } = Wallet.Cardano; + const DAPP_TOAST_DURATION = 50; export enum TxType { @@ -15,7 +17,8 @@ export enum TxType { Mint = 'Mint', Burn = 'Burn', DRepRegistration = 'DRepRegistration', - DRepRetirement = 'DRepRetirement' + DRepRetirement = 'DRepRetirement', + VoteDelegation = 'VoteDelegation' } export const getTitleKey = (txType: TxType): string => { @@ -27,6 +30,10 @@ export const getTitleKey = (txType: TxType): string => { return 'core.drepRetirement.title'; } + if (txType === TxType.VoteDelegation) { + return 'core.voteDelegation.title'; + } + return sectionTitle[DAPP_VIEWS.CONFIRM_TX]; }; @@ -84,10 +91,13 @@ export const getTxType = (tx: Wallet.Cardano.Tx): TxType => { minted: assetsMintedInspector, burned: assetsBurnedInspector, dRepRegistration: certificateInspectorFactory(CertificateType.RegisterDelegateRepresentative), - dRepRetirement: certificateInspectorFactory(CertificateType.UnregisterDelegateRepresentative) + dRepRetirement: certificateInspectorFactory(CertificateType.UnregisterDelegateRepresentative), + voteDelegation: certificateInspectorFactory(CertificateType.VoteDelegation) }); - const { minted, burned, dRepRegistration, dRepRetirement } = inspector(tx as Wallet.Cardano.HydratedTx); + const { minted, burned, dRepRegistration, dRepRetirement, voteDelegation } = inspector( + tx as Wallet.Cardano.HydratedTx + ); const isMintTransaction = minted.length > 0; const isBurnTransaction = burned.length > 0; @@ -107,6 +117,10 @@ export const getTxType = (tx: Wallet.Cardano.Tx): TxType => { return TxType.DRepRetirement; } + if (voteDelegation) { + return TxType.VoteDelegation; + } + return TxType.Send; }; diff --git a/apps/browser-extension-wallet/src/lib/translations/en.json b/apps/browser-extension-wallet/src/lib/translations/en.json index 4ecc80854f..7fad7e5e72 100644 --- a/apps/browser-extension-wallet/src/lib/translations/en.json +++ b/apps/browser-extension-wallet/src/lib/translations/en.json @@ -1121,6 +1121,14 @@ "isOwnRetirement": "This is your DRep retirement.", "isNotOwnRetirement": "The presented DRepID does not match your wallet's DRepID." }, + "voteDelegation": { + "title": "Confirm vote delegation", + "metadata": "Metadata", + "drepId": "Drep ID", + "alwaysAbstain": "Abstain", + "alwaysNoConfidence": "No Confidence", + "option": "Yes" + }, "destinationAddressInput": { "recipientAddress": "Recipient's address or $handle" }, diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index bfab885eb9..f096b9b9ce 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -30,3 +30,4 @@ export * from '@ui/components/MnemonicWordsAutoComplete'; export * from '@ui/components/AddressCard'; export * from '@ui/components/ConfirmDRepRegistration'; export * from '@ui/components/ConfirmDRepRetirement'; +export * from '@ui/components/ConfirmVoteDelegation'; diff --git a/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.stories.ts b/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.stories.ts new file mode 100644 index 0000000000..8d0e8f8eb7 --- /dev/null +++ b/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.stories.ts @@ -0,0 +1,70 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { ConfirmVoteDelegation } from './ConfirmVoteDelegation'; +import { ComponentProps } from 'react'; + +const meta: Meta = { + title: 'ConfirmVoteDelegation', + component: ConfirmVoteDelegation, + parameters: { + layout: 'centered' + }, + tags: ['autodocs'] +}; + +export default meta; +type Story = StoryObj; + +const data: ComponentProps = { + dappInfo: { + logo: 'https://cdn.mint.handle.me/favicon.png', + name: 'Mint', + url: 'https://preprod.mint.handle.me' + }, + translations: { + labels: { + drepId: 'Drep ID', + alwaysAbstain: 'Abstain', + alwaysNoConfidence: 'No Confidence' + }, + option: 'Yes', + metadata: 'Metadata' + }, + metadata: { + drepId: 'drep1ruvgm0auzdplfn7g2jf3kcnpnw5mlhwxaxj8crag8h6t2ye9y9g', + alwaysAbstain: false, + alwaysNoConfidence: false + } +}; + +export const Overview: Story = { + args: { + ...data + } +}; +export const WithError: Story = { + args: { + ...data, + errorMessage: 'Something went wrong' + } +}; + +export const WithAbstain: Story = { + args: { + ...data, + metadata: { + alwaysAbstain: true, + alwaysNoConfidence: false + } + } +}; + +export const WithNoConfidence: Story = { + args: { + ...data, + metadata: { + alwaysAbstain: false, + alwaysNoConfidence: true + } + } +}; diff --git a/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.tsx b/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.tsx new file mode 100644 index 0000000000..cad483cc3c --- /dev/null +++ b/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import { Box, Cell, Grid, TransactionSummary, Flex } from '@lace/ui'; +import { DappInfo, DappInfoProps } from '../DappInfo'; +import { ErrorPane } from '@lace/common'; + +interface Props { + dappInfo: Omit; + errorMessage?: string; + translations: { + labels: { + drepId: string; + alwaysAbstain: string; + alwaysNoConfidence: string; + }; + option: string; + metadata: string; + }; + metadata: { + drepId?: string; + alwaysAbstain: boolean; + alwaysNoConfidence: boolean; + }; +} + +export const ConfirmVoteDelegation = ({ dappInfo, errorMessage, translations, metadata }: Props): JSX.Element => ( + + + + + {errorMessage && ( + + + + )} + + + + + {metadata.drepId && ( + + + + )} + {metadata.alwaysAbstain && ( + + + + )} + {metadata.alwaysNoConfidence && ( + + + + )} + + +); diff --git a/packages/core/src/ui/components/ConfirmVoteDelegation/index.ts b/packages/core/src/ui/components/ConfirmVoteDelegation/index.ts new file mode 100644 index 0000000000..33e8e67554 --- /dev/null +++ b/packages/core/src/ui/components/ConfirmVoteDelegation/index.ts @@ -0,0 +1 @@ +export { ConfirmVoteDelegation } from './ConfirmVoteDelegation'; From cf7419ad9ee6383a846c2733e6c51a93c97e18bd Mon Sep 17 00:00:00 2001 From: Lucas Araujo Date: Tue, 24 Oct 2023 13:43:50 -0300 Subject: [PATCH 12/13] fix: type errors --- .../ConfirmVoteDelegation/ConfirmVoteDelegation.stories.ts | 3 +-- .../src/ui/components/VotingProcedures/VotingProcedures.tsx | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.stories.ts b/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.stories.ts index 8d0e8f8eb7..5d23ca14bf 100644 --- a/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.stories.ts +++ b/packages/core/src/ui/components/ConfirmVoteDelegation/ConfirmVoteDelegation.stories.ts @@ -8,8 +8,7 @@ const meta: Meta = { component: ConfirmVoteDelegation, parameters: { layout: 'centered' - }, - tags: ['autodocs'] + } }; export default meta; diff --git a/packages/core/src/ui/components/VotingProcedures/VotingProcedures.tsx b/packages/core/src/ui/components/VotingProcedures/VotingProcedures.tsx index 654f4b76f5..c7824f9880 100644 --- a/packages/core/src/ui/components/VotingProcedures/VotingProcedures.tsx +++ b/packages/core/src/ui/components/VotingProcedures/VotingProcedures.tsx @@ -1,7 +1,7 @@ import React, { Fragment } from 'react'; import { Box, Cell, Grid, Flex, Metadata, MetadataLink, Text, Divider, sx } from '@lace/ui'; import { DappInfo, DappInfoProps } from '../DappInfo'; -import { ErrorPane, Ellipsis } from '@lace/common'; +import { ErrorPane } from '@lace/common'; type VotingProcedure = { voter: { From 5000e988b86d0457b386eac746ab43abb2aaccd3 Mon Sep 17 00:00:00 2001 From: Lucas Araujo Date: Tue, 24 Oct 2023 14:18:36 -0300 Subject: [PATCH 13/13] fix: merge conflicts --- packages/core/.storybook/main.ts | 37 ---------------------------- packages/core/.storybook/preview.tsx | 27 -------------------- 2 files changed, 64 deletions(-) delete mode 100644 packages/core/.storybook/main.ts delete mode 100644 packages/core/.storybook/preview.tsx diff --git a/packages/core/.storybook/main.ts b/packages/core/.storybook/main.ts deleted file mode 100644 index 4b4aaa16c7..0000000000 --- a/packages/core/.storybook/main.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { StorybookConfig } from '@storybook/react-webpack5'; - -import { join, dirname } from 'path'; - -/** - * This function is used to resolve the absolute path of a package. - * It is needed in projects that use Yarn PnP or are set up within a monorepo. - */ -function getAbsolutePath(value: string): any { - return dirname(require.resolve(join(value, 'package.json'))); -} -const config: StorybookConfig = { - stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], - addons: [ - getAbsolutePath('@storybook/addon-links'), - getAbsolutePath('@storybook/addon-essentials'), - getAbsolutePath('@storybook/addon-onboarding'), - getAbsolutePath('@storybook/addon-interactions'), - { - name: '@storybook/addon-styling', - options: { - sass: { - // Require your Sass preprocessor here - implementation: require('sass') - } - } - } - ], - framework: { - name: getAbsolutePath('@storybook/react-webpack5'), - options: {} - }, - docs: { - autodocs: 'tag' - } -}; -export default config; diff --git a/packages/core/.storybook/preview.tsx b/packages/core/.storybook/preview.tsx deleted file mode 100644 index 397dbf0f0d..0000000000 --- a/packages/core/.storybook/preview.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import type { Preview } from '@storybook/react'; -import 'antd/dist/antd.css'; -import 'normalize.css'; -import './theme.scss'; -import { ThemeColorScheme, ThemeProvider } from '@lace/ui'; - -const preview: Preview = { - parameters: { - actions: { argTypesRegex: '^on[A-Z].*' }, - controls: { - matchers: { - color: /(background|color)$/i, - date: /Date$/ - } - } - }, - decorators: [ - (Story) => ( - - - - ) - ] -}; - -export default preview;