Skip to content

Commit

Permalink
feat: Add validation to sanctioned wallets in Bridge widget (#2389)
Browse files Browse the repository at this point in the history
  • Loading branch information
alejoloaiza authored Nov 13, 2024
1 parent 83e3ad7 commit 318c3dd
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export enum BridgeWidgetViews {
CLAIM_WITHDRAWAL_IN_PROGRESS = 'CLAIM_WITHDRAWAL_IN_PROGRESS',
CLAIM_WITHDRAWAL_SUCCESS = 'CLAIM_WITHDRAWAL_SUCCESS',
CLAIM_WITHDRAWAL_FAILURE = 'CLAIM_WITHDRAWAL_FAILURE',
SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE',
}

export type BridgeWidgetView =
Expand All @@ -28,7 +29,8 @@ export type BridgeWidgetView =
| BridgeClaimWithdrawal
| BridgeClaimWithdrawalInProgress
| BridgeClaimWithdrawalSuccess
| BridgeClaimWithdrawalFailure;
| BridgeClaimWithdrawalFailure
| BridgeServiceUnavailableView;

interface BridgeCrossWalletSelection extends ViewType {
type: BridgeWidgetViews.WALLET_NETWORK_SELECTION,
Expand Down Expand Up @@ -83,3 +85,7 @@ export interface BridgeClaimWithdrawalFailure extends ViewType {
transactionHash: string;
reason: string;
}

export interface BridgeServiceUnavailableView extends ViewType {
type: BridgeWidgetViews.SERVICE_UNAVAILABLE;
}
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ export default function BridgeWidget({
testId="claim-withdrawal-fail-view"
/>
)}
{viewState.view.type === SharedViews.SERVICE_UNAVAILABLE_ERROR_VIEW && (
{viewState.view.type === BridgeWidgetViews.SERVICE_UNAVAILABLE && (
<ServiceUnavailableErrorView
onCloseClick={() => sendBridgeWidgetCloseEvent(eventTarget)}
onBackButtonClick={() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
OptionKey,
} from '@biom3/react';
import {
fetchRiskAssessment,
GetBalanceResult, WidgetTheme,
} from '@imtbl/checkout-sdk';
import {
Expand Down Expand Up @@ -176,6 +177,27 @@ export function BridgeForm(props: BridgeFormProps) {
[formToken, tokenBalances, cryptoFiatState.conversions, formatTokenOptionsId],
);

useEffect(() => {
if (!checkout || !from || !to) {
return;
}

(async () => {
const addresses = [from.walletAddress];
if (to.walletAddress.toLowerCase() !== from.walletAddress.toLowerCase()) {
addresses.push(to.walletAddress);
}

const assessment = await fetchRiskAssessment(addresses, checkout.config);
bridgeDispatch({
payload: {
type: BridgeActions.SET_RISK_ASSESSMENT,
riskAssessment: assessment,
},
});
})();
}, [checkout, from, to]);

const canFetchEstimates = (silently: boolean): boolean => {
if (Number.isNaN(parseFloat(formAmount))) return false;
if (parseFloat(formAmount) <= 0) return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import {
GasEstimateBridgeToL2Result,
GasEstimateType,
isAddressSanctioned,
} from '@imtbl/checkout-sdk';
import { ApproveBridgeResponse, BridgeTxResponse } from '@imtbl/bridge-sdk';
import { BigNumber, utils } from 'ethers';
Expand Down Expand Up @@ -76,7 +77,7 @@ export function BridgeReviewSummary() {

const {
bridgeState: {
checkout, tokenBridge, from, to, token, amount, tokenBalances,
checkout, tokenBridge, from, to, token, amount, tokenBalances, riskAssessment,
},
bridgeDispatch,
} = useContext(BridgeContext);
Expand Down Expand Up @@ -363,6 +364,19 @@ export function BridgeReviewSummary() {

const submitBridge = useCallback(async () => {
if (!isTransfer && (!approveTransaction || !transaction)) return;
if (!from || !to) return;
if (riskAssessment && isAddressSanctioned(riskAssessment)) {
viewDispatch({
payload: {
type: ViewActions.UPDATE_VIEW,
view: {
type: BridgeWidgetViews.SERVICE_UNAVAILABLE,
},
},
});

return;
}

if (insufficientFundsForGas) {
setShowNotEnoughGasDrawer(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import {
} from 'react';
import {
ChainId,
fetchRiskAssessment,
isAddressSanctioned,
WalletProviderName,
WalletProviderRdns,
} from '@imtbl/checkout-sdk';
Expand All @@ -30,7 +28,7 @@ import {
} from '../../../lib/provider';
import { getL1ChainId, getL2ChainId } from '../../../lib';
import { getChainNameById } from '../../../lib/chains';
import { SharedViews, ViewActions, ViewContext } from '../../../context/view-context/ViewContext';
import { ViewActions, ViewContext } from '../../../context/view-context/ViewContext';
import { abbreviateAddress } from '../../../lib/addressUtils';
import {
useAnalytics,
Expand Down Expand Up @@ -213,22 +211,6 @@ export function WalletAndNetworkSelector() {
const web3Provider = new Web3Provider(event.provider as any);
const connectedProvider = await connectToProvider(checkout, web3Provider, changeAccount);

// CM-793 Check for sanctioned address
const address = await connectedProvider.getSigner().getAddress();
const sanctions = await fetchRiskAssessment([address], checkout.config);
if (isAddressSanctioned(sanctions, address)) {
viewDispatch({
payload: {
type: ViewActions.UPDATE_VIEW,
view: {
type: SharedViews.SERVICE_UNAVAILABLE_ERROR_VIEW,
error: new Error('Sanctioned address'),
},
},
});
return;
}

await handleFromWalletConnectionSuccess(connectedProvider);
},
[checkout],
Expand Down Expand Up @@ -325,6 +307,7 @@ export function WalletAndNetworkSelector() {
setToWalletWeb3Provider(fromWalletWeb3Provider);
setToWallet(event);
const address = await fromWalletWeb3Provider!.getSigner().getAddress();

setToWalletAddress(address.toLowerCase());
handleSettingToNetwork(address.toLowerCase());

Expand All @@ -345,21 +328,7 @@ export function WalletAndNetworkSelector() {
const web3Provider = new Web3Provider(event.provider as any);
const connectedProvider = await connectToProvider(checkout, web3Provider, false);

// CM-793 Check for sanctioned address
const address = await connectedProvider.getSigner().getAddress();
const sanctions = await fetchRiskAssessment([address], checkout.config);
if (isAddressSanctioned(sanctions, address)) {
viewDispatch({
payload: {
type: ViewActions.UPDATE_VIEW,
view: {
type: SharedViews.SERVICE_UNAVAILABLE_ERROR_VIEW,
error: new Error('Sanctioned address'),
},
},
});
return;
}

if (isWalletConnectProvider(connectedProvider)) {
handleWalletConnectToWalletConnection(connectedProvider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Checkout,
ChainId,
EIP6963ProviderInfo,
AssessmentResult,
} from '@imtbl/checkout-sdk';
import { createContext } from 'react';

Expand All @@ -28,6 +29,7 @@ export interface BridgeState {
allowedTokens: TokenInfo[];
token: TokenInfo | null;
amount: string;
riskAssessment: AssessmentResult | undefined;
}

export const initialBridgeState: Omit<BridgeState, 'checkout'> = {
Expand All @@ -40,6 +42,7 @@ export const initialBridgeState: Omit<BridgeState, 'checkout'> = {
allowedTokens: [],
token: null,
amount: '0',
riskAssessment: undefined,
};

export interface BridgeContextState {
Expand All @@ -58,7 +61,8 @@ type ActionPayload =
| SetTokenBalancesPayload
| SetAllowedTokensPayload
| SetTokenAndAmountPayload
| SetWalletsAndNetworksPayload;
| SetWalletsAndNetworksPayload
| SetRiskAssessmentPayload;

export enum BridgeActions {
SET_WALLETS_AND_NETWORKS = 'SET_WALLETS_AND_NETWORKS',
Expand All @@ -68,6 +72,7 @@ export enum BridgeActions {
SET_TOKEN_BALANCES = 'SET_TOKEN_BALANCES',
SET_ALLOWED_TOKENS = 'SET_ALLOWED_TOKENS',
SET_TOKEN_AND_AMOUNT = 'SET_TOKEN_AND_AMOUNT',
SET_RISK_ASSESSMENT = 'SET_RISK_ASSESSMENT',
}

export interface SetWalletProviderNamePayload {
Expand Down Expand Up @@ -107,6 +112,11 @@ export interface SetTokenAndAmountPayload {
amount: string;
}

export interface SetRiskAssessmentPayload {
type: BridgeActions.SET_RISK_ASSESSMENT;
riskAssessment: AssessmentResult;
}

// eslint-disable-next-line @typescript-eslint/naming-convention
export const BridgeContext = createContext<BridgeContextState>({
bridgeState: { ...initialBridgeState, checkout: {} as Checkout },
Expand Down Expand Up @@ -159,6 +169,11 @@ export const bridgeReducer: Reducer<BridgeState, BridgeAction> = (
token: action.payload.token,
amount: action.payload.amount,
};
case BridgeActions.SET_RISK_ASSESSMENT:
return {
...state,
riskAssessment: action.payload.riskAssessment,
};
default:
return state;
}
Expand Down

0 comments on commit 318c3dd

Please sign in to comment.