Skip to content

Commit

Permalink
stashing progress
Browse files Browse the repository at this point in the history
  • Loading branch information
prettyirrelevant committed Oct 21, 2024
1 parent db597ec commit 711f3eb
Show file tree
Hide file tree
Showing 14 changed files with 841 additions and 1,085 deletions.
7 changes: 4 additions & 3 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"dependencies": {
"@phosphor-icons/react": "^2.0.10",
"@szhsin/react-menu": "^4.0.3",
"@tanstack/react-query": "^4.33.0",
"@tanstack/react-query": "^5.59.15",
"axios": "^1.5.0",
"buffer": "^6.0.3",
"dayjs": "^1.11.9",
Expand All @@ -27,9 +27,10 @@
"react-time-ago": "^7.2.1",
"react-use": "^17.4.0",
"sass": "^1.66.1",
"sonner": "^1.5.0",
"util": "^0.12.4",
"viem": "1",
"wagmi": "1.4.13"
"viem": "^2.21.31",
"wagmi": "^2.12.20"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Toaster } from 'sonner';
import { Suspense } from 'react';
import '@szhsin/react-menu/dist/index.css';
import { Route, Routes } from 'react-router-dom';
Expand Down Expand Up @@ -26,6 +27,7 @@ const App = () => {
<Route path="/conversion/:uuid" element={<Conversion />} />
</Routes>
</div>
<Toaster position="top-right" />
</Suspense>
);
};
Expand Down
17 changes: 8 additions & 9 deletions frontend/src/context/AppContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
type SetStateAction,
} from 'react';
import axios from 'axios';
import { useAccount, useQuery } from 'wagmi';
import { useQuery } from '@tanstack/react-query';
import { useAccount } from 'wagmi';
import { metadata, tokens } from 'constants/data';

interface AppProviderProps {
Expand Down Expand Up @@ -101,18 +102,16 @@ const AppProvider = ({ children }: AppProviderProps) => {
localStorage.setItem('authorization', JSON.stringify(authorization));
}, [authorization]);

