Skip to content

Commit 2c88d2e

Browse files
committed
Add initial bridge draft
1 parent a333c4c commit 2c88d2e

File tree

30 files changed

+2104
-73
lines changed

30 files changed

+2104
-73
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ TEST_WALLET_ADDRESS=
99
PROXY_URL=https://proxy.zerion.io/
1010
FEATURE_FOOTER_BUG_BUTTON=on
1111
FEATURE_SEND_FORM=
12+
FEATURE_BRIDGE_FORM=
1213
MIXPANEL_TOKEN_PUBLIC=
1314
FEATURE_LOYALTY_FLOW=off

src/shared/types/SignatureContextParams.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import type { AnyAddressAction } from 'src/modules/ethereum/transactions/addressAction';
22
import type { Quote } from './Quote';
33

4-
type ClientScope = string | 'Swap' | 'Send' | 'Zerion DNA' | 'External Dapp';
4+
type ClientScope =
5+
| string
6+
| 'Swap'
7+
| 'Bridge'
8+
| 'Send'
9+
| 'Zerion DNA'
10+
| 'External Dapp';
511

612
export interface TransactionContextParams {
713
chain: string; // Cannot use type {Chain} because it's not serializable and this object is being sent between Ports

src/ui/App/App.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ import { BackupPage } from '../pages/Backup/Backup';
8181
import { ProgrammaticNavigationHelper } from '../shared/routing/ProgrammaticNavigationHelper';
8282
import { Invite } from '../features/referral-program';
8383
import { XpDrop } from '../features/xp-drop';
84+
import { BridgeForm } from '../pages/BridgeForm';
8485
import { RouteRestoration, registerPersistentRoute } from './RouteRestoration';
8586

8687
const isProd = process.env.NODE_ENV === 'production';
@@ -386,6 +387,14 @@ function Views({ initialRoute }: { initialRoute?: string }) {
386387
</RequireAuth>
387388
}
388389
/>
390+
<Route
391+
path="/bridge-form/*"
392+
element={
393+
<RequireAuth>
394+
<BridgeForm />
395+
</RequireAuth>
396+
}
397+
/>
389398
<Route
390399
path="/invite/*"
391400
element={
@@ -427,6 +436,7 @@ initializeApperance();
427436
dayjs.extend(relativeTime);
428437
registerPersistentRoute('/send-form');
429438
registerPersistentRoute('/swap-form');
439+
registerPersistentRoute('/bridge-form');
430440

431441
function GlobalKeyboardShortcuts() {
432442
const isDialog = urlContext.windowType === 'dialog';
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import BigNumber from 'bignumber.js';
2+
import React from 'react';
3+
import { formatCurrencyValue } from 'src/shared/units/formatCurrencyValue';
4+
import { formatPercent } from 'src/shared/units/formatPercent/formatPercent';
5+
import { UIText } from 'src/ui/ui-kit/UIText';
6+
import { isNumeric } from 'src/shared/isNumeric';
7+
import { useCurrency } from 'src/modules/currency/useCurrency';
8+
import { exceedsPriceImpactThreshold } from 'src/ui/pages/SwapForm/shared/price-impact';
9+
import type { Asset } from 'defi-sdk';
10+
11+
export function FiatInputValue({
12+
name,
13+
primaryInput,
14+
spendInput,
15+
spendAsset,
16+
receiveInput,
17+
receiveAsset,
18+
}: {
19+
name: 'spendInput' | 'receiveInput';
20+
primaryInput: 'spend' | 'receive';
21+
spendInput?: string;
22+
spendAsset: Asset | null;
23+
receiveInput?: string;
24+
receiveAsset: Asset | null;
25+
}) {
26+
const { currency } = useCurrency();
27+
28+
const asset = name === 'receiveInput' ? receiveAsset : spendAsset;
29+
const oppositeAsset = asset === receiveAsset ? spendAsset : receiveAsset;
30+
const inputValue = name === 'receiveInput' ? receiveInput : spendInput;
31+
const oppositeInputValue =
32+
name === 'receiveInput' ? spendInput : receiveInput;
33+
const isPrimaryInput =
34+
name === 'receiveInput'
35+
? primaryInput === 'receive'
36+
: primaryInput === 'spend';
37+
38+
if (inputValue == null || !isNumeric(inputValue)) {
39+
return null;
40+
}
41+
42+
const fiatValue = new BigNumber(inputValue || 0).times(
43+
asset?.price?.value || 0
44+
);
45+
46+
let diff: BigNumber | null = null;
47+
if (name === 'receiveInput') {
48+
const oppositeFiatValue = new BigNumber(oppositeInputValue || 0).times(
49+
oppositeAsset?.price?.value || 0
50+
);
51+
diff = oppositeFiatValue.isGreaterThan(0)
52+
? fiatValue.minus(oppositeFiatValue).div(oppositeFiatValue)
53+
: null;
54+
}
55+
56+
const formattedDiff = diff
57+
? `${diff.isLessThan(0) ? '' : '+'}${formatPercent(diff.times(100), 'en')}%`
58+
: null;
59+
60+
const isPriceImpactWarning = diff
61+
? exceedsPriceImpactThreshold({ relativeChange: diff })
62+
: false;
63+
64+
return (
65+
<UIText
66+
kind="small/regular"
67+
color={
68+
isPriceImpactWarning ? 'var(--negative-500)' : 'var(--neutral-600)'
69+
}
70+
style={isPriceImpactWarning ? { cursor: 'help' } : undefined}
71+
title={
72+
isPriceImpactWarning
73+
? 'The exchange rate is lower than the market rate. Lack of liquidity affects the exchange rate. Try a lower amount.'
74+
: undefined
75+
}
76+
>
77+
{isPrimaryInput ? null : '≈'}
78+
{formatCurrencyValue(fiatValue, 'en', currency)}{' '}
79+
{formattedDiff ? `(${formattedDiff})` : null}
80+
</UIText>
81+
);
82+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { FiatInputValue } from './FiatInputValue';

0 commit comments

Comments
 (0)