validateSolanaPayTransaction method
Future<TransactionDetails>
validateSolanaPayTransaction({
- required TransactionId signature,
- required Ed25519HDPublicKey recipient,
- required Decimal amount,
- Ed25519HDPublicKey? splToken,
- Iterable<
Ed25519HDPublicKey> ? reference, - TokenProgramType tokenProgramType = TokenProgramType.tokenProgram,
- 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,
TokenProgramType tokenProgramType = TokenProgramType.tokenProgram,
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) {
// ignore: avoid-type-casts, controlled type
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,
tokenProgramType: tokenProgramType,
);
// ignore: avoid-type-casts, controlled type
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) {
// ignore: avoid-type-casts, controlled type
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;
}