-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add Redesign Permit support; fix: InfoRow padding and alignment #13369
base: main
Are you sure you want to change the base?
Changes from 16 commits
499bd7c
52fa484
8b47c9d
eb76d78
fa20ff0
2f99b44
2121a96
b30458e
328e6c0
135c750
dc1e9ae
5cc3ed9
e573974
1155603
0d5d1f6
3d7e489
6756c8e
6247124
674dabe
c021969
3a7586e
6d97d98
d0d9132
65419d1
901094f
7224818
cc83559
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { StyleSheet } from 'react-native'; | ||
|
||
const styleSheet = () => StyleSheet.create({ | ||
dividerContainer: { | ||
marginTop: 4, | ||
marginBottom: 12, | ||
}, | ||
}); | ||
|
||
export default styleSheet; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import React from 'react'; | ||
|
||
import renderWithProvider from '../../../../../../../../util/test/renderWithProvider'; | ||
import { | ||
typedSignV3ConfirmationState, | ||
typedSignV4ConfirmationState, | ||
} from '../../../../../../../../util/test/confirm-data-helpers'; | ||
import { InfoSectionAddressAndOrigin } from './InfoSectionAddressAndOrigin'; | ||
|
||
describe('InfoSectionAddressAndOrigin', () => { | ||
it('renders origin', () => { | ||
const { getByText } = renderWithProvider(<InfoSectionAddressAndOrigin />, { | ||
state: typedSignV4ConfirmationState, | ||
}); | ||
|
||
expect(getByText('Request from')).toBeTruthy(); | ||
expect(getByText('metamask.github.io')).toBeTruthy(); | ||
}); | ||
|
||
it('renders "Interacting with" if associated with a valid verifying contract', () => { | ||
const { getByText } = renderWithProvider(<InfoSectionAddressAndOrigin />, { | ||
state: typedSignV4ConfirmationState, | ||
}); | ||
|
||
expect(getByText('Request from')).toBeTruthy(); | ||
}); | ||
|
||
it('renders Spender if it is a Permit', () => { | ||
const { getByText } = renderWithProvider(<InfoSectionAddressAndOrigin />, { | ||
state: typedSignV4ConfirmationState, | ||
}); | ||
|
||
expect(getByText('Interacting with')).toBeTruthy(); | ||
expect(getByText('0xCcCCc...ccccC')).toBeTruthy(); | ||
}); | ||
|
||
it('does not render Spender if it is not a Permit', () => { | ||
const { queryByText } = renderWithProvider(<InfoSectionAddressAndOrigin />, { | ||
state: typedSignV3ConfirmationState, | ||
}); | ||
|
||
expect(queryByText('Spender')).toBeNull(); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import React from 'react'; | ||
|
||
import { ConfirmationPageSectionsSelectorIDs } from '../../../../../../../../../e2e/selectors/Confirmation/ConfirmationView.selectors'; | ||
import { strings } from '../../../../../../../../../locales/i18n'; | ||
import { useStyles } from '../../../../../../../../component-library/hooks'; | ||
import InfoRow from '../../../../UI/InfoRow'; | ||
import { InfoRowDivider } from '../../../../UI/InfoRow/Divider/Divider'; | ||
import InfoSection from '../../../../UI/InfoRow/InfoSection'; | ||
import InfoRowAddress from '../../../../UI/InfoRow/InfoValue/Address'; | ||
import DisplayURL from '../../../../UI/InfoRow/InfoValue/DisplayURL'; | ||
import { isRecognizedPermit, parseTypedDataMessageFromSignatureRequest } from '../../../../../utils/signature'; | ||
import { useSignatureRequest } from '../../../../../hooks/useSignatureRequest'; | ||
import useApprovalRequest from '../../../../../hooks/useApprovalRequest'; | ||
import { View } from 'react-native'; | ||
import styleSheet from './InfoSectionAddressAndOrigin.styles'; | ||
import { isValidAddress } from 'ethereumjs-util'; | ||
|
||
export const InfoSectionAddressAndOrigin = () => { | ||
const { styles } = useStyles(styleSheet, {}); | ||
|
||
// signatureRequest from SignatureController does not include the origin | ||
// so we need to use approvalRequest | ||
const { approvalRequest } = useApprovalRequest(); | ||
const origin = approvalRequest?.origin as string; | ||
|
||
const signatureRequest = useSignatureRequest(); | ||
const isPermit = isRecognizedPermit(signatureRequest); | ||
|
||
const { | ||
domain: { verifyingContract } = {}, | ||
Check failure on line 30 in app/components/Views/confirmations/components/Confirm/Info/TypedSignV3V4/InfoSectionAddressAndOrigin/InfoSectionAddressAndOrigin.tsx
|
||
message: { spender } = {}, | ||
Check failure on line 31 in app/components/Views/confirmations/components/Confirm/Info/TypedSignV3V4/InfoSectionAddressAndOrigin/InfoSectionAddressAndOrigin.tsx
|
||
} = parseTypedDataMessageFromSignatureRequest(signatureRequest) ?? {}; | ||
|
||
if (!signatureRequest) { | ||
return null; | ||
} | ||
|
||
const chainId = signatureRequest.chainId; | ||
|
||
return ( | ||
<InfoSection | ||
testID={ConfirmationPageSectionsSelectorIDs.ORIGIN_INFO_SECTION} | ||
> | ||
{isPermit && spender && ( | ||
<> | ||
<InfoRow label={strings('confirm.label.spender')}> | ||
<InfoRowAddress address={spender} chainId={chainId} /> | ||
</InfoRow> | ||
<View style={styles.dividerContainer}> | ||
<InfoRowDivider /> | ||
</View> | ||
</> | ||
)} | ||
<InfoRow | ||
label={strings('confirm.request_from')} | ||
tooltip={strings('confirm.personal_sign_tooltip')} | ||
> | ||
<DisplayURL url={origin} /> | ||
</InfoRow> | ||
{isValidAddress(verifyingContract) && ( | ||
<InfoRow label={strings('confirm.label.interacting_with')}> | ||
<InfoRowAddress | ||
address={verifyingContract} | ||
chainId={chainId} | ||
/> | ||
</InfoRow> | ||
)} | ||
</InfoSection> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { InfoSectionAddressAndOrigin } from './InfoSectionAddressAndOrigin'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,54 @@ | ||
import React from 'react'; | ||
|
||
import renderWithProvider from '../../../../../../util/test/renderWithProvider'; | ||
import { | ||
personalSignatureConfirmationState, | ||
siweSignatureConfirmationState, | ||
typedSignV4ConfirmationState, | ||
typedSignV4NFTConfirmationState, | ||
} from '../../../../../../util/test/confirm-data-helpers'; | ||
import renderWithProvider from '../../../../../../util/test/renderWithProvider'; | ||
import Title from './Title'; | ||
|
||
describe('Title', () => { | ||
it('should render correct title and subtitle for personal sign request', async () => { | ||
describe('Confirm Title', () => { | ||
it('renders the title and subtitle for a permit signature', () => { | ||
const { getByText } = renderWithProvider(<Title />, { | ||
state: typedSignV4ConfirmationState, | ||
}); | ||
|
||
expect(getByText('Spending cap request')).toBeTruthy(); | ||
expect( | ||
getByText('This site wants permission to spend your tokens.'), | ||
).toBeTruthy(); | ||
}); | ||
|
||
it('renders the title and subtitle for a permit NFT signature', () => { | ||
const { getByText } = renderWithProvider(<Title />, { | ||
state: typedSignV4NFTConfirmationState, | ||
}); | ||
|
||
expect(getByText('Withdrawal request')).toBeTruthy(); | ||
expect( | ||
getByText('This site wants permission to withdraw your NFTs.'), | ||
).toBeTruthy(); | ||
}); | ||
|
||
it('renders correct title and subtitle for personal sign request', () => { | ||
const { getByText } = renderWithProvider(<Title />, { | ||
state: personalSignatureConfirmationState, | ||
}); | ||
expect(getByText('Signature request')).toBeDefined(); | ||
expect(getByText('Signature request')).toBeTruthy(); | ||
expect( | ||
getByText('Review request details before you confirm.'), | ||
).toBeDefined(); | ||
).toBeTruthy(); | ||
}); | ||
|
||
it('should render correct title and subtitle for personal siwe request', async () => { | ||
it('should render correct title and subtitle for personal siwe request', () => { | ||
const { getByText } = renderWithProvider(<Title />, { | ||
state: siweSignatureConfirmationState, | ||
}); | ||
expect(getByText('Sign-in request')).toBeDefined(); | ||
expect(getByText('Sign-in request')).toBeTruthy(); | ||
expect( | ||
getByText('A site wants you to sign in to prove you own this account.'), | ||
).toBeDefined(); | ||
).toBeTruthy(); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be better to be able to pass styles to divider row itself rather than wrap it in another view.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's better to avoid it in this case because the dividerContainer has these styles
for better reusability, it is better to keep outer margins and paddings separate. I think we can reconsider this once we have more cases using InfoRowDivider