Skip to content

Commit bfeae29

Browse files
authored
Release/2.2.0 (#1236)
* Update webpack-dev-server * Update @noble/ciphers usage * Add fallback to `accountName` in account-info-row component * Fix usage of `toBytes` in signWasmDeploy method * Center align Ledger sign button in sign-transaction page * Add token market price display and related logic updates * Bump version to 2.2.0 and update `casper-wallet-core` dependency to the latest commit. Add new build resource `476.bundle.js` to Xcode project. * Refactor `TokensList` component to remove redundant `useState` hooks and simplify token listing logic. * Refactor `MarketDataValue` component to improve layout alignment and styling; replace `SpaceBetweenFlexRow` with `AlignedSpaceBetweenFlexRow` for consistent spacing. * Refactor `Token` component to simplify state management and encapsulate token data retrieval logic into `getTokenData` utility function. * Fix `amount-step` fiat amount formatting by properly validating `tokenPrice` as a numeric value * Add border radius to price provider icons in `MarketDataValue` for circular styling * Release 2.2.0 version
1 parent d4b7101 commit bfeae29

File tree

26 files changed

+1205
-706
lines changed

26 files changed

+1205
-706
lines changed

package-lock.json

Lines changed: 889 additions & 538 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "Casper Wallet",
33
"description": "Securely manage your CSPR tokens and interact with dapps with the self-custody wallet for the Casper blockchain.",
4-
"version": "2.1.2",
4+
"version": "2.2.0",
55
"author": "MAKE LLC",
66
"scripts": {
77
"devtools:redux": "redux-devtools --hostname=localhost",
@@ -71,7 +71,7 @@
7171
"base64-loader": "1.0.0",
7272
"big.js": "^6.2.1",
7373
"casper-js-sdk": "^5.0.6",
74-
"casper-wallet-core": "git+ssh://[email protected]:make-software/casper-wallet-core.git#v1.1.3",
74+
"casper-wallet-core": "git+ssh://[email protected]:make-software/casper-wallet-core.git#v1.1.4",
7575
"date-fns": "^2.30.0",
7676
"dotenv-webpack": "^8.1.0",
7777
"i18next": "^23.11.0",
@@ -179,7 +179,7 @@
179179
"webextension-polyfill": "0.10.0",
180180
"webpack": "5.94.0",
181181
"webpack-cli": "5.1.4",
182-
"webpack-dev-server": "^4.15.1",
182+
"webpack-dev-server": "^5.2.1",
183183
"xcode-build-webpack-plugin": "^1.0.2"
184184
}
185185
}

scripts/build_all.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
HASH=$(git rev-parse --short HEAD)
22

3-
npm run build:chrome && npm run build:firefox && cd ./build && zip -r casper-wallet-2.1.2rc2#$HASH.zip ./* && npm run build:src
3+
npm run build:chrome && npm run build:firefox && cd ./build && zip -r casper-wallet-2.2.0rc3#$HASH.zip ./* && npm run build:src

src/apps/popup/pages/home/components/tokens-list/index.tsx

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import React, { useEffect, useState } from 'react';
1+
import Big from 'big.js';
2+
import React, { useEffect } from 'react';
23
import { Trans, useTranslation } from 'react-i18next';
34
import styled from 'styled-components';
45

@@ -9,6 +10,7 @@ import { TokenType, useCasperToken } from '@hooks/use-casper-token';
910
import { SpaceBetweenFlexRow, SpacingSize } from '@libs/layout';
1011
import { useFetchCep18Tokens } from '@libs/services/cep18-service';
1112
import { List, TokenPlate, Typography } from '@libs/ui/components';
13+
import { formatCurrency } from '@libs/ui/utils';
1214

1315
import { formatCep18Tokens } from './utils';
1416

@@ -21,30 +23,25 @@ const TotalValueContainer = styled(SpaceBetweenFlexRow)`
2123
`;
2224

