Skip to content

Commit

Permalink
Merge pull request #1196 from layerswap/dev
Browse files Browse the repository at this point in the history
Dev to main
  • Loading branch information
arentant authored Dec 27, 2024
2 parents 7592385 + 701fcda commit 3d30c28
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 30 deletions.
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

0 comments on commit 3d30c28

Please sign in to comment.