validateSolanaPayTransaction method
Future<TransactionDetails>
validateSolanaPayTransaction({
- required TransactionId signature,
- required Ed25519HDPublicKey recipient,
- required Decimal amount,
- Ed25519HDPublicKey? splToken,
- Iterable<
Ed25519HDPublicKey> ? reference, - Commitment commitment = Commitment.finalized,
Validates that a given transaction signature corresponds with a transaction containing a valid Solana Pay transfer.
Implementation
Future<TransactionDetails> validateSolanaPayTransaction({
required TransactionId signature,
required Ed25519HDPublicKey recipient,
required Decimal amount,
Ed25519HDPublicKey? splToken,
Iterable<Ed25519HDPublicKey>? reference,
Commitment commitment = Commitment.finalized,
}) async {
final response = await rpcClient.getTransaction(
signature,
commitment: commitment,
);
if (response == null) {
throw const ValidateTransactionException('Transaction not found.');
}
final meta = response.meta;
if (meta == null) {
throw const ValidateTransactionException('Missing meta.');
}
if (meta.err != null) {
throw const ValidateTransactionException('Transaction error.');
}
final Decimal preAmount, postAmount;
if (splToken == null) {
final accountIndex = (response.transaction as ParsedTransaction)
.message
.accountKeys
.indexWhere((a) => a.pubkey == recipient.toBase58());
if (accountIndex == -1) {
throw const ValidateTransactionException('Recipient not found.');
}
preAmount = Decimal.fromInt(meta.preBalances[accountIndex])
.shift(-solDecimalPlaces);
postAmount = Decimal.fromInt(meta.postBalances[accountIndex])
.shift(-solDecimalPlaces);
} else {
final recipientATA =
await findAssociatedTokenAddress(owner: recipient, mint: splToken);
final accountIndex = (response.transaction as ParsedTransaction)
.message
.accountKeys
.indexWhere((a) => a.pubkey == recipientATA.toBase58());
if (accountIndex == -1) {
throw const ValidateTransactionException('Recipient not found.');
}
final preBalance = meta.preTokenBalances
.firstWhereOrNull((a) => a.accountIndex == accountIndex);
final postBalance = meta.postTokenBalances
.firstWhereOrNull((a) => a.accountIndex == accountIndex);
preAmount =
Decimal.parse(preBalance?.uiTokenAmount.uiAmountString ?? '0');
postAmount =
Decimal.parse(postBalance?.uiTokenAmount.uiAmountString ?? '0');
}
if (postAmount - preAmount < amount) {
throw const ValidateTransactionException('Amount not transferred.');
}
if (reference != null) {
final keys = (response.transaction as ParsedTransaction)
.message
.accountKeys
.map((e) => e.pubkey);
if (reference.any((e) => !keys.contains(e.toBase58()))) {
throw const ValidateTransactionException('Reference not found.');
}
}
return response;
}