Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 'use client';
- import { Program } from '@coral-xyz/anchor';
- import { useConnectorClient, useTransactionSigner } from '@solana/connector';
- import {
- ASSOCIATED_TOKEN_PROGRAM_ID,
- createAssociatedTokenAccountInstruction,
- createSyncNativeInstruction,
- getAssociatedTokenAddressSync,
- NATIVE_MINT,
- TOKEN_PROGRAM_ID,
- } from '@solana/spl-token';
- import {
- Connection,
- PublicKey,
- SystemProgram,
- Transaction,
- type TransactionInstruction,
- } from '@solana/web3.js';
- import { useMutation } from '@tanstack/react-query';
- import BN from 'bn.js';
- import { useCallback } from 'react';
- import { YOSOL_FEE_RECIPIENT } from '@/lib/config/vaults/solana/config';
- import type { YoVault } from '@/lib/config/vaults/solana/yo-vault-sol';
- import yoVaultSolIdl from '@/lib/config/vaults/solana/yo-vault-sol.json';
- type SolanaVaultAddresses = {
- tokenMint: string; // vault.asset.address
- shareMint: string; // vault.shareAsset.address
- };
- type DepositResult = {
- signature: string;
- confirmed: boolean;
- };
- /**
- * Hook for depositing SOL into a Solana vault.
- *
- * Flow:
- * 1. Wrap SOL to WSOL (create ATA if needed, transfer SOL, sync native)
- * 2. Call vault deposit instruction via Anchor
- * 3. Sign and send transaction via ConnectorKit
- *
- * @param addresses - Vault addresses from backend vault data
- * @param enabled - Whether the hook should be active (use false for EVM vaults)
- */
- export function useSolanaDeposit(addresses: SolanaVaultAddresses | null, enabled = true) {
- const { signer, ready, address: walletAddress } = useTransactionSigner();
- const client = useConnectorClient();
- const mutation = useMutation({
- mutationFn: async (amountLamports: bigint): Promise<DepositResult> => {
- if (!signer || !walletAddress) {
- throw new Error('Wallet not connected');
- }
- if (!addresses) {
- throw new Error('Vault addresses not available');
- }
- // Get RPC URL from connector client
- const rpcUrl = client?.getRpcUrl();
- if (!rpcUrl) {
- throw new Error('No RPC endpoint configured');
- }
- const connection = new Connection(rpcUrl, 'confirmed');
- const walletPubkey = new PublicKey(walletAddress);
- const amountBN = new BN(amountLamports.toString());
- const tokenMint = new PublicKey(addresses.tokenMint);
- const shareMint = new PublicKey(addresses.shareMint);
- // Build wrap SOL instructions
- const wrapIxs = await buildWrapSolIxs(walletPubkey, amountLamports, connection);
- // Build deposit instruction via Anchor
- const program = new Program(yoVaultSolIdl as YoVault, { connection });
- const depositIx = await program.methods
- .deposit(amountBN)
- .accounts({
- user: walletPubkey,
- feeRecipient: YOSOL_FEE_RECIPIENT,
- tokenMint,
- shareMint,
- program: program.programId,
- })
- .instruction();
- // Combine instructions into transaction
- const allIxs = [...wrapIxs, depositIx];
- const tx = new Transaction().add(...allIxs);
- const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
- tx.recentBlockhash = blockhash;
- tx.feePayer = walletPubkey;
- tx.lastValidBlockHeight = lastValidBlockHeight;
- // Sign and send via ConnectorKit
- const signature = await signer.signAndSendTransaction(tx);
- return { signature, confirmed: true };
- },
- });
- const reset = useCallback(() => {
- mutation.reset();
- }, [mutation]);
- return {
- executeDeposit: mutation.mutate,
- executeDepositAsync: mutation.mutateAsync,
- isPending: mutation.isPending,
- isConfirming: false,
- isConfirmed: !!mutation.data?.signature,
- error: mutation.error,
- txSignature: mutation.data?.signature,
- isReady: enabled && ready && !!signer,
- reset,
- };
- }
- /**
- * Build instructions to wrap SOL to WSOL.
- *
- * 1. Create WSOL ATA if it doesn't exist
- * 2. Transfer SOL to WSOL ATA
- * 3. Sync native balance to update token account balance
- */
- async function buildWrapSolIxs(
- user: PublicKey,
- lamports: bigint,
- connection: Connection
- ): Promise<TransactionInstruction[]> {
- const instructions: TransactionInstruction[] = [];
- // Get user's WSOL ATA address
- const userWsolAccount = getAssociatedTokenAddressSync(NATIVE_MINT, user);
- // Check if WSOL ATA exists
- const ataInfo = await connection.getAccountInfo(userWsolAccount);
- if (!ataInfo) {
- instructions.push(
- createAssociatedTokenAccountInstruction(
- user,
- userWsolAccount,
- user,
- NATIVE_MINT,
- TOKEN_PROGRAM_ID,
- ASSOCIATED_TOKEN_PROGRAM_ID
- )
- );
- }
- // Transfer SOL to WSOL account
- instructions.push(
- SystemProgram.transfer({
- fromPubkey: user,
- toPubkey: userWsolAccount,
- lamports,
- })
- );
- // Sync native balance to update token account balance
- instructions.push(createSyncNativeInstruction(userWsolAccount, TOKEN_PROGRAM_ID));
- return instructions;
- }
- export default useSolanaDeposit;
Advertisement