Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c6d72c5
feat: erc20 bridge initilized
norugpull Jul 1, 2025
a94378c
feat(web): bridge flow sdk
norugpull Jul 14, 2025
e549204
fix: build error
norugpull Jul 17, 2025
1e4d6d6
fix: chain id type
norugpull Jul 17, 2025
da35523
feat: add missing files
norugpull Jul 22, 2025
095aa1a
Merge branch 'develop' into erc-20-bridge
norugpull Jul 28, 2025
13446a8
fix: bridge ui issues
norugpull Jul 28, 2025
5d83ca3
fix: aggregator balance issue
norugpull Jul 29, 2025
9622f41
fix: review screen data
norugpull Jul 29, 2025
2dffee7
feat: bridge receive flow
norugpull Aug 3, 2025
beacd81
fix: bridge send flow issues
norugpull Aug 11, 2025
988522a
fix: ethereum asset addresses
norugpull Aug 13, 2025
524d57f
Merge branch 'develop' into erc-20-bridge
norugpull Aug 18, 2025
d9b990e
fix: assets invalid contract address.
norugpull Aug 18, 2025
42f63ce
Merge branch 'develop' into erc-20-bridge
norugpull Aug 29, 2025
1051aea
fix: erc20 bridge improvements
norugpull Aug 29, 2025
e06857f
fix: erc20 tx hash link
norugpull Aug 29, 2025
f4eef85
fix: adjust erc20 bridge
norugpull Sep 1, 2025
636eb96
fix: erc20 bridge issues
norugpull Sep 4, 2025
8c82c97
Merge branch 'develop' into erc-20-bridge
norugpull Sep 9, 2025
487db3d
fix: bridge issues
norugpull Sep 16, 2025
2d9f3d1
Merge branch 'develop' into erc-20-bridge
norugpull Sep 18, 2025
1d165ee
fix: erc20 bridge issues
norugpull Sep 18, 2025
a090f5c
fix: update bridge service
norugpull Sep 23, 2025
aafa613
Merge branch 'develop' into erc-20-bridge
norugpull Oct 6, 2025
980a51d
Merge branch 'develop' into erc-20-bridge
norugpull Oct 10, 2025
85f69e2
fix: bridge ui issues
norugpull Oct 10, 2025
b489231
fix: bridge receiver address
grinry Oct 10, 2025
05fb778
fix: remove un-used types
norugpull Oct 10, 2025
2021d0b
fix: bridge issues
norugpull Oct 10, 2025
8b50d04
fix: erc20 bridge switch network to RSK on close
norugpull Oct 14, 2025
f9d7e29
fix: remove BSC and ETH from dropdown
norugpull Oct 14, 2025
95ea506
fix: remove switch network from erc20 bridge
norugpull Oct 15, 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
27 changes: 27 additions & 0 deletions apps/frontend/src/app/1_atoms/Stepper/Stepper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';

import classNames from 'classnames';

export interface StepperProps {
steps: number;
activeStep: number;
className?: string;
}

