withdrawSol static method

Future<List<TransactionInstruction>> withdrawSol({
  1. required SolanaProvider connection,
  2. required SolAddress stakePoolAddress,
  3. required SolAddress tokenOwner,
  4. required SolAddress solReceiver,
  5. required SolAddress userTransferAuthority,
  6. required BigInt poolAmountLamports,
  7. SolAddress? solWithdrawAuthority,
})

Creates instructions required to withdraw SOL directly from a stake pool.

Implementation

static Future<List<TransactionInstruction>> withdrawSol({
  required SolanaProvider connection,
  required SolAddress stakePoolAddress,
  required SolAddress tokenOwner,
  required SolAddress solReceiver,
  required SolAddress userTransferAuthority,
  required BigInt poolAmountLamports,
  SolAddress? solWithdrawAuthority,
}) async {
  final stakePool = await connection.request(
    SolanaRPCGetStakePoolAccount(address: stakePoolAddress),
  );
  if (stakePool == null) {
    throw const SolanaPluginException('Stake pool account does not found.');
  }

  final poolTokenAccount =
      AssociatedTokenAccountProgramUtils.associatedTokenAccount(
        mint: stakePool.poolMint,
        owner: tokenOwner,
      );

  final tokenAccount = await connection.request(
    SolanaRequestGetAccountInfo(account: poolTokenAccount.address),
  );
  if (tokenAccount == null) {
    throw const SolanaPluginException('Token account not found.');
  }
  // Check withdrawFrom balance
  if (tokenAccount.lamports < poolAmountLamports) {
    throw const SolanaPluginException(
      'Not enough token balance to withdraw.',
    );
  }

  // Construct transaction to withdraw from withdrawAccounts account list
  final instructions = <TransactionInstruction>[];

  instructions.add(
    SPLTokenProgram.approve(
      account: poolTokenAccount.address,
      delegate: userTransferAuthority,
      owner: tokenOwner,
      layout: SPLTokenApproveLayout(amount: poolAmountLamports),
    ),
  );

  final poolWithdrawAuthority =
      StakePoolProgramUtils.findWithdrawAuthorityProgramAddress(
        stakePoolAddress: stakePoolAddress,
      );

  if (solWithdrawAuthority != null) {
    if (stakePool.solWithdrawAuthority == null) {
      throw const SolanaPluginException(
        'SOL withdraw authority specified in arguments but stake pool has none',
      );
    }
    if (solWithdrawAuthority.address !=
        stakePool.solWithdrawAuthority?.address) {
      throw const SolanaPluginException('Invalid deposit withdraw specified');
    }
  }

  instructions.add(
    StakePoolProgram.withdrawSol(
      stakePool: stakePoolAddress,
      withdrawAuthority: poolWithdrawAuthority.address,
      reserveStake: stakePool.reserveStake,
      sourcePoolAccount: poolTokenAccount.address,
      sourceTransferAuthority: userTransferAuthority,
      destinationSystemAccount: solReceiver,
      managerFeeAccount: stakePool.managerFeeAccount,
      poolMint: stakePool.poolMint,
      layout: StakePoolWithdrawSolLayout(poolTokens: poolAmountLamports),
      solWithdrawAuthority: solWithdrawAuthority,
    ),
  );

  return instructions;
}