0x0x230x

Untitled

Feb 24th, 2026
51
0
Never
7
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.37 KB | None | 0 0
  1. 'use client';
  2.  
  3. import { Program } from '@coral-xyz/anchor';
  4. import { useConnectorClient, useTransactionSigner } from '@solana/connector';
  5. import {
  6. ASSOCIATED_TOKEN_PROGRAM_ID,
  7. createAssociatedTokenAccountInstruction,
  8. createCloseAccountInstruction,
  9. getAssociatedTokenAddressSync,
  10. NATIVE_MINT,
  11. TOKEN_PROGRAM_ID,
  12. } from '@solana/spl-token';
  13. import { Connection, PublicKey, Transaction, type TransactionInstruction } from '@solana/web3.js';
  14. import { useMutation } from '@tanstack/react-query';
  15. import BN from 'bn.js';
  16. import { useCallback } from 'react';
  17.  
  18. import { YOSOL_FEE_RECIPIENT } from '@/lib/config/vaults/solana/config';
  19. import type { YoVault } from '@/lib/config/vaults/solana/yo-vault-sol';
  20. import yoVaultSolIdl from '@/lib/config/vaults/solana/yo-vault-sol.json';
  21.  
  22. type SolanaVaultAddresses = {
  23. tokenMint: string; // vault.asset.address
  24. shareMint: string; // vault.shareAsset.address
  25. };
  26.  
  27. type RedeemResult = {
  28. signature: string;
  29. confirmed: boolean;
  30. };
  31.  
  32. /**
  33. * Hook for redeeming shares from a Solana vault.
  34. *
  35. * Flow:
  36. * 1. Create WSOL ATA if needed (to receive redeemed WSOL)
  37. * 2. Call vault requestRedeem instruction via Anchor
  38. * 3. Close WSOL account to unwrap WSOL back to SOL
  39. *
  40. * @param addresses - Vault addresses from backend vault data
  41. * @param enabled - Whether the hook should be active (use false for EVM vaults)
  42. */
  43. export function useSolanaRedeem(addresses: SolanaVaultAddresses | null, enabled = true) {
  44. const { signer, ready, address: walletAddress } = useTransactionSigner();
  45. const client = useConnectorClient();
  46.  
  47. const mutation = useMutation({
  48. mutationFn: async (sharesLamports: bigint): Promise<RedeemResult> => {
  49. if (!signer || !walletAddress) {
  50. throw new Error('Wallet not connected');
  51. }
  52. if (!addresses) {
  53. throw new Error('Vault addresses not available');
  54. }
  55.  
  56. // Get RPC URL from connector client
  57. const rpcUrl = client?.getRpcUrl();
  58. if (!rpcUrl) {
  59. throw new Error('No RPC endpoint configured');
  60. }
  61.  
  62. const connection = new Connection(rpcUrl, 'confirmed');
  63. const walletPubkey = new PublicKey(walletAddress);
  64. const sharesBN = new BN(sharesLamports.toString());
  65.  
  66. const tokenMint = new PublicKey(addresses.tokenMint);
  67. const shareMint = new PublicKey(addresses.shareMint);
  68.  
  69. // Build pre-redeem instructions (create WSOL ATA if needed)
  70. const preRedeemIxs = await buildPreRedeemIxs(walletPubkey, connection);
  71.  
  72. // Build redeem instruction via Anchor
  73. const program = new Program(yoVaultSolIdl as YoVault, { connection });
  74. const redeemIx = await program.methods
  75. .requestRedeem(sharesBN)
  76. .accounts({
  77. user: walletPubkey,
  78. tokenMint,
  79. shareMint,
  80. feeRecipient: YOSOL_FEE_RECIPIENT,
  81. program: program.programId,
  82. })
  83. .instruction();
  84.  
  85. // Build post-redeem instructions (close WSOL account to unwrap to SOL)
  86. const postRedeemIxs = buildUnwrapSolIxs(walletPubkey);
  87.  
  88. // Combine instructions into transaction
  89. const tx = new Transaction().add(...preRedeemIxs, redeemIx, ...postRedeemIxs);
  90. const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
  91. tx.recentBlockhash = blockhash;
  92. tx.feePayer = walletPubkey;
  93. tx.lastValidBlockHeight = lastValidBlockHeight;
  94.  
  95. // Sign and send via ConnectorKit
  96. const signature = await signer.signAndSendTransaction(tx);
  97.  
  98. return { signature, confirmed: true };
  99. },
  100. });
  101.  
  102. const reset = useCallback(() => {
  103. mutation.reset();
  104. }, [mutation]);
  105.  
  106. return {
  107. executeRedeem: mutation.mutate,
  108. executeRedeemAsync: mutation.mutateAsync,
  109. isPending: mutation.isPending,
  110. isConfirming: false,
  111. isConfirmed: !!mutation.data?.signature,
  112. error: mutation.error,
  113. txSignature: mutation.data?.signature,
  114. isReady: enabled && ready && !!signer,
  115. reset,
  116. };
  117. }
  118.  
  119. /**
  120. * Build pre-redeem instructions.
  121. *
  122. * 1. Create WSOL ATA if it doesn't exist (to receive redeemed tokens)
  123. */
  124. async function buildPreRedeemIxs(
  125. user: PublicKey,
  126. connection: Connection
  127. ): Promise<TransactionInstruction[]> {
  128. const instructions: TransactionInstruction[] = [];
  129.  
  130. // Get user's WSOL ATA address
  131. const userWsolAccount = getAssociatedTokenAddressSync(NATIVE_MINT, user);
  132.  
  133. // Check if WSOL ATA exists
  134. const ataInfo = await connection.getAccountInfo(userWsolAccount);
  135. if (!ataInfo) {
  136. instructions.push(
  137. createAssociatedTokenAccountInstruction(
  138. user,
  139. userWsolAccount,
  140. user,
  141. NATIVE_MINT,
  142. TOKEN_PROGRAM_ID,
  143. ASSOCIATED_TOKEN_PROGRAM_ID
  144. )
  145. );
  146. }
  147.  
  148. return instructions;
  149. }
  150.  
  151. /**
  152. * Build instructions to unwrap WSOL back to SOL.
  153. *
  154. * Closes the WSOL token account which returns the SOL to the owner.
  155. */
  156. function buildUnwrapSolIxs(user: PublicKey): TransactionInstruction[] {
  157. const userWsolAccount = getAssociatedTokenAddressSync(NATIVE_MINT, user);
  158.  
  159. // Close WSOL account - this transfers the lamports (SOL) back to the owner
  160. return [
  161. createCloseAccountInstruction(
  162. userWsolAccount, // account to close
  163. user, // destination for lamports
  164. user, // owner
  165. [], // multisig signers (none)
  166. TOKEN_PROGRAM_ID
  167. ),
  168. ];
  169. }
  170.  
  171. export default useSolanaRedeem;
  172.  
Advertisement
Comments
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
Add Comment
Please, Sign In to add comment