From 9c9f4333da1b843b121dd79785e976f8e1091a2e Mon Sep 17 00:00:00 2001 From: kacper Date: Tue, 19 Sep 2023 20:43:47 +0200 Subject: [PATCH 1/4] Validation of amount --- lib/data/base/text_value.dart | 11 ++++++++++ lib/data/error/input_error.dart | 13 ++++++++++++ lib/data/solana_pay_request.dart | 14 ++++++------- lib/design/input/base_input.dart | 11 ++++++---- lib/di/blocs_providers.dart | 8 +++---- lib/di/repositories_providers.dart | 4 ++++ .../input/bloc/parameters_input_cubit.dart | 21 ++++++++++++++----- .../input/bloc/parameters_input_state.dart | 5 +++-- .../input/parameters_input_screen.dart | 1 + lib/feature/qr/bloc/qr_generator_cubit.dart | 2 +- lib/validator/number_validator.dart | 21 +++++++++++++++++++ 11 files changed, 88 insertions(+), 23 deletions(-) create mode 100644 lib/data/base/text_value.dart create mode 100644 lib/data/error/input_error.dart create mode 100644 lib/validator/number_validator.dart diff --git a/lib/data/base/text_value.dart b/lib/data/base/text_value.dart new file mode 100644 index 0000000..a76073d --- /dev/null +++ b/lib/data/base/text_value.dart @@ -0,0 +1,11 @@ +import '../error/input_error.dart'; + +class TextValue { + TextValue({ + required this.text, + this.error, + }); + + final String text; + final InputError? error; +} diff --git a/lib/data/error/input_error.dart b/lib/data/error/input_error.dart new file mode 100644 index 0000000..eaf7ea4 --- /dev/null +++ b/lib/data/error/input_error.dart @@ -0,0 +1,13 @@ +abstract class InputError { + abstract String text; +} + +class NotANumber extends InputError { + @override + String text = "Field must be a number"; +} + +class EmptyAmount extends InputError { + @override + String text = "Amount must be more than 0 if present"; +} diff --git a/lib/data/solana_pay_request.dart b/lib/data/solana_pay_request.dart index fe21801..18fc5da 100644 --- a/lib/data/solana_pay_request.dart +++ b/lib/data/solana_pay_request.dart @@ -9,11 +9,11 @@ class SolanaPayRequest { this.splToken, }); - String address; - String? label; - String? splToken; - String? message; - String? amount; - String? reference; - String? memo; + final String address; + final String? label; + final String? splToken; + final String? message; + final String? amount; + final String? reference; + final String? memo; } diff --git a/lib/design/input/base_input.dart b/lib/design/input/base_input.dart index 0f5b151..66e72a2 100644 --- a/lib/design/input/base_input.dart +++ b/lib/design/input/base_input.dart @@ -5,6 +5,7 @@ class BaseInput extends StatelessWidget { final ValueChanged? _onChanged; final TextInputType? _keyboardType; final bool _focusable; + final String? _error; const BaseInput({ super.key, @@ -12,18 +13,20 @@ class BaseInput extends StatelessWidget { required onChanged, keyboardType, focusable, + error, }) : _labelText = labelText, _onChanged = onChanged, _keyboardType = keyboardType, - _focusable = focusable ?? true; + _focusable = focusable ?? true, + _error = error; @override Widget build(BuildContext context) { return TextField( decoration: InputDecoration( - border: const OutlineInputBorder(), - labelText: _labelText, - ), + border: const OutlineInputBorder(), + labelText: _labelText, + errorText: _error), onChanged: _onChanged, keyboardType: _keyboardType, focusNode: _focusable ? null : AlwaysDisabledFocusNode(), diff --git a/lib/di/blocs_providers.dart b/lib/di/blocs_providers.dart index 8d369e4..be279c6 100644 --- a/lib/di/blocs_providers.dart +++ b/lib/di/blocs_providers.dart @@ -2,24 +2,24 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:sol_pay_gen/domain/generate_transfer_request_qr_use_case.dart'; import 'package:sol_pay_gen/feature/qr/bloc/qr_generator_cubit.dart'; +import 'package:sol_pay_gen/validator/number_validator.dart'; import '../data/transfer/transfer_request_repository.dart'; import '../feature/input/bloc/parameters_input_cubit.dart'; MultiBlocProvider getBlocProviders({required StatelessWidget child}) { - ParametersInputCubit parametersInputCubit = ParametersInputCubit(); - return MultiBlocProvider( providers: [ BlocProvider( - create: (_) => parametersInputCubit, + create: (BuildContext context) => + ParametersInputCubit(context.read()), ), BlocProvider( create: (BuildContext context) => QrGeneratorCubit( generateTransferRequestQrUseCase: GenerateTransferRequestQrUseCase( context.read(), ), - parametersInputCubit: parametersInputCubit, + parametersInputCubit: context.read(), ), ) ], diff --git a/lib/di/repositories_providers.dart b/lib/di/repositories_providers.dart index b34d30b..d49c911 100644 --- a/lib/di/repositories_providers.dart +++ b/lib/di/repositories_providers.dart @@ -1,5 +1,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:sol_pay_gen/data/transfer/transfer_request_repository.dart'; +import 'package:sol_pay_gen/validator/number_validator.dart'; MultiRepositoryProvider getRepositoryProviders({ required MultiBlocProvider blocProviders, @@ -9,6 +10,9 @@ MultiRepositoryProvider getRepositoryProviders({ RepositoryProvider( create: (context) => DefaultTransferRequestRepository(), ), + RepositoryProvider( + create: (context) => DefaultNumberValidator(), + ) ], child: blocProviders, ); diff --git a/lib/feature/input/bloc/parameters_input_cubit.dart b/lib/feature/input/bloc/parameters_input_cubit.dart index f51c07a..43f1f63 100644 --- a/lib/feature/input/bloc/parameters_input_cubit.dart +++ b/lib/feature/input/bloc/parameters_input_cubit.dart @@ -1,12 +1,18 @@ import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:sol_pay_gen/data/base/text_value.dart'; import 'package:sol_pay_gen/feature/input/bloc/parameters_input_state.dart'; +import '../../../validator/number_validator.dart'; + class ParametersInputCubit extends Cubit { - ParametersInputCubit() - : super( - const ParametersInputState( + final NumberValidator _numberValidator; + + ParametersInputCubit( + this._numberValidator, + ) : super( + ParametersInputState( address: "", - amount: null, + amount: TextValue(text: ""), reference: null, memo: null, message: null, @@ -20,7 +26,12 @@ class ParametersInputCubit extends Cubit { } void onAmountChange(String amount) { - emit(state.copyWith(amount: amount)); + emit(state.copyWith( + amount: TextValue( + text: amount, + error: amount.isEmpty ? null : _numberValidator.validateAmount(amount), + ), + )); } void onLabelChange(String label) { diff --git a/lib/feature/input/bloc/parameters_input_state.dart b/lib/feature/input/bloc/parameters_input_state.dart index c8ad789..5222666 100644 --- a/lib/feature/input/bloc/parameters_input_state.dart +++ b/lib/feature/input/bloc/parameters_input_state.dart @@ -1,8 +1,9 @@ import 'package:equatable/equatable.dart'; +import 'package:sol_pay_gen/data/base/text_value.dart'; class ParametersInputState extends Equatable { final String address; - final String? amount; + final TextValue amount; final String? reference; final String? label; final String? message; @@ -31,7 +32,7 @@ class ParametersInputState extends Equatable { ParametersInputState copyWith({ String? address, - String? amount, + TextValue? amount, String? label, String? message, String? reference, diff --git a/lib/feature/input/parameters_input_screen.dart b/lib/feature/input/parameters_input_screen.dart index 4ef71b2..a924e22 100644 --- a/lib/feature/input/parameters_input_screen.dart +++ b/lib/feature/input/parameters_input_screen.dart @@ -57,6 +57,7 @@ class InputBody extends StatelessWidget { BaseInput( labelText: 'Amount', keyboardType: TextInputType.number, + error: state.amount.error?.text, onChanged: (address) => context .read() .onAmountChange(address), diff --git a/lib/feature/qr/bloc/qr_generator_cubit.dart b/lib/feature/qr/bloc/qr_generator_cubit.dart index a5828f8..94aa816 100644 --- a/lib/feature/qr/bloc/qr_generator_cubit.dart +++ b/lib/feature/qr/bloc/qr_generator_cubit.dart @@ -23,7 +23,7 @@ class QrGeneratorCubit extends Cubit { address: inputState.address, label: inputState.label, message: inputState.message, - amount: inputState.amount, + amount: inputState.amount?.text, reference: inputState.reference, memo: inputState.memo, splToken: inputState.splTokenAddress, diff --git a/lib/validator/number_validator.dart b/lib/validator/number_validator.dart new file mode 100644 index 0000000..cfe8b25 --- /dev/null +++ b/lib/validator/number_validator.dart @@ -0,0 +1,21 @@ +import '../data/error/input_error.dart'; + +abstract class NumberValidator { + InputError? validateAmount(String amount); +} + +class DefaultNumberValidator extends NumberValidator { + @override + InputError? validateAmount(String amount) { + double? parsedAmount = double.tryParse(amount); + + if (parsedAmount == null) { + return NotANumber(); + } + if (parsedAmount == 0) { + return EmptyAmount(); + } else { + return null; + } + } +} From d5c7a6127401acf29e75f6320c3141c2a6ce7638 Mon Sep 17 00:00:00 2001 From: kacper Date: Tue, 19 Sep 2023 22:00:12 +0200 Subject: [PATCH 2/4] Not generate QR when input is empty --- lib/data/base/text_value.dart | 11 ++++++++ lib/data/error/input_error.dart | 5 ++++ .../input/bloc/parameters_input_cubit.dart | 10 ++++++-- .../input/bloc/parameters_input_state.dart | 15 +++++++++-- .../input/parameters_input_screen.dart | 6 ++++- lib/feature/qr/bloc/qr_generator_cubit.dart | 25 +++++++++++-------- 6 files changed, 56 insertions(+), 16 deletions(-) diff --git a/lib/data/base/text_value.dart b/lib/data/base/text_value.dart index a76073d..f725eb2 100644 --- a/lib/data/base/text_value.dart +++ b/lib/data/base/text_value.dart @@ -8,4 +8,15 @@ class TextValue { final String text; final InputError? error; + + TextValue copyWith({ + String? text, + InputError? error, + }) => + TextValue( + text: text ?? this.text, + error: error ?? this.error, + ); + + bool isValid() => error == null; } diff --git a/lib/data/error/input_error.dart b/lib/data/error/input_error.dart index eaf7ea4..d038c98 100644 --- a/lib/data/error/input_error.dart +++ b/lib/data/error/input_error.dart @@ -11,3 +11,8 @@ class EmptyAmount extends InputError { @override String text = "Amount must be more than 0 if present"; } + +class RequiredAmount extends InputError { + @override + String text = "Field is required"; +} diff --git a/lib/feature/input/bloc/parameters_input_cubit.dart b/lib/feature/input/bloc/parameters_input_cubit.dart index 43f1f63..c2e6cbf 100644 --- a/lib/feature/input/bloc/parameters_input_cubit.dart +++ b/lib/feature/input/bloc/parameters_input_cubit.dart @@ -11,7 +11,7 @@ class ParametersInputCubit extends Cubit { this._numberValidator, ) : super( ParametersInputState( - address: "", + address: TextValue(text: ""), amount: TextValue(text: ""), reference: null, memo: null, @@ -22,7 +22,9 @@ class ParametersInputCubit extends Cubit { ); void onAddressChange(String address) { - emit(state.copyWith(address: address)); + emit( + state.copyWith(address: TextValue(text: address)), + ); } void onAmountChange(String amount) { @@ -53,4 +55,8 @@ class ParametersInputCubit extends Cubit { void onMemoChange(String memo) { emit(state.copyWith(memo: memo)); } + + void onValidate() { + emit(state.validate()); + } } diff --git a/lib/feature/input/bloc/parameters_input_state.dart b/lib/feature/input/bloc/parameters_input_state.dart index 5222666..fe99384 100644 --- a/lib/feature/input/bloc/parameters_input_state.dart +++ b/lib/feature/input/bloc/parameters_input_state.dart @@ -1,8 +1,9 @@ import 'package:equatable/equatable.dart'; import 'package:sol_pay_gen/data/base/text_value.dart'; +import 'package:sol_pay_gen/data/error/input_error.dart'; class ParametersInputState extends Equatable { - final String address; + final TextValue address; final TextValue amount; final String? reference; final String? label; @@ -31,7 +32,7 @@ class ParametersInputState extends Equatable { ]; ParametersInputState copyWith({ - String? address, + TextValue? address, TextValue? amount, String? label, String? message, @@ -48,4 +49,14 @@ class ParametersInputState extends Equatable { memo: memo ?? this.memo, splTokenAddress: splTokenAddress ?? this.splTokenAddress, ); + + ParametersInputState validate() { + return copyWith( + address: address.copyWith( + error: address.text.isEmpty ? RequiredAmount() : null, + ), + ); + } + + bool isValid() => amount.isValid() && address.isValid(); } diff --git a/lib/feature/input/parameters_input_screen.dart b/lib/feature/input/parameters_input_screen.dart index a924e22..16b95ce 100644 --- a/lib/feature/input/parameters_input_screen.dart +++ b/lib/feature/input/parameters_input_screen.dart @@ -49,6 +49,7 @@ class InputBody extends StatelessWidget { children: [ BaseInput( labelText: 'Receive wallet address', + error: state.address.error?.text, onChanged: (address) => context .read() .onAddressChange(address), @@ -102,7 +103,10 @@ class InputBody extends StatelessWidget { Padding( padding: const EdgeInsets.all(24.0), child: MaterialButton( - onPressed: () => context.read().onGenerate(), + onPressed: () { + context.read().onValidate(); + context.read().onGenerate(); + }, color: Colors.blueAccent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.0), diff --git a/lib/feature/qr/bloc/qr_generator_cubit.dart b/lib/feature/qr/bloc/qr_generator_cubit.dart index 94aa816..f81b66e 100644 --- a/lib/feature/qr/bloc/qr_generator_cubit.dart +++ b/lib/feature/qr/bloc/qr_generator_cubit.dart @@ -19,18 +19,21 @@ class QrGeneratorCubit extends Cubit { void onGenerate() async { ParametersInputState inputState = _parametersInputCubit.state; - SolanaPayRequest request = SolanaPayRequest( - address: inputState.address, - label: inputState.label, - message: inputState.message, - amount: inputState.amount?.text, - reference: inputState.reference, - memo: inputState.memo, - splToken: inputState.splTokenAddress, - ); - String qrCode = _generateTransferRequestQrUseCase.execute(request); + if (inputState.isValid()) { + SolanaPayRequest request = SolanaPayRequest( + address: inputState.address.text, + label: inputState.label, + message: inputState.message, + amount: inputState.amount.text, + reference: inputState.reference, + memo: inputState.memo, + splToken: inputState.splTokenAddress, + ); - emit(QrCode(qrCode)); + String qrCode = _generateTransferRequestQrUseCase.execute(request); + + emit(QrCode(qrCode)); + } } } From 83a49c9168f0831d3d86eaeef40e2daa763409ad Mon Sep 17 00:00:00 2001 From: kacper Date: Tue, 19 Sep 2023 22:54:34 +0200 Subject: [PATCH 3/4] Add validation for keys --- .idea/libraries/Dart_Packages.xml | 104 ++++++++++++++++++ lib/data/base/text_value.dart | 2 +- lib/data/error/input_error.dart | 10 ++ lib/di/blocs_providers.dart | 7 +- lib/di/repositories_providers.dart | 8 +- .../input/bloc/parameters_input_cubit.dart | 38 +++++-- .../input/bloc/parameters_input_state.dart | 16 +-- .../input/parameters_input_screen.dart | 1 + lib/feature/qr/bloc/qr_generator_cubit.dart | 2 +- lib/validator/keys_validator.dart | 27 +++++ pubspec.lock | 104 ++++++++++++++++++ pubspec.yaml | 1 + 12 files changed, 294 insertions(+), 26 deletions(-) create mode 100644 lib/validator/keys_validator.dart diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 3fce297..d7fd112 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -30,6 +30,13 @@ + + + + + + @@ -44,6 +51,13 @@ + + + + + + @@ -86,6 +100,13 @@ + + + + + + @@ -93,6 +114,20 @@ + + + + + + + + + + + + @@ -142,6 +177,13 @@ + + + + + + @@ -156,6 +198,20 @@ + + + + + + + + + + + + @@ -184,6 +240,13 @@ + + + + + + @@ -254,6 +317,20 @@ + + + + + + + + + + + + @@ -289,6 +366,13 @@ + + + + + + @@ -324,6 +408,13 @@ + + + + + + @@ -450,26 +541,35 @@ + + + + + + + + + @@ -480,15 +580,19 @@ + + + + diff --git a/lib/data/base/text_value.dart b/lib/data/base/text_value.dart index f725eb2..019ae13 100644 --- a/lib/data/base/text_value.dart +++ b/lib/data/base/text_value.dart @@ -2,7 +2,7 @@ import '../error/input_error.dart'; class TextValue { TextValue({ - required this.text, + this.text = "", this.error, }); diff --git a/lib/data/error/input_error.dart b/lib/data/error/input_error.dart index d038c98..b552079 100644 --- a/lib/data/error/input_error.dart +++ b/lib/data/error/input_error.dart @@ -16,3 +16,13 @@ class RequiredAmount extends InputError { @override String text = "Field is required"; } + +class KeyNotBase58Encoded extends InputError { + @override + String text = "Invalid value, must be base58 encoded"; +} + +class KeyLengthInvalid extends InputError { + @override + String text = "Key value must be between 32 and 44 characters"; +} diff --git a/lib/di/blocs_providers.dart b/lib/di/blocs_providers.dart index be279c6..bc486b8 100644 --- a/lib/di/blocs_providers.dart +++ b/lib/di/blocs_providers.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:sol_pay_gen/domain/generate_transfer_request_qr_use_case.dart'; import 'package:sol_pay_gen/feature/qr/bloc/qr_generator_cubit.dart'; +import 'package:sol_pay_gen/validator/keys_validator.dart'; import 'package:sol_pay_gen/validator/number_validator.dart'; import '../data/transfer/transfer_request_repository.dart'; @@ -11,8 +12,10 @@ MultiBlocProvider getBlocProviders({required StatelessWidget child}) { return MultiBlocProvider( providers: [ BlocProvider( - create: (BuildContext context) => - ParametersInputCubit(context.read()), + create: (BuildContext context) => ParametersInputCubit( + context.read(), + context.read(), + ), ), BlocProvider( create: (BuildContext context) => QrGeneratorCubit( diff --git a/lib/di/repositories_providers.dart b/lib/di/repositories_providers.dart index d49c911..9de3dcd 100644 --- a/lib/di/repositories_providers.dart +++ b/lib/di/repositories_providers.dart @@ -1,5 +1,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:sol_pay_gen/data/transfer/transfer_request_repository.dart'; +import 'package:sol_pay_gen/validator/keys_validator.dart'; import 'package:sol_pay_gen/validator/number_validator.dart'; MultiRepositoryProvider getRepositoryProviders({ @@ -8,10 +9,13 @@ MultiRepositoryProvider getRepositoryProviders({ return MultiRepositoryProvider( providers: [ RepositoryProvider( - create: (context) => DefaultTransferRequestRepository(), + create: (_) => DefaultTransferRequestRepository(), ), RepositoryProvider( - create: (context) => DefaultNumberValidator(), + create: (_) => DefaultNumberValidator(), + ), + RepositoryProvider( + create: (_) => DefaultKeysValidator(), ) ], child: blocProviders, diff --git a/lib/feature/input/bloc/parameters_input_cubit.dart b/lib/feature/input/bloc/parameters_input_cubit.dart index c2e6cbf..e798ad4 100644 --- a/lib/feature/input/bloc/parameters_input_cubit.dart +++ b/lib/feature/input/bloc/parameters_input_cubit.dart @@ -2,18 +2,22 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:sol_pay_gen/data/base/text_value.dart'; import 'package:sol_pay_gen/feature/input/bloc/parameters_input_state.dart'; +import '../../../data/error/input_error.dart'; +import '../../../validator/keys_validator.dart'; import '../../../validator/number_validator.dart'; class ParametersInputCubit extends Cubit { final NumberValidator _numberValidator; + final KeysValidator _keysValidator; ParametersInputCubit( this._numberValidator, + this._keysValidator, ) : super( ParametersInputState( - address: TextValue(text: ""), - amount: TextValue(text: ""), - reference: null, + address: TextValue(), + amount: TextValue(), + reference: TextValue(), memo: null, message: null, label: null, @@ -22,9 +26,12 @@ class ParametersInputCubit extends Cubit { ); void onAddressChange(String address) { - emit( - state.copyWith(address: TextValue(text: address)), - ); + emit(state.copyWith( + address: TextValue( + text: address, + error: _validateAddress(address), + ), + )); } void onAmountChange(String amount) { @@ -45,7 +52,12 @@ class ParametersInputCubit extends Cubit { } void onReferenceChange(String reference) { - emit(state.copyWith(reference: reference)); + emit(state.copyWith( + reference: TextValue( + text: reference, + error: reference.isEmpty ? null : _keysValidator.validateKey(reference), + ), + )); } void onSplTokenChange(String token) { @@ -57,6 +69,16 @@ class ParametersInputCubit extends Cubit { } void onValidate() { - emit(state.validate()); + emit(state.copyWith( + address: state.address.copyWith( + error: _validateAddress(state.address.text), + ), + )); + } + + InputError? _validateAddress(String address) { + return address.isEmpty + ? RequiredAmount() + : _keysValidator.validateKey(address); } } diff --git a/lib/feature/input/bloc/parameters_input_state.dart b/lib/feature/input/bloc/parameters_input_state.dart index fe99384..d9d5b7c 100644 --- a/lib/feature/input/bloc/parameters_input_state.dart +++ b/lib/feature/input/bloc/parameters_input_state.dart @@ -1,11 +1,10 @@ import 'package:equatable/equatable.dart'; import 'package:sol_pay_gen/data/base/text_value.dart'; -import 'package:sol_pay_gen/data/error/input_error.dart'; class ParametersInputState extends Equatable { final TextValue address; final TextValue amount; - final String? reference; + final TextValue reference; final String? label; final String? message; final String? memo; @@ -36,7 +35,7 @@ class ParametersInputState extends Equatable { TextValue? amount, String? label, String? message, - String? reference, + TextValue? reference, String? memo, String? splTokenAddress, }) => @@ -50,13 +49,6 @@ class ParametersInputState extends Equatable { splTokenAddress: splTokenAddress ?? this.splTokenAddress, ); - ParametersInputState validate() { - return copyWith( - address: address.copyWith( - error: address.text.isEmpty ? RequiredAmount() : null, - ), - ); - } - - bool isValid() => amount.isValid() && address.isValid(); + bool isValid() => + amount.isValid() && address.isValid() && reference.isValid(); } diff --git a/lib/feature/input/parameters_input_screen.dart b/lib/feature/input/parameters_input_screen.dart index 16b95ce..55978f4 100644 --- a/lib/feature/input/parameters_input_screen.dart +++ b/lib/feature/input/parameters_input_screen.dart @@ -79,6 +79,7 @@ class InputBody extends StatelessWidget { const Padding(padding: EdgeInsets.only(top: 16.0)), BaseInput( labelText: 'Reference', + error: state.reference.error?.text, onChanged: (address) => context .read() .onReferenceChange(address), diff --git a/lib/feature/qr/bloc/qr_generator_cubit.dart b/lib/feature/qr/bloc/qr_generator_cubit.dart index f81b66e..b6d84a9 100644 --- a/lib/feature/qr/bloc/qr_generator_cubit.dart +++ b/lib/feature/qr/bloc/qr_generator_cubit.dart @@ -26,7 +26,7 @@ class QrGeneratorCubit extends Cubit { label: inputState.label, message: inputState.message, amount: inputState.amount.text, - reference: inputState.reference, + reference: inputState.reference.text, memo: inputState.memo, splToken: inputState.splTokenAddress, ); diff --git a/lib/validator/keys_validator.dart b/lib/validator/keys_validator.dart new file mode 100644 index 0000000..ae7cc5f --- /dev/null +++ b/lib/validator/keys_validator.dart @@ -0,0 +1,27 @@ +import 'package:solana/base58.dart'; + +import '../data/error/input_error.dart'; + +abstract class KeysValidator { + InputError? validateKey(String key); +} + +class DefaultKeysValidator extends KeysValidator { + // https://docs.solana.com/cli/transfer-tokens#:~:text=The%20public%20key%20is%20a,from%2032%20to%2044%20characters. + static const minSolanaKeyLength = 32; + static const maxSolanaKeyLength = 44; + + @override + InputError? validateKey(String key) { + if (key.length < minSolanaKeyLength || key.length > maxSolanaKeyLength) { + return KeyLengthInvalid(); + } else { + try { + base58decode(key); + return null; + } on FormatException catch (_) { + return KeyNotBase58Encoded(); + } + } + } +} diff --git a/pubspec.lock b/pubspec.lock index 903bafd..b0a9240 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -33,6 +33,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.11.0" + bip39: + dependency: transitive + description: + name: bip39 + sha256: de1ee27ebe7d96b84bb3a04a4132a0a3007dcdd5ad27dd14aa87a29d97c45edc + url: "https://pub.dev" + source: hosted + version: "1.0.6" bloc: dependency: transitive description: @@ -49,6 +57,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + borsh_annotation: + dependency: transitive + description: + name: borsh_annotation + sha256: "8c2cc353cb99a12b6c4f9c69e3640d2e18f5127628391658b9fceb96d4fec4d6" + url: "https://pub.dev" + source: hosted + version: "0.3.1+4" characters: dependency: transitive description: @@ -97,6 +113,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + cryptography: + dependency: transitive + description: + name: cryptography + sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35 + url: "https://pub.dev" + source: hosted + version: "2.5.0" cupertino_icons: dependency: "direct main" description: @@ -105,6 +129,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + decimal: + dependency: transitive + description: + name: decimal + sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21" + url: "https://pub.dev" + source: hosted + version: "2.3.3" + ed25519_hd_key: + dependency: transitive + description: + name: ed25519_hd_key + sha256: c5c9f11a03f5789bf9dcd9ae88d641571c802640851f1cacdb13123f171b3a26 + url: "https://pub.dev" + source: hosted + version: "2.2.1" equatable: dependency: "direct main" description: @@ -155,6 +195,14 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + url: "https://pub.dev" + source: hosted + version: "2.4.1" frontend_server_client: dependency: transitive description: @@ -171,6 +219,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + hex: + dependency: transitive + description: + name: hex + sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + http: + dependency: transitive + description: + name: http + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" + source: hosted + version: "0.13.6" http_multi_server: dependency: transitive description: @@ -203,6 +267,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" lints: dependency: transitive description: @@ -283,6 +355,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.3" + pinenacl: + dependency: transitive + description: + name: pinenacl + sha256: "3a5503637587d635647c93ea9a8fecf48a420cc7deebe6f1fc85c2a5637ab327" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + url: "https://pub.dev" + source: hosted + version: "3.7.3" pool: dependency: transitive description: @@ -323,6 +411,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + rational: + dependency: transitive + description: + name: rational + sha256: ba58e9e18df9abde280e8b10051e4bce85091e41e8e7e411b6cde2e738d357cf + url: "https://pub.dev" + source: hosted + version: "2.2.2" shelf: dependency: transitive description: @@ -360,6 +456,14 @@ packages: description: flutter source: sdk version: "0.0.99" + solana: + dependency: "direct main" + description: + name: solana + sha256: "24f6e87a28035ce7ce54a488f7476432fc5f9ffccd70547f514a2ec9c6251c87" + url: "https://pub.dev" + source: hosted + version: "0.30.0" source_map_stack_trace: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 97068b4..5567ddc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,6 +17,7 @@ dependencies: equatable: ^2.0.5 cupertino_icons: ^1.0.2 pretty_qr_code: ^2.0.3 + solana: ^0.30.0 dev_dependencies: flutter_test: From 1543fe01c162edb76796b8ec1cd015a9130022c7 Mon Sep 17 00:00:00 2001 From: kacper Date: Tue, 19 Sep 2023 22:59:26 +0200 Subject: [PATCH 4/4] Add checklist to Read.me --- README.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 004e847..9b9ee33 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,15 @@ -# sol_pay_gen +# Solana Pay QR generator QR code generator for Solana Pay -## Getting Started +## Checklist -This project is a starting point for a Flutter application. +- ✅ Validation -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +- 🚧 Download QR code +- 🚧 SPL token picker +- 🚧 Upload custom icon +- 🚧 Adaptive layout +- 🚧 How it works page +- 🚧 Transaction request +- 🚧 Transactions history