Skip to content

Commit

Permalink
Merge branch 'fix/rosen-app-issues' into 'dev'
Browse files Browse the repository at this point in the history
misc rosen app bug fixes

Closes #109

See merge request ergo/rosen-bridge/ui!80
  • Loading branch information
vorujack committed Nov 5, 2023
2 parents 89a2d2a + 4c28acd commit 588cd08
Show file tree
Hide file tree
Showing 14 changed files with 137 additions and 79 deletions.
3 changes: 3 additions & 0 deletions apps/rosen/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
NEXT_PUBLIC_ERGO_LOCK_ADDRESS=''
NEXT_PUBLIC_CARDANO_LOCK_ADDRESS=''
NEXT_PUBLIC_FEE_CONFIG_TOKEN_ID=''
93 changes: 60 additions & 33 deletions apps/rosen/app/(bridge)/BridgeForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useCallback, ChangeEvent } from 'react';
import Image from 'next/image';
import { countDecimals } from '@rosen-ui/utils';
import { getDecimalString, getNonDecimalString } from '@rosen-ui/utils';

import {
alpha,
Expand Down Expand Up @@ -88,7 +88,7 @@ const BridgeForm = () => {
} = useBridgeForm();

const { availableNetworks, tokens, targetNetworks } = useNetwork();
const { isLoading, amount } = useTokenBalance();
const { isLoading, amount, token } = useTokenBalance();

const renderSelectedAsset = (value: unknown) => {
const network = availableNetworks.find(
Expand Down Expand Up @@ -152,41 +152,69 @@ const BridgeForm = () => {
);

const handleAmountChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
if (countDecimals(e.target.value) <= tokenField.value?.decimals) {
amountField.onChange(e);
}
(event: ChangeEvent<HTMLInputElement>) => {
const newValue = event.target.value;

// match any complete or incomplete decimal number
const match = newValue.match(/^(\d+(\.(?<floatingDigits>\d+)?)?)?$/);

// prevent user from entering invalid numbers
const isValueInvalid = !match;
if (isValueInvalid) return;

// prevent user from entering more decimals than token decimals
const isDecimalsLarge =
(match?.groups?.floatingDigits?.length ?? 0) >
tokenField.value?.decimals;
if (isDecimalsLarge) return;

// prevent user from entering more than token amount
const isAmountLarge =
BigInt(getNonDecimalString(newValue, tokenField.value?.decimals)) >
BigInt(amount.toString());
if (isAmountLarge) return;

amountField.onChange(event);
},
[amountField, tokenField],
[amountField, tokenField, amount],
);

const handleSelectMax = useCallback(() => {
setValue('amount', amount, {
shouldDirty: true,
shouldTouch: true,
});
}, [setValue, amount]);
setValue(
'amount',
getDecimalString(amount.toString(), token?.decimals ?? 0),
{
shouldDirty: true,
shouldTouch: true,
},
);
}, [setValue, amount, token?.decimals]);

const renderInputActions = () => (
<Grid container justifyContent="space-between">
<MaxButton
disabled={isLoading || !tokenField.value}
onClick={handleSelectMax}
color="primary"
>
<Typography variant="caption">
{`Balance: ${isLoading ? 'loading...' : amount}`}
</Typography>
</MaxButton>
<MaxButton
disabled={isLoading || !tokenField.value}
onClick={handleSelectMax}
color="primary"
>
MAX
</MaxButton>
</Grid>
);
const renderInputActions = () =>
tokenField.value && (
<Grid container justifyContent="space-between">
<MaxButton
disabled={isLoading || !tokenField.value}
onClick={handleSelectMax}
color="primary"
>
<Typography variant="caption">
{`Balance: ${
isLoading
? 'loading...'
: getDecimalString(amount.toString(), token?.decimals ?? 0)
}`}
</Typography>
</MaxButton>
<MaxButton
disabled={isLoading || !tokenField.value}
onClick={handleSelectMax}
color="primary"
>
MAX
</MaxButton>
</Grid>
);

