diff --git a/packages/solana/lib/src/rpc/extension.dart b/packages/solana/lib/src/rpc/extension.dart index e8afb55fc..68e0da8dd 100644 --- a/packages/solana/lib/src/rpc/extension.dart +++ b/packages/solana/lib/src/rpc/extension.dart @@ -71,6 +71,90 @@ extension RpcClientExt on RpcClient { ); } + /// Get multiple transactions for multiple addresses in 1 call. + /// + /// For [commitment] parameter description [see this document][see this document] + /// [Commitment.processed] is not supported as [commitment]. + /// + /// [see this document]: https://docs.solana.com/developing/clients/jsonrpc-api#configuring-state-commitment + Future> getTransactionListForAddresses( + List addresses, { + int limit = 10, + String? before, + String? until, + Commitment? commitment, + Encoding? encoding, + // ignore: avoid-nullable-parameters-with-default-values, null has a meaning here + num? maxSupportedTransactionVersion = 0, + num? minContextSlot, + }) async { + final signatures = await getMultipleSignaturesForAddresses( + addresses, + limit: limit, + before: before, + until: until, + commitment: commitment, + minContextSlot: minContextSlot, + ); + + final allSignatures = signatures.expand((s) => s).toList(); + if (allSignatures.isEmpty) return []; + + return getMultipleTransactions( + allSignatures, + commitment: commitment, + encoding: encoding ?? Encoding.jsonParsed, + maxSupportedTransactionVersion: maxSupportedTransactionVersion, + ); + } + + /// Get multiple signatures for multiple addresses in 1 call. + /// The parameters are "passed as is" + /// to the internal call to [RpcClient.getSignaturesForAddress()] + Future>> + getMultipleSignaturesForAddresses( + List addresses, { + int limit = 10, + String? before, + String? until, + Commitment? commitment, + num? minContextSlot, + }) async { + final response = await _jsonRpcClient.bulkRequest( + 'getSignaturesForAddress', + addresses + .map( + (address) => [ + address.toBase58(), + GetSignaturesForAddressConfig( + limit: limit, + before: before, + until: until, + commitment: commitment, + minContextSlot: minContextSlot, + ).toJson(), + ], + ) + .toList(), + ); + + return response + .map>((dynamic result) { + if (result == null) return []; + final data = getResult(result); + if (data == null) return []; + if (data is! List) return []; + + return data + .map( + (dynamic s) => TransactionSignatureInformation.fromJson( + s as Map, + ), + ) + .toList(); + }).toList(); + } + /// Get multiple transactions in 1 call. /// /// Gets one transaction for each signature in the [signatures] list. @@ -102,6 +186,7 @@ extension RpcClientExt on RpcClient { final Iterable transactions = response.map(getResult); return transactions + .where((t) => t != null) .map( (dynamic t) => TransactionDetails.fromJson(t as Map), ) diff --git a/packages/solana/test/rpc_client_test.dart b/packages/solana/test/rpc_client_test.dart index c04853b7c..c575e9fcf 100644 --- a/packages/solana/test/rpc_client_test.dart +++ b/packages/solana/test/rpc_client_test.dart @@ -230,6 +230,32 @@ void main() { expect(txs.length, greaterThan(0)); }); + test('List recent transactions for multiple addresses', () async { + final secondWallet = await Ed25519HDKeyPair.fromMnemonic( + generateMnemonic(), + account: 2, + ); + + await client.rpcClient.requestAirdrop( + secondWallet.address, + _transferredAmount, + commitment: Commitment.confirmed, + ); + + final txs = await client.rpcClient.getTransactionListForAddresses( + [source.publicKey, secondWallet.publicKey], + commitment: Commitment.confirmed, + ); + + expect(txs, isNot(null)); + + for (final tx in txs) { + expect(tx, isNot(null)); + } + + expect(txs.length, greaterThan(0)); + }); + test('Transfer SOL with Versioned Transaction', () async { final bh = await client.rpcClient .getLatestBlockhash(commitment: Commitment.confirmed)