Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a960e98
feat: implement consent for all forms
limitofzero Dec 25, 2025
9bad188
feat: add cache for restricted token list
limitofzero Dec 25, 2025
8ac48eb
chore: remove unused
limitofzero Dec 25, 2025
94afb02
chore: remove unused
limitofzero Dec 25, 2025
b292fb2
feat: remove i18n for consents
limitofzero Dec 25, 2025
4e98cf3
feat: show conesnts before import modal
limitofzero Dec 25, 2025
22720a1
feat: add i18n for block reason
limitofzero Dec 25, 2025
1785f97
refactor: reuse a hook
limitofzero Dec 25, 2025
e5e2c2d
feat: don't allow to user switch on restricted token list for blocked…
limitofzero Dec 25, 2025
f8d0e91
feat: add block to import restricted list
limitofzero Dec 26, 2025
c3df4e4
Merge branch 'develop' into feat/implement-consents-2
limitofzero Dec 26, 2025
63a2178
Merge branch 'feat/implement-consents-2' into feat/implement-consent-…
limitofzero Dec 26, 2025
b3227da
Merge branch 'feat/implement-consent-for-token-importing' of github.c…
limitofzero Dec 26, 2025
7d2a497
feat: consent flow for token lists
limitofzero Dec 29, 2025
5a60f7d
test: add tests for hooks
limitofzero Dec 29, 2025
0a86fc8
fix: build
limitofzero Dec 30, 2025
7d40283
refactor: decompose component
limitofzero Dec 30, 2025
ac427ea
fix: don't hide list if the consent required
limitofzero Dec 30, 2025
0127f82
refactor: use helper for keys
limitofzero Dec 30, 2025
911160a
test: fix cases
limitofzero Dec 30, 2025
fe662c9
fix: don't require consent when wallet is disconnected
limitofzero Dec 30, 2025
2625c84
fix: merge conflicts
limitofzero Dec 30, 2025
a752b85
fix: image size in importing
limitofzero Dec 30, 2025
7b7a567
refactor: small improvements
limitofzero Dec 30, 2025
2c31147
fix: types
limitofzero Dec 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 22 additions & 23 deletions apps/cowswap-frontend/src/locales/en-US.po
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,8 @@ msgid "Your TWAP order won't execute and is protected if the market price dips m
msgstr "Your TWAP order won't execute and is protected if the market price dips more than your set price protection."

#: apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/index.tsx
msgid "If you fall into any of these categories, select Cancel."
msgstr "If you fall into any of these categories, select Cancel."
#~ msgid "If you fall into any of these categories, select Cancel."
#~ msgstr "If you fall into any of these categories, select Cancel."

#: apps/cowswap-frontend/src/api/cowProtocol/errors/OperatorError.ts
msgid "The order cannot be {statusText}. Your account is deny-listed."
Expand Down Expand Up @@ -542,8 +542,8 @@ msgid "(modified)"
msgstr "(modified)"

#: apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/index.tsx
msgid "A resident of any jurisdiction where trading securities or cryptographic tokens is regulated or prohibited by applicable laws."
msgstr "A resident of any jurisdiction where trading securities or cryptographic tokens is regulated or prohibited by applicable laws."
#~ msgid "A resident of any jurisdiction where trading securities or cryptographic tokens is regulated or prohibited by applicable laws."
#~ msgstr "A resident of any jurisdiction where trading securities or cryptographic tokens is regulated or prohibited by applicable laws."

#: apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/deadlines.ts
#: apps/cowswap-frontend/src/modules/twap/const.ts
Expand Down Expand Up @@ -583,8 +583,8 @@ msgid "When selling {aNativeCurrency}, the minimum slippage tolerance is set to
msgstr "When selling {aNativeCurrency}, the minimum slippage tolerance is set to {minimumETHFlowSlippage}% or higher to ensure a high likelihood of order matching, even in volatile market conditions."

#: apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/index.tsx
msgid "A U.S. Person or resident of the United States."
msgstr "A U.S. Person or resident of the United States."
#~ msgid "A U.S. Person or resident of the United States."
#~ msgstr "A U.S. Person or resident of the United States."

#: apps/cowswap-frontend/src/modules/account/pure/ConnectedAccountBlocked/index.tsx
msgid "If you believe this is an error, please send an email including your address to "
Expand Down Expand Up @@ -1053,8 +1053,8 @@ msgid "Orders history"
msgstr "Orders history"