return (
<FormContainer>
Expand Down Expand Up @@ -280,7 +308,6 @@ const BridgeForm = () => {
})}
</FormInputs>
<FormInputs
type="number"
id="amount"
size="medium"
label="Amount"
Expand Down
21 changes: 14 additions & 7 deletions apps/rosen/app/(bridge)/BridgeTransaction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const FeesContainer = styled('div')(({ theme }) => ({
const BridgeTransaction = () => {
const {
sourceValue,
targetValue,
tokenValue,
amountValue,
formState: { isValidating },
Expand All @@ -59,7 +60,7 @@ const BridgeTransaction = () => {

const tokenInfo = tokenValue && getTokenNameAndId(tokenValue, sourceValue);
const WalletIcon = selectedWallet?.icon;
const { startTransaction } = useTransaction();
const { startTransaction, isSubmitting } = useTransaction();

const handleFormSubmit = handleSubmit(() => {
startTransaction(+bridgeFee, +networkFee);
Expand All @@ -68,7 +69,7 @@ const BridgeTransaction = () => {
const renderFee = (
title: string,
unit: string,
amount: number | string,
amount: string,
color: string,
) => {
return (
Expand All @@ -77,11 +78,17 @@ const BridgeTransaction = () => {

<Grid container flexWrap="nowrap">
<Typography color={color} fontWeight="bold">
{isLoadingFees ? 'Pending...' : amount}
</Typography>
<Typography sx={(theme) => ({ margin: theme.spacing(0, 0.5) })}>
{unit}
{isLoadingFees && sourceValue && targetValue && tokenValue
? 'Pending...'
: +amount
? amount
: '-'}
</Typography>
{!!+amount && (
<Typography sx={(theme) => ({ margin: theme.spacing(0, 0.5) })}>
{unit}
</Typography>
)}
</Grid>
</PriceItem>
);
Expand Down Expand Up @@ -165,7 +172,7 @@ const BridgeTransaction = () => {
sx={{ width: '100%' }}
color={selectedWallet ? 'success' : 'primary'}
variant="contained"
loading={isValidating}
loading={isValidating || isSubmitting}
disabled={!availableWallets}
onClick={() => {
if (!selectedWallet) {
Expand Down
4 changes: 2 additions & 2 deletions apps/rosen/app/(bridge)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ const BridgeContainer = styled(Card)(({ theme }) => ({
[theme.breakpoints.up('tablet')]: {
gridTemplateColumns: '3fr auto 2fr',
gridTemplateRows: '1fr',
maxWidth: '45%',
width: 'auto',
minWidth: '600px',
maxWidth: '40vmax',
},
}));

Expand Down
4 changes: 4 additions & 0 deletions apps/rosen/app/SideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const SideBar = () => {
}
onClick={() => router.push('/assets')}
isActive={pathname.startsWith('/assets')}
disabled
/>
</Grid>
<Grid item>
Expand All @@ -70,6 +71,7 @@ const SideBar = () => {
}
onClick={() => router.push('/transactions')}
isActive={pathname === '/transactions'}
disabled
/>
</Grid>
<Grid item>
Expand All @@ -82,6 +84,7 @@ const SideBar = () => {
}
onClick={() => router.push('/support')}
isActive={pathname.startsWith('/support')}
disabled
/>
</Grid>
<Grid item>
Expand All @@ -94,6 +97,7 @@ const SideBar = () => {
}
onClick={() => router.push('/dashboard')}
isActive={pathname.startsWith('/dashboard')}
disabled
/>
</Grid>
</Grid>
Expand Down
5 changes: 1 addition & 4 deletions apps/rosen/app/_constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,4 @@ export const Networks = {
cardano: 'cardano',
} as const;

// FIXME: read some of this value from the bridge api and migrate the rest of the to env
// local:ergo/rosen-bridge/ui#88
export const feeConfigTokenId =
'05690d3e7a8daae13495b32af8ab58aaec8a5435f5974f6adf17095d28cac1f5';
export const feeConfigTokenId = process.env.NEXT_PUBLIC_FEE_CONFIG_TOKEN_ID!;
1 change: 0 additions & 1 deletion apps/rosen/app/_hooks/useBridgeForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ const useBridgeForm = () => {
name: 'walletAddress',
control,
rules: {
required: true,
validate: async (value) =>
(await validateAddress(targetField.value, value)).message,
},
Expand Down
14 changes: 11 additions & 3 deletions apps/rosen/app/_hooks/useTokenBalance.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import { useState, useEffect, useCallback } from 'react';
import { SupportedWallets } from '@/_types/network';

import { TokenInfo } from '@rosen-ui/types';

import useBridgeForm from './useBridgeForm';
import useWallet from './useWallet';

import { SupportedWallets } from '@/_types/network';

interface UseTokenBalance {
isLoading: boolean;
amount: number;
token: TokenInfo | null;
}

/**
* returns the amount of currently selected asset
*/

const useTokenBalance = () => {
const [balanceState, setBalanceState] = useState({
const [balanceState, setBalanceState] = useState<UseTokenBalance>({
isLoading: false,
amount: 0,
token: null,
Expand Down
29 changes: 19 additions & 10 deletions apps/rosen/app/_hooks/useTransaction.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useState } from 'react';

import { RosenChainToken } from '@rosen-bridge/tokens';
import { useSnackbar } from '@rosen-bridge/ui-kit';

Expand All @@ -13,6 +15,7 @@ export const useTransaction = () => {
useTransactionFormData();

const { selectedWallet } = useWallet();
const [isSubmitting, setIsSubmitting] = useState(false);

const lockAddress = useLockAddress();

Expand All @@ -27,20 +30,26 @@ export const useTransaction = () => {
bridgeFee &&
networkFee
) {
const txId = await selectedWallet?.transfer(
tokenValue as RosenChainToken,
amountValue,
targetValue,
walletAddressValue,
bridgeFee,
networkFee,
lockAddress,
);
openSnackbar(`Transaction submitted with id [${txId}]`, 'success');
setIsSubmitting(true);
try {
const txId = await selectedWallet?.transfer(
tokenValue as RosenChainToken,
amountValue,
targetValue,
walletAddressValue,
bridgeFee,
networkFee,
lockAddress,
);
openSnackbar(`Transaction submitted with id [${txId}]`, 'success');
} finally {
setIsSubmitting(false);
}
}
};

return {
startTransaction,
isSubmitting,
};
};
6 changes: 2 additions & 4 deletions apps/rosen/app/_networks/cardano/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ const CardanoNetwork: Network<Wallet> = {
const amount = balances.find(
(asset) => asset.policyId === token.policyId,
);
return amount
? Number(getDecimalString(amount.quantity.toString(), token.decimals))
: 0;
return amount ? Number(amount.quantity) : 0;
},
transfer: async (
token: RosenChainToken,
Expand Down Expand Up @@ -92,7 +90,7 @@ const CardanoNetwork: Network<Wallet> = {
explorerUrl: 'https://api.koios.rest/api',
networkStatusUrl: 'https://api.koios.rest/api/v0/blocks?limit=1',
},
lockAddress: '',
lockAddress: process.env.NEXT_PUBLIC_CARDANO_LOCK_ADDRESS!,
};

export default CardanoNetwork;
11 changes: 9 additions & 2 deletions apps/rosen/app/_networks/ergo/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@ const ErgoNetwork: Network<Wallet> = {
...getNautilusWallet(),
getBalance: async (token) => {
const context = await getNautilusWallet().api.getContext();
const balance = await context.get_balance((token as ErgoToken).tokenId);
const tokenId = (token as ErgoToken).tokenId;
/**
* The following condition is required because nautilus only accepts
* uppercase ERG as tokenId for the erg native token
*/
const balance = await context.get_balance(
tokenId === 'erg' ? 'ERG' : tokenId,
);
return +balance;
},
transfer: async (
Expand Down Expand Up @@ -68,7 +75,7 @@ const ErgoNetwork: Network<Wallet> = {
explorerUrl: 'https://api.ergoplatform.com/',
networkStatusUrl: 'https://api.ergoplatform.com/api/v1/networkState',
},
lockAddress: '',
lockAddress: process.env.NEXT_PUBLIC_ERGO_LOCK_ADDRESS!,
};

export default ErgoNetwork;
10 changes: 8 additions & 2 deletions apps/rosen/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import App from './App';

import fs from 'fs';
import path from 'path';

import { Metadata } from 'next';

import App from './App';

export const metadata: Metadata = {
title: 'Rosen Bridge',
};

const RootLayout = ({ children }: { children: React.ReactNode }) => {
const tokensMap = JSON.parse(
fs.readFileSync(path.resolve('./configs/tokensMap.json'), {
Expand Down
Loading

0 comments on commit 588cd08

Please sign in to comment.