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

CW-829 Solana Enhancements #1858

Merged
merged 6 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 55 additions & 4 deletions cw_solana/lib/solana_client.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'dart:developer';
import 'dart:math' as math;

import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/node.dart';
Expand Down Expand Up @@ -179,7 +180,7 @@ class SolanaWalletClient {
bool isOutgoingTx = transfer.source == publicKey.toBase58();

double amount = (double.tryParse(transfer.amount) ?? 0.0) /
pow(10, splTokenDecimal ?? 9);
math.pow(10, splTokenDecimal ?? 9);

transactions.add(
SolanaTransactionModel(
Expand Down Expand Up @@ -275,6 +276,7 @@ class SolanaWalletClient {
required String destinationAddress,
required Ed25519HDKeyPair ownerKeypair,
required bool isSendAll,
required double solBalance,
String? tokenMint,
List<String> references = const [],
}) async {
Expand All @@ -289,6 +291,7 @@ class SolanaWalletClient {
ownerKeypair: ownerKeypair,
commitment: commitment,
isSendAll: isSendAll,
solBalance: solBalance,
);
return pendingNativeTokenTransaction;
} else {
Expand All @@ -300,6 +303,7 @@ class SolanaWalletClient {
destinationAddress: destinationAddress,
ownerKeypair: ownerKeypair,
commitment: commitment,
solBalance: solBalance,
);
return pendingSPLTokenTransaction;
}
Expand Down Expand Up @@ -352,6 +356,34 @@ class SolanaWalletClient {
return fee;
}

Future<bool> hasSufficientFundsLeftForRent(
double inputAmount, double fee, double solBalance) async {
final rent =
await _client!.getMinimumBalanceForMintRentExemption(commitment: Commitment.confirmed);

final rentInSol = (rent / lamportsPerSol).toDouble();

final remnant = solBalance - (inputAmount + fee);

log('Fee: $fee');

log('Rent: $rent');

log('Remnant: $remnant');

log('Rent In Sol: $rentInSol');

log('Sol Balance: $solBalance');

log('Total amount: $inputAmount');

log("Remnant is more than rent: ${remnant > rentInSol}");

if (remnant > rentInSol) return true;

return false;
}

Future<PendingSolanaTransaction> _signNativeTokenTransaction({
required String tokenTitle,
required int tokenDecimals,
Expand All @@ -360,6 +392,7 @@ class SolanaWalletClient {
required Ed25519HDKeyPair ownerKeypair,
required Commitment commitment,
required bool isSendAll,
required double solBalance,
}) async {
// Convert SOL to lamport
int lamports = (inputAmount * lamportsPerSol).toInt();
Expand All @@ -377,6 +410,14 @@ class SolanaWalletClient {
commitment,
);

bool hasSufficientFundsLeft = await hasSufficientFundsLeftForRent(inputAmount, fee, solBalance);

if (!hasSufficientFundsLeft) {
throw Exception(
'Transaction cannot be completed. Insufficient SOL left for rent after transaction. Kindly top up your SOL balance or reduce the amount of SOL you\'re sending.',
);
}

SignedTx signedTx;
if (isSendAll) {
final feeInLamports = (fee * lamportsPerSol).toInt();
Expand Down Expand Up @@ -424,6 +465,7 @@ class SolanaWalletClient {
required String destinationAddress,
required Ed25519HDKeyPair ownerKeypair,
required Commitment commitment,
required double solBalance,
}) async {
final destinationOwner = Ed25519HDPublicKey.fromBase58(destinationAddress);
final mint = Ed25519HDPublicKey.fromBase58(tokenMint);
Expand Down Expand Up @@ -456,11 +498,12 @@ class SolanaWalletClient {
funder: ownerKeypair,
);
} catch (e) {
throw Exception('Insufficient SOL balance to complete this transaction: ${e.toString()}');
throw Exception(
'Error creating associated token account for receipient address. ${e.toString()}');
}

// Input by the user
final amount = (inputAmount * pow(10, tokenDecimals)).toInt();
final amount = (inputAmount * math.pow(10, tokenDecimals)).toInt();

final instruction = TokenInstruction.transfer(
source: Ed25519HDPublicKey.fromBase58(associatedSenderAccount.pubkey),
Expand All @@ -482,6 +525,14 @@ class SolanaWalletClient {
commitment,
);

bool hasSufficientFundsLeft = await hasSufficientFundsLeftForRent(inputAmount, fee, solBalance);

if (!hasSufficientFundsLeft) {
throw Exception(
'Transaction cannot be completed. Insufficient SOL left for rent after transaction. Kindly top up your SOL balance.',
);
}

final signedTx = await _signTransactionInternal(
message: message,
signers: signers,
Expand Down
3 changes: 3 additions & 0 deletions cw_solana/lib/solana_wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ abstract class SolanaWalletBase

final walletBalanceForCurrency = balance[transactionCurrency]!.balance;

final solBalance = balance[CryptoCurrency.sol]!.balance;

double totalAmount = 0.0;

bool isSendAll = false;
Expand Down Expand Up @@ -278,6 +280,7 @@ abstract class SolanaWalletBase
? solCredentials.outputs.first.extractedAddress!
: solCredentials.outputs.first.address,
isSendAll: isSendAll,
solBalance: solBalance,
);

return pendingSolanaTransaction;
Expand Down