Skip to content

Commit

Permalink
feat: Transaction broadcasting (#72)
Browse files Browse the repository at this point in the history
* Add classes for transaction broadcasting

* fix broadcasting compilation problems

* Reformat transaction_hash.dart

* Review PR suggestions

Co-authored-by: Andrzej Chmielewski <[email protected]>
  • Loading branch information
wal33d006 and andrzejchm authored Aug 2, 2021
1 parent 2dc9754 commit 5f4b350
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import 'package:alan/transactions/sender/tx_sender.dart';
import 'package:dartz/dartz.dart';
import 'package:transaction_signing_gateway/alan/alan_private_wallet_credentials.dart';
import 'package:transaction_signing_gateway/alan/alan_transaction.dart';
import 'package:transaction_signing_gateway/model/private_wallet_credentials.dart';
import 'package:transaction_signing_gateway/model/signed_transaction.dart';
import 'package:transaction_signing_gateway/model/transaction_broadcasting_failure.dart';
import 'package:transaction_signing_gateway/model/transaction_hash.dart';
import 'package:transaction_signing_gateway/transaction_broadcaster.dart';

class AlanTransactionBroadcaster implements TransactionBroadcaster {
@override
Future<Either<TransactionBroadcastingFailure, TransactionHash>> broadcast(
{required SignedTransaction transaction, required PrivateWalletCredentials privateWalletCredentials}) async {
if (transaction is! SignedAlanTransaction) {
return left(AlanTransactionBroadcastingFailure('passed transaction is not $SignedAlanTransaction'));
}
if (privateWalletCredentials is! AlanPrivateWalletCredentials) {
return left(AlanTransactionBroadcastingFailure("passed privateCredentials is not $AlanPrivateWalletCredentials"));
}
final txSender = TxSender.fromNetworkInfo(privateWalletCredentials.networkInfo);
final response = await txSender.broadcastTx(transaction.signedTransaction);

if (response.hasTxhash()) {
return right(TransactionHash(txHash: response.txhash));
} else {
return left(AlanTransactionBroadcastingFailure('Tx error: $response'));
}
}

@override
bool canBroadcast(SignedTransaction signedTransaction) => signedTransaction is SignedAlanTransaction;
}

class AlanTransactionBroadcastingFailure extends TransactionBroadcastingFailure {
final Object cause;

AlanTransactionBroadcastingFailure(this.cause);

@override
String toString() {
return 'AlanTransactionSigningFailure{cause: $cause}';
}

@override
// TODO: implement type
TransactionBroadcastingFailType get type => TransactionBroadcastingFailType.unknown;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,30 @@ import 'package:dartz/dartz.dart';
import 'package:transaction_signing_gateway/key_info_storage.dart';
import 'package:transaction_signing_gateway/model/credentials_storage_failure.dart';
import 'package:transaction_signing_gateway/model/signed_transaction.dart';
import 'package:transaction_signing_gateway/model/transaction_broadcasting_failure.dart';
import 'package:transaction_signing_gateway/model/transaction_hash.dart';
import 'package:transaction_signing_gateway/model/transaction_signing_failure.dart';
import 'package:transaction_signing_gateway/model/unsigned_transaction.dart';
import 'package:transaction_signing_gateway/model/wallet_lookup_key.dart';
import 'package:transaction_signing_gateway/model/wallet_public_info.dart';
import 'package:transaction_signing_gateway/transaction_broadcaster.dart';
import 'package:transaction_signing_gateway/transaction_signer.dart';
import 'package:transaction_signing_gateway/transaction_signing_gateway.dart';
import 'package:transaction_signing_gateway/transaction_summary_ui.dart';

class TransactionSigningGateway {
final List<TransactionSigner> _signers;
final List<TransactionBroadcaster> _broadcasters;
final KeyInfoStorage _infoStorage;
final TransactionSummaryUI _transactionSummaryUI;

TransactionSigningGateway({
required List<TransactionSigner> signers,
required List<TransactionBroadcaster> broadcasters,
required KeyInfoStorage infoStorage,
required TransactionSummaryUI transactionSummaryUI,
}) : _signers = List.unmodifiable(signers),
_broadcasters = List.unmodifiable(broadcasters),
_infoStorage = infoStorage,
_transactionSummaryUI = transactionSummaryUI;

Expand Down Expand Up @@ -60,6 +66,18 @@ class TransactionSigningGateway {
transaction: transaction,
));

Future<Either<TransactionBroadcastingFailure, TransactionHash>> broadcastTransaction({
required WalletLookupKey walletLookupKey,
required SignedTransaction transaction,
}) async =>
_infoStorage
.getPrivateCredentials(walletLookupKey)
.leftMap<TransactionBroadcastingFailure>((err) => left(StorageProblemBroadcastingFailure()))
.flatMap((privateCreds) async => _findCapableBroadcaster(transaction).broadcast(
transaction: transaction,
privateWalletCredentials: privateCreds,
));

Future<Either<CredentialsStorageFailure, List<WalletPublicInfo>>> getWalletsList() => _infoStorage.getWalletsList();

/// Verifies if passed lookupKey is pointing to a valid wallet stored within the secure storage.
Expand All @@ -70,4 +88,9 @@ class TransactionSigningGateway {
(element) => element.canSign(transaction),
orElse: () => NotFoundTransactionSigner(),
);

TransactionBroadcaster _findCapableBroadcaster(SignedTransaction transaction) => _broadcasters.firstWhere(
(element) => element.canBroadcast(transaction),
orElse: () => NotFoundBroadcaster(),
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
enum TransactionBroadcastingFailType {
noTransactionBroadcasterFound,
walletCredentialsStorageFailure,
unknown,
}

abstract class TransactionBroadcastingFailure {
TransactionBroadcastingFailType get type;
}

class TransactionBroadcasterNotFoundFailure extends TransactionBroadcastingFailure {
@override
TransactionBroadcastingFailType get type => TransactionBroadcastingFailType.noTransactionBroadcasterFound;
}

class StorageProblemBroadcastingFailure extends TransactionBroadcastingFailure {
@override
// TODO: implement type
TransactionBroadcastingFailType get type => TransactionBroadcastingFailType.walletCredentialsStorageFailure;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class TransactionHash {
String txHash;

TransactionHash({required this.txHash});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:dartz/dartz.dart';
import 'package:transaction_signing_gateway/model/private_wallet_credentials.dart';
import 'package:transaction_signing_gateway/model/signed_transaction.dart';
import 'package:transaction_signing_gateway/model/transaction_broadcasting_failure.dart';
import 'package:transaction_signing_gateway/model/transaction_hash.dart';

abstract class TransactionBroadcaster {
Future<Either<TransactionBroadcastingFailure, TransactionHash>> broadcast({
required SignedTransaction transaction,
required PrivateWalletCredentials privateWalletCredentials,
});

bool canBroadcast(SignedTransaction signedTransaction);
}

class NotFoundBroadcaster implements TransactionBroadcaster {
@override
Future<Either<TransactionBroadcastingFailure, TransactionHash>> broadcast(
{required SignedTransaction transaction, required PrivateWalletCredentials privateWalletCredentials}) async =>
left(TransactionBroadcasterNotFoundFailure());

@override
bool canBroadcast(SignedTransaction signedTransaction) => true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ void main() {
signingGateway = TransactionSigningGateway(
transactionSummaryUI: summaryUI,
signers: [],
broadcasters: [],
infoStorage: infoStorage,
);
});
Expand Down

0 comments on commit 5f4b350

Please sign in to comment.