export const Stepper: React.FC<StepperProps> = ({
steps,
activeStep,
className,
}) => (
<div className={classNames('flex items-center gap-2 w-full', className)}>
{Array.from({ length: steps }, (_, index) => (
<div
className={classNames('h-1 flex-1 rounded-full transition-colors', {
'bg-primary-20': index < activeStep,
'bg-gray-40': index >= activeStep,
})}
key={index}
/>
))}
</div>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';

import { t } from 'i18next';

import {
AddressBadge,
Button,
ButtonStyle,
Dialog,
DialogSize,
Heading,
Paragraph,
ParagraphSize,
Tabs,
VerticalTabs,
} from '@sovryn/ui';

import { MobileCloseButton } from '../../1_atoms/MobileCloseButton/MobileCloseButton';
import { useAccount } from '../../../hooks/useAccount';
import { useIsMobile } from '../../../hooks/useIsMobile';
import { translations } from '../../../locales/i18n';
import { useChainDetails } from '../RuneBridgeDialog/hooks/useChainDetails';
import { ReceiveFlow } from './components/ReceiveFlow/ReceiveFlow';
import { SendFlow } from './components/SendFlow/SendFlow';
import { ACTIVE_CLASSNAME } from './constants';
import { SendFlowContextProvider } from './contextproviders/SendFlowContext';

const translation = translations.erc20Bridge.mainScreen;

type ERC20BridgeDialogProps = {
isOpen: boolean;
onClose: () => void;
step?: number;
};

export const ERC20BridgeDialog: React.FC<ERC20BridgeDialogProps> = ({
isOpen,
onClose,
step = 0,
}) => {
const [index, setIndex] = useState(step);
const { account } = useAccount();
const { supported: isChainSupported, chainName } = useChainDetails();
const { isMobile } = useIsMobile();

useEffect(() => {
setIndex(step);
}, [step]);

const items = useMemo(() => {
if (!isChainSupported) {
return [
{
label: '',
infoText: '',
content: (
<div className="mt-0 md:mt-12">
<Paragraph
size={ParagraphSize.base}
children={`${chainName} is currently not supported by the ERC20 Bridge.`}
/>
<MobileCloseButton onClick={onClose} />
</div>
),
activeClassName: ACTIVE_CLASSNAME,
},
];
}
return [
{
label: t(translation.tabs.receiveLabel),
infoText: t(translation.tabs.receiveInfoText),
content: (
<>
<ReceiveFlow onClose={onClose} />
<MobileCloseButton onClick={onClose} />
</>
),
activeClassName: ACTIVE_CLASSNAME,
dataAttribute: 'erc20-bridge-receive',
},
{
label: t(translation.tabs.sendLabel),
infoText: t(translation.tabs.sendInfoText),
content: (
<SendFlowContextProvider>
<SendFlow onClose={onClose} />
<MobileCloseButton onClick={onClose} />
</SendFlowContextProvider>
),
activeClassName: ACTIVE_CLASSNAME,
dataAttribute: 'erc20-bridge-send',
},
];
}, [onClose, chainName, isChainSupported]);

const onChangeIndex = useCallback((index: number | null) => {
index !== null ? setIndex(index) : setIndex(0);
}, []);

const dialogSize = useMemo(
() => (isMobile ? DialogSize.md : DialogSize.xl3),
[isMobile],
);

useEffect(() => {
setIndex(0);
}, [account]);

return (
<Dialog
isOpen={isOpen}
width={dialogSize}
className="p-4 flex items-center sm:p-0"
disableFocusTrap
closeOnEscape={false}
>
<Tabs
index={index}
items={items}
onChange={onChangeIndex}
className="w-full md:hidden"
contentClassName="pt-9 px-6 pb-7 h-full"
/>
<VerticalTabs
items={items}
onChange={onChangeIndex}
selectedIndex={index}
tabsClassName="min-h-[42rem] block pt-0 relative"
headerClassName="pb-0 pt-5"
footerClassName="absolute bottom-5 left-5"
contentClassName="px-10 pb-10 pt-6"
className="hidden md:flex"
header={() => (
<>
<div className="rounded bg-gray-60 px-2 py-1 w-fit mb-9">
<AddressBadge address={account} />
</div>
<Heading className="mb-6">{t(translation.title)}</Heading>
</>
)}
footer={() => (
<Button
text={t(translations.common.buttons.close)}
onClick={onClose}
style={ButtonStyle.ghost}
dataAttribute="erc20-bridge-close"
/>
)}
/>
</Dialog>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';

import { t } from 'i18next';
import { Trans } from 'react-i18next';

import { Heading, HeadingType, Link } from '@sovryn/ui';

import { HELPDESK_LINK } from '../../../../constants/links';
import { translations } from '../../../../locales/i18n';

type InstructionsProps = {
isReceive?: boolean;
};

export const Instructions: React.FC<InstructionsProps> = () => {
return (
<>
<Heading type={HeadingType.h2} className="font-medium leading-[1.375rem]">
{t(translations.erc20Bridge.instructions.title)}:
</Heading>

<ul className="list-disc list-inside text-xs leading-5 font-medium text-gray-30 mt-4 mb-12">
<li className="mb-4">
{t(translations.erc20Bridge.instructions['1'])}
</li>
<li className="mb-4">
{t(translations.erc20Bridge.instructions['2'])}
</li>
<li className="mb-4">
{t(translations.erc20Bridge.instructions['3'])}
</li>
<li className="mb-4">
{t(translations.erc20Bridge.instructions['4'])}
</li>
<li className="mb-4">
<Trans
i18nKey={t(translations.erc20Bridge.instructions['5'])}
tOptions={{ hours: 1.5 }}
components={[
<Link
text={t(
translations.erc20Bridge.instructions.createSupportTicketCta,
)}
href={HELPDESK_LINK}
/>,
]}
/>
</li>
</ul>
</>
);
};
Comment thread
norugpull marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';

import { Paragraph, ParagraphSize } from '@sovryn/ui';

type ReceiveFlowProps = {
onClose: () => void;
};

export const ReceiveFlow: React.FC<ReceiveFlowProps> = () => {
return (
<div className="flex flex-col gap-4">
<Paragraph size={ParagraphSize.base}>
Placeholder for ERC20 Bridge Receive Flow
</Paragraph>
{/* Add your receive flow implementation here */}
</div>
);
};
Comment thread
norugpull marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useCallback } from 'react';

import { GoBackButton } from '../../../../1_atoms/GoBackButton/GoBackButton';
import { Stepper } from '../../../../1_atoms/Stepper/Stepper';
import { SendFlowStep, useSendFlowContext } from '../../contexts/sendflow';
import { InitialScreen } from './components/InitialScreen';
import { MainScreen } from './components/MainScreen';

type SendFlowProps = {
onClose: () => void;
};

const allowedStepsToGoBackFrom = [
SendFlowStep.MAIN,
SendFlowStep.AMOUNT,
SendFlowStep.REVIEW,
];

const getBackStep = (step: SendFlowStep) => {
switch (step) {
case SendFlowStep.MAIN:
return SendFlowStep.INITIAL;
case SendFlowStep.AMOUNT:
return SendFlowStep.MAIN;
case SendFlowStep.REVIEW:
return SendFlowStep.AMOUNT;
default:
return SendFlowStep.AMOUNT;
}
};

export const SendFlow: React.FC<SendFlowProps> = () => {
const { set, step } = useSendFlowContext();
const onBackClick = useCallback(() => {
set(prevState => ({ ...prevState, step: getBackStep(step) }));
}, [set, step]);

return (
<>
{allowedStepsToGoBackFrom.includes(step) && (
<GoBackButton onClick={onBackClick} />
)}

{step !== SendFlowStep.INITIAL && (
<Stepper className="mt-6" steps={4} activeStep={step} />
)}

<div className="mt-0 md:mt-20">
{step === SendFlowStep.INITIAL && <InitialScreen />}
{step === SendFlowStep.MAIN && <MainScreen />}
</div>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { useCallback, useContext } from 'react';

import { t } from 'i18next';

import { Button, ButtonStyle, ErrorBadge, ErrorLevel } from '@sovryn/ui';

import { useAccount } from '../../../../../../hooks/useAccount';
import { translations } from '../../../../../../locales/i18n';
import { SendFlowContext, SendFlowStep } from '../../../contexts/sendflow';
import { Instructions } from '../../Instructions';

export const InitialScreen: React.FC = () => {
const { account } = useAccount();
const { set } = useContext(SendFlowContext);
const erc20BridgeLocked = false;
const onContinueClick = useCallback(
() => set(prevState => ({ ...prevState, step: SendFlowStep.MAIN })),
[set],
);

return (
<div>
<Instructions />

{erc20BridgeLocked ? (
<ErrorBadge
level={ErrorLevel.Warning}
message={t(translations.maintenanceMode.erc20Bridge)}
/>
) : (
<Button
disabled={!account}
onClick={onContinueClick}
text={t(translations.common.buttons.continue)}
className="w-full"
style={ButtonStyle.secondary}
dataAttribute="funding-send-instructions-confirm"
/>
)}
</div>
);
};
Loading