Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev to main #1196

Merged
merged 9 commits into from
Dec 27, 2024
1 change: 1 addition & 0 deletions Models/Network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,5 @@ export class Metadata {
evm_oracle_contract?: `0x${string}` | null
evm_multicall_contract?: string | null
listing_date: string
zks_paymaster_contract?: `0x${string}` | null
}
10 changes: 5 additions & 5 deletions components/Input/Address/AddressPicker/AddressWithIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const AddressWithIcon: FC<Props> = ({ addressItem, connectedWallet, partner, net

return (
<div className="w-full flex items-center justify-between">
<div className="flex bg-secondary-400 text-primary-text items-center justify-center rounded-md h-9 overflow-hidden w-9">
<div className="flex bg-secondary-400 text-primary-text items-center justify-center rounded-md h-8 overflow-hidden w-8">
{
(partner?.is_wallet && addressItem.group === AddressGroup.FromQuery) ? (
partner?.logo && (
Expand All @@ -78,12 +78,12 @@ const AddressWithIcon: FC<Props> = ({ addressItem, connectedWallet, partner, net

<div className="flex flex-col items-start flex-grow min-w-0 ml-3 text-sm">
<div className="flex w-full min-w-0">
<ExtendedAddress address={addressItem.address} network={network} />
<ExtendedAddress address={addressItem.address} network={network} addressClassNames="font-normal" />
</div>
<div className="text-secondary-text w-full min-w-0 mt-1">
<div className="flex items-center gap-1.5">
<div className="text-secondary-text w-full min-w-0">
<div className="flex items-center gap-1 text-xs">
{itemDescription?.icon && (
<itemDescription.icon className="rounded flex-shrink-0 h-4 w-4" />
<itemDescription.icon className="rounded flex-shrink-0 h-3.5 w-3.5" />
)}
{itemDescription?.text}
</div>
Expand Down
61 changes: 61 additions & 0 deletions components/Swap/Withdraw/Wallet/FuelWalletWithdrawal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { FC, useCallback, useState } from 'react'
import toast from 'react-hot-toast';
import { BackendTransactionStatus } from '../../../../lib/layerSwapApiClient';
import useWallet from '../../../../hooks/useWallet';
import { useSwapTransactionStore } from '../../../../stores/swapTransactionStore';
import WalletIcon from '../../../icons/WalletIcon';
import { WithdrawPageProps } from './WalletTransferContent';
import { ButtonWrapper, ConnectWalletButton } from './WalletTransfer/buttons';
import {
useWallet as useFuelWallet,
} from '@fuels/react';

const FuelWalletWithdrawStep: FC<WithdrawPageProps> = ({ network, callData, swapId }) => {
const [loading, setLoading] = useState(false);
const { setSwapTransaction } = useSwapTransactionStore()

const { provider } = useWallet(network, 'withdrawal');
const { wallet: fuelWallet } = useFuelWallet()
const wallet = provider?.activeWallet

const handleTransfer = useCallback(async () => {
try {
setLoading(true)

if (!fuelWallet) throw Error("Fuel wallet not connected")
if (!callData) throw Error("Call data not found")

const tx = JSON.parse(callData)
const transactionResponse = await fuelWallet.sendTransaction(tx)

if (swapId && transactionResponse) setSwapTransaction(swapId, BackendTransactionStatus.Completed, transactionResponse.id)

}
catch (e) {
if (e?.message) {
toast(e.message)
return
}
}
finally {
setLoading(false)
}
}, [swapId, callData, fuelWallet])

if (!wallet) {
return <ConnectWalletButton />
}

return (
<div className="w-full space-y-5 flex flex-col justify-between h-full text-primary-text">
{
fuelWallet &&
<ButtonWrapper isDisabled={!!loading} isSubmitting={!!loading} onClick={handleTransfer} icon={<WalletIcon className="stroke-2 w-6 h-6" aria-hidden="true" />} >
Send from wallet
</ButtonWrapper>
}
</div>
)
}

export default FuelWalletWithdrawStep;
94 changes: 94 additions & 0 deletions components/Swap/Withdraw/Wallet/SophonWalletWithdraw.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { ArrowLeftRight } from 'lucide-react';
import { FC, useCallback, useState } from 'react'
import toast from 'react-hot-toast';
import { useSwapTransactionStore } from '../../../../stores/swapTransactionStore';
import { BackendTransactionStatus } from '../../../../lib/layerSwapApiClient';
import { ButtonWrapper, ChangeNetworkButton, ConnectWalletButton } from './WalletTransfer/buttons';
import { useAccount } from 'wagmi';
import useWallet from '../../../../hooks/useWallet';
import { WithdrawPageProps } from './WalletTransferContent';
import { sophon, sophonTestnet } from 'viem/chains';
import { createWalletClient, custom, JsonRpcAccount } from 'viem';
import { eip712WalletActions, getGeneralPaymasterInput } from 'viem/zksync';
import KnownInternalNames from '../../../../lib/knownIds';

const SophonWalletWithdraw: FC<WithdrawPageProps> = ({ amount, depositAddress, network, token, swapId, callData }) => {
const [loading, setLoading] = useState(false);

const { setSwapTransaction } = useSwapTransactionStore();
const { chain: activeChain, connector } = useAccount();

const networkChainId = Number(network?.chain_id) ?? undefined
const { provider } = useWallet(network, 'withdrawal')
const wallet = provider?.activeWallet

const handleTransfer = useCallback(async () => {

if (!wallet?.address || !swapId || !depositAddress || !token || amount == undefined || !callData || !network?.metadata.zks_paymaster_contract) return

try {
setLoading(true)

const walletProvider = await connector?.getProvider() as any

if (!walletProvider) throw new Error('Could not get provider')

const account = {
address: wallet?.address,
type: 'json-rpc'
} as JsonRpcAccount

const walletClient = createWalletClient({
chain: network.name === KnownInternalNames.Networks.SophonSepolia ? sophonTestnet : sophon,
transport: custom(walletProvider),
account: account
}).extend(eip712WalletActions());

const request = await walletClient.prepareTransactionRequest({
to: depositAddress,
data: callData as `0x${string}`,
paymaster: network?.metadata.zks_paymaster_contract,
paymasterInput: getGeneralPaymasterInput({ innerInput: "0x" }),
})

const signature = await walletClient.signTransaction(request as any)
const hash = await walletClient.sendRawTransaction({
serializedTransaction: signature
})

if (hash) {
setSwapTransaction(swapId, BackendTransactionStatus.Pending, hash);
}
}
catch (e) {
if (e?.message) {
if (e.name.includes("EstimateGasExecutionError")) return toast("You don't have enough funds")
toast(e.message)
return
}
}
finally {
setLoading(false)
}
}, [swapId, depositAddress, token, amount, callData])

if (!wallet) {
return <ConnectWalletButton />
}

else if (activeChain?.id !== networkChainId && network) {
return <ChangeNetworkButton
chainId={networkChainId}
network={network.display_name}
/>
}

return (
<>
<ButtonWrapper isDisabled={!!(loading)} isSubmitting={!!loading} onClick={handleTransfer} icon={<ArrowLeftRight className="h-5 w-5 ml-2" aria-hidden="true" />} >
Send from wallet
</ButtonWrapper>
</>
)
}
export default SophonWalletWithdraw;
4 changes: 2 additions & 2 deletions components/Swap/Withdraw/Wallet/WalletTransfer/networkGas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ const NetworkGas: FC<NetworkGasProps> = ({ address, token, network }) => {

const { gas: networkGas, isGasLoading } = useSWRGas(address, network, token)

if (!networkGas)
if (networkGas == undefined)
return <></>

return <div className="flex flex-row items-center gap-1 w-full text-sm px-1 mb-2.5 justify-end">
<Fuel className="h-4 w-4 text-secondary-text" />
<p className="text-secondary-text">Estimated gas:</p>
<div className="text-right flex items-center gap-1">
{isGasLoading ? <div className='h-[10px] w-10 bg-gray-500 rounded-sm animate-pulse' /> : networkGas?.toFixed(token.precision || 0)} <span>{token?.symbol}</span>
{isGasLoading ? <div className='h-[10px] w-10 bg-gray-500 rounded-sm animate-pulse' /> : networkGas?.toFixed(networkGas == 0 ? 0 : token.precision || 0)} <span>{token?.symbol}</span>
</div>
</div>
}
Expand Down
25 changes: 25 additions & 0 deletions components/Swap/Withdraw/Wallet/WalletTransferContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import LoopringWalletWithdraw from "./Loopring";
import { Network, Token } from "../../../../Models/Network";
import TonWalletWithdrawStep from "./TonWalletWithdraw";
import ParadexWalletWithdrawStep from "./paradex/index";
import FuelWalletWithdrawStep from "./FuelWalletWithdrawal";
import SophonWalletWithdraw from "./SophonWalletWithdraw";

//TODO have separate components for evm and none_evm as others are sweepless anyway
export const WalletTransferContent: FC = () => {
Expand Down Expand Up @@ -43,6 +45,11 @@ export const WalletTransferContent: FC = () => {
const sourceIsParadex = source_network_internal_name?.toUpperCase() === KnownInternalNames.Networks.ParadexMainnet?.toUpperCase()
|| source_network_internal_name?.toUpperCase() === KnownInternalNames.Networks.ParadexTestnet?.toUpperCase();

const sourceIsFuel = source_network_internal_name?.toUpperCase() === KnownInternalNames.Networks.FuelMainnet?.toUpperCase()
|| source_network_internal_name?.toUpperCase() === KnownInternalNames.Networks.FuelTestnet?.toUpperCase();
const sourceIsSophon = source_network_internal_name?.toUpperCase() === KnownInternalNames.Networks.SophonMainnet?.toUpperCase()
|| source_network_internal_name?.toUpperCase() === KnownInternalNames.Networks.SophonSepolia?.toUpperCase();

const depositAddress = depositActionsResponse?.find(da => true)?.to_address;
const amount = depositActionsResponse?.find(da => true)?.amount || 0;
const callData = depositActionsResponse?.find(da => true)?.call_data;
Expand Down Expand Up @@ -106,6 +113,24 @@ export const WalletTransferContent: FC = () => {
swapId={swap?.id}
callData={callData}
/>;
else if (sourceIsFuel)
return <FuelWalletWithdrawStep
amount={amount}
depositAddress={depositAddress}
network={swap?.source_network}
token={swap?.source_token}
swapId={swap?.id}
callData={callData}
/>
else if (sourceIsSophon)
return <SophonWalletWithdraw
amount={amount}
depositAddress={depositAddress}
network={swap?.source_network}
token={swap?.source_token}
swapId={swap?.id}
callData={callData}
/>;
else
return <>
{
Expand Down
9 changes: 1 addition & 8 deletions components/Swap/Withdraw/WalletTransferContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ import AddressWithIcon from '../../Input/Address/AddressPicker/AddressWithIcon';
import { AddressGroup } from '../../Input/Address/AddressPicker';
import { ChevronRight } from 'lucide-react';
import { truncateDecimals } from '../../utils/RoundDecimals';
import { useConfig, useSwitchAccount } from 'wagmi';
import VaulDrawer from '../../modal/vaulModal';
import { Wallet } from '../../../Models/WalletProvider';
import useSWRBalance from '../../../lib/balances/useSWRBalance';
import { useSettingsState } from '../../../context/settings';
import WalletsList from '../../Wallet/WalletsList';
import { getConnections } from '@wagmi/core'

const WalletTransferContent: FC = () => {
const { networks } = useSettingsState()
Expand All @@ -22,16 +20,11 @@ const WalletTransferContent: FC = () => {
const { source_token, source_network: swap_source_network } = swap || {}
const source_network = swap_source_network && networks.find(n => n.name === swap_source_network?.name)
const { provider } = useWallet(source_network, 'withdrawal')
const { switchAccount } = useSwitchAccount()
const config = useConfig()

const [openModal, setOpenModal] = useState(false)

const changeWallet = async (wallet: Wallet, address: string) => {
const connections = getConnections(config)
const connector = connections?.find(c => c.connector.name === wallet.id)
if (!connector) return
switchAccount({ connector: connector.connector })
provider?.switchAccount && provider.switchAccount(wallet, address)
setSelectedSourceAccount({ wallet, address })
setOpenModal(false)
}
Expand Down
2 changes: 2 additions & 0 deletions lib/gases/providers/evmGasProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export class EVMGasProvider implements Provider {

try {

if (network.metadata.zks_paymaster_contract) return 0

const { createPublicClient, http } = await import("viem")
const resolveNetworkChain = (await import("../../resolveChain")).default
const publicClient = createPublicClient({
Expand Down
6 changes: 6 additions & 0 deletions lib/knownIds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ export default class KnownInternalNames {

public static readonly FuelTestnet: string = "FUEL_TESTNET"

public static readonly FuelDevnet: string = "FUEL_DEVNET"

public static readonly TronMainnet: string = "TRON_MAINNET"

public static readonly TronTestnet: string = "TRON_TESTNET"
Expand All @@ -180,6 +182,10 @@ export default class KnownInternalNames {

public static readonly EclipseMainnet: string = "ECLIPSE_MAINNET"

public static readonly SophonMainnet: string = "SOPHON_MAINNET"

public static readonly SophonSepolia: string = "SOPHON_SEPOLIA"

}

static Currencies = class {
Expand Down
Loading
Loading