diff --git a/.gitignore b/.gitignore index c0dd0b51..25bdfb5f 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ ios/Flutter/Release.xcconfig ios/Flutter/Debug.xcconfig macos/Flutter/Flutter-Debug.xcconfig macos/Flutter/Flutter-Release.xcconfig +pubspec.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index dde35419..31643f70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ Changelog ========= +#### Version 3.2.0 +* Add utility methods to handle message exchange mechanisms within the context of messaging. +* Add a transaction utility method to handle confirmations when a transaction is sent to the blockchain. +* Add logs activation property on Service classes + #### Version 3.1.1 (2023-05-22) * Fix getStorageNoncePublicKey method diff --git a/analysis_options.yaml b/analysis_options.yaml index 18eb1348..791941a8 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -9,8 +9,8 @@ # packages, and plugins designed to encourage good coding practices. analyzer: exclude: - - '**/*.freezed.dart' - - '**/*.g.dart' + - "**/*.freezed.dart" + - "**/*.g.dart" language: strict-casts: true @@ -127,7 +127,6 @@ linter: - prefer_const_literals_to_create_immutables - prefer_constructors_over_static_methods - prefer_contains - - prefer_equal_for_default_values - prefer_final_fields - prefer_final_in_for_each - prefer_final_locals @@ -205,6 +204,5 @@ linter: - use_to_and_as_if_applicable - valid_regexps - void_checks - # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options diff --git a/lib/archethic_lib_dart.dart b/lib/archethic_lib_dart.dart index 5d590dae..39b99257 100644 --- a/lib/archethic_lib_dart.dart +++ b/lib/archethic_lib_dart.dart @@ -20,6 +20,9 @@ export 'src/model/keychain.dart'; export 'src/model/ledger.dart'; export 'src/model/ledger_operations.dart'; export 'src/model/location.dart'; +export 'src/model/messaging/ae_group_message.dart'; +export 'src/model/messaging/ae_message.dart'; +export 'src/model/messaging/transaction_content_messaging.dart'; export 'src/model/node.dart'; export 'src/model/on_chain_wallet_data.dart'; export 'src/model/oracle_chain/oracle_uco_price.dart'; @@ -35,6 +38,7 @@ export 'src/model/transaction.dart'; export 'src/model/transaction_fee.dart'; export 'src/model/transaction_input.dart'; export 'src/model/transaction_movement.dart'; +export 'src/model/transaction_notification.dart'; export 'src/model/transaction_status.dart'; export 'src/model/uco.dart'; export 'src/model/uco_ledger.dart'; @@ -44,6 +48,14 @@ export 'src/model/validation_stamp.dart'; export 'src/services/address_service.dart'; export 'src/services/api_service.dart'; export 'src/services/oracle_service.dart'; +export 'src/utils/confirmations/archethic_transaction_sender.dart'; +export 'src/utils/confirmations/phoenix_link.dart'; +export 'src/utils/confirmations/transaction_event.dart'; +export 'src/utils/confirmations/transaction_remote.dart'; +export 'src/utils/confirmations/transaction_sender.dart'; export 'src/utils/crypto.dart'; +export 'src/utils/messenger_util.dart'; +export 'src/utils/notification_util.dart'; +export 'src/utils/transaction_util.dart'; export 'src/utils/utils.dart'; export 'src/utils/wallet_encoder.dart'; diff --git a/lib/crypto_keys/src/asymmetric_operator.dart b/lib/crypto_keys/src/asymmetric_operator.dart index 41ea43ea..6f978db9 100644 --- a/lib/crypto_keys/src/asymmetric_operator.dart +++ b/lib/crypto_keys/src/asymmetric_operator.dart @@ -2,7 +2,7 @@ part of '../crypto_keys.dart'; -abstract class _AsymmetricOperator implements Operator { +abstract mixin class _AsymmetricOperator implements Operator { static pc.ECDomainParameters createCurveParameters(Identifier curve) { var name = curve.name.split('/').last; switch (name) { diff --git a/lib/crypto_keys/src/keys.dart b/lib/crypto_keys/src/keys.dart index 5e4c994d..783ff5dc 100644 --- a/lib/crypto_keys/src/keys.dart +++ b/lib/crypto_keys/src/keys.dart @@ -3,7 +3,7 @@ part of '../crypto_keys.dart'; /// A cryptographic key -abstract class Key { +abstract mixin class Key { /// Creates an [Encrypter] using this key and the specified algorithm Encrypter createEncrypter(Identifier algorithm) { if (this is SymmetricKey) { @@ -15,7 +15,7 @@ abstract class Key { } /// A cryptographic public key -abstract class PublicKey implements Key { +abstract mixin class PublicKey implements Key { /// Creates a signature [Verifier] using this key and the specified algorithm Verifier createVerifier(Identifier algorithm) { if (this is SymmetricKey) { @@ -27,7 +27,7 @@ abstract class PublicKey implements Key { } /// A cryptographic private key -abstract class PrivateKey implements Key { +abstract mixin class PrivateKey implements Key { /// Creates a [Signer] using this key and the specified algorithm. Signer createSigner(Identifier algorithm) { if (this is SymmetricKey) { diff --git a/lib/src/model/messaging/ae_group_message.dart b/lib/src/model/messaging/ae_group_message.dart new file mode 100644 index 00000000..091d9173 --- /dev/null +++ b/lib/src/model/messaging/ae_group_message.dart @@ -0,0 +1,20 @@ +/// SPDX-License-Identifier: AGPL-3.0-or-later +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'ae_group_message.freezed.dart'; +part 'ae_group_message.g.dart'; + +@freezed +class AEGroupMessage with _$AEGroupMessage { + const factory AEGroupMessage({ + @Default('') final String groupName, + @Default('') final String address, + @Default([]) final List usersPubKey, + @Default([]) final List adminPublicKey, + @Default(0) final int timestampLastUpdate, + }) = _AEGroupMessage; + const AEGroupMessage._(); + + factory AEGroupMessage.fromJson(Map json) => + _$AEGroupMessageFromJson(json); +} diff --git a/lib/src/model/messaging/ae_group_message.freezed.dart b/lib/src/model/messaging/ae_group_message.freezed.dart new file mode 100644 index 00000000..902206e4 --- /dev/null +++ b/lib/src/model/messaging/ae_group_message.freezed.dart @@ -0,0 +1,266 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'ae_group_message.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +AEGroupMessage _$AEGroupMessageFromJson(Map json) { + return _AEGroupMessage.fromJson(json); +} + +/// @nodoc +mixin _$AEGroupMessage { + String get groupName => throw _privateConstructorUsedError; + String get address => throw _privateConstructorUsedError; + List get usersPubKey => throw _privateConstructorUsedError; + List get adminPublicKey => throw _privateConstructorUsedError; + int get timestampLastUpdate => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $AEGroupMessageCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AEGroupMessageCopyWith<$Res> { + factory $AEGroupMessageCopyWith( + AEGroupMessage value, $Res Function(AEGroupMessage) then) = + _$AEGroupMessageCopyWithImpl<$Res, AEGroupMessage>; + @useResult + $Res call( + {String groupName, + String address, + List usersPubKey, + List adminPublicKey, + int timestampLastUpdate}); +} + +/// @nodoc +class _$AEGroupMessageCopyWithImpl<$Res, $Val extends AEGroupMessage> + implements $AEGroupMessageCopyWith<$Res> { + _$AEGroupMessageCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? groupName = null, + Object? address = null, + Object? usersPubKey = null, + Object? adminPublicKey = null, + Object? timestampLastUpdate = null, + }) { + return _then(_value.copyWith( + groupName: null == groupName + ? _value.groupName + : groupName // ignore: cast_nullable_to_non_nullable + as String, + address: null == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String, + usersPubKey: null == usersPubKey + ? _value.usersPubKey + : usersPubKey // ignore: cast_nullable_to_non_nullable + as List, + adminPublicKey: null == adminPublicKey + ? _value.adminPublicKey + : adminPublicKey // ignore: cast_nullable_to_non_nullable + as List, + timestampLastUpdate: null == timestampLastUpdate + ? _value.timestampLastUpdate + : timestampLastUpdate // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_AEGroupMessageCopyWith<$Res> + implements $AEGroupMessageCopyWith<$Res> { + factory _$$_AEGroupMessageCopyWith( + _$_AEGroupMessage value, $Res Function(_$_AEGroupMessage) then) = + __$$_AEGroupMessageCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String groupName, + String address, + List usersPubKey, + List adminPublicKey, + int timestampLastUpdate}); +} + +/// @nodoc +class __$$_AEGroupMessageCopyWithImpl<$Res> + extends _$AEGroupMessageCopyWithImpl<$Res, _$_AEGroupMessage> + implements _$$_AEGroupMessageCopyWith<$Res> { + __$$_AEGroupMessageCopyWithImpl( + _$_AEGroupMessage _value, $Res Function(_$_AEGroupMessage) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? groupName = null, + Object? address = null, + Object? usersPubKey = null, + Object? adminPublicKey = null, + Object? timestampLastUpdate = null, + }) { + return _then(_$_AEGroupMessage( + groupName: null == groupName + ? _value.groupName + : groupName // ignore: cast_nullable_to_non_nullable + as String, + address: null == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String, + usersPubKey: null == usersPubKey + ? _value._usersPubKey + : usersPubKey // ignore: cast_nullable_to_non_nullable + as List, + adminPublicKey: null == adminPublicKey + ? _value._adminPublicKey + : adminPublicKey // ignore: cast_nullable_to_non_nullable + as List, + timestampLastUpdate: null == timestampLastUpdate + ? _value.timestampLastUpdate + : timestampLastUpdate // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_AEGroupMessage extends _AEGroupMessage { + const _$_AEGroupMessage( + {this.groupName = '', + this.address = '', + final List usersPubKey = const [], + final List adminPublicKey = const [], + this.timestampLastUpdate = 0}) + : _usersPubKey = usersPubKey, + _adminPublicKey = adminPublicKey, + super._(); + + factory _$_AEGroupMessage.fromJson(Map json) => + _$$_AEGroupMessageFromJson(json); + + @override + @JsonKey() + final String groupName; + @override + @JsonKey() + final String address; + final List _usersPubKey; + @override + @JsonKey() + List get usersPubKey { + if (_usersPubKey is EqualUnmodifiableListView) return _usersPubKey; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_usersPubKey); + } + + final List _adminPublicKey; + @override + @JsonKey() + List get adminPublicKey { + if (_adminPublicKey is EqualUnmodifiableListView) return _adminPublicKey; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_adminPublicKey); + } + + @override + @JsonKey() + final int timestampLastUpdate; + + @override + String toString() { + return 'AEGroupMessage(groupName: $groupName, address: $address, usersPubKey: $usersPubKey, adminPublicKey: $adminPublicKey, timestampLastUpdate: $timestampLastUpdate)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_AEGroupMessage && + (identical(other.groupName, groupName) || + other.groupName == groupName) && + (identical(other.address, address) || other.address == address) && + const DeepCollectionEquality() + .equals(other._usersPubKey, _usersPubKey) && + const DeepCollectionEquality() + .equals(other._adminPublicKey, _adminPublicKey) && + (identical(other.timestampLastUpdate, timestampLastUpdate) || + other.timestampLastUpdate == timestampLastUpdate)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + groupName, + address, + const DeepCollectionEquality().hash(_usersPubKey), + const DeepCollectionEquality().hash(_adminPublicKey), + timestampLastUpdate); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_AEGroupMessageCopyWith<_$_AEGroupMessage> get copyWith => + __$$_AEGroupMessageCopyWithImpl<_$_AEGroupMessage>(this, _$identity); + + @override + Map toJson() { + return _$$_AEGroupMessageToJson( + this, + ); + } +} + +abstract class _AEGroupMessage extends AEGroupMessage { + const factory _AEGroupMessage( + {final String groupName, + final String address, + final List usersPubKey, + final List adminPublicKey, + final int timestampLastUpdate}) = _$_AEGroupMessage; + const _AEGroupMessage._() : super._(); + + factory _AEGroupMessage.fromJson(Map json) = + _$_AEGroupMessage.fromJson; + + @override + String get groupName; + @override + String get address; + @override + List get usersPubKey; + @override + List get adminPublicKey; + @override + int get timestampLastUpdate; + @override + @JsonKey(ignore: true) + _$$_AEGroupMessageCopyWith<_$_AEGroupMessage> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/src/model/messaging/ae_group_message.g.dart b/lib/src/model/messaging/ae_group_message.g.dart new file mode 100644 index 00000000..39c11068 --- /dev/null +++ b/lib/src/model/messaging/ae_group_message.g.dart @@ -0,0 +1,31 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'ae_group_message.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_AEGroupMessage _$$_AEGroupMessageFromJson(Map json) => + _$_AEGroupMessage( + groupName: json['groupName'] as String? ?? '', + address: json['address'] as String? ?? '', + usersPubKey: (json['usersPubKey'] as List?) + ?.map((e) => e as String) + .toList() ?? + const [], + adminPublicKey: (json['adminPublicKey'] as List?) + ?.map((e) => e as String) + .toList() ?? + const [], + timestampLastUpdate: json['timestampLastUpdate'] as int? ?? 0, + ); + +Map _$$_AEGroupMessageToJson(_$_AEGroupMessage instance) => + { + 'groupName': instance.groupName, + 'address': instance.address, + 'usersPubKey': instance.usersPubKey, + 'adminPublicKey': instance.adminPublicKey, + 'timestampLastUpdate': instance.timestampLastUpdate, + }; diff --git a/lib/src/model/messaging/ae_message.dart b/lib/src/model/messaging/ae_message.dart new file mode 100644 index 00000000..2f537c61 --- /dev/null +++ b/lib/src/model/messaging/ae_message.dart @@ -0,0 +1,20 @@ +/// SPDX-License-Identifier: AGPL-3.0-or-later +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'ae_message.freezed.dart'; +part 'ae_message.g.dart'; + +@freezed +class AEMessage with _$AEMessage { + const factory AEMessage({ + @Default('') final String address, + @Default('') final String senderGenesisPublicKey, + @Default('') final String content, + @Default(0) final int timestampCreation, + @Default('') final String sender, + }) = _AEMessage; + const AEMessage._(); + + factory AEMessage.fromJson(Map json) => + _$AEMessageFromJson(json); +} diff --git a/lib/src/model/messaging/ae_message.freezed.dart b/lib/src/model/messaging/ae_message.freezed.dart new file mode 100644 index 00000000..a0e9ed09 --- /dev/null +++ b/lib/src/model/messaging/ae_message.freezed.dart @@ -0,0 +1,243 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'ae_message.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +AEMessage _$AEMessageFromJson(Map json) { + return _AEMessage.fromJson(json); +} + +/// @nodoc +mixin _$AEMessage { + String get address => throw _privateConstructorUsedError; + String get senderGenesisPublicKey => throw _privateConstructorUsedError; + String get content => throw _privateConstructorUsedError; + int get timestampCreation => throw _privateConstructorUsedError; + String get sender => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $AEMessageCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AEMessageCopyWith<$Res> { + factory $AEMessageCopyWith(AEMessage value, $Res Function(AEMessage) then) = + _$AEMessageCopyWithImpl<$Res, AEMessage>; + @useResult + $Res call( + {String address, + String senderGenesisPublicKey, + String content, + int timestampCreation, + String sender}); +} + +/// @nodoc +class _$AEMessageCopyWithImpl<$Res, $Val extends AEMessage> + implements $AEMessageCopyWith<$Res> { + _$AEMessageCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? address = null, + Object? senderGenesisPublicKey = null, + Object? content = null, + Object? timestampCreation = null, + Object? sender = null, + }) { + return _then(_value.copyWith( + address: null == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String, + senderGenesisPublicKey: null == senderGenesisPublicKey + ? _value.senderGenesisPublicKey + : senderGenesisPublicKey // ignore: cast_nullable_to_non_nullable + as String, + content: null == content + ? _value.content + : content // ignore: cast_nullable_to_non_nullable + as String, + timestampCreation: null == timestampCreation + ? _value.timestampCreation + : timestampCreation // ignore: cast_nullable_to_non_nullable + as int, + sender: null == sender + ? _value.sender + : sender // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_AEMessageCopyWith<$Res> implements $AEMessageCopyWith<$Res> { + factory _$$_AEMessageCopyWith( + _$_AEMessage value, $Res Function(_$_AEMessage) then) = + __$$_AEMessageCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String address, + String senderGenesisPublicKey, + String content, + int timestampCreation, + String sender}); +} + +/// @nodoc +class __$$_AEMessageCopyWithImpl<$Res> + extends _$AEMessageCopyWithImpl<$Res, _$_AEMessage> + implements _$$_AEMessageCopyWith<$Res> { + __$$_AEMessageCopyWithImpl( + _$_AEMessage _value, $Res Function(_$_AEMessage) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? address = null, + Object? senderGenesisPublicKey = null, + Object? content = null, + Object? timestampCreation = null, + Object? sender = null, + }) { + return _then(_$_AEMessage( + address: null == address + ? _value.address + : address // ignore: cast_nullable_to_non_nullable + as String, + senderGenesisPublicKey: null == senderGenesisPublicKey + ? _value.senderGenesisPublicKey + : senderGenesisPublicKey // ignore: cast_nullable_to_non_nullable + as String, + content: null == content + ? _value.content + : content // ignore: cast_nullable_to_non_nullable + as String, + timestampCreation: null == timestampCreation + ? _value.timestampCreation + : timestampCreation // ignore: cast_nullable_to_non_nullable + as int, + sender: null == sender + ? _value.sender + : sender // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_AEMessage extends _AEMessage { + const _$_AEMessage( + {this.address = '', + this.senderGenesisPublicKey = '', + this.content = '', + this.timestampCreation = 0, + this.sender = ''}) + : super._(); + + factory _$_AEMessage.fromJson(Map json) => + _$$_AEMessageFromJson(json); + + @override + @JsonKey() + final String address; + @override + @JsonKey() + final String senderGenesisPublicKey; + @override + @JsonKey() + final String content; + @override + @JsonKey() + final int timestampCreation; + @override + @JsonKey() + final String sender; + + @override + String toString() { + return 'AEMessage(address: $address, senderGenesisPublicKey: $senderGenesisPublicKey, content: $content, timestampCreation: $timestampCreation, sender: $sender)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_AEMessage && + (identical(other.address, address) || other.address == address) && + (identical(other.senderGenesisPublicKey, senderGenesisPublicKey) || + other.senderGenesisPublicKey == senderGenesisPublicKey) && + (identical(other.content, content) || other.content == content) && + (identical(other.timestampCreation, timestampCreation) || + other.timestampCreation == timestampCreation) && + (identical(other.sender, sender) || other.sender == sender)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, address, senderGenesisPublicKey, + content, timestampCreation, sender); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_AEMessageCopyWith<_$_AEMessage> get copyWith => + __$$_AEMessageCopyWithImpl<_$_AEMessage>(this, _$identity); + + @override + Map toJson() { + return _$$_AEMessageToJson( + this, + ); + } +} + +abstract class _AEMessage extends AEMessage { + const factory _AEMessage( + {final String address, + final String senderGenesisPublicKey, + final String content, + final int timestampCreation, + final String sender}) = _$_AEMessage; + const _AEMessage._() : super._(); + + factory _AEMessage.fromJson(Map json) = + _$_AEMessage.fromJson; + + @override + String get address; + @override + String get senderGenesisPublicKey; + @override + String get content; + @override + int get timestampCreation; + @override + String get sender; + @override + @JsonKey(ignore: true) + _$$_AEMessageCopyWith<_$_AEMessage> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/src/model/messaging/ae_message.g.dart b/lib/src/model/messaging/ae_message.g.dart new file mode 100644 index 00000000..21cb5ead --- /dev/null +++ b/lib/src/model/messaging/ae_message.g.dart @@ -0,0 +1,24 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'ae_message.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_AEMessage _$$_AEMessageFromJson(Map json) => _$_AEMessage( + address: json['address'] as String? ?? '', + senderGenesisPublicKey: json['senderGenesisPublicKey'] as String? ?? '', + content: json['content'] as String? ?? '', + timestampCreation: json['timestampCreation'] as int? ?? 0, + sender: json['sender'] as String? ?? '', + ); + +Map _$$_AEMessageToJson(_$_AEMessage instance) => + { + 'address': instance.address, + 'senderGenesisPublicKey': instance.senderGenesisPublicKey, + 'content': instance.content, + 'timestampCreation': instance.timestampCreation, + 'sender': instance.sender, + }; diff --git a/lib/src/model/messaging/transaction_content_messaging.dart b/lib/src/model/messaging/transaction_content_messaging.dart new file mode 100644 index 00000000..08a1620d --- /dev/null +++ b/lib/src/model/messaging/transaction_content_messaging.dart @@ -0,0 +1,16 @@ +/// SPDX-License-Identifier: AGPL-3.0-or-later +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'transaction_content_messaging.freezed.dart'; +part 'transaction_content_messaging.g.dart'; + +@freezed +abstract class TransactionContentMessaging with _$TransactionContentMessaging { + const factory TransactionContentMessaging({ + required String compressionAlgo, + required String message, + }) = _TransactionContentMessaging; + + factory TransactionContentMessaging.fromJson(Map json) => + _$TransactionContentMessagingFromJson(json); +} diff --git a/lib/src/model/messaging/transaction_content_messaging.freezed.dart b/lib/src/model/messaging/transaction_content_messaging.freezed.dart new file mode 100644 index 00000000..8fb6e714 --- /dev/null +++ b/lib/src/model/messaging/transaction_content_messaging.freezed.dart @@ -0,0 +1,180 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'transaction_content_messaging.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +TransactionContentMessaging _$TransactionContentMessagingFromJson( + Map json) { + return _TransactionContentMessaging.fromJson(json); +} + +/// @nodoc +mixin _$TransactionContentMessaging { + String get compressionAlgo => throw _privateConstructorUsedError; + String get message => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $TransactionContentMessagingCopyWith + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $TransactionContentMessagingCopyWith<$Res> { + factory $TransactionContentMessagingCopyWith( + TransactionContentMessaging value, + $Res Function(TransactionContentMessaging) then) = + _$TransactionContentMessagingCopyWithImpl<$Res, + TransactionContentMessaging>; + @useResult + $Res call({String compressionAlgo, String message}); +} + +/// @nodoc +class _$TransactionContentMessagingCopyWithImpl<$Res, + $Val extends TransactionContentMessaging> + implements $TransactionContentMessagingCopyWith<$Res> { + _$TransactionContentMessagingCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? compressionAlgo = null, + Object? message = null, + }) { + return _then(_value.copyWith( + compressionAlgo: null == compressionAlgo + ? _value.compressionAlgo + : compressionAlgo // ignore: cast_nullable_to_non_nullable + as String, + message: null == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_TransactionContentMessagingCopyWith<$Res> + implements $TransactionContentMessagingCopyWith<$Res> { + factory _$$_TransactionContentMessagingCopyWith( + _$_TransactionContentMessaging value, + $Res Function(_$_TransactionContentMessaging) then) = + __$$_TransactionContentMessagingCopyWithImpl<$Res>; + @override + @useResult + $Res call({String compressionAlgo, String message}); +} + +/// @nodoc +class __$$_TransactionContentMessagingCopyWithImpl<$Res> + extends _$TransactionContentMessagingCopyWithImpl<$Res, + _$_TransactionContentMessaging> + implements _$$_TransactionContentMessagingCopyWith<$Res> { + __$$_TransactionContentMessagingCopyWithImpl( + _$_TransactionContentMessaging _value, + $Res Function(_$_TransactionContentMessaging) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? compressionAlgo = null, + Object? message = null, + }) { + return _then(_$_TransactionContentMessaging( + compressionAlgo: null == compressionAlgo + ? _value.compressionAlgo + : compressionAlgo // ignore: cast_nullable_to_non_nullable + as String, + message: null == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_TransactionContentMessaging implements _TransactionContentMessaging { + const _$_TransactionContentMessaging( + {required this.compressionAlgo, required this.message}); + + factory _$_TransactionContentMessaging.fromJson(Map json) => + _$$_TransactionContentMessagingFromJson(json); + + @override + final String compressionAlgo; + @override + final String message; + + @override + String toString() { + return 'TransactionContentMessaging(compressionAlgo: $compressionAlgo, message: $message)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_TransactionContentMessaging && + (identical(other.compressionAlgo, compressionAlgo) || + other.compressionAlgo == compressionAlgo) && + (identical(other.message, message) || other.message == message)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, compressionAlgo, message); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_TransactionContentMessagingCopyWith<_$_TransactionContentMessaging> + get copyWith => __$$_TransactionContentMessagingCopyWithImpl< + _$_TransactionContentMessaging>(this, _$identity); + + @override + Map toJson() { + return _$$_TransactionContentMessagingToJson( + this, + ); + } +} + +abstract class _TransactionContentMessaging + implements TransactionContentMessaging { + const factory _TransactionContentMessaging( + {required final String compressionAlgo, + required final String message}) = _$_TransactionContentMessaging; + + factory _TransactionContentMessaging.fromJson(Map json) = + _$_TransactionContentMessaging.fromJson; + + @override + String get compressionAlgo; + @override + String get message; + @override + @JsonKey(ignore: true) + _$$_TransactionContentMessagingCopyWith<_$_TransactionContentMessaging> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/src/model/messaging/transaction_content_messaging.g.dart b/lib/src/model/messaging/transaction_content_messaging.g.dart new file mode 100644 index 00000000..ac7c1a94 --- /dev/null +++ b/lib/src/model/messaging/transaction_content_messaging.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'transaction_content_messaging.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_TransactionContentMessaging _$$_TransactionContentMessagingFromJson( + Map json) => + _$_TransactionContentMessaging( + compressionAlgo: json['compressionAlgo'] as String, + message: json['message'] as String, + ); + +Map _$$_TransactionContentMessagingToJson( + _$_TransactionContentMessaging instance) => + { + 'compressionAlgo': instance.compressionAlgo, + 'message': instance.message, + }; diff --git a/lib/src/model/transaction_notification.dart b/lib/src/model/transaction_notification.dart new file mode 100644 index 00000000..0c858aeb --- /dev/null +++ b/lib/src/model/transaction_notification.dart @@ -0,0 +1,25 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'transaction_notification.freezed.dart'; +part 'transaction_notification.g.dart'; + +@freezed +class TransactionNotification with _$TransactionNotification { + const factory TransactionNotification({ + required String txAddress, + required String txChainGenesisAddress, + }) = _TransactionNotification; + const TransactionNotification._(); +} + +@freezed +class PushNotification with _$PushNotification { + const factory PushNotification({ + String? title, + String? body, + }) = _PushNotification; + const PushNotification._(); + + factory PushNotification.fromJson(Map json) => + _$PushNotificationFromJson(json); +} diff --git a/lib/src/model/transaction_notification.freezed.dart b/lib/src/model/transaction_notification.freezed.dart new file mode 100644 index 00000000..1b4b73af --- /dev/null +++ b/lib/src/model/transaction_notification.freezed.dart @@ -0,0 +1,315 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'transaction_notification.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +mixin _$TransactionNotification { + String get txAddress => throw _privateConstructorUsedError; + String get txChainGenesisAddress => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $TransactionNotificationCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $TransactionNotificationCopyWith<$Res> { + factory $TransactionNotificationCopyWith(TransactionNotification value, + $Res Function(TransactionNotification) then) = + _$TransactionNotificationCopyWithImpl<$Res, TransactionNotification>; + @useResult + $Res call({String txAddress, String txChainGenesisAddress}); +} + +/// @nodoc +class _$TransactionNotificationCopyWithImpl<$Res, + $Val extends TransactionNotification> + implements $TransactionNotificationCopyWith<$Res> { + _$TransactionNotificationCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? txAddress = null, + Object? txChainGenesisAddress = null, + }) { + return _then(_value.copyWith( + txAddress: null == txAddress + ? _value.txAddress + : txAddress // ignore: cast_nullable_to_non_nullable + as String, + txChainGenesisAddress: null == txChainGenesisAddress + ? _value.txChainGenesisAddress + : txChainGenesisAddress // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_TransactionNotificationCopyWith<$Res> + implements $TransactionNotificationCopyWith<$Res> { + factory _$$_TransactionNotificationCopyWith(_$_TransactionNotification value, + $Res Function(_$_TransactionNotification) then) = + __$$_TransactionNotificationCopyWithImpl<$Res>; + @override + @useResult + $Res call({String txAddress, String txChainGenesisAddress}); +} + +/// @nodoc +class __$$_TransactionNotificationCopyWithImpl<$Res> + extends _$TransactionNotificationCopyWithImpl<$Res, + _$_TransactionNotification> + implements _$$_TransactionNotificationCopyWith<$Res> { + __$$_TransactionNotificationCopyWithImpl(_$_TransactionNotification _value, + $Res Function(_$_TransactionNotification) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? txAddress = null, + Object? txChainGenesisAddress = null, + }) { + return _then(_$_TransactionNotification( + txAddress: null == txAddress + ? _value.txAddress + : txAddress // ignore: cast_nullable_to_non_nullable + as String, + txChainGenesisAddress: null == txChainGenesisAddress + ? _value.txChainGenesisAddress + : txChainGenesisAddress // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$_TransactionNotification extends _TransactionNotification { + const _$_TransactionNotification( + {required this.txAddress, required this.txChainGenesisAddress}) + : super._(); + + @override + final String txAddress; + @override + final String txChainGenesisAddress; + + @override + String toString() { + return 'TransactionNotification(txAddress: $txAddress, txChainGenesisAddress: $txChainGenesisAddress)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_TransactionNotification && + (identical(other.txAddress, txAddress) || + other.txAddress == txAddress) && + (identical(other.txChainGenesisAddress, txChainGenesisAddress) || + other.txChainGenesisAddress == txChainGenesisAddress)); + } + + @override + int get hashCode => + Object.hash(runtimeType, txAddress, txChainGenesisAddress); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_TransactionNotificationCopyWith<_$_TransactionNotification> + get copyWith => + __$$_TransactionNotificationCopyWithImpl<_$_TransactionNotification>( + this, _$identity); +} + +abstract class _TransactionNotification extends TransactionNotification { + const factory _TransactionNotification( + {required final String txAddress, + required final String txChainGenesisAddress}) = + _$_TransactionNotification; + const _TransactionNotification._() : super._(); + + @override + String get txAddress; + @override + String get txChainGenesisAddress; + @override + @JsonKey(ignore: true) + _$$_TransactionNotificationCopyWith<_$_TransactionNotification> + get copyWith => throw _privateConstructorUsedError; +} + +PushNotification _$PushNotificationFromJson(Map json) { + return _PushNotification.fromJson(json); +} + +/// @nodoc +mixin _$PushNotification { + String? get title => throw _privateConstructorUsedError; + String? get body => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $PushNotificationCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PushNotificationCopyWith<$Res> { + factory $PushNotificationCopyWith( + PushNotification value, $Res Function(PushNotification) then) = + _$PushNotificationCopyWithImpl<$Res, PushNotification>; + @useResult + $Res call({String? title, String? body}); +} + +/// @nodoc +class _$PushNotificationCopyWithImpl<$Res, $Val extends PushNotification> + implements $PushNotificationCopyWith<$Res> { + _$PushNotificationCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? title = freezed, + Object? body = freezed, + }) { + return _then(_value.copyWith( + title: freezed == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String?, + body: freezed == body + ? _value.body + : body // ignore: cast_nullable_to_non_nullable + as String?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_PushNotificationCopyWith<$Res> + implements $PushNotificationCopyWith<$Res> { + factory _$$_PushNotificationCopyWith( + _$_PushNotification value, $Res Function(_$_PushNotification) then) = + __$$_PushNotificationCopyWithImpl<$Res>; + @override + @useResult + $Res call({String? title, String? body}); +} + +/// @nodoc +class __$$_PushNotificationCopyWithImpl<$Res> + extends _$PushNotificationCopyWithImpl<$Res, _$_PushNotification> + implements _$$_PushNotificationCopyWith<$Res> { + __$$_PushNotificationCopyWithImpl( + _$_PushNotification _value, $Res Function(_$_PushNotification) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? title = freezed, + Object? body = freezed, + }) { + return _then(_$_PushNotification( + title: freezed == title + ? _value.title + : title // ignore: cast_nullable_to_non_nullable + as String?, + body: freezed == body + ? _value.body + : body // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$_PushNotification extends _PushNotification { + const _$_PushNotification({this.title, this.body}) : super._(); + + factory _$_PushNotification.fromJson(Map json) => + _$$_PushNotificationFromJson(json); + + @override + final String? title; + @override + final String? body; + + @override + String toString() { + return 'PushNotification(title: $title, body: $body)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_PushNotification && + (identical(other.title, title) || other.title == title) && + (identical(other.body, body) || other.body == body)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, title, body); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_PushNotificationCopyWith<_$_PushNotification> get copyWith => + __$$_PushNotificationCopyWithImpl<_$_PushNotification>(this, _$identity); + + @override + Map toJson() { + return _$$_PushNotificationToJson( + this, + ); + } +} + +abstract class _PushNotification extends PushNotification { + const factory _PushNotification({final String? title, final String? body}) = + _$_PushNotification; + const _PushNotification._() : super._(); + + factory _PushNotification.fromJson(Map json) = + _$_PushNotification.fromJson; + + @override + String? get title; + @override + String? get body; + @override + @JsonKey(ignore: true) + _$$_PushNotificationCopyWith<_$_PushNotification> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/src/model/transaction_notification.g.dart b/lib/src/model/transaction_notification.g.dart new file mode 100644 index 00000000..2545b325 --- /dev/null +++ b/lib/src/model/transaction_notification.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'transaction_notification.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$_PushNotification _$$_PushNotificationFromJson(Map json) => + _$_PushNotification( + title: json['title'] as String?, + body: json['body'] as String?, + ); + +Map _$$_PushNotificationToJson(_$_PushNotification instance) => + { + 'title': instance.title, + 'body': instance.body, + }; diff --git a/lib/src/utils/confirmations/archethic_transaction_sender.dart b/lib/src/utils/confirmations/archethic_transaction_sender.dart new file mode 100644 index 00000000..036ab6d8 --- /dev/null +++ b/lib/src/utils/confirmations/archethic_transaction_sender.dart @@ -0,0 +1,242 @@ +import 'dart:async'; +import 'dart:developer'; +import 'package:archethic_lib_dart/archethic_lib_dart.dart'; +import 'package:graphql/client.dart'; +import 'package:phoenix_socket/phoenix_socket.dart'; + +/// [TransactionSenderInterface] which talks to the Phoenix API. +class ArchethicTransactionSender + with ArchethicTransactionParser + implements TransactionSenderInterface { + ArchethicTransactionSender({ + required this.phoenixHttpEndpoint, + required this.websocketEndpoint, + required this.apiService, + }); + + final String phoenixHttpEndpoint; + final String websocketEndpoint; + final ApiService apiService; + + PhoenixChannel? _channel; + GraphQLClient? _client; + + StreamSubscription? _transactionConfirmedSubscription; + StreamSubscription? _transactionErrorSubscription; + Timer? _timer; + + @override + void close() { + _timer?.cancel(); + _channel?.close(); + _transactionConfirmedSubscription?.cancel(); + _transactionErrorSubscription?.cancel(); + } + + /// Sends a transaction and listens to confirmations. + /// + /// Sender auto-closes in the following situations : + /// - when transaction is fully confirmed + /// - when timeout is reached + /// - when transaction fails + @override + Future send({ + required Transaction transaction, + Duration timeout = const Duration(seconds: 60), + required TransactionConfirmationHandler onConfirmation, + required TransactionErrorHandler onError, + }) async { + _timer = Timer( + timeout, + () { + onError(const TransactionError.timeout()); + close(); + }, + ); + + await _connect( + phoenixHttpEndpoint, + websocketEndpoint, + ); + + _listenTransactionConfirmed( + transaction.address!.address!, + onConfirmation, + onError, + ); + _listenTransactionError( + transaction.address!.address!, + onError, + ); + + await _sendTransaction( + transaction: transaction, + onError: onError, + ); + } + + Future _connect( + String phoenixHttpEndpoint, + String websocketEndpoint, + ) async { + assert( + _client == null, + 'Connection already established. That instance of [SubscriptionChannel] must not be reused.', + ); + + final phoenixHttpLink = HttpLink( + phoenixHttpEndpoint, + ); + + _channel = await PhoenixLink.createChannel( + websocketUri: websocketEndpoint, + ); + final phoenixLink = PhoenixLink( + channel: _channel!, + ); + + final link = Link.split( + (request) => request.isSubscription, + phoenixLink, + phoenixHttpLink, + ); + _client = GraphQLClient( + link: link, + cache: GraphQLCache(), + ); + } + + Stream> _subscribe(String operation) async* { + assert( + _client != null, + 'You must call [connect] before [subscribing].', + ); + final subscriptionDocument = gql(operation); + yield* _client!.subscribe( + SubscriptionOptions( + document: subscriptionDocument, + ), + ); + } + + Future _sendTransaction({ + required Transaction transaction, + required TransactionErrorHandler onError, + }) async { + try { + final transactionStatus = await apiService.sendTx(transaction); + + if (transactionStatus.status == 'invalid') { + close(); + await onError( + const TransactionError.invalidTransaction(), + ); + } + } on ArchethicConnectionException { + close(); + await onError( + const TransactionError.connectivity(), + ); + } on Exception { + close(); + await onError( + const TransactionError.other(), + ); + } + } + + void _listenTransactionError( + String address, + TransactionErrorHandler onError, + ) { + _transactionErrorSubscription = _subscribe( + 'subscription { transactionError(address: "$address") { context, reason} }', + ).listen( + (result) { + close(); + final transactionError = _errorDtoToModel(result.data); + log( + '>>> Transaction KO $address <<< (${transactionError.message})', + ); + onError( + transactionError, + ); + }, + ); + } + + void _listenTransactionConfirmed( + String address, + TransactionConfirmationHandler onConfirmation, + TransactionErrorHandler onError, + ) { + _transactionConfirmedSubscription = _subscribe( + 'subscription { transactionConfirmed(address: "$address") { nbConfirmations, maxConfirmations } }', + ).listen( + (result) async { + final transactionEvent = _confirmationDtoToModel( + transactionAddress: address, + data: result.data, + ); + if (transactionEvent == null) { + await onError(const TransactionError.invalidConfirmation()); + return; + } + + log( + '>>> Transaction confirmed $address <<< ${transactionEvent.nbConfirmations} / ${transactionEvent.maxConfirmations}', + ); + + if (transactionEvent.isFullyConfirmed) close(); + + await onConfirmation( + transactionEvent, + ); + }, + ); + } +} + +/// Handles conversion from Archethic DTOs to Models +mixin ArchethicTransactionParser { + TransactionError _errorDtoToModel(Map? data) { + try { + final transactionError = data?['transactionError']; + final reason = transactionError?['reason']; + + if (reason == 'Insufficient funds') { + return const TransactionError.insufficientFunds(); + } + + if (reason == 'consensus not reached') { + return const TransactionError.consensusNotReached(); + } + + if (reason == 'timeout' || reason == 'connection timeout') { + return const TransactionError.timeout(); + } + + // TODO(reddwarf03): Handle other error types. + + return TransactionError.other(reason: reason); + } catch (e) { + return const TransactionError.other(); + } + } + + TransactionConfirmation? _confirmationDtoToModel({ + required String transactionAddress, + Map? data, + }) { + final transactionConfirmation = data?['transactionConfirmed']; + if (transactionConfirmation == null) return null; + + final nbConfirmations = transactionConfirmation?['nbConfirmations'] ?? 0; + final maxConfirmations = transactionConfirmation?['maxConfirmations'] ?? 0; + return TransactionConfirmation( + transactionAddress: transactionAddress, + nbConfirmations: nbConfirmations, + maxConfirmations: maxConfirmations, + ); + } +} diff --git a/lib/src/utils/confirmations/phoenix_link.dart b/lib/src/utils/confirmations/phoenix_link.dart new file mode 100644 index 00000000..6669142d --- /dev/null +++ b/lib/src/utils/confirmations/phoenix_link.dart @@ -0,0 +1,90 @@ +import 'dart:async'; +import 'dart:developer'; +import 'package:graphql/client.dart'; +import 'package:phoenix_socket/phoenix_socket.dart'; + +/// a link for subscriptions (or also mutations/queries) over phoenix channels +class PhoenixLink extends Link { + /// create a new [PhoenixLink] using an established PhoenixChannel [channel]. + /// You can use the static [createChannel] method to create a [PhoenixChannel] + /// from a websocket URI and optional parameters (e.g. for authentication) + PhoenixLink({ + required this.channel, + ResponseParser parser = const ResponseParser(), + RequestSerializer serializer = const RequestSerializer(), + }) : _serializer = serializer, + _parser = parser; + + /// the underlying phoenix channel + final PhoenixChannel channel; + + final RequestSerializer _serializer; + final ResponseParser _parser; + + /// create a new phoenix socket from the given websocketUri, + /// connect to it, and create a channel, and join it + static Future createChannel({ + required String websocketUri, + Map? params, + }) async { + final socket = PhoenixSocket( + websocketUri, + socketOptions: PhoenixSocketOptions(params: params), + ); + await socket.connect(); + + final channel = socket.addChannel(topic: '__absinthe__:control'); + final push = channel.join(); + await push.future; + + return channel; + } + + @override + Stream request(Request request, [NextLink? forward]) async* { + final payload = _serializer.serializeRequest(request); + String? phoenixSubscriptionId; + StreamSubscription? websocketSubscription; + + StreamController? streamController; + final push = channel.push('doc', payload); + try { + final pushResponse = await push.future; + //set the subscription id in order to cancel the subscription later + phoenixSubscriptionId = + pushResponse.response['subscriptionId'] as String?; + + if (phoenixSubscriptionId != null) { + //yield all messages for this subscription + streamController = StreamController(); + + websocketSubscription = channel.socket + .streamForTopic(phoenixSubscriptionId) + .map( + (event) => _parser.parseResponse( + event.payload!['result'] as Map, + ), + ) + .listen(streamController.add, onError: streamController.addError); + yield* streamController.stream; + } else if (pushResponse.isOk) { + yield _parser + .parseResponse(pushResponse.response as Map); + } else if (pushResponse.isError) { + // ignore: only_throw_errors + throw _parser.parseError(pushResponse.response as Map); + } + } catch (e, stackTrace) { + log(e.toString(), error: e, stackTrace: stackTrace); + } finally { + await websocketSubscription?.cancel(); + await streamController?.close(); + //this will be called once the caller stops listening to the stream + // (yield* stops if there is no one listening) + if (channel.state == PhoenixChannelState.joined && + phoenixSubscriptionId != null) { + channel.push('unsubscribe', {'subscriptionId': phoenixSubscriptionId}); + } + } + } +} diff --git a/lib/src/utils/confirmations/transaction_event.dart b/lib/src/utils/confirmations/transaction_event.dart new file mode 100644 index 00000000..fd1014c3 --- /dev/null +++ b/lib/src/utils/confirmations/transaction_event.dart @@ -0,0 +1,69 @@ +import 'dart:math'; + +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'transaction_event.freezed.dart'; + +@freezed +class TransactionError with _$TransactionError implements Exception { + const TransactionError._(); + const factory TransactionError.timeout() = _TransactionTimeout; + const factory TransactionError.connectivity() = _TransactionConnectionError; + const factory TransactionError.consensusNotReached() = + _TransactionConsensusNotReachedError; + const factory TransactionError.invalidTransaction() = _TransactionInvalid; + const factory TransactionError.invalidConfirmation() = + _TransactionInvalidConfirmation; + const factory TransactionError.insufficientFunds() = + _TransactionInsufficientFunds; + const factory TransactionError.serviceNotFound() = + _TransactionServiceNotFound; + const factory TransactionError.serviceAlreadyExists() = + _TransactionServiceAlreadyExists; + const factory TransactionError.userRejected() = _TransactionUserRejected; + const factory TransactionError.unknownAccount({ + required String accountName, + }) = _TransactionUnknownAccount; + const factory TransactionError.other({ + String? reason, + }) = _TransactionOtherError; + + String get message => map( + timeout: (_) => 'connection timeout', + connectivity: (_) => 'connectivity issue', + consensusNotReached: (_) => 'consensus not reached', + invalidTransaction: (_) => 'invalid transaction', + invalidConfirmation: (_) => 'invalid confirmation', + insufficientFunds: (_) => 'insufficient funds', + serviceNotFound: (_) => 'service not found', + serviceAlreadyExists: (_) => 'service already exists in the keychain', + userRejected: (_) => 'user rejected', + unknownAccount: (_) => 'unknown account', + other: (other) => other.reason ?? 'other reason', + ); +} + +@freezed +class TransactionConfirmation with _$TransactionConfirmation { + const factory TransactionConfirmation({ + required String transactionAddress, + @Default(0) int nbConfirmations, + @Default(0) int maxConfirmations, + }) = _TransactionConfirmation; + + const TransactionConfirmation._(); + + bool get isFullyConfirmed => nbConfirmations >= maxConfirmations; + bool get isEnoughConfirmed => isEnoughConfirmations( + nbConfirmations, + maxConfirmations, + ); + + double get confirmationRatio => max(1, maxConfirmations / nbConfirmations); + + static bool isEnoughConfirmations( + int nbConfirmations, + int maxConfirmations, + ) => + nbConfirmations > 0; +} diff --git a/lib/src/utils/confirmations/transaction_event.freezed.dart b/lib/src/utils/confirmations/transaction_event.freezed.dart new file mode 100644 index 00000000..9cc97c70 --- /dev/null +++ b/lib/src/utils/confirmations/transaction_event.freezed.dart @@ -0,0 +1,2256 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'transaction_event.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +mixin _$TransactionError { + @optionalTypeArgs + TResult when({ + required TResult Function() timeout, + required TResult Function() connectivity, + required TResult Function() consensusNotReached, + required TResult Function() invalidTransaction, + required TResult Function() invalidConfirmation, + required TResult Function() insufficientFunds, + required TResult Function() serviceNotFound, + required TResult Function() serviceAlreadyExists, + required TResult Function() userRejected, + required TResult Function(String accountName) unknownAccount, + required TResult Function(String? reason) other, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? timeout, + TResult? Function()? connectivity, + TResult? Function()? consensusNotReached, + TResult? Function()? invalidTransaction, + TResult? Function()? invalidConfirmation, + TResult? Function()? insufficientFunds, + TResult? Function()? serviceNotFound, + TResult? Function()? serviceAlreadyExists, + TResult? Function()? userRejected, + TResult? Function(String accountName)? unknownAccount, + TResult? Function(String? reason)? other, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? timeout, + TResult Function()? connectivity, + TResult Function()? consensusNotReached, + TResult Function()? invalidTransaction, + TResult Function()? invalidConfirmation, + TResult Function()? insufficientFunds, + TResult Function()? serviceNotFound, + TResult Function()? serviceAlreadyExists, + TResult Function()? userRejected, + TResult Function(String accountName)? unknownAccount, + TResult Function(String? reason)? other, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_TransactionTimeout value) timeout, + required TResult Function(_TransactionConnectionError value) connectivity, + required TResult Function(_TransactionConsensusNotReachedError value) + consensusNotReached, + required TResult Function(_TransactionInvalid value) invalidTransaction, + required TResult Function(_TransactionInvalidConfirmation value) + invalidConfirmation, + required TResult Function(_TransactionInsufficientFunds value) + insufficientFunds, + required TResult Function(_TransactionServiceNotFound value) + serviceNotFound, + required TResult Function(_TransactionServiceAlreadyExists value) + serviceAlreadyExists, + required TResult Function(_TransactionUserRejected value) userRejected, + required TResult Function(_TransactionUnknownAccount value) unknownAccount, + required TResult Function(_TransactionOtherError value) other, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_TransactionTimeout value)? timeout, + TResult? Function(_TransactionConnectionError value)? connectivity, + TResult? Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult? Function(_TransactionInvalid value)? invalidTransaction, + TResult? Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult? Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult? Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult? Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult? Function(_TransactionUserRejected value)? userRejected, + TResult? Function(_TransactionUnknownAccount value)? unknownAccount, + TResult? Function(_TransactionOtherError value)? other, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_TransactionTimeout value)? timeout, + TResult Function(_TransactionConnectionError value)? connectivity, + TResult Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult Function(_TransactionInvalid value)? invalidTransaction, + TResult Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult Function(_TransactionUserRejected value)? userRejected, + TResult Function(_TransactionUnknownAccount value)? unknownAccount, + TResult Function(_TransactionOtherError value)? other, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $TransactionErrorCopyWith<$Res> { + factory $TransactionErrorCopyWith( + TransactionError value, $Res Function(TransactionError) then) = + _$TransactionErrorCopyWithImpl<$Res, TransactionError>; +} + +/// @nodoc +class _$TransactionErrorCopyWithImpl<$Res, $Val extends TransactionError> + implements $TransactionErrorCopyWith<$Res> { + _$TransactionErrorCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$_TransactionTimeoutCopyWith<$Res> { + factory _$$_TransactionTimeoutCopyWith(_$_TransactionTimeout value, + $Res Function(_$_TransactionTimeout) then) = + __$$_TransactionTimeoutCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_TransactionTimeoutCopyWithImpl<$Res> + extends _$TransactionErrorCopyWithImpl<$Res, _$_TransactionTimeout> + implements _$$_TransactionTimeoutCopyWith<$Res> { + __$$_TransactionTimeoutCopyWithImpl( + _$_TransactionTimeout _value, $Res Function(_$_TransactionTimeout) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_TransactionTimeout extends _TransactionTimeout { + const _$_TransactionTimeout() : super._(); + + @override + String toString() { + return 'TransactionError.timeout()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_TransactionTimeout); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() timeout, + required TResult Function() connectivity, + required TResult Function() consensusNotReached, + required TResult Function() invalidTransaction, + required TResult Function() invalidConfirmation, + required TResult Function() insufficientFunds, + required TResult Function() serviceNotFound, + required TResult Function() serviceAlreadyExists, + required TResult Function() userRejected, + required TResult Function(String accountName) unknownAccount, + required TResult Function(String? reason) other, + }) { + return timeout(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? timeout, + TResult? Function()? connectivity, + TResult? Function()? consensusNotReached, + TResult? Function()? invalidTransaction, + TResult? Function()? invalidConfirmation, + TResult? Function()? insufficientFunds, + TResult? Function()? serviceNotFound, + TResult? Function()? serviceAlreadyExists, + TResult? Function()? userRejected, + TResult? Function(String accountName)? unknownAccount, + TResult? Function(String? reason)? other, + }) { + return timeout?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? timeout, + TResult Function()? connectivity, + TResult Function()? consensusNotReached, + TResult Function()? invalidTransaction, + TResult Function()? invalidConfirmation, + TResult Function()? insufficientFunds, + TResult Function()? serviceNotFound, + TResult Function()? serviceAlreadyExists, + TResult Function()? userRejected, + TResult Function(String accountName)? unknownAccount, + TResult Function(String? reason)? other, + required TResult orElse(), + }) { + if (timeout != null) { + return timeout(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_TransactionTimeout value) timeout, + required TResult Function(_TransactionConnectionError value) connectivity, + required TResult Function(_TransactionConsensusNotReachedError value) + consensusNotReached, + required TResult Function(_TransactionInvalid value) invalidTransaction, + required TResult Function(_TransactionInvalidConfirmation value) + invalidConfirmation, + required TResult Function(_TransactionInsufficientFunds value) + insufficientFunds, + required TResult Function(_TransactionServiceNotFound value) + serviceNotFound, + required TResult Function(_TransactionServiceAlreadyExists value) + serviceAlreadyExists, + required TResult Function(_TransactionUserRejected value) userRejected, + required TResult Function(_TransactionUnknownAccount value) unknownAccount, + required TResult Function(_TransactionOtherError value) other, + }) { + return timeout(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_TransactionTimeout value)? timeout, + TResult? Function(_TransactionConnectionError value)? connectivity, + TResult? Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult? Function(_TransactionInvalid value)? invalidTransaction, + TResult? Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult? Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult? Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult? Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult? Function(_TransactionUserRejected value)? userRejected, + TResult? Function(_TransactionUnknownAccount value)? unknownAccount, + TResult? Function(_TransactionOtherError value)? other, + }) { + return timeout?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_TransactionTimeout value)? timeout, + TResult Function(_TransactionConnectionError value)? connectivity, + TResult Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult Function(_TransactionInvalid value)? invalidTransaction, + TResult Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult Function(_TransactionUserRejected value)? userRejected, + TResult Function(_TransactionUnknownAccount value)? unknownAccount, + TResult Function(_TransactionOtherError value)? other, + required TResult orElse(), + }) { + if (timeout != null) { + return timeout(this); + } + return orElse(); + } +} + +abstract class _TransactionTimeout extends TransactionError { + const factory _TransactionTimeout() = _$_TransactionTimeout; + const _TransactionTimeout._() : super._(); +} + +/// @nodoc +abstract class _$$_TransactionConnectionErrorCopyWith<$Res> { + factory _$$_TransactionConnectionErrorCopyWith( + _$_TransactionConnectionError value, + $Res Function(_$_TransactionConnectionError) then) = + __$$_TransactionConnectionErrorCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_TransactionConnectionErrorCopyWithImpl<$Res> + extends _$TransactionErrorCopyWithImpl<$Res, _$_TransactionConnectionError> + implements _$$_TransactionConnectionErrorCopyWith<$Res> { + __$$_TransactionConnectionErrorCopyWithImpl( + _$_TransactionConnectionError _value, + $Res Function(_$_TransactionConnectionError) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_TransactionConnectionError extends _TransactionConnectionError { + const _$_TransactionConnectionError() : super._(); + + @override + String toString() { + return 'TransactionError.connectivity()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_TransactionConnectionError); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() timeout, + required TResult Function() connectivity, + required TResult Function() consensusNotReached, + required TResult Function() invalidTransaction, + required TResult Function() invalidConfirmation, + required TResult Function() insufficientFunds, + required TResult Function() serviceNotFound, + required TResult Function() serviceAlreadyExists, + required TResult Function() userRejected, + required TResult Function(String accountName) unknownAccount, + required TResult Function(String? reason) other, + }) { + return connectivity(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? timeout, + TResult? Function()? connectivity, + TResult? Function()? consensusNotReached, + TResult? Function()? invalidTransaction, + TResult? Function()? invalidConfirmation, + TResult? Function()? insufficientFunds, + TResult? Function()? serviceNotFound, + TResult? Function()? serviceAlreadyExists, + TResult? Function()? userRejected, + TResult? Function(String accountName)? unknownAccount, + TResult? Function(String? reason)? other, + }) { + return connectivity?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? timeout, + TResult Function()? connectivity, + TResult Function()? consensusNotReached, + TResult Function()? invalidTransaction, + TResult Function()? invalidConfirmation, + TResult Function()? insufficientFunds, + TResult Function()? serviceNotFound, + TResult Function()? serviceAlreadyExists, + TResult Function()? userRejected, + TResult Function(String accountName)? unknownAccount, + TResult Function(String? reason)? other, + required TResult orElse(), + }) { + if (connectivity != null) { + return connectivity(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_TransactionTimeout value) timeout, + required TResult Function(_TransactionConnectionError value) connectivity, + required TResult Function(_TransactionConsensusNotReachedError value) + consensusNotReached, + required TResult Function(_TransactionInvalid value) invalidTransaction, + required TResult Function(_TransactionInvalidConfirmation value) + invalidConfirmation, + required TResult Function(_TransactionInsufficientFunds value) + insufficientFunds, + required TResult Function(_TransactionServiceNotFound value) + serviceNotFound, + required TResult Function(_TransactionServiceAlreadyExists value) + serviceAlreadyExists, + required TResult Function(_TransactionUserRejected value) userRejected, + required TResult Function(_TransactionUnknownAccount value) unknownAccount, + required TResult Function(_TransactionOtherError value) other, + }) { + return connectivity(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_TransactionTimeout value)? timeout, + TResult? Function(_TransactionConnectionError value)? connectivity, + TResult? Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult? Function(_TransactionInvalid value)? invalidTransaction, + TResult? Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult? Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult? Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult? Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult? Function(_TransactionUserRejected value)? userRejected, + TResult? Function(_TransactionUnknownAccount value)? unknownAccount, + TResult? Function(_TransactionOtherError value)? other, + }) { + return connectivity?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_TransactionTimeout value)? timeout, + TResult Function(_TransactionConnectionError value)? connectivity, + TResult Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult Function(_TransactionInvalid value)? invalidTransaction, + TResult Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult Function(_TransactionUserRejected value)? userRejected, + TResult Function(_TransactionUnknownAccount value)? unknownAccount, + TResult Function(_TransactionOtherError value)? other, + required TResult orElse(), + }) { + if (connectivity != null) { + return connectivity(this); + } + return orElse(); + } +} + +abstract class _TransactionConnectionError extends TransactionError { + const factory _TransactionConnectionError() = _$_TransactionConnectionError; + const _TransactionConnectionError._() : super._(); +} + +/// @nodoc +abstract class _$$_TransactionConsensusNotReachedErrorCopyWith<$Res> { + factory _$$_TransactionConsensusNotReachedErrorCopyWith( + _$_TransactionConsensusNotReachedError value, + $Res Function(_$_TransactionConsensusNotReachedError) then) = + __$$_TransactionConsensusNotReachedErrorCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_TransactionConsensusNotReachedErrorCopyWithImpl<$Res> + extends _$TransactionErrorCopyWithImpl<$Res, + _$_TransactionConsensusNotReachedError> + implements _$$_TransactionConsensusNotReachedErrorCopyWith<$Res> { + __$$_TransactionConsensusNotReachedErrorCopyWithImpl( + _$_TransactionConsensusNotReachedError _value, + $Res Function(_$_TransactionConsensusNotReachedError) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_TransactionConsensusNotReachedError + extends _TransactionConsensusNotReachedError { + const _$_TransactionConsensusNotReachedError() : super._(); + + @override + String toString() { + return 'TransactionError.consensusNotReached()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_TransactionConsensusNotReachedError); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() timeout, + required TResult Function() connectivity, + required TResult Function() consensusNotReached, + required TResult Function() invalidTransaction, + required TResult Function() invalidConfirmation, + required TResult Function() insufficientFunds, + required TResult Function() serviceNotFound, + required TResult Function() serviceAlreadyExists, + required TResult Function() userRejected, + required TResult Function(String accountName) unknownAccount, + required TResult Function(String? reason) other, + }) { + return consensusNotReached(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? timeout, + TResult? Function()? connectivity, + TResult? Function()? consensusNotReached, + TResult? Function()? invalidTransaction, + TResult? Function()? invalidConfirmation, + TResult? Function()? insufficientFunds, + TResult? Function()? serviceNotFound, + TResult? Function()? serviceAlreadyExists, + TResult? Function()? userRejected, + TResult? Function(String accountName)? unknownAccount, + TResult? Function(String? reason)? other, + }) { + return consensusNotReached?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? timeout, + TResult Function()? connectivity, + TResult Function()? consensusNotReached, + TResult Function()? invalidTransaction, + TResult Function()? invalidConfirmation, + TResult Function()? insufficientFunds, + TResult Function()? serviceNotFound, + TResult Function()? serviceAlreadyExists, + TResult Function()? userRejected, + TResult Function(String accountName)? unknownAccount, + TResult Function(String? reason)? other, + required TResult orElse(), + }) { + if (consensusNotReached != null) { + return consensusNotReached(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_TransactionTimeout value) timeout, + required TResult Function(_TransactionConnectionError value) connectivity, + required TResult Function(_TransactionConsensusNotReachedError value) + consensusNotReached, + required TResult Function(_TransactionInvalid value) invalidTransaction, + required TResult Function(_TransactionInvalidConfirmation value) + invalidConfirmation, + required TResult Function(_TransactionInsufficientFunds value) + insufficientFunds, + required TResult Function(_TransactionServiceNotFound value) + serviceNotFound, + required TResult Function(_TransactionServiceAlreadyExists value) + serviceAlreadyExists, + required TResult Function(_TransactionUserRejected value) userRejected, + required TResult Function(_TransactionUnknownAccount value) unknownAccount, + required TResult Function(_TransactionOtherError value) other, + }) { + return consensusNotReached(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_TransactionTimeout value)? timeout, + TResult? Function(_TransactionConnectionError value)? connectivity, + TResult? Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult? Function(_TransactionInvalid value)? invalidTransaction, + TResult? Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult? Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult? Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult? Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult? Function(_TransactionUserRejected value)? userRejected, + TResult? Function(_TransactionUnknownAccount value)? unknownAccount, + TResult? Function(_TransactionOtherError value)? other, + }) { + return consensusNotReached?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_TransactionTimeout value)? timeout, + TResult Function(_TransactionConnectionError value)? connectivity, + TResult Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult Function(_TransactionInvalid value)? invalidTransaction, + TResult Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult Function(_TransactionUserRejected value)? userRejected, + TResult Function(_TransactionUnknownAccount value)? unknownAccount, + TResult Function(_TransactionOtherError value)? other, + required TResult orElse(), + }) { + if (consensusNotReached != null) { + return consensusNotReached(this); + } + return orElse(); + } +} + +abstract class _TransactionConsensusNotReachedError extends TransactionError { + const factory _TransactionConsensusNotReachedError() = + _$_TransactionConsensusNotReachedError; + const _TransactionConsensusNotReachedError._() : super._(); +} + +/// @nodoc +abstract class _$$_TransactionInvalidCopyWith<$Res> { + factory _$$_TransactionInvalidCopyWith(_$_TransactionInvalid value, + $Res Function(_$_TransactionInvalid) then) = + __$$_TransactionInvalidCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_TransactionInvalidCopyWithImpl<$Res> + extends _$TransactionErrorCopyWithImpl<$Res, _$_TransactionInvalid> + implements _$$_TransactionInvalidCopyWith<$Res> { + __$$_TransactionInvalidCopyWithImpl( + _$_TransactionInvalid _value, $Res Function(_$_TransactionInvalid) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_TransactionInvalid extends _TransactionInvalid { + const _$_TransactionInvalid() : super._(); + + @override + String toString() { + return 'TransactionError.invalidTransaction()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_TransactionInvalid); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() timeout, + required TResult Function() connectivity, + required TResult Function() consensusNotReached, + required TResult Function() invalidTransaction, + required TResult Function() invalidConfirmation, + required TResult Function() insufficientFunds, + required TResult Function() serviceNotFound, + required TResult Function() serviceAlreadyExists, + required TResult Function() userRejected, + required TResult Function(String accountName) unknownAccount, + required TResult Function(String? reason) other, + }) { + return invalidTransaction(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? timeout, + TResult? Function()? connectivity, + TResult? Function()? consensusNotReached, + TResult? Function()? invalidTransaction, + TResult? Function()? invalidConfirmation, + TResult? Function()? insufficientFunds, + TResult? Function()? serviceNotFound, + TResult? Function()? serviceAlreadyExists, + TResult? Function()? userRejected, + TResult? Function(String accountName)? unknownAccount, + TResult? Function(String? reason)? other, + }) { + return invalidTransaction?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? timeout, + TResult Function()? connectivity, + TResult Function()? consensusNotReached, + TResult Function()? invalidTransaction, + TResult Function()? invalidConfirmation, + TResult Function()? insufficientFunds, + TResult Function()? serviceNotFound, + TResult Function()? serviceAlreadyExists, + TResult Function()? userRejected, + TResult Function(String accountName)? unknownAccount, + TResult Function(String? reason)? other, + required TResult orElse(), + }) { + if (invalidTransaction != null) { + return invalidTransaction(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_TransactionTimeout value) timeout, + required TResult Function(_TransactionConnectionError value) connectivity, + required TResult Function(_TransactionConsensusNotReachedError value) + consensusNotReached, + required TResult Function(_TransactionInvalid value) invalidTransaction, + required TResult Function(_TransactionInvalidConfirmation value) + invalidConfirmation, + required TResult Function(_TransactionInsufficientFunds value) + insufficientFunds, + required TResult Function(_TransactionServiceNotFound value) + serviceNotFound, + required TResult Function(_TransactionServiceAlreadyExists value) + serviceAlreadyExists, + required TResult Function(_TransactionUserRejected value) userRejected, + required TResult Function(_TransactionUnknownAccount value) unknownAccount, + required TResult Function(_TransactionOtherError value) other, + }) { + return invalidTransaction(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_TransactionTimeout value)? timeout, + TResult? Function(_TransactionConnectionError value)? connectivity, + TResult? Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult? Function(_TransactionInvalid value)? invalidTransaction, + TResult? Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult? Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult? Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult? Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult? Function(_TransactionUserRejected value)? userRejected, + TResult? Function(_TransactionUnknownAccount value)? unknownAccount, + TResult? Function(_TransactionOtherError value)? other, + }) { + return invalidTransaction?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_TransactionTimeout value)? timeout, + TResult Function(_TransactionConnectionError value)? connectivity, + TResult Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult Function(_TransactionInvalid value)? invalidTransaction, + TResult Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult Function(_TransactionUserRejected value)? userRejected, + TResult Function(_TransactionUnknownAccount value)? unknownAccount, + TResult Function(_TransactionOtherError value)? other, + required TResult orElse(), + }) { + if (invalidTransaction != null) { + return invalidTransaction(this); + } + return orElse(); + } +} + +abstract class _TransactionInvalid extends TransactionError { + const factory _TransactionInvalid() = _$_TransactionInvalid; + const _TransactionInvalid._() : super._(); +} + +/// @nodoc +abstract class _$$_TransactionInvalidConfirmationCopyWith<$Res> { + factory _$$_TransactionInvalidConfirmationCopyWith( + _$_TransactionInvalidConfirmation value, + $Res Function(_$_TransactionInvalidConfirmation) then) = + __$$_TransactionInvalidConfirmationCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_TransactionInvalidConfirmationCopyWithImpl<$Res> + extends _$TransactionErrorCopyWithImpl<$Res, + _$_TransactionInvalidConfirmation> + implements _$$_TransactionInvalidConfirmationCopyWith<$Res> { + __$$_TransactionInvalidConfirmationCopyWithImpl( + _$_TransactionInvalidConfirmation _value, + $Res Function(_$_TransactionInvalidConfirmation) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_TransactionInvalidConfirmation + extends _TransactionInvalidConfirmation { + const _$_TransactionInvalidConfirmation() : super._(); + + @override + String toString() { + return 'TransactionError.invalidConfirmation()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_TransactionInvalidConfirmation); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() timeout, + required TResult Function() connectivity, + required TResult Function() consensusNotReached, + required TResult Function() invalidTransaction, + required TResult Function() invalidConfirmation, + required TResult Function() insufficientFunds, + required TResult Function() serviceNotFound, + required TResult Function() serviceAlreadyExists, + required TResult Function() userRejected, + required TResult Function(String accountName) unknownAccount, + required TResult Function(String? reason) other, + }) { + return invalidConfirmation(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? timeout, + TResult? Function()? connectivity, + TResult? Function()? consensusNotReached, + TResult? Function()? invalidTransaction, + TResult? Function()? invalidConfirmation, + TResult? Function()? insufficientFunds, + TResult? Function()? serviceNotFound, + TResult? Function()? serviceAlreadyExists, + TResult? Function()? userRejected, + TResult? Function(String accountName)? unknownAccount, + TResult? Function(String? reason)? other, + }) { + return invalidConfirmation?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? timeout, + TResult Function()? connectivity, + TResult Function()? consensusNotReached, + TResult Function()? invalidTransaction, + TResult Function()? invalidConfirmation, + TResult Function()? insufficientFunds, + TResult Function()? serviceNotFound, + TResult Function()? serviceAlreadyExists, + TResult Function()? userRejected, + TResult Function(String accountName)? unknownAccount, + TResult Function(String? reason)? other, + required TResult orElse(), + }) { + if (invalidConfirmation != null) { + return invalidConfirmation(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_TransactionTimeout value) timeout, + required TResult Function(_TransactionConnectionError value) connectivity, + required TResult Function(_TransactionConsensusNotReachedError value) + consensusNotReached, + required TResult Function(_TransactionInvalid value) invalidTransaction, + required TResult Function(_TransactionInvalidConfirmation value) + invalidConfirmation, + required TResult Function(_TransactionInsufficientFunds value) + insufficientFunds, + required TResult Function(_TransactionServiceNotFound value) + serviceNotFound, + required TResult Function(_TransactionServiceAlreadyExists value) + serviceAlreadyExists, + required TResult Function(_TransactionUserRejected value) userRejected, + required TResult Function(_TransactionUnknownAccount value) unknownAccount, + required TResult Function(_TransactionOtherError value) other, + }) { + return invalidConfirmation(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_TransactionTimeout value)? timeout, + TResult? Function(_TransactionConnectionError value)? connectivity, + TResult? Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult? Function(_TransactionInvalid value)? invalidTransaction, + TResult? Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult? Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult? Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult? Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult? Function(_TransactionUserRejected value)? userRejected, + TResult? Function(_TransactionUnknownAccount value)? unknownAccount, + TResult? Function(_TransactionOtherError value)? other, + }) { + return invalidConfirmation?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_TransactionTimeout value)? timeout, + TResult Function(_TransactionConnectionError value)? connectivity, + TResult Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult Function(_TransactionInvalid value)? invalidTransaction, + TResult Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult Function(_TransactionUserRejected value)? userRejected, + TResult Function(_TransactionUnknownAccount value)? unknownAccount, + TResult Function(_TransactionOtherError value)? other, + required TResult orElse(), + }) { + if (invalidConfirmation != null) { + return invalidConfirmation(this); + } + return orElse(); + } +} + +abstract class _TransactionInvalidConfirmation extends TransactionError { + const factory _TransactionInvalidConfirmation() = + _$_TransactionInvalidConfirmation; + const _TransactionInvalidConfirmation._() : super._(); +} + +/// @nodoc +abstract class _$$_TransactionInsufficientFundsCopyWith<$Res> { + factory _$$_TransactionInsufficientFundsCopyWith( + _$_TransactionInsufficientFunds value, + $Res Function(_$_TransactionInsufficientFunds) then) = + __$$_TransactionInsufficientFundsCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_TransactionInsufficientFundsCopyWithImpl<$Res> + extends _$TransactionErrorCopyWithImpl<$Res, + _$_TransactionInsufficientFunds> + implements _$$_TransactionInsufficientFundsCopyWith<$Res> { + __$$_TransactionInsufficientFundsCopyWithImpl( + _$_TransactionInsufficientFunds _value, + $Res Function(_$_TransactionInsufficientFunds) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_TransactionInsufficientFunds extends _TransactionInsufficientFunds { + const _$_TransactionInsufficientFunds() : super._(); + + @override + String toString() { + return 'TransactionError.insufficientFunds()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_TransactionInsufficientFunds); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() timeout, + required TResult Function() connectivity, + required TResult Function() consensusNotReached, + required TResult Function() invalidTransaction, + required TResult Function() invalidConfirmation, + required TResult Function() insufficientFunds, + required TResult Function() serviceNotFound, + required TResult Function() serviceAlreadyExists, + required TResult Function() userRejected, + required TResult Function(String accountName) unknownAccount, + required TResult Function(String? reason) other, + }) { + return insufficientFunds(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? timeout, + TResult? Function()? connectivity, + TResult? Function()? consensusNotReached, + TResult? Function()? invalidTransaction, + TResult? Function()? invalidConfirmation, + TResult? Function()? insufficientFunds, + TResult? Function()? serviceNotFound, + TResult? Function()? serviceAlreadyExists, + TResult? Function()? userRejected, + TResult? Function(String accountName)? unknownAccount, + TResult? Function(String? reason)? other, + }) { + return insufficientFunds?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? timeout, + TResult Function()? connectivity, + TResult Function()? consensusNotReached, + TResult Function()? invalidTransaction, + TResult Function()? invalidConfirmation, + TResult Function()? insufficientFunds, + TResult Function()? serviceNotFound, + TResult Function()? serviceAlreadyExists, + TResult Function()? userRejected, + TResult Function(String accountName)? unknownAccount, + TResult Function(String? reason)? other, + required TResult orElse(), + }) { + if (insufficientFunds != null) { + return insufficientFunds(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_TransactionTimeout value) timeout, + required TResult Function(_TransactionConnectionError value) connectivity, + required TResult Function(_TransactionConsensusNotReachedError value) + consensusNotReached, + required TResult Function(_TransactionInvalid value) invalidTransaction, + required TResult Function(_TransactionInvalidConfirmation value) + invalidConfirmation, + required TResult Function(_TransactionInsufficientFunds value) + insufficientFunds, + required TResult Function(_TransactionServiceNotFound value) + serviceNotFound, + required TResult Function(_TransactionServiceAlreadyExists value) + serviceAlreadyExists, + required TResult Function(_TransactionUserRejected value) userRejected, + required TResult Function(_TransactionUnknownAccount value) unknownAccount, + required TResult Function(_TransactionOtherError value) other, + }) { + return insufficientFunds(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_TransactionTimeout value)? timeout, + TResult? Function(_TransactionConnectionError value)? connectivity, + TResult? Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult? Function(_TransactionInvalid value)? invalidTransaction, + TResult? Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult? Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult? Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult? Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult? Function(_TransactionUserRejected value)? userRejected, + TResult? Function(_TransactionUnknownAccount value)? unknownAccount, + TResult? Function(_TransactionOtherError value)? other, + }) { + return insufficientFunds?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_TransactionTimeout value)? timeout, + TResult Function(_TransactionConnectionError value)? connectivity, + TResult Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult Function(_TransactionInvalid value)? invalidTransaction, + TResult Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult Function(_TransactionUserRejected value)? userRejected, + TResult Function(_TransactionUnknownAccount value)? unknownAccount, + TResult Function(_TransactionOtherError value)? other, + required TResult orElse(), + }) { + if (insufficientFunds != null) { + return insufficientFunds(this); + } + return orElse(); + } +} + +abstract class _TransactionInsufficientFunds extends TransactionError { + const factory _TransactionInsufficientFunds() = + _$_TransactionInsufficientFunds; + const _TransactionInsufficientFunds._() : super._(); +} + +/// @nodoc +abstract class _$$_TransactionServiceNotFoundCopyWith<$Res> { + factory _$$_TransactionServiceNotFoundCopyWith( + _$_TransactionServiceNotFound value, + $Res Function(_$_TransactionServiceNotFound) then) = + __$$_TransactionServiceNotFoundCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_TransactionServiceNotFoundCopyWithImpl<$Res> + extends _$TransactionErrorCopyWithImpl<$Res, _$_TransactionServiceNotFound> + implements _$$_TransactionServiceNotFoundCopyWith<$Res> { + __$$_TransactionServiceNotFoundCopyWithImpl( + _$_TransactionServiceNotFound _value, + $Res Function(_$_TransactionServiceNotFound) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_TransactionServiceNotFound extends _TransactionServiceNotFound { + const _$_TransactionServiceNotFound() : super._(); + + @override + String toString() { + return 'TransactionError.serviceNotFound()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_TransactionServiceNotFound); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() timeout, + required TResult Function() connectivity, + required TResult Function() consensusNotReached, + required TResult Function() invalidTransaction, + required TResult Function() invalidConfirmation, + required TResult Function() insufficientFunds, + required TResult Function() serviceNotFound, + required TResult Function() serviceAlreadyExists, + required TResult Function() userRejected, + required TResult Function(String accountName) unknownAccount, + required TResult Function(String? reason) other, + }) { + return serviceNotFound(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? timeout, + TResult? Function()? connectivity, + TResult? Function()? consensusNotReached, + TResult? Function()? invalidTransaction, + TResult? Function()? invalidConfirmation, + TResult? Function()? insufficientFunds, + TResult? Function()? serviceNotFound, + TResult? Function()? serviceAlreadyExists, + TResult? Function()? userRejected, + TResult? Function(String accountName)? unknownAccount, + TResult? Function(String? reason)? other, + }) { + return serviceNotFound?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? timeout, + TResult Function()? connectivity, + TResult Function()? consensusNotReached, + TResult Function()? invalidTransaction, + TResult Function()? invalidConfirmation, + TResult Function()? insufficientFunds, + TResult Function()? serviceNotFound, + TResult Function()? serviceAlreadyExists, + TResult Function()? userRejected, + TResult Function(String accountName)? unknownAccount, + TResult Function(String? reason)? other, + required TResult orElse(), + }) { + if (serviceNotFound != null) { + return serviceNotFound(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_TransactionTimeout value) timeout, + required TResult Function(_TransactionConnectionError value) connectivity, + required TResult Function(_TransactionConsensusNotReachedError value) + consensusNotReached, + required TResult Function(_TransactionInvalid value) invalidTransaction, + required TResult Function(_TransactionInvalidConfirmation value) + invalidConfirmation, + required TResult Function(_TransactionInsufficientFunds value) + insufficientFunds, + required TResult Function(_TransactionServiceNotFound value) + serviceNotFound, + required TResult Function(_TransactionServiceAlreadyExists value) + serviceAlreadyExists, + required TResult Function(_TransactionUserRejected value) userRejected, + required TResult Function(_TransactionUnknownAccount value) unknownAccount, + required TResult Function(_TransactionOtherError value) other, + }) { + return serviceNotFound(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_TransactionTimeout value)? timeout, + TResult? Function(_TransactionConnectionError value)? connectivity, + TResult? Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult? Function(_TransactionInvalid value)? invalidTransaction, + TResult? Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult? Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult? Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult? Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult? Function(_TransactionUserRejected value)? userRejected, + TResult? Function(_TransactionUnknownAccount value)? unknownAccount, + TResult? Function(_TransactionOtherError value)? other, + }) { + return serviceNotFound?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_TransactionTimeout value)? timeout, + TResult Function(_TransactionConnectionError value)? connectivity, + TResult Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult Function(_TransactionInvalid value)? invalidTransaction, + TResult Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult Function(_TransactionUserRejected value)? userRejected, + TResult Function(_TransactionUnknownAccount value)? unknownAccount, + TResult Function(_TransactionOtherError value)? other, + required TResult orElse(), + }) { + if (serviceNotFound != null) { + return serviceNotFound(this); + } + return orElse(); + } +} + +abstract class _TransactionServiceNotFound extends TransactionError { + const factory _TransactionServiceNotFound() = _$_TransactionServiceNotFound; + const _TransactionServiceNotFound._() : super._(); +} + +/// @nodoc +abstract class _$$_TransactionServiceAlreadyExistsCopyWith<$Res> { + factory _$$_TransactionServiceAlreadyExistsCopyWith( + _$_TransactionServiceAlreadyExists value, + $Res Function(_$_TransactionServiceAlreadyExists) then) = + __$$_TransactionServiceAlreadyExistsCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_TransactionServiceAlreadyExistsCopyWithImpl<$Res> + extends _$TransactionErrorCopyWithImpl<$Res, + _$_TransactionServiceAlreadyExists> + implements _$$_TransactionServiceAlreadyExistsCopyWith<$Res> { + __$$_TransactionServiceAlreadyExistsCopyWithImpl( + _$_TransactionServiceAlreadyExists _value, + $Res Function(_$_TransactionServiceAlreadyExists) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_TransactionServiceAlreadyExists + extends _TransactionServiceAlreadyExists { + const _$_TransactionServiceAlreadyExists() : super._(); + + @override + String toString() { + return 'TransactionError.serviceAlreadyExists()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_TransactionServiceAlreadyExists); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() timeout, + required TResult Function() connectivity, + required TResult Function() consensusNotReached, + required TResult Function() invalidTransaction, + required TResult Function() invalidConfirmation, + required TResult Function() insufficientFunds, + required TResult Function() serviceNotFound, + required TResult Function() serviceAlreadyExists, + required TResult Function() userRejected, + required TResult Function(String accountName) unknownAccount, + required TResult Function(String? reason) other, + }) { + return serviceAlreadyExists(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? timeout, + TResult? Function()? connectivity, + TResult? Function()? consensusNotReached, + TResult? Function()? invalidTransaction, + TResult? Function()? invalidConfirmation, + TResult? Function()? insufficientFunds, + TResult? Function()? serviceNotFound, + TResult? Function()? serviceAlreadyExists, + TResult? Function()? userRejected, + TResult? Function(String accountName)? unknownAccount, + TResult? Function(String? reason)? other, + }) { + return serviceAlreadyExists?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? timeout, + TResult Function()? connectivity, + TResult Function()? consensusNotReached, + TResult Function()? invalidTransaction, + TResult Function()? invalidConfirmation, + TResult Function()? insufficientFunds, + TResult Function()? serviceNotFound, + TResult Function()? serviceAlreadyExists, + TResult Function()? userRejected, + TResult Function(String accountName)? unknownAccount, + TResult Function(String? reason)? other, + required TResult orElse(), + }) { + if (serviceAlreadyExists != null) { + return serviceAlreadyExists(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_TransactionTimeout value) timeout, + required TResult Function(_TransactionConnectionError value) connectivity, + required TResult Function(_TransactionConsensusNotReachedError value) + consensusNotReached, + required TResult Function(_TransactionInvalid value) invalidTransaction, + required TResult Function(_TransactionInvalidConfirmation value) + invalidConfirmation, + required TResult Function(_TransactionInsufficientFunds value) + insufficientFunds, + required TResult Function(_TransactionServiceNotFound value) + serviceNotFound, + required TResult Function(_TransactionServiceAlreadyExists value) + serviceAlreadyExists, + required TResult Function(_TransactionUserRejected value) userRejected, + required TResult Function(_TransactionUnknownAccount value) unknownAccount, + required TResult Function(_TransactionOtherError value) other, + }) { + return serviceAlreadyExists(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_TransactionTimeout value)? timeout, + TResult? Function(_TransactionConnectionError value)? connectivity, + TResult? Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult? Function(_TransactionInvalid value)? invalidTransaction, + TResult? Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult? Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult? Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult? Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult? Function(_TransactionUserRejected value)? userRejected, + TResult? Function(_TransactionUnknownAccount value)? unknownAccount, + TResult? Function(_TransactionOtherError value)? other, + }) { + return serviceAlreadyExists?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_TransactionTimeout value)? timeout, + TResult Function(_TransactionConnectionError value)? connectivity, + TResult Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult Function(_TransactionInvalid value)? invalidTransaction, + TResult Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult Function(_TransactionUserRejected value)? userRejected, + TResult Function(_TransactionUnknownAccount value)? unknownAccount, + TResult Function(_TransactionOtherError value)? other, + required TResult orElse(), + }) { + if (serviceAlreadyExists != null) { + return serviceAlreadyExists(this); + } + return orElse(); + } +} + +abstract class _TransactionServiceAlreadyExists extends TransactionError { + const factory _TransactionServiceAlreadyExists() = + _$_TransactionServiceAlreadyExists; + const _TransactionServiceAlreadyExists._() : super._(); +} + +/// @nodoc +abstract class _$$_TransactionUserRejectedCopyWith<$Res> { + factory _$$_TransactionUserRejectedCopyWith(_$_TransactionUserRejected value, + $Res Function(_$_TransactionUserRejected) then) = + __$$_TransactionUserRejectedCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_TransactionUserRejectedCopyWithImpl<$Res> + extends _$TransactionErrorCopyWithImpl<$Res, _$_TransactionUserRejected> + implements _$$_TransactionUserRejectedCopyWith<$Res> { + __$$_TransactionUserRejectedCopyWithImpl(_$_TransactionUserRejected _value, + $Res Function(_$_TransactionUserRejected) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_TransactionUserRejected extends _TransactionUserRejected { + const _$_TransactionUserRejected() : super._(); + + @override + String toString() { + return 'TransactionError.userRejected()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_TransactionUserRejected); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() timeout, + required TResult Function() connectivity, + required TResult Function() consensusNotReached, + required TResult Function() invalidTransaction, + required TResult Function() invalidConfirmation, + required TResult Function() insufficientFunds, + required TResult Function() serviceNotFound, + required TResult Function() serviceAlreadyExists, + required TResult Function() userRejected, + required TResult Function(String accountName) unknownAccount, + required TResult Function(String? reason) other, + }) { + return userRejected(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? timeout, + TResult? Function()? connectivity, + TResult? Function()? consensusNotReached, + TResult? Function()? invalidTransaction, + TResult? Function()? invalidConfirmation, + TResult? Function()? insufficientFunds, + TResult? Function()? serviceNotFound, + TResult? Function()? serviceAlreadyExists, + TResult? Function()? userRejected, + TResult? Function(String accountName)? unknownAccount, + TResult? Function(String? reason)? other, + }) { + return userRejected?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? timeout, + TResult Function()? connectivity, + TResult Function()? consensusNotReached, + TResult Function()? invalidTransaction, + TResult Function()? invalidConfirmation, + TResult Function()? insufficientFunds, + TResult Function()? serviceNotFound, + TResult Function()? serviceAlreadyExists, + TResult Function()? userRejected, + TResult Function(String accountName)? unknownAccount, + TResult Function(String? reason)? other, + required TResult orElse(), + }) { + if (userRejected != null) { + return userRejected(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_TransactionTimeout value) timeout, + required TResult Function(_TransactionConnectionError value) connectivity, + required TResult Function(_TransactionConsensusNotReachedError value) + consensusNotReached, + required TResult Function(_TransactionInvalid value) invalidTransaction, + required TResult Function(_TransactionInvalidConfirmation value) + invalidConfirmation, + required TResult Function(_TransactionInsufficientFunds value) + insufficientFunds, + required TResult Function(_TransactionServiceNotFound value) + serviceNotFound, + required TResult Function(_TransactionServiceAlreadyExists value) + serviceAlreadyExists, + required TResult Function(_TransactionUserRejected value) userRejected, + required TResult Function(_TransactionUnknownAccount value) unknownAccount, + required TResult Function(_TransactionOtherError value) other, + }) { + return userRejected(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_TransactionTimeout value)? timeout, + TResult? Function(_TransactionConnectionError value)? connectivity, + TResult? Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult? Function(_TransactionInvalid value)? invalidTransaction, + TResult? Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult? Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult? Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult? Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult? Function(_TransactionUserRejected value)? userRejected, + TResult? Function(_TransactionUnknownAccount value)? unknownAccount, + TResult? Function(_TransactionOtherError value)? other, + }) { + return userRejected?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_TransactionTimeout value)? timeout, + TResult Function(_TransactionConnectionError value)? connectivity, + TResult Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult Function(_TransactionInvalid value)? invalidTransaction, + TResult Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult Function(_TransactionUserRejected value)? userRejected, + TResult Function(_TransactionUnknownAccount value)? unknownAccount, + TResult Function(_TransactionOtherError value)? other, + required TResult orElse(), + }) { + if (userRejected != null) { + return userRejected(this); + } + return orElse(); + } +} + +abstract class _TransactionUserRejected extends TransactionError { + const factory _TransactionUserRejected() = _$_TransactionUserRejected; + const _TransactionUserRejected._() : super._(); +} + +/// @nodoc +abstract class _$$_TransactionUnknownAccountCopyWith<$Res> { + factory _$$_TransactionUnknownAccountCopyWith( + _$_TransactionUnknownAccount value, + $Res Function(_$_TransactionUnknownAccount) then) = + __$$_TransactionUnknownAccountCopyWithImpl<$Res>; + @useResult + $Res call({String accountName}); +} + +/// @nodoc +class __$$_TransactionUnknownAccountCopyWithImpl<$Res> + extends _$TransactionErrorCopyWithImpl<$Res, _$_TransactionUnknownAccount> + implements _$$_TransactionUnknownAccountCopyWith<$Res> { + __$$_TransactionUnknownAccountCopyWithImpl( + _$_TransactionUnknownAccount _value, + $Res Function(_$_TransactionUnknownAccount) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? accountName = null, + }) { + return _then(_$_TransactionUnknownAccount( + accountName: null == accountName + ? _value.accountName + : accountName // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$_TransactionUnknownAccount extends _TransactionUnknownAccount { + const _$_TransactionUnknownAccount({required this.accountName}) : super._(); + + @override + final String accountName; + + @override + String toString() { + return 'TransactionError.unknownAccount(accountName: $accountName)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_TransactionUnknownAccount && + (identical(other.accountName, accountName) || + other.accountName == accountName)); + } + + @override + int get hashCode => Object.hash(runtimeType, accountName); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_TransactionUnknownAccountCopyWith<_$_TransactionUnknownAccount> + get copyWith => __$$_TransactionUnknownAccountCopyWithImpl< + _$_TransactionUnknownAccount>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() timeout, + required TResult Function() connectivity, + required TResult Function() consensusNotReached, + required TResult Function() invalidTransaction, + required TResult Function() invalidConfirmation, + required TResult Function() insufficientFunds, + required TResult Function() serviceNotFound, + required TResult Function() serviceAlreadyExists, + required TResult Function() userRejected, + required TResult Function(String accountName) unknownAccount, + required TResult Function(String? reason) other, + }) { + return unknownAccount(accountName); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? timeout, + TResult? Function()? connectivity, + TResult? Function()? consensusNotReached, + TResult? Function()? invalidTransaction, + TResult? Function()? invalidConfirmation, + TResult? Function()? insufficientFunds, + TResult? Function()? serviceNotFound, + TResult? Function()? serviceAlreadyExists, + TResult? Function()? userRejected, + TResult? Function(String accountName)? unknownAccount, + TResult? Function(String? reason)? other, + }) { + return unknownAccount?.call(accountName); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? timeout, + TResult Function()? connectivity, + TResult Function()? consensusNotReached, + TResult Function()? invalidTransaction, + TResult Function()? invalidConfirmation, + TResult Function()? insufficientFunds, + TResult Function()? serviceNotFound, + TResult Function()? serviceAlreadyExists, + TResult Function()? userRejected, + TResult Function(String accountName)? unknownAccount, + TResult Function(String? reason)? other, + required TResult orElse(), + }) { + if (unknownAccount != null) { + return unknownAccount(accountName); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_TransactionTimeout value) timeout, + required TResult Function(_TransactionConnectionError value) connectivity, + required TResult Function(_TransactionConsensusNotReachedError value) + consensusNotReached, + required TResult Function(_TransactionInvalid value) invalidTransaction, + required TResult Function(_TransactionInvalidConfirmation value) + invalidConfirmation, + required TResult Function(_TransactionInsufficientFunds value) + insufficientFunds, + required TResult Function(_TransactionServiceNotFound value) + serviceNotFound, + required TResult Function(_TransactionServiceAlreadyExists value) + serviceAlreadyExists, + required TResult Function(_TransactionUserRejected value) userRejected, + required TResult Function(_TransactionUnknownAccount value) unknownAccount, + required TResult Function(_TransactionOtherError value) other, + }) { + return unknownAccount(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_TransactionTimeout value)? timeout, + TResult? Function(_TransactionConnectionError value)? connectivity, + TResult? Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult? Function(_TransactionInvalid value)? invalidTransaction, + TResult? Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult? Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult? Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult? Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult? Function(_TransactionUserRejected value)? userRejected, + TResult? Function(_TransactionUnknownAccount value)? unknownAccount, + TResult? Function(_TransactionOtherError value)? other, + }) { + return unknownAccount?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_TransactionTimeout value)? timeout, + TResult Function(_TransactionConnectionError value)? connectivity, + TResult Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult Function(_TransactionInvalid value)? invalidTransaction, + TResult Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult Function(_TransactionUserRejected value)? userRejected, + TResult Function(_TransactionUnknownAccount value)? unknownAccount, + TResult Function(_TransactionOtherError value)? other, + required TResult orElse(), + }) { + if (unknownAccount != null) { + return unknownAccount(this); + } + return orElse(); + } +} + +abstract class _TransactionUnknownAccount extends TransactionError { + const factory _TransactionUnknownAccount( + {required final String accountName}) = _$_TransactionUnknownAccount; + const _TransactionUnknownAccount._() : super._(); + + String get accountName; + @JsonKey(ignore: true) + _$$_TransactionUnknownAccountCopyWith<_$_TransactionUnknownAccount> + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$_TransactionOtherErrorCopyWith<$Res> { + factory _$$_TransactionOtherErrorCopyWith(_$_TransactionOtherError value, + $Res Function(_$_TransactionOtherError) then) = + __$$_TransactionOtherErrorCopyWithImpl<$Res>; + @useResult + $Res call({String? reason}); +} + +/// @nodoc +class __$$_TransactionOtherErrorCopyWithImpl<$Res> + extends _$TransactionErrorCopyWithImpl<$Res, _$_TransactionOtherError> + implements _$$_TransactionOtherErrorCopyWith<$Res> { + __$$_TransactionOtherErrorCopyWithImpl(_$_TransactionOtherError _value, + $Res Function(_$_TransactionOtherError) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? reason = freezed, + }) { + return _then(_$_TransactionOtherError( + reason: freezed == reason + ? _value.reason + : reason // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc + +class _$_TransactionOtherError extends _TransactionOtherError { + const _$_TransactionOtherError({this.reason}) : super._(); + + @override + final String? reason; + + @override + String toString() { + return 'TransactionError.other(reason: $reason)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_TransactionOtherError && + (identical(other.reason, reason) || other.reason == reason)); + } + + @override + int get hashCode => Object.hash(runtimeType, reason); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_TransactionOtherErrorCopyWith<_$_TransactionOtherError> get copyWith => + __$$_TransactionOtherErrorCopyWithImpl<_$_TransactionOtherError>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() timeout, + required TResult Function() connectivity, + required TResult Function() consensusNotReached, + required TResult Function() invalidTransaction, + required TResult Function() invalidConfirmation, + required TResult Function() insufficientFunds, + required TResult Function() serviceNotFound, + required TResult Function() serviceAlreadyExists, + required TResult Function() userRejected, + required TResult Function(String accountName) unknownAccount, + required TResult Function(String? reason) other, + }) { + return other(reason); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? timeout, + TResult? Function()? connectivity, + TResult? Function()? consensusNotReached, + TResult? Function()? invalidTransaction, + TResult? Function()? invalidConfirmation, + TResult? Function()? insufficientFunds, + TResult? Function()? serviceNotFound, + TResult? Function()? serviceAlreadyExists, + TResult? Function()? userRejected, + TResult? Function(String accountName)? unknownAccount, + TResult? Function(String? reason)? other, + }) { + return other?.call(reason); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? timeout, + TResult Function()? connectivity, + TResult Function()? consensusNotReached, + TResult Function()? invalidTransaction, + TResult Function()? invalidConfirmation, + TResult Function()? insufficientFunds, + TResult Function()? serviceNotFound, + TResult Function()? serviceAlreadyExists, + TResult Function()? userRejected, + TResult Function(String accountName)? unknownAccount, + TResult Function(String? reason)? other, + required TResult orElse(), + }) { + if (other != null) { + return other(reason); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_TransactionTimeout value) timeout, + required TResult Function(_TransactionConnectionError value) connectivity, + required TResult Function(_TransactionConsensusNotReachedError value) + consensusNotReached, + required TResult Function(_TransactionInvalid value) invalidTransaction, + required TResult Function(_TransactionInvalidConfirmation value) + invalidConfirmation, + required TResult Function(_TransactionInsufficientFunds value) + insufficientFunds, + required TResult Function(_TransactionServiceNotFound value) + serviceNotFound, + required TResult Function(_TransactionServiceAlreadyExists value) + serviceAlreadyExists, + required TResult Function(_TransactionUserRejected value) userRejected, + required TResult Function(_TransactionUnknownAccount value) unknownAccount, + required TResult Function(_TransactionOtherError value) other, + }) { + return other(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_TransactionTimeout value)? timeout, + TResult? Function(_TransactionConnectionError value)? connectivity, + TResult? Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult? Function(_TransactionInvalid value)? invalidTransaction, + TResult? Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult? Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult? Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult? Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult? Function(_TransactionUserRejected value)? userRejected, + TResult? Function(_TransactionUnknownAccount value)? unknownAccount, + TResult? Function(_TransactionOtherError value)? other, + }) { + return other?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_TransactionTimeout value)? timeout, + TResult Function(_TransactionConnectionError value)? connectivity, + TResult Function(_TransactionConsensusNotReachedError value)? + consensusNotReached, + TResult Function(_TransactionInvalid value)? invalidTransaction, + TResult Function(_TransactionInvalidConfirmation value)? + invalidConfirmation, + TResult Function(_TransactionInsufficientFunds value)? insufficientFunds, + TResult Function(_TransactionServiceNotFound value)? serviceNotFound, + TResult Function(_TransactionServiceAlreadyExists value)? + serviceAlreadyExists, + TResult Function(_TransactionUserRejected value)? userRejected, + TResult Function(_TransactionUnknownAccount value)? unknownAccount, + TResult Function(_TransactionOtherError value)? other, + required TResult orElse(), + }) { + if (other != null) { + return other(this); + } + return orElse(); + } +} + +abstract class _TransactionOtherError extends TransactionError { + const factory _TransactionOtherError({final String? reason}) = + _$_TransactionOtherError; + const _TransactionOtherError._() : super._(); + + String? get reason; + @JsonKey(ignore: true) + _$$_TransactionOtherErrorCopyWith<_$_TransactionOtherError> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$TransactionConfirmation { + String get transactionAddress => throw _privateConstructorUsedError; + int get nbConfirmations => throw _privateConstructorUsedError; + int get maxConfirmations => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $TransactionConfirmationCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $TransactionConfirmationCopyWith<$Res> { + factory $TransactionConfirmationCopyWith(TransactionConfirmation value, + $Res Function(TransactionConfirmation) then) = + _$TransactionConfirmationCopyWithImpl<$Res, TransactionConfirmation>; + @useResult + $Res call( + {String transactionAddress, int nbConfirmations, int maxConfirmations}); +} + +/// @nodoc +class _$TransactionConfirmationCopyWithImpl<$Res, + $Val extends TransactionConfirmation> + implements $TransactionConfirmationCopyWith<$Res> { + _$TransactionConfirmationCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? transactionAddress = null, + Object? nbConfirmations = null, + Object? maxConfirmations = null, + }) { + return _then(_value.copyWith( + transactionAddress: null == transactionAddress + ? _value.transactionAddress + : transactionAddress // ignore: cast_nullable_to_non_nullable + as String, + nbConfirmations: null == nbConfirmations + ? _value.nbConfirmations + : nbConfirmations // ignore: cast_nullable_to_non_nullable + as int, + maxConfirmations: null == maxConfirmations + ? _value.maxConfirmations + : maxConfirmations // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$_TransactionConfirmationCopyWith<$Res> + implements $TransactionConfirmationCopyWith<$Res> { + factory _$$_TransactionConfirmationCopyWith(_$_TransactionConfirmation value, + $Res Function(_$_TransactionConfirmation) then) = + __$$_TransactionConfirmationCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String transactionAddress, int nbConfirmations, int maxConfirmations}); +} + +/// @nodoc +class __$$_TransactionConfirmationCopyWithImpl<$Res> + extends _$TransactionConfirmationCopyWithImpl<$Res, + _$_TransactionConfirmation> + implements _$$_TransactionConfirmationCopyWith<$Res> { + __$$_TransactionConfirmationCopyWithImpl(_$_TransactionConfirmation _value, + $Res Function(_$_TransactionConfirmation) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? transactionAddress = null, + Object? nbConfirmations = null, + Object? maxConfirmations = null, + }) { + return _then(_$_TransactionConfirmation( + transactionAddress: null == transactionAddress + ? _value.transactionAddress + : transactionAddress // ignore: cast_nullable_to_non_nullable + as String, + nbConfirmations: null == nbConfirmations + ? _value.nbConfirmations + : nbConfirmations // ignore: cast_nullable_to_non_nullable + as int, + maxConfirmations: null == maxConfirmations + ? _value.maxConfirmations + : maxConfirmations // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc + +class _$_TransactionConfirmation extends _TransactionConfirmation { + const _$_TransactionConfirmation( + {required this.transactionAddress, + this.nbConfirmations = 0, + this.maxConfirmations = 0}) + : super._(); + + @override + final String transactionAddress; + @override + @JsonKey() + final int nbConfirmations; + @override + @JsonKey() + final int maxConfirmations; + + @override + String toString() { + return 'TransactionConfirmation(transactionAddress: $transactionAddress, nbConfirmations: $nbConfirmations, maxConfirmations: $maxConfirmations)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_TransactionConfirmation && + (identical(other.transactionAddress, transactionAddress) || + other.transactionAddress == transactionAddress) && + (identical(other.nbConfirmations, nbConfirmations) || + other.nbConfirmations == nbConfirmations) && + (identical(other.maxConfirmations, maxConfirmations) || + other.maxConfirmations == maxConfirmations)); + } + + @override + int get hashCode => Object.hash( + runtimeType, transactionAddress, nbConfirmations, maxConfirmations); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_TransactionConfirmationCopyWith<_$_TransactionConfirmation> + get copyWith => + __$$_TransactionConfirmationCopyWithImpl<_$_TransactionConfirmation>( + this, _$identity); +} + +abstract class _TransactionConfirmation extends TransactionConfirmation { + const factory _TransactionConfirmation( + {required final String transactionAddress, + final int nbConfirmations, + final int maxConfirmations}) = _$_TransactionConfirmation; + const _TransactionConfirmation._() : super._(); + + @override + String get transactionAddress; + @override + int get nbConfirmations; + @override + int get maxConfirmations; + @override + @JsonKey(ignore: true) + _$$_TransactionConfirmationCopyWith<_$_TransactionConfirmation> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/src/utils/confirmations/transaction_remote.dart b/lib/src/utils/confirmations/transaction_remote.dart new file mode 100644 index 00000000..30239ebf --- /dev/null +++ b/lib/src/utils/confirmations/transaction_remote.dart @@ -0,0 +1,18 @@ +/// SPDX-License-Identifier: AGPL-3.0-or-later +import 'package:archethic_lib_dart/archethic_lib_dart.dart'; + +typedef TransactionConfirmationHandler = Future Function( + TransactionConfirmation confirmation, +); +typedef TransactionErrorHandler = Future Function(TransactionError error); + +abstract class TransactionRemoteRepositoryInterface { + const TransactionRemoteRepositoryInterface(); + + Future send({ + required Transaction transaction, + Duration timeout = const Duration(seconds: 10), + required TransactionConfirmationHandler onConfirmation, + required TransactionErrorHandler onError, + }); +} diff --git a/lib/src/utils/confirmations/transaction_sender.dart b/lib/src/utils/confirmations/transaction_sender.dart new file mode 100644 index 00000000..70095cb3 --- /dev/null +++ b/lib/src/utils/confirmations/transaction_sender.dart @@ -0,0 +1,27 @@ +/// SPDX-License-Identifier: AGPL-3.0-or-later +import 'dart:async'; + +import 'package:archethic_lib_dart/src/model/transaction.dart'; +import 'package:archethic_lib_dart/src/utils/confirmations/transaction_remote.dart'; + +// Project imports: + +abstract class TransactionSenderInterface { + const TransactionSenderInterface(); + + /// Sends a transaction and listens to confirmations. + /// + /// Sender auto-closes in the following situations : + /// - when transaction is fully confirmed + /// - when timeout is reached + /// - when transaction fails + Future send({ + required Transaction transaction, + Duration timeout = const Duration(seconds: 10), + required TransactionConfirmationHandler onConfirmation, + required TransactionErrorHandler onError, + }); + + /// Releases all PhoenixTransactionSender resources. + void close(); +} diff --git a/lib/src/utils/messenger_util.dart b/lib/src/utils/messenger_util.dart new file mode 100644 index 00000000..6bfd806c --- /dev/null +++ b/lib/src/utils/messenger_util.dart @@ -0,0 +1,419 @@ +/// SPDX-License-Identifier: AGPL-3.0-or-later +import 'dart:convert'; +import 'dart:developer' as dev; +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:archethic_lib_dart/archethic_lib_dart.dart'; +import 'package:archive/archive_io.dart'; + +mixin MessengerMixin { + Future createNewSC({ + required Keychain keychain, + required ApiService apiService, + required List usersPubKey, + required String groupName, + required List adminsPubKey, + required String adminAddress, + required String serviceName, + }) async { + // Build SC Transaction + final code = ''' + @version 1 + + condition transaction: [ + + previous_public_key: List.in?([ + ${usersPubKey.map((key) => '"$key"').join(', ')} + ], + Chain.get_genesis_public_key(transaction.previous_public_key) + ) + + ] + + actions triggered_by: transaction do + + end + + '''; + + final aesKey = uint8ListToHex( + Uint8List.fromList( + List.generate(32, (int i) => Random.secure().nextInt(256)), + ), + ); + + final messageGroupKeyAccess = uint8ListToHex( + Uint8List.fromList( + List.generate(32, (int i) => Random.secure().nextInt(256)), + ), + ); + + final content = ''' +{ + "groupName": "$groupName", + "adminPublicKey": [${adminsPubKey.map((key) => '"$key"').join(', ')}] +} + '''; + + final cryptedContent = + aesEncrypt(utf8.encode(content), messageGroupKeyAccess); + final cryptedContentBase64 = base64.encode(cryptedContent); + + final authorizedPublicKeys = List.empty(growable: true) + ..addAll(usersPubKey); + + final contactsAuthorizedKeys = List.empty(growable: true); + for (final key in authorizedPublicKeys) { + contactsAuthorizedKeys.add( + AuthorizedKey( + encryptedSecretKey: uint8ListToHex(ecEncrypt(aesKey, key)), + publicKey: key, + ), + ); + } + + final storageNoncePublicKey = await apiService.getStorageNoncePublicKey(); + var seedSC = ''; + const chars = 'abcdef0123456789'; + final rng = Random.secure(); + for (var i = 0; i < 64; i++) { + // ignore: use_string_buffers + seedSC += chars[rng.nextInt(chars.length)]; + } + + final scAuthorizedKeys = List.empty(growable: true); + scAuthorizedKeys.add( + AuthorizedKey( + encryptedSecretKey: + uint8ListToHex(ecEncrypt(aesKey, storageNoncePublicKey)), + publicKey: storageNoncePublicKey, + ), + ); + + final originPrivateKey = apiService.getOriginKey(); + + final transactionSC = + Transaction(type: 'contract', data: Transaction.initData()) + .setCode(code) + .setContent(cryptedContentBase64) + .addOwnership( + uint8ListToHex( + aesEncrypt(messageGroupKeyAccess, aesKey), + ), + contactsAuthorizedKeys, + ) + .addOwnership( + uint8ListToHex( + aesEncrypt(seedSC, aesKey), + ), + scAuthorizedKeys, + ) + .build(seedSC, 0) + .originSign(originPrivateKey); + + // Estimation of fees + const slippage = 1.01; + final transactionFee = await apiService.getTransactionFee(transactionSC); + final fees = fromBigInt(transactionFee.fee) * slippage; + final genesisAddressSC = deriveAddress(seedSC, 0); + final transactionTransfer = + Transaction(type: 'transfer', data: Transaction.initData()) + .addUCOTransfer(genesisAddressSC, toBigInt(fees)); + + final indexMap = await apiService.getTransactionIndex( + [adminAddress], + ); + + final transactionTransferSigned = keychain + .buildTransaction( + transactionTransfer, + serviceName, + indexMap[adminAddress] ?? 0, + ) + .originSign(originPrivateKey); + + await TransactionUtil().sendTransactions( + transactions: [transactionTransferSigned, transactionSC], + apiService: apiService, + ); + + return transactionSC; + } + + Future<({Transaction transaction, int transactionIndex})> + buildMessageSendTransaction({ + required Keychain keychain, + required ApiService apiService, + required String scAddress, + required String messageContent, + required String senderAddress, + required String senderServiceName, + required KeyPair senderKeyPair, + }) async { + final message = ''' + { + "compressionAlgo": "gzip", + "message": "${await _encodeMessage(message: messageContent, apiService: apiService, scAddress: scAddress, senderKeyPair: senderKeyPair)}" + } + '''; + + final tx = Transaction(type: 'transfer', data: Transaction.initData()) + .setContent(message) + .addRecipient(scAddress); + + final indexMap = await apiService.getTransactionIndex( + [senderAddress], + ); + + final index = indexMap[senderAddress] ?? 0; + final originPrivateKey = apiService.getOriginKey(); + + return ( + transaction: keychain + .buildTransaction(tx, senderServiceName, index) + .originSign(originPrivateKey), + transactionIndex: index + 1, + ); + } + + Future<({Address transactionAddress, int transactionIndex})> sendMessage({ + required Keychain keychain, + required ApiService apiService, + required String scAddress, + required String messageContent, + required String senderAddress, + required String senderServiceName, + required KeyPair senderKeyPair, + }) async { + final result = await buildMessageSendTransaction( + keychain: keychain, + apiService: apiService, + scAddress: scAddress, + messageContent: messageContent, + senderAddress: senderAddress, + senderServiceName: senderServiceName, + senderKeyPair: senderKeyPair, + ); + + final transaction = result.transaction; + await TransactionUtil().sendTransactions( + transactions: [transaction], + apiService: apiService, + ); + return ( + transactionAddress: transaction.address!, + transactionIndex: result.transactionIndex, + ); + } + + Future getMessageGroup({ + required ApiService apiService, + required String scAddress, + required KeyPair keyPair, + }) async { + final smartContractMap = await apiService.getTransaction([scAddress]); + if (smartContractMap[scAddress] == null) { + return null; + } + + try { + final messageGroupKeyAccess = await getMessageGroupKeyAccess( + apiService: apiService, + scAddress: scAddress, + keyPair: keyPair, + ); + + final smartContract = smartContractMap[scAddress]; + + final cryptedContent = base64.decode(smartContract!.data!.content!); + + final content = utf8.decode( + aesDecrypt(cryptedContent, messageGroupKeyAccess), + ); + final jsonContentMap = jsonDecode(content); + + final usersPubKey = []; + for (final authorizedPublicKey + in smartContract.data!.ownerships[0].authorizedPublicKeys) { + usersPubKey.add(authorizedPublicKey.publicKey!); + } + + final aeGroupMessage = AEGroupMessage( + address: smartContract.address!.address!, + groupName: jsonContentMap['groupName'], + usersPubKey: usersPubKey, + adminPublicKey: List.from(jsonContentMap['adminPublicKey']), + timestampLastUpdate: smartContract.validationStamp!.timestamp!, + ); + + return aeGroupMessage; + } catch (e) { + dev.log(e.toString()); + return null; + } + } + + Future getMessageGroupKeyAccess({ + required ApiService apiService, + required String scAddress, + required KeyPair keyPair, + }) async { + // Get message key from SC secret + final mapTransactionOwnerships = + await apiService.getTransactionOwnerships([scAddress]); + final ownerships = mapTransactionOwnerships[scAddress]; + if (ownerships == null && ownerships!.isEmpty) { + throw Exception(); + } + + final authorizedPublicKey = ownerships[0].authorizedPublicKeys.firstWhere( + (AuthorizedKey authKey) => + authKey.publicKey!.toUpperCase() == + uint8ListToHex(Uint8List.fromList(keyPair.publicKey!)) + .toUpperCase(), + orElse: AuthorizedKey.new, + ); + if (authorizedPublicKey.encryptedSecretKey == null) { + throw Exception(); + } + final aesKey = ecDecrypt( + authorizedPublicKey.encryptedSecretKey, + Uint8List.fromList(keyPair.privateKey!), + ); + return aesDecrypt(ownerships[0].secret, aesKey); + } + + Future _encodeMessage({ + required String message, + required ApiService apiService, + required String scAddress, + required KeyPair senderKeyPair, + }) async { + final messageGroupKeyAccess = await getMessageGroupKeyAccess( + apiService: apiService, + scAddress: scAddress, + keyPair: senderKeyPair, + ); + + // Encode message with message key + final stringPayload = utf8.encode(message); + final compressedPayload = GZipEncoder().encode(stringPayload); + final cryptedPayload = aesEncrypt(compressedPayload, messageGroupKeyAccess); + return base64.encode(cryptedPayload); + } + + Uint8List _decodeMessage( + String compressedData, + String messageGroupKeyAccess, { + String compressionAlgo = '', + }) { + final payload = base64.decode(compressedData); + final decryptedPayload = aesDecrypt( + payload, + messageGroupKeyAccess, + ); + late List decompressedPayload; + switch (compressionAlgo) { + case 'gzip': + decompressedPayload = GZipDecoder().decodeBytes(decryptedPayload); + break; + default: + decompressedPayload = decryptedPayload; + } + + return Uint8List.fromList(decompressedPayload); + } + + Future> readMessages({ + required ApiService apiService, + required String scAddress, + required KeyPair readerKeyPair, + int limit = 0, + int pagingOffset = 0, + }) async { + final messagesList = await apiService.getTransactionInputs( + [scAddress], + limit: limit, + pagingOffset: pagingOffset, + ); + final txContentMessagesList = + messagesList[scAddress] ?? []; + final txContentMessagesAddresses = txContentMessagesList + .where( + (txContentMessage) => + txContentMessage.from != null && txContentMessage.type == 'call', + ) + .map((txContentMessage) => txContentMessage.from) + .whereType() + .toList(); + + final aeMessages = []; + final contents = await apiService.getTransaction( + txContentMessagesAddresses, + request: + ' address, chainLength, data { content }, previousPublicKey, validationStamp { timestamp } ', + ); + + if (contents.isEmpty) return []; + + final messageGroupKeyAccess = uint8ListToHex( + await getMessageGroupKeyAccess( + apiService: apiService, + scAddress: scAddress, + keyPair: readerKeyPair, + ), + ); + + for (final contentMessageAddress in txContentMessagesAddresses) { + final contentMessageTransaction = contents[contentMessageAddress]; + if (contentMessageTransaction == null) continue; + + final transactionContentIM = TransactionContentMessaging.fromJson( + jsonDecode(contentMessageTransaction.data!.content!), + ); + final message = utf8.decode( + _decodeMessage( + transactionContentIM.message, + messageGroupKeyAccess, + compressionAlgo: transactionContentIM.compressionAlgo, + ), + ); + + final senderGenesisPublicKeyMap = await apiService.getTransactionChain( + {contentMessageTransaction.address!.address!: ''}, + request: 'previousPublicKey', + ); + var senderGenesisPublicKey = ''; + if (senderGenesisPublicKeyMap.isNotEmpty && + senderGenesisPublicKeyMap[ + contentMessageTransaction.address!.address!] != + null && + senderGenesisPublicKeyMap[ + contentMessageTransaction.address!.address!]! + .isNotEmpty) { + senderGenesisPublicKey = senderGenesisPublicKeyMap[ + contentMessageTransaction.address!.address!]?[0] + .previousPublicKey ?? + ''; + } + + final aeMEssage = AEMessage( + senderGenesisPublicKey: senderGenesisPublicKey, + address: contentMessageTransaction.address!.address!, + sender: contentMessageTransaction.previousPublicKey!, + timestampCreation: + contentMessageTransaction.validationStamp!.timestamp!, + content: message, + ); + + aeMessages.add( + aeMEssage, + ); + } + + return aeMessages; + } +} + +class TransactionUtil with TransactionMixin {} diff --git a/lib/src/utils/notification_util.dart b/lib/src/utils/notification_util.dart new file mode 100644 index 00000000..34f6ffcb --- /dev/null +++ b/lib/src/utils/notification_util.dart @@ -0,0 +1,52 @@ +import 'dart:convert'; +import 'dart:developer'; +import 'dart:typed_data'; + +import 'package:archethic_lib_dart/archethic_lib_dart.dart'; +import 'package:archethic_lib_dart/src/utils/crypto.dart' as crypto; +import 'package:http/http.dart' as http; + +mixin NotificationUtil { + Future signTransactionNotification({ + required TransactionNotification notification, + required KeyPair senderKeyPair, + }) async { + final payload = concatUint8List([ + Uint8List.fromList(hexToUint8List(notification.txAddress)), + Uint8List.fromList(hexToUint8List(notification.txChainGenesisAddress)), + ]); + + return crypto.sign(payload, senderKeyPair.privateKey); + } + + Future sendTransactionNotification({ + required TransactionNotification notification, + required KeyPair senderKeyPair, + required int txIndex, + required String notifBackendBaseUrl, + required Map pushNotification, + }) async { + final signature = uint8ListToHex( + await signTransactionNotification( + notification: notification, + senderKeyPair: senderKeyPair, + ), + ); + + final body = jsonEncode({ + 'txAddress': notification.txAddress, + 'txChainGenesisAddress': notification.txChainGenesisAddress, + 'payloadSignature': signature, + 'pushNotification': pushNotification, + }); + log('Sending notification. $body'); + await http.post( + Uri.parse('$notifBackendBaseUrl/transactionSent'), + body: body, + headers: { + 'Content-type': 'application/json', + 'Accept': 'application/json', + }, + ); + } +} diff --git a/lib/src/utils/transaction_util.dart b/lib/src/utils/transaction_util.dart new file mode 100644 index 00000000..f12bfbce --- /dev/null +++ b/lib/src/utils/transaction_util.dart @@ -0,0 +1,98 @@ +import 'dart:async'; +import 'dart:developer'; +import 'package:archethic_lib_dart/archethic_lib_dart.dart'; + +mixin TransactionMixin { + Future calculateFees({ + required Transaction transaction, + required ApiService apiService, + double slippage = 0.01, + }) async { + final transactionFee = await apiService.getTransactionFee(transaction); + final fees = fromBigInt(transactionFee.fee) * slippage; + log( + 'Transaction ${transaction.address} : $fees UCO', + ); + return fees; + } + + Future sendTransactions({ + required List transactions, + required ApiService apiService, + }) async { + var errorDetail = ''; + for (final transaction in transactions) { + if (errorDetail.isNotEmpty) { + break; + } + var next = false; + String websocketEndpoint; + switch (apiService.endpoint) { + case 'https://mainnet.archethic.net': + case 'https://testnet.archethic.net': + websocketEndpoint = + "${apiService.endpoint.replaceAll('https:', 'wss:').replaceAll('http:', 'wss:')}/socket/websocket"; + break; + default: + websocketEndpoint = + "${apiService.endpoint.replaceAll('https:', 'wss:').replaceAll('http:', 'ws:')}/socket/websocket"; + break; + } + + final transactionRepository = ArchethicTransactionSender( + phoenixHttpEndpoint: '${apiService.endpoint}/socket/websocket', + websocketEndpoint: websocketEndpoint, + apiService: apiService, + ); + log('Send ${transaction.address!.address}'); + + await transactionRepository.send( + transaction: transaction, + onConfirmation: (confirmation) async { + if (confirmation.isFullyConfirmed) { + log('nbConfirmations: ${confirmation.nbConfirmations}, transactionAddress: ${confirmation.transactionAddress}, maxConfirmations: ${confirmation.maxConfirmations}'); + transactionRepository.close(); + if (confirmation.nbConfirmations >= confirmation.maxConfirmations) { + next = true; + } + } + }, + onError: (error) async { + transactionRepository.close(); + error.maybeMap( + connectivity: (_) { + errorDetail = 'No connection'; + }, + consensusNotReached: (_) { + errorDetail = 'Consensus not reached'; + }, + timeout: (_) { + errorDetail = 'Timeout'; + }, + invalidConfirmation: (_) { + errorDetail = 'Invalid Confirmation'; + }, + insufficientFunds: (_) { + errorDetail = 'Insufficient funds'; + }, + other: (error) { + errorDetail = error.message; + }, + orElse: () { + errorDetail = 'An error is occured'; + }, + ); + }, + ); + + while (next == false && errorDetail.isEmpty) { + await Future.delayed(const Duration(seconds: 1)); + log('wait...'); + } + } + + if (errorDetail.isNotEmpty) { + throw Exception(errorDetail); + } + } +} diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 60f13d6b..00000000 --- a/pubspec.lock +++ /dev/null @@ -1,757 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: "569ddca58d535e601dd1584afa117710abc999d036c0cd2c51777fb257df78e8" - url: "https://pub.dev" - source: hosted - version: "53.0.0" - adaptive_number: - dependency: transitive - description: - name: adaptive_number - sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: "10927c4b7c7c88b1adbca278c3d5531db92e2f4b4abf04e2919a800af965f3f5" - url: "https://pub.dev" - source: hosted - version: "5.5.0" - args: - dependency: transitive - description: - name: args - sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440" - url: "https://pub.dev" - source: hosted - version: "2.4.0" - async: - dependency: transitive - description: - name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 - url: "https://pub.dev" - source: hosted - version: "2.10.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - build: - dependency: transitive - description: - name: build - sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" - url: "https://pub.dev" - source: hosted - version: "2.3.1" - build_config: - dependency: transitive - description: - name: build_config - sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 - url: "https://pub.dev" - source: hosted - version: "1.1.1" - build_daemon: - dependency: transitive - description: - name: build_daemon - sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf" - url: "https://pub.dev" - source: hosted - version: "3.1.0" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - sha256: db49b8609ef8c81cca2b310618c3017c00f03a92af44c04d310b907b2d692d95 - url: "https://pub.dev" - source: hosted - version: "2.2.0" - build_runner: - dependency: "direct dev" - description: - name: build_runner - sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727 - url: "https://pub.dev" - source: hosted - version: "2.3.3" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292" - url: "https://pub.dev" - source: hosted - version: "7.2.7" - built_collection: - dependency: transitive - description: - name: built_collection - sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" - url: "https://pub.dev" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - sha256: "169565c8ad06adb760c3645bf71f00bff161b00002cace266cad42c5d22a7725" - url: "https://pub.dev" - source: hosted - version: "8.4.3" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - code_builder: - dependency: transitive - description: - name: code_builder - sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe" - url: "https://pub.dev" - source: hosted - version: "4.4.0" - collection: - dependency: "direct main" - description: - name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" - url: "https://pub.dev" - source: hosted - version: "1.17.1" - convert: - dependency: transitive - description: - name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" - url: "https://pub.dev" - source: hosted - version: "3.1.1" - coverage: - dependency: transitive - description: - name: coverage - sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" - url: "https://pub.dev" - source: hosted - version: "1.6.3" - crypto: - dependency: "direct main" - description: - name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 - url: "https://pub.dev" - source: hosted - version: "3.0.2" - cryptography: - dependency: transitive - description: - name: cryptography - sha256: ffd770340e5a48f57e473c42d9036a773c43b396e80b41a2dd164ffaf53f57a4 - url: "https://pub.dev" - source: hosted - version: "2.1.1" - dart_style: - dependency: transitive - description: - name: dart_style - sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" - url: "https://pub.dev" - source: hosted - version: "2.2.4" - ecdsa: - dependency: "direct main" - description: - name: ecdsa - sha256: dd1efbaf6c18bfde9347dddcfe10dce3dd044e5a1b237457a49b5c24850dfb95 - url: "https://pub.dev" - source: hosted - version: "0.0.4" - elliptic: - dependency: "direct main" - description: - name: elliptic - sha256: "8c7396126c81c574fe970ac4afe9ba919b1ca754da20b509664be2345ffb2845" - url: "https://pub.dev" - source: hosted - version: "0.3.8" - file: - dependency: transitive - description: - name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" - url: "https://pub.dev" - source: hosted - version: "6.1.4" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c - url: "https://pub.dev" - source: hosted - version: "2.0.1" - freezed: - dependency: "direct dev" - description: - name: freezed - sha256: e819441678f1679b719008ff2ff0ef045d66eed9f9ec81166ca0d9b02a187454 - url: "https://pub.dev" - source: hosted - version: "2.3.2" - freezed_annotation: - dependency: "direct main" - description: - name: freezed_annotation - sha256: aeac15850ef1b38ee368d4c53ba9a847e900bb2c53a4db3f6881cbb3cb684338 - url: "https://pub.dev" - source: hosted - version: "2.2.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" - url: "https://pub.dev" - source: hosted - version: "3.2.0" - glob: - dependency: transitive - description: - name: glob - sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - gql: - dependency: "direct main" - description: - name: gql - sha256: "998304fbb88a3956cfea10cd27a56f8e5d4b3bc110f03c952c18a9310774e8bb" - url: "https://pub.dev" - source: hosted - version: "0.14.0" - gql_dedupe_link: - dependency: transitive - description: - name: gql_dedupe_link - sha256: "89681048cf956348e865da872a40081499b8c087fc84dd4d4b9c134bd70d27b3" - url: "https://pub.dev" - source: hosted - version: "2.0.3+1" - gql_error_link: - dependency: transitive - description: - name: gql_error_link - sha256: e7bfdd2b6232f3e15861cd96c2ad6b7c9c94693843b3dea18295136a5fb5b534 - url: "https://pub.dev" - source: hosted - version: "0.2.3+1" - gql_exec: - dependency: transitive - description: - name: gql_exec - sha256: "0d1fdb2e4154efbfc1dcf3f35ec36d19c8428ff0d560eb4c45b354f8f871dc50" - url: "https://pub.dev" - source: hosted - version: "0.4.3" - gql_http_link: - dependency: transitive - description: - name: gql_http_link - sha256: "89ef87b32947acf4189f564c095f1148b0ab9bb9996fe518716dbad66708b834" - url: "https://pub.dev" - source: hosted - version: "0.4.5" - gql_link: - dependency: transitive - description: - name: gql_link - sha256: f7973279126bc922d465c4f4da6ed93d187085e597b3480f5e14e74d28fe14bd - url: "https://pub.dev" - source: hosted - version: "0.5.1" - gql_transform_link: - dependency: transitive - description: - name: gql_transform_link - sha256: b1735a9a92d25a92960002a8b40dfaede95ec1e5ed848906125d69efd878661f - url: "https://pub.dev" - source: hosted - version: "0.2.2+1" - graphql: - dependency: "direct main" - description: - name: graphql - sha256: b061201579040e9548cec2bae17bbdea0ab30666cb4e7ba48b9675f14d982199 - url: "https://pub.dev" - source: hosted - version: "5.1.3" - graphs: - dependency: transitive - description: - name: graphs - sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2 - url: "https://pub.dev" - source: hosted - version: "2.2.0" - hex: - dependency: "direct main" - description: - name: hex - sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a" - url: "https://pub.dev" - source: hosted - version: "0.2.0" - hive: - dependency: transitive - description: - name: hive - sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" - url: "https://pub.dev" - source: hosted - version: "2.2.3" - http: - dependency: "direct main" - description: - name: http - sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" - url: "https://pub.dev" - source: hosted - version: "0.13.5" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - io: - dependency: transitive - description: - name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" - url: "https://pub.dev" - source: hosted - version: "1.0.4" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" - json_annotation: - dependency: "direct main" - description: - name: json_annotation - sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 - url: "https://pub.dev" - source: hosted - version: "4.8.0" - json_serializable: - dependency: "direct dev" - description: - name: json_serializable - sha256: dadc08bd61f72559f938dd08ec20dbfec6c709bba83515085ea943d2078d187a - url: "https://pub.dev" - source: hosted - version: "6.6.1" - jwk: - dependency: "direct main" - description: - name: jwk - sha256: "90a38db729726443e687e7620f5ee0b2a41b0670b3a6eee43a84fdf2e0ea643b" - url: "https://pub.dev" - source: hosted - version: "0.1.1" - lints: - dependency: transitive - description: - name: lints - sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" - url: "https://pub.dev" - source: hosted - version: "2.0.1" - logging: - dependency: transitive - description: - name: logging - sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - matcher: - dependency: transitive - description: - name: matcher - sha256: c94db23593b89766cda57aab9ac311e3616cf87c6fa4e9749df032f66f30dcb8 - url: "https://pub.dev" - source: hosted - version: "0.12.14" - meta: - dependency: transitive - description: - name: meta - sha256: "12307e7f0605ce3da64cf0db90e5fcab0869f3ca03f76be6bb2991ce0a55e82b" - url: "https://pub.dev" - source: hosted - version: "1.9.0" - mime: - dependency: transitive - description: - name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e - url: "https://pub.dev" - source: hosted - version: "1.0.4" - ninja_asn1: - dependency: transitive - description: - name: ninja_asn1 - sha256: b0f04877243fda51c475ec2bcaadb55a92759baee9f02888124c60775760ccf7 - url: "https://pub.dev" - source: hosted - version: "2.0.0" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "8ebdbaa3b96d5285d068f80772390d27c21e1fa10fb2df6627b1b9415043608d" - url: "https://pub.dev" - source: hosted - version: "2.0.1" - normalize: - dependency: transitive - description: - name: normalize - sha256: baf8caf2d8b745af5737cca6c24f7fe3cf3158897fdbcde9a909b9c8d3e2e5af - url: "https://pub.dev" - source: hosted - version: "0.7.2" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - path: - dependency: transitive - description: - name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" - url: "https://pub.dev" - source: hosted - version: "1.8.3" - pinenacl: - dependency: "direct main" - description: - name: pinenacl - sha256: "3a5503637587d635647c93ea9a8fecf48a420cc7deebe6f1fc85c2a5637ab327" - url: "https://pub.dev" - source: hosted - version: "0.5.1" - pointycastle: - dependency: "direct main" - description: - name: pointycastle - sha256: "57b6b78df14175658f09c5dfcfc51a46ad9561a3504fe679913dab404d0cc0f2" - url: "https://pub.dev" - source: hosted - version: "3.7.0" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" - url: "https://pub.dev" - source: hosted - version: "2.1.3" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" - url: "https://pub.dev" - source: hosted - version: "1.2.1" - quiver: - dependency: "direct main" - description: - name: quiver - sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 - url: "https://pub.dev" - source: hosted - version: "3.2.1" - rxdart: - dependency: transitive - description: - name: rxdart - sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" - url: "https://pub.dev" - source: hosted - version: "0.27.7" - secp256k1: - dependency: "direct main" - description: - name: secp256k1 - sha256: "66310c1fce68d0c3cfae61f9f23aba11f459fb8c84a50bdc6520548c62a4828a" - url: "https://pub.dev" - source: hosted - version: "0.3.0" - shelf: - dependency: transitive - description: - name: shelf - sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c - url: "https://pub.dev" - source: hosted - version: "1.4.0" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: aef74dc9195746a384843102142ab65b6a4735bb3beea791e63527b88cc83306 - url: "https://pub.dev" - source: hosted - version: "3.0.1" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: e792b76b96a36d4a41b819da593aff4bdd413576b3ba6150df5d8d9996d2e74c - url: "https://pub.dev" - source: hosted - version: "1.1.1" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 - url: "https://pub.dev" - source: hosted - version: "1.0.3" - source_gen: - dependency: transitive - description: - name: source_gen - sha256: c2bea18c95cfa0276a366270afaa2850b09b4a76db95d546f3d003dcc7011298 - url: "https://pub.dev" - source: hosted - version: "1.2.7" - source_helper: - dependency: transitive - description: - name: source_helper - sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - source_maps: - dependency: transitive - description: - name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" - url: "https://pub.dev" - source: hosted - version: "0.10.12" - source_span: - dependency: transitive - description: - name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 - url: "https://pub.dev" - source: hosted - version: "1.9.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 - url: "https://pub.dev" - source: hosted - version: "1.11.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - stream_transform: - dependency: transitive - description: - name: stream_transform - sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test: - dependency: "direct dev" - description: - name: test - sha256: "5301f54eb6fe945daa99bc8df6ece3f88b5ceaa6f996f250efdaaf63e22886be" - url: "https://pub.dev" - source: hosted - version: "1.23.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: "6182294da5abf431177fccc1ee02401f6df30f766bc6130a0852c6b6d7ee6b2d" - url: "https://pub.dev" - source: hosted - version: "0.4.18" - test_core: - dependency: transitive - description: - name: test_core - sha256: d2e9240594b409565524802b84b7b39341da36dd6fd8e1660b53ad928ec3e9af - url: "https://pub.dev" - source: hosted - version: "0.4.24" - timing: - dependency: transitive - description: - name: timing - sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - uuid: - dependency: transitive - description: - name: uuid - sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" - url: "https://pub.dev" - source: hosted - version: "3.0.7" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: a4040e9852e56bf8a3c5a2e08a56f6facd76e75500cf2a922ce5d52394c4998a - url: "https://pub.dev" - source: hosted - version: "11.0.1" - watcher: - dependency: transitive - description: - name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: "3a969ddcc204a3e34e863d204b29c0752716f78b6f9cc8235083208d268a4ccd" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - x25519: - dependency: "direct main" - description: - name: x25519 - sha256: cec3c125f0d934dccba6c4cab48f3fbf866dc78895dcc5a1584d35b0a845005b - url: "https://pub.dev" - source: hosted - version: "0.1.1" - yaml: - dependency: transitive - description: - name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" - url: "https://pub.dev" - source: hosted - version: "3.1.1" -sdks: - dart: ">=2.19.0 <4.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index b591db85..26567982 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,12 +3,15 @@ name: archethic_lib_dart description: Archethic dart library for Flutter for Node and Browser. This library aims to provide a easy way to create Archethic transaction and to send them over the network homepage: https://github.com/archethic-foundation/libdart -version: 3.1.1 +version: 3.2.0 environment: - sdk: ">=2.19.0 <3.0.0" + sdk: ">=3.0.0 <4.0.0" dependencies: + # Compression + archive: ^3.3.7 + # Collections and utilities functions and classes related to collections. collection: ^1.14.13 @@ -40,6 +43,9 @@ dependencies: # JWK (JSON Web Key) encoding and decoding jwk: ^0.1.1 + # PhoenixSocket provides a feature-complete implementation of Phoenix Sockets, using a single API based on StreamChannels compatible with any deployment of Flutter + phoenix_socket: ^0.6.3 + # The Dart implementation of the PyNaCl APIs with the TweetNaCl cryptographic library pinenacl: ^0.5.1 diff --git a/test/messenger_test.dart b/test/messenger_test.dart new file mode 100644 index 00000000..8b88d1dc --- /dev/null +++ b/test/messenger_test.dart @@ -0,0 +1,253 @@ +library messenger.api_test; + +import 'dart:typed_data'; + +import 'package:archethic_lib_dart/src/model/crypto/key_pair.dart'; +import 'package:archethic_lib_dart/src/model/keychain.dart'; +import 'package:archethic_lib_dart/src/services/api_service.dart'; +import 'package:archethic_lib_dart/src/utils/messenger_util.dart'; +import 'package:archethic_lib_dart/src/utils/utils.dart'; +import 'package:test/test.dart'; + +void main() { + group( + 'messenger', + () { + test('createNewSCTestnet', () async { + final apiService = ApiService('https://testnet.archethic.net'); + final keychain = Keychain( + seed: hexToUint8List( + '8CAC8029F526FD4E4856E00161882F9F9F6B81B7C9221BB8529690FDCB642F03', + ), + ).copyWithService('uco', "m/650'/0/0"); + + final tx = await TestMessengerMixin().createNewSC( + apiService: apiService, + usersPubKey: [ + '0000A78DC064FAD98277B6B2FE0C2EB09B1292DE13DFFCE1AA3991F67803D14415F6', + '0000FD5BCC80A8E7C689487597D3DE0FD9910B087910437E4D1AAB543E9CEDEF49F9', + '0000C3B2EA5B16F1CF2791FA6F4536E90BFD00D3B5596575FEB5B2448A4C7DC2DEF0' + ], + groupName: 'testGroup', + adminsPubKey: [ + '0000A78DC064FAD98277B6B2FE0C2EB09B1292DE13DFFCE1AA3991F67803D14415F6' + ], + keychain: keychain, + adminAddress: + '00008C64EE10053C34E7B5679D3BD935616B45D910FDBBC46A2516709CBB375DF703', + serviceName: 'archethic-wallet-ALICE', + ); + + expect( + tx.version, + 1, + ); + }); + + test('sendMessageTestnet', () async { + final apiService = ApiService('https://testnet.archethic.net'); + + final keychain = Keychain( + seed: hexToUint8List( + '8CAC8029F526FD4E4856E00161882F9F9F6B81B7C9221BB8529690FDCB642F03', + ), + ).copyWithService('uco', "m/650'/0/0"); + + await TestMessengerMixin().sendMessage( + apiService: apiService, + keychain: keychain, + messageContent: 'First message', + scAddress: + '00000162D81A8BADB078C430693DF1D8ED6A9F6FC9D484A0CCCD5935E353D2275362', + senderAddress: + '00008C64EE10053C34E7B5679D3BD935616B45D910FDBBC46A2516709CBB375DF703', + senderServiceName: 'archethic-wallet-ALICE', + senderKeyPair: KeyPair( + privateKey: Uint8List.fromList([]), + publicKey: Uint8List.fromList([]), + ), + ); + }); + + test('createNewSCLocal', () async { + final apiService = ApiService('http://localhost:4000'); + + final keychain = Keychain( + seed: hexToUint8List( + '8CAC8029F526FD4E4856E00161882F9F9F6B81B7C9221BB8529690FDCB642F03', + ), + ).copyWithService('uco', "m/650'/0/0"); + + final tx = await TestMessengerMixin().createNewSC( + apiService: apiService, + usersPubKey: [ + '00008601B566BA8580B03D4AF47C96DD36686FC7BBB0309D4BB6B5C54C0E7B97736E' + ], + groupName: 'testGroup2', + adminsPubKey: [ + '00008601B566BA8580B03D4AF47C96DD36686FC7BBB0309D4BB6B5C54C0E7B97736E' + ], + keychain: keychain, + adminAddress: + '00000162D81A8BADB078C430693DF1D8ED6A9F6FC9D484A0CCCD5935E353D2275362', + serviceName: 'archethic-wallet-TEST', + ); + + expect( + tx.version, + 1, + ); + }); + + test('sendMessageLocal', () async { + final apiService = ApiService('http://localhost:4000'); + + final keychain = Keychain( + seed: hexToUint8List( + '8CAC8029F526FD4E4856E00161882F9F9F6B81B7C9221BB8529690FDCB642F03', + ), + ).copyWithService('uco', "m/650'/0/0"); + + await TestMessengerMixin().sendMessage( + apiService: apiService, + keychain: keychain, + messageContent: '3ème message', + scAddress: + '000049d1b99645d0168c084983477b0db00e53ac8cc9957ef93bb56777ce0e8d82b1', + senderAddress: + '00000162D81A8BADB078C430693DF1D8ED6A9F6FC9D484A0CCCD5935E353D2275362', + senderServiceName: 'archethic-wallet-TEST', + senderKeyPair: KeyPair( + privateKey: hexToUint8List( + '000001b98027e90c0bd9020aee089a50c84da7185e6258d22d8f1b73c9e56e7f4134', + ), + publicKey: hexToUint8List( + '00008601B566BA8580B03D4AF47C96DD36686FC7BBB0309D4BB6B5C54C0E7B97736E', + ), + ), + ); + }); + + test('readMessagesLocal', () async { + final apiService = ApiService('http://localhost:4000'); + + await TestMessengerMixin().readMessages( + apiService: apiService, + scAddress: + '000049d1b99645d0168c084983477b0db00e53ac8cc9957ef93bb56777ce0e8d82b1', + readerKeyPair: KeyPair( + privateKey: hexToUint8List( + '000001b98027e90c0bd9020aee089a50c84da7185e6258d22d8f1b73c9e56e7f4134', + ), + publicKey: hexToUint8List( + '00008601B566BA8580B03D4AF47C96DD36686FC7BBB0309D4BB6B5C54C0E7B97736E', + ), + ), + ); + }); + + test('getMessageGroupLocal', () async { + final apiService = ApiService('http://localhost:4000'); + + final messageGroup = await TestMessengerMixin().getMessageGroup( + apiService: apiService, + scAddress: + '00004C24CFFC29B0DC509260B64055F2E40086BD0F48CC34BF26FE40D77DFC2D5E68', + keyPair: KeyPair( + privateKey: hexToUint8List( + '0000969b5e894dda119e3717e540f60104640a987f2d5b7efa1c4268b58b0d2cfb2a', + ), + publicKey: hexToUint8List( + '000087cdadbe3f19e5db8e434ca3c862600942a0e206e2c6c340ce1cdfde472e4c5c', + ), + ), + ); + + expect( + messageGroup!.address, + '00004C24CFFC29B0DC509260B64055F2E40086BD0F48CC34BF26FE40D77DFC2D5E68', + ); + }); + + test( + 'createSendReadLocal', + () async { + final apiService = ApiService('http://localhost:4000'); + + final keychain = Keychain( + seed: hexToUint8List( + '8CAC8029F526FD4E4856E00161882F9F9F6B81B7C9221BB8529690FDCB642F03', + ), + ).copyWithService('uco', "m/650'/0/0"); + + final tx = await TestMessengerMixin().createNewSC( + apiService: apiService, + usersPubKey: [ + '00008601B566BA8580B03D4AF47C96DD36686FC7BBB0309D4BB6B5C54C0E7B97736E' + ], + groupName: 'testGroup2', + adminsPubKey: [ + '00008601B566BA8580B03D4AF47C96DD36686FC7BBB0309D4BB6B5C54C0E7B97736E' + ], + keychain: keychain, + adminAddress: + '00000162D81A8BADB078C430693DF1D8ED6A9F6FC9D484A0CCCD5935E353D2275362', + serviceName: 'archethic-wallet-TEST', + ); + + await TestMessengerMixin().sendMessage( + apiService: apiService, + keychain: keychain, + messageContent: '1er message', + scAddress: tx.address!.address!, + senderAddress: + '00000162D81A8BADB078C430693DF1D8ED6A9F6FC9D484A0CCCD5935E353D2275362', + senderServiceName: 'archethic-wallet-TEST', + senderKeyPair: KeyPair( + privateKey: hexToUint8List( + '000001b98027e90c0bd9020aee089a50c84da7185e6258d22d8f1b73c9e56e7f4134', + ), + publicKey: hexToUint8List( + '00008601B566BA8580B03D4AF47C96DD36686FC7BBB0309D4BB6B5C54C0E7B97736E', + ), + ), + ); + + await TestMessengerMixin().sendMessage( + apiService: apiService, + keychain: keychain, + messageContent: '2ème message', + scAddress: tx.address!.address!, + senderAddress: + '00000162D81A8BADB078C430693DF1D8ED6A9F6FC9D484A0CCCD5935E353D2275362', + senderServiceName: 'archethic-wallet-TEST', + senderKeyPair: KeyPair( + privateKey: hexToUint8List( + '000001b98027e90c0bd9020aee089a50c84da7185e6258d22d8f1b73c9e56e7f4134', + ), + publicKey: hexToUint8List( + '00008601B566BA8580B03D4AF47C96DD36686FC7BBB0309D4BB6B5C54C0E7B97736E', + ), + ), + ); + + await TestMessengerMixin().readMessages( + apiService: apiService, + scAddress: tx.address!.address!, + readerKeyPair: KeyPair( + privateKey: hexToUint8List( + '000001b98027e90c0bd9020aee089a50c84da7185e6258d22d8f1b73c9e56e7f4134', + ), + publicKey: hexToUint8List( + '00008601B566BA8580B03D4AF47C96DD36686FC7BBB0309D4BB6B5C54C0E7B97736E', + ), + ), + ); + }, + ); + }, + tags: ['noCI'], + ); +} + +class TestMessengerMixin with MessengerMixin {}