#: apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/index.tsx
msgid "We could not reliably determine your location (e.g., due to VPN or privacy settings). Access to {displaySymbol} is strictly limited to specific regions."
msgstr "We could not reliably determine your location (e.g., due to VPN or privacy settings). Access to {displaySymbol} is strictly limited to specific regions."
#~ msgid "We could not reliably determine your location (e.g., due to VPN or privacy settings). Access to {displaySymbol} is strictly limited to specific regions."
#~ msgstr "We could not reliably determine your location (e.g., due to VPN or privacy settings). Access to {displaySymbol} is strictly limited to specific regions."

#: apps/cowswap-frontend/src/modules/erc20Approve/pure/ApprovalTooltip/index.tsx
msgid "You must give the CoW Protocol smart contracts permission to use your <0/>."
Expand Down Expand Up @@ -1365,8 +1365,8 @@ msgid "Please read more in this"
msgstr "Please read more in this"

#: apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/index.tsx
msgid "Additional confirmation required for this token"
msgstr "Additional confirmation required for this token"
#~ msgid "Additional confirmation required for this token"
#~ msgstr "Additional confirmation required for this token"

#: libs/hook-dapp-lib/src/hookDappsRegistry.ts
#~ msgid "Bungee"
Expand Down Expand Up @@ -1530,8 +1530,8 @@ msgid "Enter a hook dapp URL"
msgstr "Enter a hook dapp URL"

#: apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/index.tsx
msgid "By clicking Confirm, you expressly represent and warrant that you are NOT:"
msgstr "By clicking Confirm, you expressly represent and warrant that you are NOT:"
#~ msgid "By clicking Confirm, you expressly represent and warrant that you are NOT:"
#~ msgstr "By clicking Confirm, you expressly represent and warrant that you are NOT:"

#: apps/cowswap-frontend/src/modules/ordersTable/pure/ReceiptModal/index.tsx
#: apps/cowswap-frontend/src/modules/trade/pure/TotalFeeRow/index.tsx
Expand Down Expand Up @@ -1891,8 +1891,8 @@ msgid "Failed to cancel order selling {sellTokenSymbol}"
msgstr "Failed to cancel order selling {sellTokenSymbol}"

#: apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/index.tsx
msgid "You are solely responsible for complying with your local laws."
msgstr "You are solely responsible for complying with your local laws."
#~ msgid "You are solely responsible for complying with your local laws."
#~ msgstr "You are solely responsible for complying with your local laws."

#: apps/cowswap-frontend/src/modules/swap/containers/SwapConfirmModal/useLabelsAndTooltips.tsx
#: apps/cowswap-frontend/src/modules/trade/containers/TradeBasicConfirmDetails/index.tsx
Expand Down Expand Up @@ -2007,8 +2007,8 @@ msgid "Creating..."
msgstr "Creating..."

#: apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/index.tsx
msgid "A resident of any country subject to international sanctions (e.g., OFAC, UN lists)."
msgstr "A resident of any country subject to international sanctions (e.g., OFAC, UN lists)."
#~ msgid "A resident of any country subject to international sanctions (e.g., OFAC, UN lists)."
#~ msgstr "A resident of any country subject to international sanctions (e.g., OFAC, UN lists)."

#: apps/cowswap-frontend/src/modules/hooksStore/pure/HookDappDetails/index.tsx
msgid "{typeLabel} hooks are externally hosted code which needs to be independently verified by the user."
Expand Down Expand Up @@ -3423,8 +3423,8 @@ msgid "Wrap <0/> and Swap"
msgstr "Wrap <0/> and Swap"

#: apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/index.tsx
msgid "View full consent terms ↗"
msgstr "View full consent terms ↗"
#~ msgid "View full consent terms ↗"
#~ msgstr "View full consent terms ↗"

#: apps/cowswap-frontend/src/modules/twap/containers/TwapFormWarnings/warnings/BigPartTimeWarning.tsx
msgid "A maximum of <0>{time}</0> between parts is required. Increase the number of parts or decrease the total duration."
Expand Down Expand Up @@ -3613,8 +3613,8 @@ msgid "Approving <0>{currencySymbolOrContext}</0> for trading"
msgstr "Approving <0>{currencySymbolOrContext}</0> for trading"

#: apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/index.tsx
msgid "A resident of the EU or EEA."
msgstr "A resident of the EU or EEA."
#~ msgid "A resident of the EU or EEA."
#~ msgstr "A resident of the EU or EEA."

