From 1ce9f0472cf5f50b6508a0cee686cd0181ff11bb Mon Sep 17 00:00:00 2001 From: Ken Liao Date: Fri, 6 Oct 2023 12:26:34 +0800 Subject: [PATCH] release v0.20.0 (#29) * release: v0.19.0 (#607) * release: v0.19.0 * update package-lock * bump xverse core version to fix fee issue --------- Co-authored-by: Yukan * Build analytics tracking for web-extension (#590) * Build analytics tracking for web-extension * Add `/privacy-preferences` screen * Build analytics tracking for web-extension * Update mixpanel tracking logic * Remove unused wallet action name * Add authorize data collection toggler and popup * Update tracking logic * Add translation keys * Update mixpanel tracking logic * Remove unused imports * Make some code changes after PR review, upgrade `xverse-core` package version * Upgrade `xverse-core` package version * Resolve git conflicts * Handling fees with thresholds (#601) * Handling fees with thresholds * Add margin under the high fees warning * Change the high fees warning position for Ordinals & Brc-20 txs * Show the warning if the initial fee from transaction is greater than the threshold * Add high fee warning for one-step brc20 transfer * update copy --------- Co-authored-by: Yukan * Refactor ledger-related logic (#586) * Add STX support for Ledger accounts * Update the copy and ledger account import logic * Update the ledger account import logic for STX support * Add `/add-stx-address-ledger` route for adding stx account * Remove the old case handling when there is no `ordinalsAddress` * Add STX address verification with ledger device * Remove the `/send-stx-ledger` path and update `/send-stx` to handle ledger * Handle regular STX transactions * Remove unused `/review-ledger-stx-tx` path, add STX NFT handling * Remove `/review-ledger-ft-tx` and `/send-ft-ledger` routes, update `/send-ft` to support ledger * Enable STX auth requests for ledger accounts that have an STX address * Add link to the auth popup to add the STX Ledger account * Update screen UI for STX NFT sending * Update copy for STX incoming tx signing * Update STX message signing logic * Update STX-related logic for ledger accounts * Update error handling for STX message signing with ledger * Get rid of `findLedgerAccountId` ledger util, move more copy to locales * Fix cropped button container for tx signing popup * Update address index definition for adding stx address * Update address index definition for address verification and stx tx confirmation * Update address index definition for stx jwt auth * Refactor ledger-related logic * Refactor ledger account import * Fix ledger account import when both BTC and STX options are selected * Refactor ledger address verification screen * Refactor ledger tx confirmation screen * Refactor Add stx address screen * Fix `unsignedTx` type * Add `StacksRecipient` type and make some small code fixes * Add `icon` prop for the `ActionButton` component * Change the ledger steps in a callback * Add types for ledger tx state objects * Fix account index for stx account import, update ledger tx types and utils * Change the import path for `StacksRecipient` * Change the steps numeration for ledger account import * Get rid of unused step changing logic for ledger account import * Add more error handling * Update xverse-core version for testing purposes * Remove caret symbol in xverse-core package * Fix CI build * Make a couple of code fixes according to PR review comments * Add more transaltions * Add the `DEFAULT_TRANSITION_OPTIONS` constant * Make separate components for Steps and StepControls for the Ledger account import flow * Fix style imports * Upgrade the `xverse-core` package version * Upgrade `xverse-core` package version * Disable PSBT tx signing for ledger accounts * update xverse-core * package-lock --------- Co-authored-by: Yukan * release v0.20.0 * chore: bump to xverse-core 1.8.2 for bip322 signing fix * fix: collectibles dashboard should ignore invalid params errors (#33) * fix: put in a quick fix for more location.state serialization bugs (#34) * chore: add support for rare sats in tx confirmation screen (#35) * chore: add support for rare sats in tx confirmation screen * chore: remove logs and fix typo * chore: change unknown icon --------- Co-authored-by: Tim Man Co-authored-by: Den <36603049+dhriaznov@users.noreply.github.com> Co-authored-by: Tim Man Co-authored-by: fede erbes --- package-lock.json | 22 +++--- package.json | 4 +- .../components/rareSatIcon/rareSatIcon.tsx | 23 ++---- src/app/hooks/useDetectOrdinalInSignPsbt.ts | 42 +++++----- .../confirmOrdinalTransaction/index.tsx | 11 ++- src/app/screens/nftDashboard/index.tsx | 6 +- ...Component.tsx => bundleItemsComponent.tsx} | 76 +++++++++++++------ src/app/screens/signPsbtRequest/index.tsx | 23 +++--- src/app/utils/query.ts | 7 +- .../img/nftDashboard/rareSats/unknown.svg | 7 ++ src/locales/en.json | 4 +- 11 files changed, 128 insertions(+), 97 deletions(-) rename src/app/screens/signPsbtRequest/{ordinalDetailComponent.tsx => bundleItemsComponent.tsx} (65%) create mode 100644 src/assets/img/nftDashboard/rareSats/unknown.svg diff --git a/package-lock.json b/package-lock.json index a4b80a5e3..ba1c9ab17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "xverse-web-extension", - "version": "0.19.0", + "version": "0.20.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "xverse-web-extension", - "version": "0.19.0", + "version": "0.20.0", "dependencies": { "@ledgerhq/hw-transport-webusb": "^6.27.13", "@phosphor-icons/react": "^2.0.10", "@react-spring/web": "^9.6.1", - "@secretkeylabs/xverse-core": "1.8.1", + "@secretkeylabs/xverse-core": "1.8.2", "@stacks/connect": "^6.10.2", "@stacks/encryption": "4.3.5", "@stacks/stacks-blockchain-api-types": "^6.1.1", @@ -2209,15 +2209,15 @@ } }, "node_modules/@secretkeylabs/xverse-core": { - "version": "1.8.1", - "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/1.8.1/e8656470eb2f1c662353883a03e675330303791b", - "integrity": "sha512-8rzgQLSHEHLLrEsBs6BE7p6W55/zSU4ySKw5v/q9n55p1HVnt3WfZoEzJcQ4fd6Hrxaz2gSlnf2ut9EuEDegUQ==", + "version": "1.8.2", + "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/1.8.2/da050d0fa956e39c47f4547596214ce301fec05b", + "integrity": "sha512-M0KlJ6qAl8WAh3kSqsBjnGgl9TKkZ02mBc/CPdOtnKZQc+92xtVxlv6dV44sn4k6BCKxGHNkhlPDXVt2rtGxUQ==", "license": "ISC", "dependencies": { "@bitcoinerlab/secp256k1": "^1.0.2", "@noble/secp256k1": "^1.7.1", "@scure/base": "^1.1.1", - "@scure/btc-signer": "^1.0.0", + "@scure/btc-signer": "1.1.0", "@stacks/auth": "^6.5.1", "@stacks/encryption": "6.1.1", "@stacks/network": "4.3.5", @@ -20408,14 +20408,14 @@ } }, "@secretkeylabs/xverse-core": { - "version": "1.8.1", - "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/1.8.1/e8656470eb2f1c662353883a03e675330303791b", - "integrity": "sha512-8rzgQLSHEHLLrEsBs6BE7p6W55/zSU4ySKw5v/q9n55p1HVnt3WfZoEzJcQ4fd6Hrxaz2gSlnf2ut9EuEDegUQ==", + "version": "1.8.2", + "resolved": "https://npm.pkg.github.com/download/@secretkeylabs/xverse-core/1.8.2/da050d0fa956e39c47f4547596214ce301fec05b", + "integrity": "sha512-M0KlJ6qAl8WAh3kSqsBjnGgl9TKkZ02mBc/CPdOtnKZQc+92xtVxlv6dV44sn4k6BCKxGHNkhlPDXVt2rtGxUQ==", "requires": { "@bitcoinerlab/secp256k1": "^1.0.2", "@noble/secp256k1": "^1.7.1", "@scure/base": "^1.1.1", - "@scure/btc-signer": "^1.0.0", + "@scure/btc-signer": "1.1.0", "@stacks/auth": "^6.5.1", "@stacks/encryption": "6.1.1", "@stacks/network": "4.3.5", diff --git a/package.json b/package.json index 00ad41b2b..21e54fe26 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { "name": "xverse-web-extension", "description": "A Bitcoin wallet for Web3", - "version": "0.19.0", + "version": "0.20.0", "private": true, "dependencies": { "@ledgerhq/hw-transport-webusb": "^6.27.13", "@phosphor-icons/react": "^2.0.10", "@react-spring/web": "^9.6.1", - "@secretkeylabs/xverse-core": "1.8.1", + "@secretkeylabs/xverse-core": "1.8.2", "@stacks/connect": "^6.10.2", "@stacks/encryption": "4.3.5", "@stacks/stacks-blockchain-api-types": "^6.1.1", diff --git a/src/app/components/rareSatIcon/rareSatIcon.tsx b/src/app/components/rareSatIcon/rareSatIcon.tsx index 94a7bb8e1..163a230cd 100644 --- a/src/app/components/rareSatIcon/rareSatIcon.tsx +++ b/src/app/components/rareSatIcon/rareSatIcon.tsx @@ -3,9 +3,9 @@ import Legendary from '@assets/img/nftDashboard/rareSats/legendary.svg'; import Mythic from '@assets/img/nftDashboard/rareSats/mythic.svg'; import Rare from '@assets/img/nftDashboard/rareSats/rare.svg'; import Uncommon from '@assets/img/nftDashboard/rareSats/uncommon.svg'; +import Unknown from '@assets/img/nftDashboard/rareSats/unknown.svg'; import { RareSatsType, getRareSatsColorsByRareSatsType } from '@utils/rareSats'; import styled from 'styled-components'; -import { Question } from '@phosphor-icons/react'; import Theme from '../../../theme'; @@ -27,9 +27,6 @@ const Image = styled.img` height: 100%; zindex: 2; `; -const QuestionIcon = styled(Question)((props) => ({ - color: props.theme.colors.white_0, -})); type GlowProps = { color: string; outerColor: string; @@ -79,27 +76,17 @@ function RareSatIcon({ mythic: Mythic, rare: Rare, uncommon: Uncommon, + unknown: Unknown, }[type]; const backgroundColor = bgColor ? Theme.colors.background[bgColor] : 'transparent'; const { color, backgroundColor: outerColor } = getRareSatsColorsByRareSatsType(type); return ( - {type === 'unknown' ? ( - - ) : ( - <> - {glow && ( - - )} - {type} - + {glow && type !== 'unknown' && ( + )} + {type} ); diff --git a/src/app/hooks/useDetectOrdinalInSignPsbt.ts b/src/app/hooks/useDetectOrdinalInSignPsbt.ts index 98779e567..db6b4261c 100644 --- a/src/app/hooks/useDetectOrdinalInSignPsbt.ts +++ b/src/app/hooks/useDetectOrdinalInSignPsbt.ts @@ -1,42 +1,34 @@ -import { getOrdinalIdFromUtxo, Inscription, ParsedPSBT, UTXO } from '@secretkeylabs/xverse-core'; +import { getUtxoOrdinalBundle, ParsedPSBT } from '@secretkeylabs/xverse-core'; import { useEffect, useState } from 'react'; -import useOrdinalsApi from './useOrdinalsApi'; +import { BundleItem, mapRareSatsAPIResponseToRareSats } from '@utils/rareSats'; import useWalletSelector from './useWalletSelector'; const useDetectOrdinalInSignPsbt = (parsedPsbt: '' | ParsedPSBT) => { const [loading, setLoading] = useState(false); const [userReceivesOrdinal, setUserReceivesOrdinal] = useState(false); - const [ordinalInfoData, setOrdinalInfoData] = useState>([]); + const [bundleItemsData, setBundleItemsData] = useState([]); const { ordinalsAddress } = useWalletSelector(); - const OrdinalsApi = useOrdinalsApi(); - - const getOrdinalId = async (utxoHash: string, index: number) => { - const utxo: UTXO = { - txid: utxoHash, - vout: index, - status: { - confirmed: false, - }, - value: 0, - }; - const data = await getOrdinalIdFromUtxo(utxo); - return data; - }; async function handleOrdinalAndOrdinalInfo() { - const ordinals: Inscription[] = []; + const bundleItems: BundleItem[] = []; if (parsedPsbt) { setLoading(true); await Promise.all( parsedPsbt.inputs.map(async (input) => { - const data = await getOrdinalId(input.txid, input.index); - if (data) { - const response = await OrdinalsApi.getInscription(data); - ordinals.push(response); - } + const data = await getUtxoOrdinalBundle(input.txid, input.index); + console.log({ data }); + + const bundle = mapRareSatsAPIResponseToRareSats(data); + bundle.items.forEach((item) => { + // we don't show unknown items for now + if (item.type === 'unknown') { + return; + } + bundleItems.push(item); + }); }), ); - setOrdinalInfoData(ordinals); + setBundleItemsData(bundleItems); setLoading(false); parsedPsbt.outputs.forEach(async (output) => { if (output.address === ordinalsAddress) { @@ -52,7 +44,7 @@ const useDetectOrdinalInSignPsbt = (parsedPsbt: '' | ParsedPSBT) => { return { loading, - ordinalInfoData, + bundleItemsData, userReceivesOrdinal, }; }; diff --git a/src/app/screens/confirmOrdinalTransaction/index.tsx b/src/app/screens/confirmOrdinalTransaction/index.tsx index c2065a12f..2819190ff 100644 --- a/src/app/screens/confirmOrdinalTransaction/index.tsx +++ b/src/app/screens/confirmOrdinalTransaction/index.tsx @@ -63,7 +63,16 @@ function ConfirmOrdinalTransaction() { const btcClient = useBtcClient(); const [recipientAddress, setRecipientAddress] = useState(''); const location = useLocation(); - const { fee, feePerVByte, signedTxHex, ordinalUtxo, isRareSat } = location.state; + + // TODO tim: refactor to not use location.state. + const { feePerVByte, signedTxHex, ordinalUtxo, isRareSat } = location.state; + // this hack is necessary because the browser back/forward buttons + // serialize BigNumber objects into plain objects + let { fee } = location.state; + if (!BigNumber.isBigNumber(fee)) { + fee = BigNumber(fee); + } + const { selectedOrdinal, selectedSatBundle } = useNftDataSelector(); const { refetch } = useBtcWalletData(); const [currentFee, setCurrentFee] = useState(fee); diff --git a/src/app/screens/nftDashboard/index.tsx b/src/app/screens/nftDashboard/index.tsx index 4938d5cc0..a5b8dc046 100644 --- a/src/app/screens/nftDashboard/index.tsx +++ b/src/app/screens/nftDashboard/index.tsx @@ -19,6 +19,7 @@ import { import { useDispatch } from 'react-redux'; import { StyledHeading } from '@ui-library/common.styled'; import Dialog from '@ui-library/dialog'; +import { InvalidParamsError } from '@utils/query'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { MoonLoader } from 'react-spinners'; @@ -286,7 +287,10 @@ const useNftDashboard = (): NftDashboardState => { }; const NftListView = useCallback(() => { - if (stacksError || ordinalsError) { + if ( + (stacksError && !(stacksError instanceof InvalidParamsError)) || + (ordinalsError && !(ordinalsError instanceof InvalidParamsError)) + ) { return ( diff --git a/src/app/screens/signPsbtRequest/ordinalDetailComponent.tsx b/src/app/screens/signPsbtRequest/bundleItemsComponent.tsx similarity index 65% rename from src/app/screens/signPsbtRequest/ordinalDetailComponent.tsx rename to src/app/screens/signPsbtRequest/bundleItemsComponent.tsx index 603036687..6f69fcb1d 100644 --- a/src/app/screens/signPsbtRequest/ordinalDetailComponent.tsx +++ b/src/app/screens/signPsbtRequest/bundleItemsComponent.tsx @@ -3,8 +3,11 @@ import { useState } from 'react'; import { animated, useSpring } from '@react-spring/web'; import Cross from '@assets/img/dashboard/X.svg'; import styled from 'styled-components'; -import { Inscription } from '@secretkeylabs/xverse-core'; -import OrdinalImage from '@screens/ordinals/ordinalImage'; +import { BundleItem, getBundleItemSubText } from '@utils/rareSats'; +import { useTranslation } from 'react-i18next'; +import IconOrdinal from '@assets/img/transactions/ordinal.svg'; +import RareSatAsset from '@components/rareSatAsset/rareSatAsset'; +import { getTruncatedAddress } from '@utils/helper'; const Container = styled.div((props) => ({ display: 'flex', @@ -64,6 +67,9 @@ const InscriptionText = styled.h1((props) => ({ marginTop: 24, textAlign: 'center', color: props.theme.colors.white[0], + overflowWrap: 'break-word', + wordWrap: 'break-word', + wordBreak: 'break-word', })); const ColumnContainer = styled.div({ @@ -117,21 +123,11 @@ const EyeIcon = styled.img({ }); interface Props { - ordinalInscription: string; - ordinalDetail?: string; - icon: string; - title: string; - heading?: string; - ordinal?: Inscription; + item: BundleItem; + userReceivesOrdinal: boolean; } -function OrdinalDetailComponent({ - ordinalInscription, - ordinalDetail, - icon, - title, - heading, - ordinal, -}: Props) { +function BundleItemsComponent({ item, userReceivesOrdinal }: Props) { + const { t } = useTranslation('translation'); const [showOrdinal, setShowOrdinal] = useState(false); const styles = useSpring({ from: { @@ -151,6 +147,34 @@ function OrdinalDetailComponent({ const onCrossClick = () => { setShowOrdinal(false); }; + const getItemId = () => { + if (item.type === 'inscription') { + return item.inscription.id; + } + if (item.type === 'inscribed-sat' || item.type === 'rare-sat') { + return item.number; + } + return ''; + }; + const itemSubText = getBundleItemSubText({ + satType: item.type, + rareSatsType: item.rarity_ranking, + }); + const getDetail = () => { + if (item.type === 'inscription' || item.type === 'inscribed-sat') { + return item.inscription.content_type; + } + return itemSubText; + }; + const getTitle = () => { + if (item.type === 'inscription') { + return t('COMMON.INSCRIPTION'); + } + if (item.type === 'inscribed-sat') { + return t('RARE_SATS.INSCRIBED_SAT'); + } + return t('RARE_SATS.RARE_SAT'); + }; return ( <> {showOrdinal && ( @@ -162,25 +186,29 @@ function OrdinalDetailComponent({ - + - {`Inscription ${ordinal?.number} `} + {`${getTitle()} ${getItemId()} `} )} - {heading && {heading}} + + {userReceivesOrdinal + ? t('CONFIRM_TRANSACTION.YOU_WILL_RECEIVE') + : t('CONFIRM_TRANSACTION.YOU_WILL_TRANSFER')} + - - {title} + + {getTitle()} - {ordinalInscription} + {getTruncatedAddress(String(getItemId()))} - {ordinalDetail && {ordinalDetail}} + {getDetail()} @@ -188,4 +216,4 @@ function OrdinalDetailComponent({ ); } -export default OrdinalDetailComponent; +export default BundleItemsComponent; diff --git a/src/app/screens/signPsbtRequest/index.tsx b/src/app/screens/signPsbtRequest/index.tsx index f3fc59703..6efb0d39e 100644 --- a/src/app/screens/signPsbtRequest/index.tsx +++ b/src/app/screens/signPsbtRequest/index.tsx @@ -1,6 +1,5 @@ import ledgerConnectDefaultIcon from '@assets/img/ledger/ledger_connect_default.svg'; import ledgerConnectBtcIcon from '@assets/img/ledger/ledger_import_connect_btc.svg'; -import IconOrdinal from '@assets/img/transactions/ordinal.svg'; import { ExternalSatsMethods, MESSAGE_SOURCE } from '@common/types/message-types'; import { ledgerDelay } from '@common/utils/ledger'; import AccountHeaderComponent from '@components/accountHeader'; @@ -33,7 +32,7 @@ import { useLocation, useNavigate } from 'react-router-dom'; import { MoonLoader } from 'react-spinners'; import { SignTransactionOptions } from 'sats-connect'; import styled from 'styled-components'; -import OrdinalDetailComponent from './ordinalDetailComponent'; +import BundleItemsComponent from './bundleItemsComponent'; const OuterContainer = styled.div` display: flex; @@ -130,7 +129,7 @@ function SignPsbtRequest() { }, [selectedAccount, payload.psbtBase64]); const parsedPsbt = useMemo(() => handlePsbtParsing(), [handlePsbtParsing]); - const { loading, ordinalInfoData, userReceivesOrdinal } = useDetectOrdinalInSignPsbt(parsedPsbt); + const { loading, bundleItemsData, userReceivesOrdinal } = useDetectOrdinalInSignPsbt(parsedPsbt); const signingAddresses = useMemo( () => getSigningAddresses(payload.inputsToSign), [payload.inputsToSign], @@ -339,7 +338,7 @@ function SignPsbtRequest() { return ( <> - + {loading ? ( @@ -357,15 +356,13 @@ function SignPsbtRequest() { {!payload.broadcast && ( )} - {ordinalInfoData && - ordinalInfoData.map((ordinalData) => ( - ( + ))} + + + + + + diff --git a/src/locales/en.json b/src/locales/en.json index 3d2e0052f..3b6941066 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1078,6 +1078,8 @@ "SATS_VALUE": "Sats value", "SATS_BUNDLE": "Sats Bundle", "RARE_SATS_BUNDLE": "Rare Sats Bundle", - "BUNDLE_PENDING_SEND_DESCRIPTION": "This Bundle is already in a pending transfer." + "BUNDLE_PENDING_SEND_DESCRIPTION": "This bundle is already in a pending transfer.", + "RARE_SAT": "Rare Sat", + "INSCRIBED_SAT": "Inscribed Sat" } }