const conversions = useQuery(
['tokens'],
async () => {
const conversions = useQuery({
queryKey: ['tokens'],
queryFn: async () => {
return await axios
.get('conversions/routes')
.then((response) => response?.data?.data);
},
{
refetchOnReconnect: false,
refetchOnWindowFocus: false,
},
);
refetchOnReconnect: false,
refetchOnWindowFocus: false,
});

const routes = useMemo(() => {
const routesArr = Object.keys(conversions.data || {});
Expand Down
14 changes: 10 additions & 4 deletions frontend/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import './utils/axios';
import './styles/index.scss';
import * as React from 'react';
import { WagmiConfig } from 'wagmi';
import { WagmiProvider } from 'wagmi';
import { config } from './wagmi-setup';
import * as ReactDOM from 'react-dom/client';
import { Providers } from './context/Providers';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

// biome-ignore lint/style/noNonNullAssertion: <explanation>
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<WagmiConfig config={config}>
<Providers />
</WagmiConfig>
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<Providers />
</QueryClientProvider>
</WagmiProvider>
</React.StrictMode>,
);
128 changes: 67 additions & 61 deletions frontend/src/pages/bridge/CctpTxnBtn.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,44 @@
import {
erc20ABI,
useClient,
useAccount,
useNetwork,
useSignMessage,
usePublicClient,
useContractRead,
useSwitchNetwork,
useContractWrite,
usePrepareContractWrite,
useSwitchChain,
useReadContract,
useWriteContract,
useSimulateContract,
} from 'wagmi';
import { fromBytes, toBytes } from 'viem';
import axios from 'axios';
import { useMemo, useState } from 'react';
import { toast } from 'sonner';
import { erc20Abi } from 'viem';
import { useState } from 'react';
import { metadata } from 'constants/data';
import { useApp } from 'context/AppContext';
import { ClipLoader } from 'react-spinners';
import { useNetworkState } from 'react-use';
import { getDomain } from 'helpers/contract';
import { useNavigate } from 'react-router-dom';
import { useMutation } from '@tanstack/react-query';
import { evmAddressToBytes32 } from 'utils/address';
import { crossChainBridgeAbi } from 'contracts/index';
import { networkContracts } from 'contracts/addresses';
import { evmAddressToBytes32 } from 'utils/address';
import { waitForTransactionReceipt } from '@wagmi/core';

import { config } from '../../wagmi-setup';

interface ConversionPayload {
address: string;
signature: string;
data: {
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
[key: string]: any;
};
}

const CctpTxnBtn = () => {
const { chain } = useNetwork();
const navigate = useNavigate();
const { address } = useAccount();
const { address, chain } = useAccount();
const onlineState = useNetworkState();
const { switchNetworkAsync } = useSwitchNetwork();
const { switchChainAsync } = useSwitchChain();
const [confirmingTxn, setConfirmingTxn] = useState(false);

const {
Expand All @@ -49,49 +51,41 @@ const CctpTxnBtn = () => {
setAuthorization,
} = useApp();

const publicClient = usePublicClient({
const client = useClient({
chainId: Number(metadata?.[currentChain]?.chain_id),
});

const { signMessageAsync, isLoading } = useSignMessage({
message:
'Message: Welcome to BridgeBloc!\nURI: https://bridgebloc.vercel.app',
});
const { signMessageAsync, isPending } = useSignMessage();

const getDepositContract = () =>
networkContracts[currentChain] as `0x${string}`;

/**
* Prepare txn to approve allowance (max amount that can be spent)
*/
const { config: approveConfig } = usePrepareContractWrite({
abi: erc20ABI,
const { data: approveData } = useSimulateContract({
abi: erc20Abi,
functionName: 'approve',
args: [
getDepositContract(),
BigInt(
Number(transferAmt ?? 0) *
Math.pow(10, Number(currentToken?.decimals ?? 0)),
Number(transferAmt ?? 0) * 10 ** Number(currentToken?.decimals ?? 0),
),
],
chainId: Number(metadata?.[currentChain]?.chain_id),
address: currentToken.address as `0x${string}`,
enabled:
!!currentToken?.address &&
!isNaN(Number(transferAmt)) &&
Number(transferAmt) > 0,
});

// Prompt user to set allowance
const { isLoading: approving, writeAsync: approveAsync } =
useContractWrite(approveConfig);
const { isPending: approving, writeContractAsync: approveAsync, isError: isApproveError, error: approveError } =
useWriteContract();

/**
* Read the contract to confirm if the allowed amount is greated than the txn amount
*/
const { refetch: refetchApprovedAmount, data: approvedAmount } =
useContractRead({
abi: erc20ABI,
useReadContract({
abi: erc20Abi,
functionName: 'allowance',
args: [address as `0x${string}`, getDepositContract()],
chainId: Number(metadata?.[currentChain]?.chain_id),
Expand All @@ -101,13 +95,11 @@ const CctpTxnBtn = () => {
/**
* Prepare txn to send tokens
*/
const { config } = usePrepareContractWrite({
const { data: depositData } = useSimulateContract({
...crossChainBridgeAbi,
functionName: 'deposit',
args: [
BigInt(
Number(transferAmt) * Math.pow(10, Number(currentToken?.decimals ?? 0)),
),
BigInt(Number(transferAmt) * 10 ** Number(currentToken?.decimals ?? 0)),
currentToken?.address as `0x${string}`,
0, // hardcoding fee here since it's testnet
evmAddressToBytes32(destinationToken?.address),
Expand All @@ -117,24 +109,18 @@ const CctpTxnBtn = () => {
],
chainId: Number(metadata?.[currentChain]?.chain_id),
address: getDepositContract(),
enabled: false
// !!currentToken?.address &&
// address &&
// destinationToken?.address &&
// !isNaN(Number(transferAmt)) &&
// Number(transferAmt) > 0,
});

// Prompt user to approve tokens transfer txn
const { writeAsync, isLoading: depositLoading } = useContractWrite(config);
const { writeContractAsync: depositAsync, isPending: depositLoading, error: depositError, isError: isDepositError } = useWriteContract();

/**
* Send txn-hash to the server
*/
const cctpConversion = useMutation({
mutationFn: async (payload: ConversionPayload) => {
return await axios
.post(`/conversions/cctp`, payload?.data, {
.post('/conversions/cctp', payload?.data, {
headers: {
Authorization: `Signature ${payload?.address}:${payload?.signature}`,
},
Expand All @@ -144,15 +130,18 @@ const CctpTxnBtn = () => {
onSuccess: (data) => {
navigate(`/conversion/${data?.id}`);
},
onError(error, variables, context) {
toast.error(JSON.stringify(error));
},
});

const processConversion = async () => {
if (
isLoading ||
isPending ||
approving ||
confirmingTxn ||
depositLoading ||
cctpConversion.isLoading
cctpConversion.isPending
)
return;

Expand All @@ -164,14 +153,20 @@ const CctpTxnBtn = () => {
!currentRoute?.chain ||
!currentToken?.address ||
!destinationToken?.address ||
isNaN(Number(transferAmt))
Number.isNaN(transferAmt)
)
return;

try {
const authData = {
address: authorization.address || address,
signature: authorization.signature || (await signMessageAsync()) || '',
signature:
authorization.signature ||
(await signMessageAsync({
message:
'Message: Welcome to BridgeBloc!\nURI: https://bridgebloc.vercel.app',
})) ||
'',
};

if (authData?.signature !== authorization?.signature)
Expand All @@ -180,58 +175,69 @@ const CctpTxnBtn = () => {
const shouldSwitchNetwork =
chain?.id !== Number(metadata?.[currentChain]?.chain_id);
if (shouldSwitchNetwork) {
await switchNetworkAsync?.(Number(metadata?.[currentChain]?.chain_id));
await switchChainAsync?.({
chainId: Number(metadata?.[currentChain]?.chain_id),
});
}

if (
Number(approvedAmount) <
BigInt(
Number(transferAmt) *
Math.pow(10, Number(currentToken?.decimals ?? 0)),
)
BigInt(Number(transferAmt) * 10 ** Number(currentToken?.decimals ?? 0))
) {
await approveAsync?.();
// biome-ignore lint/style/noNonNullAssertion: <explanation>
await approveAsync(approveData!.request);
if (isApproveError){
toast.error(approveError.message)
return
}

refetchApprovedAmount();
}

const txn = await writeAsync?.();
if (isDepositError) {
toast.error(depositError.message)
return
}

// biome-ignore lint/style/noNonNullAssertion: <explanation>
const txn = await depositAsync(depositData!.request);

if (txn?.hash) {
if (txn) {
setConfirmingTxn(true);
await publicClient.waitForTransactionReceipt({
hash: txn?.hash,
});

await waitForTransactionReceipt(config, { hash: txn });
setConfirmingTxn(!true);

cctpConversion.mutate({
address: authData.address,
signature: authData.signature,
data: {
tx_hash: txn?.hash,
tx_hash: txn,
source_chain: currentChain,
destination_chain: currentRoute.chain,
},
});
}
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
} catch (error: any) {
console.log(error?.message);
toast.error(error?.message);
} finally {
setConfirmingTxn(false);
}
};

return (
<button
type="button"
className="primary-btn"
style={{
marginTop: '10px',
}}
onClick={processConversion}
>
Continue
{(cctpConversion.isLoading ||
isLoading ||
{(cctpConversion.isPending ||
isPending ||
confirmingTxn ||
approving ||
depositLoading) && (
Expand Down
1 change: 1 addition & 0 deletions frontend/src/pages/bridge/components/sourceChain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const SourceChain = () => {
isObject: true,
setDefault: true,
defaultOption: routes[0],
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
onOptionChange: (option: any) => {
setCurrentRoute('');
setCurrentToken({});
Expand Down
Loading

0 comments on commit 711f3eb

Please sign in to comment.