2325
export const TokensList = () => {
24-
const [tokensList, setTokensList] = useState<TokenType[]>([]);
25-
const [totalAmountFiat, setTotalAmountFiat] = useState<string | null>(null);
26-
2726
const casperToken = useCasperToken();
2827
const { cep18Tokens } = useFetchCep18Tokens();
2928
const { t } = useTranslation();
3029
const navigate = useTypedNavigate();
3130

32-
useEffect(() => {
33-
const formatedCep18Tokens = formatCep18Tokens(cep18Tokens);
34-
35-
const tokensList: TokenType[] = [];
36-
37-
if (casperToken) {
38-
tokensList.push(casperToken);
39-
setTotalAmountFiat(casperToken.amountFiat);
31+
const tokensList: TokenType[] = [
32+
...(casperToken ? [casperToken] : []),
33+
...(formatCep18Tokens(cep18Tokens) ?? [])
34+
];
35+
36+
const totalAmountFiat = formatCurrency(
37+
tokensList
38+
.reduce((acc, cur) => acc.add(cur.amountFiatDecimal || 0), Big(0))
39+
.toFixed(),
40+
'USD',
41+
{
42+
precision: 2
4043
}
41-
42-
if (formatedCep18Tokens) {
43-
tokensList.push(...formatedCep18Tokens);
44-
}
45-
46-
setTokensList(tokensList);
47-
}, [casperToken, cep18Tokens]);
44+
);
4845

4946
useEffect(() => {
5047
const container = document.querySelector('#ms-container');

src/apps/popup/pages/home/components/tokens-list/utils.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { TokenDto } from 'casper-wallet-core/src/data/dto';
1+
import { ITokenWithFiatBalance } from 'casper-wallet-core';
22

33
import { TokenType } from '@hooks/use-casper-token';
44

55
export const formatCep18Tokens = (
6-
cep18Tokens: TokenDto[] | undefined
6+
cep18Tokens: ITokenWithFiatBalance[] | undefined
77
): TokenType[] | undefined => {
88
return cep18Tokens
99
?.map<TokenType>(token => ({
@@ -14,7 +14,11 @@ export const formatCep18Tokens = (
1414
amount: token.formattedDecimalBalance,
1515
symbol: token.symbol,
1616
decimals: token.decimals,
17-
amountFiat: null,
17+
amountFiat: token.formattedFiatBalance,
18+
amountFiatDecimal: token.fiatBalance,
19+
tokenPrice: token.fiatPrice?.toString(),
20+
tokenPriceProvider: token.marketDataProvider,
21+
tokenPriceProviderUrl: token.marketDataProviderUrl,
1822
icon: token.iconUrl || 'assets/icons/cep18-contract-icon.svg'
1923
}))
2024
.sort((a, b) => {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { SupportedMarketDataProviders } from 'casper-wallet-core';
2+
import React from 'react';
3+
4+
import { TokenType } from '@hooks/use-casper-token';
5+
6+
import { CenteredFlexRow, SpacingSize } from '@libs/layout';
7+
import { Button, Typography } from '@libs/ui/components';
8+
9+
interface IMarketDataValueProps {
10+
token: TokenType;
11+
}
12+
13+
const priceProviderAssetsMap: Record<SupportedMarketDataProviders, string> = {
14+
CoinGecko: 'assets/icons/coingecko.png',
15+
FriendlyMarket: 'assets/icons/friendly-market.png'
16+
};
17+
18+
export const MarketDataValue: React.FC<IMarketDataValueProps> = ({ token }) => (
19+
<Button
20+
inline
21+
disabled={!token.tokenPriceProviderUrl}
22+
style={{ background: 'transparent', padding: 0 }}
23+
onClick={() => {
24+
if (token.tokenPriceProviderUrl) {
25+
window.open(token.tokenPriceProviderUrl, '_blank');
26+
}
27+
}}
28+
>
29+
<CenteredFlexRow gap={SpacingSize.Small}>
30+
{token.tokenPrice && (
31+
<Typography
32+
wordBreak={true}
33+
type="captionRegular"
34+
color="contentAction"
35+
>
36+
{`$${Number(token.tokenPrice).toLocaleString('en-US', {
37+
maximumFractionDigits: 10
38+
})}`}
39+
</Typography>
40+
)}
41+
{token.tokenPriceProvider && (
42+
<img
43+
alt={`${token.tokenPriceProvider} icon`}
44+
src={priceProviderAssetsMap[token.tokenPriceProvider]}
45+
width="20"
46+
height="20"
47+
style={{
48+
borderRadius: '50%'
49+
}}
50+
/>
51+
)}
52+
</CenteredFlexRow>
53+
</Button>
54+
);

src/apps/popup/pages/token-details/token.tsx

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect, useState } from 'react';
1+
import React from 'react';
22
import { Trans, useTranslation } from 'react-i18next';
33
import { useSelector } from 'react-redux';
44
import { useParams } from 'react-router-dom';
@@ -8,20 +8,18 @@ import { NetworkSetting } from '@src/constants';
88
import { isSafariBuild } from '@src/utils';
99

1010
import { formatCep18Tokens } from '@popup/pages/home/components/tokens-list/utils';
11+
import { MarketDataValue } from '@popup/pages/token-details/MarketDataValue';
12+
import { getTokenData } from '@popup/pages/token-details/utils';
1113
import { RouterPath, useTypedLocation, useTypedNavigate } from '@popup/router';
1214

13-
import {
14-
selectActiveNetworkSetting,
15-
selectApiConfigBasedOnActiveNetwork
16-
} from '@background/redux/settings/selectors';
17-
import { selectVaultActiveAccount } from '@background/redux/vault/selectors';
15+
import { selectActiveNetworkSetting } from '@background/redux/settings/selectors';
1816

19-
import { TokenType, useCasperToken } from '@hooks/use-casper-token';
17+
import { useCasperToken } from '@hooks/use-casper-token';
2018

2119
import {
20+
AlignedSpaceBetweenFlexRow,
2221
CenteredFlexColumn,
2322
CenteredFlexRow,
24-
SpaceBetweenFlexRow,
2523
SpacingSize
2624
} from '@libs/layout';
2725
import { useFetchCep18Tokens } from '@libs/services/cep18-service';
@@ -33,7 +31,7 @@ import {
3331
Typography
3432
} from '@libs/ui/components';
3533

36-
const ListItemContainer = styled(SpaceBetweenFlexRow)`
34+
const ListItemContainer = styled(AlignedSpaceBetweenFlexRow)`
3735
padding: 16px;
3836
`;
3937

@@ -50,80 +48,82 @@ const ButtonContainer = styled(CenteredFlexColumn)`
5048
type TokenInfoList = {
5149
id: number;
5250
name: string;
53-
value: string;
51+
value: string | JSX.Element;
5452
};
5553

5654
export const Token = () => {
5755
const location = useTypedLocation();
58-
const [tokenData, setTokenData] = useState<TokenType | null>(
59-
location.state.tokenData ?? null
60-
);
61-
const [tokenInfoList, setTokenInfoList] = useState<TokenInfoList[] | []>([]);
56+
const initialTokenData = location.state.tokenData ?? null;
6257

6358
const { t } = useTranslation();
6459
const navigate = useTypedNavigate();
6560
const { tokenName } = useParams();
6661
const casperToken = useCasperToken();
6762

68-
const { casperLiveUrl } = useSelector(selectApiConfigBasedOnActiveNetwork);
69-
const activeAccount = useSelector(selectVaultActiveAccount);
7063
const network = useSelector(selectActiveNetworkSetting);
7164
const { cep18Tokens } = useFetchCep18Tokens();
7265

73-
useEffect(() => {
74-
if (tokenName === 'Casper') {
75-
// Casper Coin case
76-
if (casperToken && activeAccount) {
77-
setTokenData(casperToken);
78-
setTokenInfoList([
79-
{ id: 1, name: 'Symbol', value: casperToken?.symbol }
80-
]);
81-
}
66+
const tokenData = getTokenData(
67+
initialTokenData,
68+
cep18Tokens,
69+
casperToken,
70+
tokenName
71+
);
72+
73+
const getTokenInfoList = (): TokenInfoList[] => {
74+
if (tokenName === 'Casper' && casperToken) {
75+
return [
76+
{ id: 1, name: 'Symbol', value: casperToken?.symbol },
77+
...(casperToken.tokenPrice
78+
? [
79+
{
80+
id: 2,
81+
name: 'Market Price',
82+
value: <MarketDataValue token={casperToken} />
83+
}
84+
]
85+
: [])
86+
];
8287
} else {
8388
// CEP-18 token case
8489
const formatedCep18Tokens = formatCep18Tokens(cep18Tokens);
8590

86-
const token = formatedCep18Tokens?.find(token => token.id === tokenName);
87-
88-
if (token) {
89-
setTokenData(token);
90-
setTokenInfoList([
91-
{ id: 1, name: 'Symbol', value: token?.symbol },
92-
{ id: 2, name: 'Decimals', value: (token?.decimals || 0).toString() }
93-
]);
94-
} else {
95-
setTokenData(prev => (prev ? { ...prev, amount: '0' } : null));
96-
setTokenInfoList([
97-
{ id: 1, name: 'Symbol', value: tokenData?.symbol ?? '' },
98-
{
99-
id: 2,
100-
name: 'Decimals',
101-
value: (tokenData?.decimals || 0).toString()
102-
}
103-
]);
104-
}
91+
const token =
92+
formatedCep18Tokens?.find(token => token.id === tokenName) ?? tokenData;
93+
94+
return [
95+
{ id: 1, name: 'Symbol', value: token?.symbol ?? '' },
96+
{ id: 2, name: 'Decimals', value: (token?.decimals || 0).toString() },
97+
...(Boolean(Number(token?.tokenPrice)) && token
98+
? [
99+
{
100+
id: 3,
101+
name: 'Market Price',
102+
value: <MarketDataValue token={token} />
103+
}
104+
]
105+
: [])
106+
];
105107
}
106-
}, [
107-
tokenName,
108-
casperToken,
109-
activeAccount,
110-
casperLiveUrl,
111-
cep18Tokens,
112-
tokenData?.symbol,
113-
tokenData?.decimals
114-
]);
108+
};
115109

116110
return (
117111
<List
118112
contentTop={SpacingSize.Small}
119-
rows={tokenInfoList}
113+
rows={getTokenInfoList()}
120114
renderHeader={() => <TokenPlate token={tokenData} />}
121115
renderRow={({ name, value }) => (
122116
<ListItemContainer>
123117
<Typography type="captionRegular" color="contentSecondary">
124118
{name}
125119
</Typography>
126-
<Typography type="captionRegular">{value}</Typography>
120+
{typeof value === 'string' ? (
121+
<Typography wordBreak={true} type="captionRegular">
122+
{value}
123+
</Typography>
124+
) : (
125+
value
126+
)}
127127
</ListItemContainer>
128128
)}
129129
renderFooter={() => (
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { ITokenWithFiatBalance } from 'casper-wallet-core';
2+
3+
import { formatCep18Tokens } from '@popup/pages/home/components/tokens-list/utils';
4+
5+
import { TokenType } from '@hooks/use-casper-token';
6+
7+
export const getTokenData = (
8+
initialTokenData: TokenType | null,
9+
cep18Tokens: ITokenWithFiatBalance[],
10+
casperToken: TokenType | null,
11+
tokenName?: string
12+
) => {
13+
if (tokenName === 'Casper') {
14+
return casperToken;
15+
} else {
16+
// CEP-18 token case
17+
const formatedCep18Tokens = formatCep18Tokens(cep18Tokens);
18+
19+
const token = formatedCep18Tokens?.find(token => token.id === tokenName);
20+
21+
if (token) {
22+
return token;
23+
} else {
24+
return initialTokenData ? { ...initialTokenData, amount: '0' } : null;
25+
}
26+
}
27+
};

0 commit comments

Comments
 (0)