#: apps/cowswap-frontend/src/modules/tradeFormValidation/pure/TradeFormButtons/tradeButtonsMap.tsx
msgid "Couldn't load balances"
Expand Down Expand Up @@ -4185,7 +4185,6 @@ msgstr "Governance"
#: apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/index.tsx
#: apps/cowswap-frontend/src/modules/orderProgressBar/pure/TransactionSubmittedContent/index.tsx
#: apps/cowswap-frontend/src/modules/ordersTable/containers/MultipleCancellationMenu/index.tsx
#: apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/index.tsx
#: apps/cowswap-frontend/src/modules/twap/pure/CustomDeadlineSelector/index.tsx
msgid "Cancel"
msgstr "Cancel"
Expand Down Expand Up @@ -5962,8 +5961,8 @@ msgid "User rejected signing COW claim transaction"
msgstr "User rejected signing COW claim transaction"

#: apps/cowswap-frontend/src/modules/rwa/pure/RwaConsentModal/index.tsx
msgid "I Confirm"
msgstr "I Confirm"
#~ msgid "I Confirm"
#~ msgstr "I Confirm"

#: apps/cowswap-frontend/src/modules/account/containers/Transaction/StatusDetails.tsx
#: apps/cowswap-frontend/src/modules/orderProgressBar/pure/TransactionSubmittedContent/index.tsx
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { MessageDescriptor } from '@lingui/core'
import { useLingui } from '@lingui/react/macro'

