Skip to content

Commit 13cab76

Browse files
committed
feat: add siwe
1 parent 57b149e commit 13cab76

File tree

12 files changed

+310
-58
lines changed

12 files changed

+310
-58
lines changed

packages/popup/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"@fluent-wallet/tx-history-checker": "workspace:*",
3636
"@fluent-wallet/use-rpc": "workspace:packages/ui/useRPC",
3737
"@fluent-wallet/utils": "workspace:packages/utils",
38+
"@spruceid/siwe-parser": "patch:@spruceid/siwe-parser@npm%3A3.0.0#~/.yarn/patches/@spruceid-siwe-parser-npm-3.0.0-4572197cda.patch",
3839
"bn.js": "5.2.1",
3940
"dayjs": "1.10.7",
4041
"i18next": "21.5.2",

packages/popup/src/locales/en.js

+3
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,9 @@ const en = {
279279
signThisMessage: 'Sign this Message?',
280280
signTypeMessage: 'Sign Type Message',
281281
message: 'Message',
282+
signWithEthereumTitle: 'Sign-in request',
283+
signWithEthereum:
284+
'A site wants you to sign in to prove you own this account.',
282285

283286
// - add network
284287
addNetwork: 'Add Network',

packages/popup/src/locales/fr.js

+3
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,9 @@ const fr = {
285285

286286
// - request signature - 2. Sign Message
287287
signThisMessage: 'Signer ce Message ?',
288+
signWithEthereumTitle: 'Demande de connexion',
289+
signWithEthereum:
290+
'Un site souhaite que vous vous connectiez pour prouver que vous possédez ce compte.',
288291
signTypeMessage: 'Signer le message saisi',
289292
message: 'Message',
290293

packages/popup/src/locales/ru.js

+3
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,9 @@ const ru = {
278278

279279
// - request signature - 2. Sign Message
280280
signThisMessage: 'Подписать это сообщение?',
281+
signWithEthereumTitle: 'Запрос на вход',
282+
signWithEthereum:
283+
'Сайт просит вас подписаться, чтобы подтвердить владение этим аккаунтом.',
281284
signTypeMessage: 'Подписать написанное сообщение',
282285
message: 'Сообщение',
283286

packages/popup/src/locales/uk.js

+3
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,9 @@ const uk = {
277277

278278
// - request signature - 2. Sign Message
279279
signThisMessage: 'Підписати це повідомлення?',
280+
signWithEthereumTitle: 'Запит на вхід',
281+
signWithEthereum:
282+
'Сайт просить вас підписатися, щоб підтвердити володіння цим акаунтом.',
280283
signTypeMessage: 'Підписати написане повідомлення',
281284
message: 'Повідомлення',
282285

packages/popup/src/locales/zh.js

+2
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,8 @@ const zh = {
269269

270270
// - request signature - 2. Sign Message
271271
signThisMessage: '签署这个信息?',
272+
signWithEthereumTitle: '登录请求',
273+
signWithEthereum: '网站请求您签名以证明您拥有此账户。',
272274
signTypeMessage: '签署类型信息',
273275
message: '信息',
274276

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import PropTypes from 'prop-types'
2+
import {useTranslation} from 'react-i18next'
3+
import {CompWithLabel} from '../../../components'
4+
import Alert from '@fluent-wallet/component-alert'
5+
6+
export const PersonalSign = ({personalSignData, isHw}) => {
7+
const {t} = useTranslation()
8+
9+
return (
10+
<main className="rounded-t-xl pt-4 px-3 bg-gray-0">
11+
<CompWithLabel
12+
label={
13+
<p id="labelDes" className="font-medium">
14+
{t('signThisText')}
15+
</p>
16+
}
17+
>
18+
<div
19+
id="plaintext"
20+
className="pl-3 max-h-[316px] pr-3 pt-3 pb-4 rounded bg-gray-4 overflow-auto break-words"
21+
>
22+
{personalSignData
23+
.replace(/\r/g, '\n')
24+
.split('\n')
25+
.map(str => (
26+
<div key={str} className={str ? '' : 'h-[18px]'}>
27+
{str}
28+
</div>
29+
))}
30+
</div>
31+
</CompWithLabel>
32+
<Alert
33+
open={isHw}
34+
className="mt-3"
35+
type="warning"
36+
closable={false}
37+
width="w-full"
38+
content={t('disablePersonSign')}
39+
/>
40+
</main>
41+
)
42+
}
43+
44+
PersonalSign.propTypes = {
45+
personalSignData: PropTypes.string.isRequired,
46+
isHw: PropTypes.bool,
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import PropTypes from 'prop-types'
2+
import Alert from '@fluent-wallet/component-alert'
3+
import {CompWithLabel, CurrentNetworkDisplay} from '../../../components'
4+
import {useTranslation} from 'react-i18next'
5+
6+
export const SignInSign = ({isHw, parsedMessage, currentNetwork}) => {
7+
const {t} = useTranslation()
8+
return (
9+
<main className="rounded-t-xl pt-4 px-3 bg-gray-0">
10+
<div className="ml-1" id="signTypeMsgDes">
11+
<div className="text-sm text-gray-80 font-medium">
12+
{t('signWithEthereum')}
13+
</div>
14+
</div>
15+
16+
<CompWithLabel>
17+
<div
18+
id="plaintext"
19+
className={`${'pl-1 max-h-[282px]'} pr-3 pt-3 pb-4 rounded bg-gray-4 overflow-auto break-words`}
20+
>
21+
<div className="info-list-container flex flex-col">
22+
<div className="flex justify-between mb-4">
23+
<span className="text-gray-40 mr-2">Message</span>
24+
<span>{parsedMessage?.statement}</span>
25+
</div>
26+
27+
<div className="flex justify-between mb-4">
28+
<span className="text-gray-40 mr-2">URL</span>
29+
<span>{parsedMessage?.uri}</span>
30+
</div>
31+
32+
<div className="flex justify-between mb-4">
33+
<span className="text-gray-40 mr-2">Network</span>
34+
<CurrentNetworkDisplay
35+
contentClassName="mr-1"
36+
currentNetwork={currentNetwork}
37+
/>
38+
</div>
39+
40+
<div className="flex justify-between mb-4">
41+
<span className="text-gray-40 mr-2">Account</span>
42+
<span className="break-all">{parsedMessage?.address}</span>
43+
</div>
44+
45+
<div className="flex justify-between mb-4">
46+
<span className="text-gray-40 mr-2">Version</span>
47+
<span>{parsedMessage?.version}</span>
48+
</div>
49+
50+
<div className="flex justify-between mb-4">
51+
<span className="text-gray-40 mr-2">Chain ID</span>
52+
<span>{parsedMessage?.chainId}</span>
53+
</div>
54+
55+
<div className="flex justify-between mb-4">
56+
<span className="text-gray-40 mr-2">Nonce</span>
57+
<span>{parsedMessage?.nonce}</span>
58+
</div>
59+
60+
<div className="flex justify-between mb-4">
61+
<span className="text-gray-40 mr-2">Issued</span>
62+
<span>{parsedMessage?.issuedAt}</span>
63+
</div>
64+
</div>
65+
</div>
66+
</CompWithLabel>
67+
<Alert
68+
open={isHw}
69+
className="mt-3"
70+
type="warning"
71+
closable={false}
72+
width="w-full"
73+
content={t('disableTypeSign')}
74+
/>
75+
</main>
76+
)
77+
}
78+
79+
SignInSign.propTypes = {
80+
isHw: PropTypes.bool,
81+
parsedMessage: PropTypes.object,
82+
currentNetwork: PropTypes.object,
83+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import PropTypes from 'prop-types'
2+
import {useTranslation} from 'react-i18next'
3+
import {CompWithLabel} from '../../../components'
4+
import Alert from '@fluent-wallet/component-alert'
5+
import PlaintextMessage from './PlaintextMessage'
6+
7+
export const TypedDataSign = ({plaintextData, isHw}) => {
8+
const {t} = useTranslation()
9+
10+
return (
11+
<main className="rounded-t-xl pt-4 px-3 bg-gray-0">
12+
<div className="ml-1" id="signTypeMsgDes">
13+
<div className="text-sm text-gray-80 font-medium">
14+
{t('signThisMessage')}
15+
</div>
16+
<div className="text-xs text-gray-40 mt-1">
17+
{plaintextData?.domain?.name}
18+
</div>
19+
</div>
20+
21+
<CompWithLabel
22+
label={
23+
<p id="labelDes" className="font-medium">
24+
{t('message')}
25+
</p>
26+
}
27+
>
28+
<div
29+
id="plaintext"
30+
className={`${'pl-1 max-h-[282px]'} pr-3 pt-3 pb-4 rounded bg-gray-4 overflow-auto break-words`}
31+
>
32+
{<PlaintextMessage message={plaintextData?.message ?? {}} />}
33+
</div>
34+
</CompWithLabel>
35+
<Alert
36+
open={isHw}
37+
className="mt-3"
38+
type="warning"
39+
closable={false}
40+
width="w-full"
41+
content={t('disableTypeSign')}
42+
/>
43+
</main>
44+
)
45+
}
46+
47+
TypedDataSign.propTypes = {
48+
plaintextData: PropTypes.object.isRequired,
49+
isHw: PropTypes.bool,
50+
}

packages/popup/src/pages/RequestSignature/index.js

+53-58
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import {useTranslation} from 'react-i18next'
22
import {isUndefined} from '@fluent-wallet/checks'
3-
import Alert from '@fluent-wallet/component-alert'
3+
44
import {
55
DappFooter,
6-
CompWithLabel,
76
TitleNav,
87
AccountDisplay,
98
DisplayBalance,
@@ -15,8 +14,13 @@ import {
1514
useCurrentTicker,
1615
useAddress,
1716
} from '../../hooks/useApi'
18-
import PlaintextMessage from './components/PlaintextMessage'
17+
1918
import {RPC_METHODS} from '../../constants'
19+
import {detectSIWEMessage} from '../../utils'
20+
import {useMemo} from 'react'
21+
import {TypedDataSign} from './components/TypedDataSign'
22+
import {PersonalSign} from './components/PersonalSign'
23+
import {SignInSign} from './components/SignInSign'
2024
const {PERSONAL_SIGN, ACCOUNT_GROUP_TYPE} = RPC_METHODS
2125

2226
function RequestSignature() {
@@ -38,20 +42,59 @@ function RequestSignature() {
3842
const isHw =
3943
AddressData?.account?.accountGroup?.vault?.type === ACCOUNT_GROUP_TYPE.HW
4044

41-
const plaintextData =
42-
!isPersonalSign && req?.params?.[1] ? JSON.parse(req.params[1]) : {}
45+
const plaintextData = useMemo(
46+
() =>
47+
!isPersonalSign && req?.params?.[1] ? JSON.parse(req.params[1]) : {},
48+
[isPersonalSign, req?.params],
49+
)
4350
const personalSignData = isPersonalSign ? req?.params?.[0] ?? '' : ''
4451

52+
const {isSIWEMessage, parsedMessage} = detectSIWEMessage(personalSignData)
53+
54+
const Content = useMemo(() => {
55+
if (isPersonalSign) {
56+
if (!isSIWEMessage)
57+
return <PersonalSign personalSignData={personalSignData} isHw={isHw} />
58+
59+
return (
60+
<SignInSign
61+
parsedMessage={parsedMessage}
62+
isHw={isHw}
63+
currentNetwork={app?.currentNetwork}
64+
/>
65+
)
66+
}
67+
68+
return <TypedDataSign plaintextData={plaintextData} isHw={isHw} />
69+
}, [
70+
isPersonalSign,
71+
isSIWEMessage,
72+
parsedMessage,
73+
isHw,
74+
plaintextData,
75+
app?.currentNetwork,
76+
personalSignData,
77+
])
78+
79+
const signTitle = useMemo(() => {
80+
if (isPersonalSign) {
81+
if (isSIWEMessage) {
82+
return t('signWithEthereumTitle')
83+
}
84+
85+
return t('signText')
86+
}
87+
88+
return t('signTypeMessage')
89+
}, [isPersonalSign, isSIWEMessage, t])
90+
4591
return (
4692
<div
4793
id="requestSignatureContainer"
4894
className="flex flex-col h-full w-full bg-blue-circles bg-no-repeat bg-bg"
4995
>
5096
<header id="header">
51-
<TitleNav
52-
title={isPersonalSign ? t('signText') : t('signTypeMessage')}
53-
hasGoBack={false}
54-
/>
97+
<TitleNav title={signTitle} hasGoBack={false} />
5598
<div className="flex mt-1 px-4 pb-3 items-center justify-between">
5699
<AccountDisplay
57100
address={address}
@@ -71,55 +114,7 @@ function RequestSignature() {
71114
</div>
72115
</header>
73116
<div className="flex-1 flex justify-between flex-col bg-gray-0 rounded-t-xl pb-4">
74-
<main className="rounded-t-xl pt-4 px-3 bg-gray-0">
75-
{!isPersonalSign ? (
76-
<div className="ml-1" id="signTypeMsgDes">
77-
<div className="text-sm text-gray-80 font-medium">
78-
{t('signThisMessage')}
79-
</div>
80-
<div className="text-xs text-gray-40 mt-1">
81-
{plaintextData?.domain?.name}
82-
</div>
83-
</div>
84-
) : null}
85-
<CompWithLabel
86-
label={
87-
<p id="labelDes" className="font-medium">
88-
{isPersonalSign ? t('signThisText') : t('message')}
89-
</p>
90-
}
91-
>
92-
<div
93-
id="plaintext"
94-
className={`${
95-
isPersonalSign ? 'pl-3 max-h-[316px]' : 'pl-1 max-h-[282px]'
96-
} pr-3 pt-3 pb-4 rounded bg-gray-4 overflow-auto break-words`}
97-
>
98-
{isPersonalSign ? (
99-
personalSignData
100-
.replace(/\r/g, '\n')
101-
.split('\n')
102-
.map(str => (
103-
<div key={str} className={str ? '' : 'h-[18px]'}>
104-
{str}
105-
</div>
106-
))
107-
) : (
108-
<PlaintextMessage message={plaintextData?.message ?? {}} />
109-
)}
110-
</div>
111-
</CompWithLabel>
112-
<Alert
113-
open={isHw}
114-
className="mt-3"
115-
type="warning"
116-
closable={false}
117-
width="w-full"
118-
content={t(
119-
isPersonalSign ? 'disablePersonSign' : 'disableTypeSign',
120-
)}
121-
/>
122-
</main>
117+
{Content}
123118
<DappFooter
124119
cancelText={t('cancel')}
125120
confirmText={t('sign')}

0 commit comments

Comments
 (0)