import { useLimitOrdersWarningsAccepted } from 'modules/limitOrders/hooks/useLimitOrdersWarningsAccepted'
import { useTradeConfirmActions } from 'modules/trade'
import { useConfirmTradeWithRwaCheck } from 'modules/trade'
import {
TradeFormBlankButton,
TradeFormButtons,
Expand Down Expand Up @@ -34,9 +34,8 @@ export function TradeButtons({ isTradeContextReady }: TradeButtonsProps) {
const localFormValidation = useLimitOrdersFormState()
const primaryFormValidation = useGetTradeFormValidation()
const warningsAccepted = useLimitOrdersWarningsAccepted(false)
const tradeConfirmActions = useTradeConfirmActions()

const confirmTrade = tradeConfirmActions.onOpen
const { confirmTrade } = useConfirmTradeWithRwaCheck()

const tradeFormButtonContext = useTradeFormButtonContext(CONFIRM_TEXT, confirmTrade)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@ import { ReactNode, useCallback, useMemo } from 'react'

import { useWalletInfo } from '@cowprotocol/wallet'

import { RwaConsentKey, RwaConsentModal, useRwaConsentModalState, useRwaConsentStatus } from 'modules/rwa'
import { useTradeConfirmActions } from 'modules/trade'

import { useRwaConsentModalState } from '../../hooks/useRwaConsentModalState'
import { useRwaConsentStatus } from '../../hooks/useRwaConsentStatus'
import { RwaConsentModal } from '../../pure/RwaConsentModal'
import { RwaConsentKey } from '../../types/rwaConsent'

export function RwaConsentModalContainer(): ReactNode {
const { account } = useWalletInfo()
const { isModalOpen, closeModal, context } = useRwaConsentModalState()
Expand Down Expand Up @@ -37,7 +33,14 @@ export function RwaConsentModalContainer(): ReactNode {

confirmConsent()
closeModal()
tradeConfirmActions.onOpen()

// if this is a token import flow, call the success callback to proceed to import modal
// if this is a trade flow, open the trade confirmation
if (context.onImportSuccess) {
context.onImportSuccess()
} else {
tradeConfirmActions.onOpen()
}
}, [account, context, consentKey, confirmConsent, closeModal, tradeConfirmActions])

if (!isModalOpen || !context) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import { useAtomValue, useSetAtom } from 'jotai'
import { useCallback } from 'react'

import { TokenWithLogo } from '@cowprotocol/common-const'

import {
rwaConsentModalStateAtom,
updateRwaConsentModalStateAtom,
RwaConsentModalState,
RwaConsentModalContext,
} from '../state/rwaConsentModalStateAtom'

export interface RwaConsentModalContext {
consentHash: string
token?: TokenWithLogo
}
export type { RwaConsentModalContext }

export function useRwaConsentModalState(): {
isModalOpen: boolean
Expand Down
1 change: 1 addition & 0 deletions apps/cowswap-frontend/src/modules/rwa/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './state/geoDataAtom'
export * from './hooks/useRwaConsentStatus'
export * from './hooks/useRwaConsentModalState'
export * from './hooks/useGeoCountry'
export * from './hooks/useGeoStatus'
export * from './hooks/useRwaTokenStatus'
export * from './pure/RwaConsentModal'
export * from './containers/RwaConsentModalContainer'
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,23 @@ import { TokenWithLogo } from '@cowprotocol/common-const'
import { TokenLogo } from '@cowprotocol/tokens'
import { ButtonPrimary, ButtonOutlined, ModalHeader } from '@cowprotocol/ui'

import { Trans } from '@lingui/react/macro'

import * as styledEl from './styled'

export interface RwaConsentModalProps {
onDismiss(): void
onConfirm(): void
token?: TokenWithLogo
consentHash: string
consentHash?: string
}

const IPFS_GATEWAY = 'https://ipfs.io/ipfs'

export function RwaConsentModal(props: RwaConsentModalProps): ReactNode {
const { onDismiss, onConfirm, token, consentHash } = props
const { onDismiss, onConfirm, token } = props

const displaySymbol = token?.symbol || 'this token'
const consentUrl = `${IPFS_GATEWAY}/${consentHash}`

return (
<styledEl.Wrapper>
<ModalHeader onClose={onDismiss}>
<Trans>Additional confirmation required for this token</Trans>
</ModalHeader>
<ModalHeader onClose={onDismiss}>Additional confirmation required for this token</ModalHeader>
<styledEl.Contents>
{token && (
<styledEl.TokenBlock>
Expand All @@ -45,50 +38,27 @@ export function RwaConsentModal(props: RwaConsentModalProps): ReactNode {
)}
<styledEl.Body>
<p>
<Trans>
We could not reliably determine your location (e.g., due to VPN or privacy settings). Access to{' '}
{displaySymbol} is strictly limited to specific regions.
</Trans>
We could not reliably determine your location (e.g., due to VPN or privacy settings). Access to{' '}
{displaySymbol} is strictly limited to specific regions.
</p>
<styledEl.AcknowledgementSection>
<p>
<Trans>By clicking Confirm, you expressly represent and warrant that you are NOT:</Trans>
</p>
<p>By clicking Confirm, you expressly represent and warrant that you are NOT:</p>
<styledEl.BulletList>
<li>A U.S. Person or resident of the United States.</li>
<li>A resident of the EU or EEA.</li>
<li>A resident of any country subject to international sanctions (e.g., OFAC, UN lists).</li>
<li>
<Trans>A U.S. Person or resident of the United States.</Trans>
</li>
<li>
<Trans>A resident of the EU or EEA.</Trans>
</li>
<li>
<Trans>A resident of any country subject to international sanctions (e.g., OFAC, UN lists).</Trans>
</li>
<li>
<Trans>
A resident of any jurisdiction where trading securities or cryptographic tokens is regulated or
prohibited by applicable laws.
</Trans>
A resident of any jurisdiction where trading securities or cryptographic tokens is regulated or
prohibited by applicable laws.
</li>
</styledEl.BulletList>
</styledEl.AcknowledgementSection>
<p>
<Trans>If you fall into any of these categories, select Cancel.</Trans>
</p>
<p>
<Trans>You are solely responsible for complying with your local laws.</Trans>
</p>
<styledEl.ConsentLink href={consentUrl} target="_blank" rel="noopener noreferrer">
<Trans>View full consent terms ↗</Trans>
</styledEl.ConsentLink>
<p>If you fall into any of these categories, select Cancel.</p>
<p>You are solely responsible for complying with your local laws.</p>
</styledEl.Body>
<styledEl.ButtonContainer>
<ButtonPrimary onClick={onConfirm}>
<Trans>I Confirm</Trans>
</ButtonPrimary>
<ButtonOutlined onClick={onDismiss}>
<Trans>Cancel</Trans>
</ButtonOutlined>
<ButtonPrimary onClick={onConfirm}>I Confirm</ButtonPrimary>
<ButtonOutlined onClick={onDismiss}>Cancel</ButtonOutlined>
</styledEl.ButtonContainer>
</styledEl.Contents>
</styledEl.Wrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,24 +100,3 @@ export const ButtonContainer = styled.div`
min-height: 56px;
}
`

export const ConsentLink = styled.a`
display: inline-flex;
align-items: center;
gap: 4px;
color: var(${UI.COLOR_PRIMARY});
font-size: 13px;
text-decoration: none;
opacity: 0.8;
transition: opacity 0.15s ease-in-out;

&:hover {
opacity: 1;
text-decoration: underline;
}

> svg {
width: 12px;
height: 12px;
}
`
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ import { atom } from 'jotai'
import { TokenWithLogo } from '@cowprotocol/common-const'
import { atomWithPartialUpdate } from '@cowprotocol/common-utils'

export interface RwaConsentModalContext {
consentHash: string
token?: TokenWithLogo
pendingImportTokens?: TokenWithLogo[]
onImportSuccess?: () => void
}

export interface RwaConsentModalState {
isModalOpen: boolean
context?: {
consentHash: string
token?: TokenWithLogo
}
context?: RwaConsentModalContext
}

const initialRwaConsentModalState: RwaConsentModalState = {
Expand Down
Loading