From f8b90aa28c615e7b4bb1b14f9137a9ea6acf498d Mon Sep 17 00:00:00 2001 From: Mohsen <56779182+mrtnetwork@users.noreply.github.com> Date: Tue, 23 Apr 2024 21:06:51 +0330 Subject: [PATCH] v5.1.0 Add features to solana network SPLToken, Create Account, TokenProgram, etc. --- mrt_wallet/lib/app/constant/page_path.dart | 4 +- mrt_wallet/lib/app/extention/context.dart | 26 +- .../lib/app/localization/localization.dart | 71 +- .../blockchin_utils/solana/solana.dart | 3 + .../global_pages/select_provider.dart | 35 +- .../global_pages/setup_amount.dart | 21 +- .../global_pages/token_details.dart | 87 ++- .../global_pages/transaction_amount.dart | 6 +- .../global_pages/update_tokens.dart | 96 +++ .../global_pages/wallet_signing_password.dart | 2 + .../network/bitcoin_pages/setup_address.dart | 12 +- .../import_electrum_provider.dart | 12 +- .../network/cardano_pages/account_page.dart | 11 - .../cardano_pages/setup_address_page.dart | 8 +- .../transaction/controller/impl/fee_impl.dart | 13 +- .../controller/impl/memo_impl.dart | 13 +- .../controller/impl/transaction.dart | 103 +-- .../network/cosmos/setup_address.dart | 59 +- .../transaction/controller/controller.dart | 7 +- .../transaction/controller/impl/fee.dart | 17 +- .../controller/impl/transaction.dart | 2 + .../cosmos/transaction/fields/thor_swap.dart | 1 + .../ethereum_account_page_view.dart | 44 +- .../network/ethereum_pages/setup_address.dart | 9 +- .../network/ripple_pages/account_page.dart | 45 +- .../network/ripple_pages/setup_address.dart | 9 +- .../fields/fields/payment_fields.dart | 2 +- .../ripple_global_transaction_fields.dart | 30 +- .../fields/fields/signer_list_fields.dart | 8 +- .../fields/ripple_tranaction_fields_view.dart | 5 +- .../network/solana_pages/account_page.dart | 104 ++- .../network/solana_pages/setup_address.dart | 9 +- .../transaction/controller/imp/fee_impl.dart | 35 +- .../transaction/controller/imp/memo_impl.dart | 4 +- .../controller/imp/signer_impl.dart | 17 +- .../controller/imp/transaction_impl.dart | 8 +- .../solana_transaction_controller.dart | 14 +- .../transaction/fields/transaction.dart | 679 ++++++++++++++++-- .../transaction/fields/transfer.dart | 2 +- .../network/solana_pages/update_provider.dart | 465 ++++++++++++ .../network/tron_pages/setup_address.dart | 9 +- .../tron_pages/tron_account_page_view.dart | 44 +- .../lib/future/widgets/bottom_sheet.dart | 1 + .../lib/future/widgets/dialog_view.dart | 45 +- .../progress_bar/progress_widgets.dart | 14 +- mrt_wallet/lib/main.dart | 6 + .../wallet_models/address/core/address.dart | 1 + .../core/derivation/address_derivation.dart | 7 +- .../core/derivation/bip32_address_index.dart | 100 +-- .../byron_legacy_address_index.dart | 45 +- .../derivation/imported_address_index.dart | 48 +- .../derivation/multi_sig_address_index.dart | 6 +- .../bitcoin/bitcoin_account.dart | 3 + .../network_address/cardano/cardano.dart | 2 + .../network_address/cosmos/cosmos.dart | 3 +- .../ethereum/ethereum_account.dart | 14 + .../solana/solana_address.dart | 13 + .../network_address/tron/tron_account.dart | 24 +- .../network_address/xrp/xrp_account.dart | 13 + .../lib/models/wallet_models/chain/chain.dart | 4 +- .../chain/defauilt_node_providers.dart | 4 + .../wallet_models/network/core/network.dart | 26 + .../network/params/networks/solana.dart | 23 +- .../networks/solana/solana.dart | 3 +- .../models/wallet_models/token/core/core.dart | 2 +- .../token/networks/ethereum/erc20_token.dart | 8 +- .../networks/ripple/ripple_issue_token.dart | 5 +- .../token/networks/solana/spl_token.dart | 7 +- .../token/networks/tron/trc10_token.dart | 5 +- .../token/networks/tron/trc20_token.dart | 7 +- .../provider/api/http_services/solana.dart | 22 +- .../networks/ethereum/evm_api_providr.dart | 4 +- .../api/networks/solana/api_provider.dart | 10 + .../core/transaction_validator_core.dart | 6 - .../core/validator_fields.dart | 22 +- .../transaction_validator/swap/swap.dart | 32 + .../transfer/transfer.dart | 20 +- .../transfer/transfer.dart | 26 +- .../account_set/account_set_validator.dart | 7 +- .../core/ripple_field_validator.dart | 6 +- .../ripple_escrow_cancel_validator.dart | 8 +- .../ripple_escrow_create_validator.dart | 7 +- .../ripple_escrow_finish_validator.dart | 7 +- .../nft/ripple_accept_offer_validator.dart | 7 +- .../nft/ripple_burn_token_validator.dart | 7 +- .../nft/ripple_cancel_offer_valiator.dart | 7 +- .../nft/ripple_create_offer_validator.dart | 7 +- .../nft/ripple_mint_token_validator.dart | 6 +- .../payment/ripple_payment_validator.dart | 7 +- .../ripple_regular_key_validator.dart | 7 +- .../ripple_signer_list_validator.dart | 7 +- .../trust_set/ripple_trust_set_validator.dart | 7 +- .../solana/core/solana_transaction_type.dart | 9 +- .../transaction_validator/solana/solana.dart | 4 + .../solana/transfer/create_account.dart | 146 ++++ ...te_associated_token_account_validator.dart | 106 +++ .../solana/transfer/initialize_mint.dart | 98 +++ .../solana/transfer/mint_to.dart | 188 +++++ .../solana/transfer/transfer.dart | 26 +- ..._update_contract_permission_validator.dart | 20 +- .../account/update_account.dart | 22 +- .../resource_v2/delegated_resource.dart | 32 +- .../resource_v2/freez_balance_v2.dart | 24 +- .../resource_v2/undelegated_resource.dart | 26 +- .../resource_v2/unfreez_balance_v2.dart | 24 +- .../transfer/transfer.dart | 35 +- .../vote_sr/create_witness.dart | 22 +- mrt_wallet/lib/provider/wallet/core/core.dart | 16 + .../provider/wallet/network/network_imp.dart | 14 + .../provider/wallet/signer/signer_impl.dart | 17 +- mrt_wallet/pubspec.lock | 4 +- mrt_wallet/pubspec.yaml | 4 +- 112 files changed, 2720 insertions(+), 946 deletions(-) create mode 100644 mrt_wallet/lib/future/pages/wallet_pages/global_pages/update_tokens.dart delete mode 100644 mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/account_page.dart create mode 100644 mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/fields/thor_swap.dart create mode 100644 mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/update_provider.dart create mode 100644 mrt_wallet/lib/provider/transaction_validator/cosmos/transaction_validator/swap/swap.dart create mode 100644 mrt_wallet/lib/provider/transaction_validator/solana/transfer/create_account.dart create mode 100644 mrt_wallet/lib/provider/transaction_validator/solana/transfer/create_associated_token_account_validator.dart create mode 100644 mrt_wallet/lib/provider/transaction_validator/solana/transfer/initialize_mint.dart create mode 100644 mrt_wallet/lib/provider/transaction_validator/solana/transfer/mint_to.dart diff --git a/mrt_wallet/lib/app/constant/page_path.dart b/mrt_wallet/lib/app/constant/page_path.dart index 707b4ed4..3243d05b 100644 --- a/mrt_wallet/lib/app/constant/page_path.dart +++ b/mrt_wallet/lib/app/constant/page_path.dart @@ -21,6 +21,7 @@ class PagePathConst { static const String tronMultiSigAddress = "/tron/setup_multisig_address"; // solana transfer static const String solanaTransfer = "/solana/transfer"; + static const String solanaTransaction = "/solana/transaction"; /// cardano static const String cardanoTransaction = "/cardano/transaction"; @@ -58,9 +59,10 @@ class PagePathConst { static const String importEVMNetwork = "/networks/import"; static const String editEvmNetwork = "/networks/edit"; static const String updateElectrumProviders = "/networks/bitcoin/providers"; - + static const String editSolanaNetwork = "/networks/solana/providers"; static String providerDetails(AppNetworkImpl network) { if (network is APPEVMNetwork) return editEvmNetwork; + if (network is APPSolanaNetwork) return editSolanaNetwork; return updateElectrumProviders; } diff --git a/mrt_wallet/lib/app/extention/context.dart b/mrt_wallet/lib/app/extention/context.dart index c227d894..a476b937 100644 --- a/mrt_wallet/lib/app/extention/context.dart +++ b/mrt_wallet/lib/app/extention/context.dart @@ -36,6 +36,15 @@ extension QuickContextAccsess on BuildContext { return null; } + Future offTo(String path, {dynamic argruments}) async { + if (mounted) { + final push = + Navigator.popAndPushNamed(this, path, arguments: argruments); + return push; + } + return null; + } + void showAlert(String message) { if (mounted) { final sc = Repository.messengerKey(this); @@ -88,7 +97,22 @@ extension QuickContextAccsess on BuildContext { return DialogView( title: label, content: content?.call(context) ?? const [], - child: widget(context), + widget: widget(context), + ); + }, + ); + } + + Future openDialogPage(WidgetContext child, String label, + {List Function(BuildContext)? content}) async { + return await showAdaptiveDialog( + context: this, + useRootNavigator: true, + builder: (context) { + return DialogView( + title: label, + content: content?.call(context) ?? const [], + child: child(context), ); }, ); diff --git a/mrt_wallet/lib/app/localization/localization.dart b/mrt_wallet/lib/app/localization/localization.dart index 0a9c3b53..8432c9f7 100644 --- a/mrt_wallet/lib/app/localization/localization.dart +++ b/mrt_wallet/lib/app/localization/localization.dart @@ -1312,9 +1312,9 @@ class Localization { "The header of the current block chain tip.", "network_update_node_provider": "Update node provider", "network_security_title": - "Ensuring wallet security: tips for adding Electrum servers", + "Ensuring wallet security: tips for adding node providers", "network_security_desc": - "Ensuring the security of your wallet is paramount. When adding a new Electrum server, it's crucial to verify the RPC endpoint's accuracy to prevent potential security compromises. Before integration, double-check the RPC URL for correctness. Take an additional layer of caution by cross-referencing the current server header with a trusted block explorer or other reliable sources. These measures enhance security, providing confidence that the Electrum server added to your wallet is secure and free from any malicious intent.", + "Ensuring the security of your wallet is paramount. When adding a new provider, it's crucial to verify the RPC endpoint's accuracy to prevent potential security compromises. Before integration, double-check the RPC URL for correctness. Take an additional layer of caution by cross-referencing the current server header with a trusted block explorer or other reliable sources. These measures enhance security, providing confidence that the provider added to your wallet is secure and free from any malicious intent.", "network_add_to_providers": "Add to providers.", "network_update_network_providers": "Update network providers.", "network": "Network", @@ -1366,7 +1366,8 @@ class Localization { "When using RBF, make sure your UTXOs have been confirmed; otherwise, you may encounter a non-final error", "inaccessible_key_algorithm": "Key algorithm inaccessible in multisig account.", - "recipient_info": "Recipient info", + "destination_info": "Destination info", + "destination_info_desc": "The information about destination account", "executable": "Executable", "import_spl_tokens": "Import SPL Tokens", "unable_to_locate_token": @@ -1424,7 +1425,69 @@ class Localization { "enther_valid_un_label": "Please enter a valid unsigned number for the label.", "label_already_exists": "The label you entered already exists.", - "no_account_chosen": "No account has been chosen." + "no_account_chosen": "No account has been chosen.", + "associated_token_program": "Associated Token Program", + "create_associated_token_account": "Create Associated Token Account", + "mint": "Mint", + "token_program": "Token Program", + "owner_address": "Owner address", + "mint_address": "Mint address", + "mint_address_desc": "The mint account address", + "program_address": "Program address", + "program_address_desc": "The address of token program", + "associated_token_address": "Associated token address", + "new_account_address": "New Account address", + "solana_new_account_desc": + "Please provide the address for the account you wish to create, the account should be imported to your wallet before creation", + "owner_of_account": "The owner of account", + "account_size": "Account size", + "lamports": "Lamports", + "create_account": "Create Account", + "solana_create_account_desc": + "A created account is initialized to be owned by a built-in program called the System program.", + "setup_account_size": "Setup account size", + "solana_create_account_lamports_desc": + "Amount of lamports to transfer to the created account", + "required_signer_account_missing": + "Required signer account is missing", + "solana_account_size_desc": + "the amount of memory allocated to store data associated with the account on the blockchain", + "mint_authority": "Mint authority", + "decimals": "Decimals", + "solana_mint_decimal_desc": + "Number of base 10 digits to the right of the decimal place", + "mint_authority_desc": "The authority of mint tokens.", + "freeze_authority": "Freeze authority", + "freeze_authority_desc": "The freeze authority of the mint.", + "program_id": "Program ID", + "solana_program_id_desc": "The unique identifier of the application", + "mint_address_to_initialize": "The mint address to initialize.", + "setup_token_decimal": "Setup token decimals", + "initialize_mint": "Initialize mint", + "initiailize_mint_desc": + "Initializing a mint in Solana creates a new token type.", + "transfer_symbol": "Transfer ___1__", + "mint_to": "Mint to", + "mint_address_mint_desc": "The mint address", + "mint_to_desc": "Mints new tokens to an account.", + "authority": "Authority", + "mint_to_authority_desc": "The mint's minting authority.", + "mint_to_destination_desc": "The account to mint tokens to.", + "unknown_token": "Unknown token", + "mint_to_amount_desc": "The amount of new tokens to mint.", + "use_owner_account_instead_pda_desc": + "The account to mint tokens to. Utilize owner account. application automatically locates current PDA account.", + "name": "Name", + "update_token": "Update token", + "update_token_information": "Update token information", + "update_token_desc": "Update the name and symbol of the token", + "token_symbol_validator": + "The token symbol must be at least 2 characters long", + "token_name_validator": + "The token name must be at least 3 characters long", + "create_new_provider": "Create New Provider", + "gnesis_hash_desc": + "The genesis hash is the unique identifier for the initial block in a blockchain network, often used for network bootstrapping and verifying network state" } }; } diff --git a/mrt_wallet/lib/app/utility/blockchin_utils/solana/solana.dart b/mrt_wallet/lib/app/utility/blockchin_utils/solana/solana.dart index e94ab01f..5ee464f0 100644 --- a/mrt_wallet/lib/app/utility/blockchin_utils/solana/solana.dart +++ b/mrt_wallet/lib/app/utility/blockchin_utils/solana/solana.dart @@ -1,3 +1,4 @@ +import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:mrt_wallet/models/wallet_models/currency_balance/currency_balance.dart'; class SolanaConstants { @@ -6,4 +7,6 @@ class SolanaConstants { static final NoneDecimalBalance systemProgramRent = NoneDecimalBalance(BigInt.from(890880), decimal, imutable: true); static const int decimal = 9; + static final BigRational maximumAccountSizeBytes = BigRational.from(10240); + static final BigRational maxSPLTokenDecimalPlaces = BigRational.from(18); } diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/select_provider.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/select_provider.dart index f6100af9..3e87ac1f 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/select_provider.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/select_provider.dart @@ -18,8 +18,7 @@ class SelectProviderIcon extends StatelessWidget { return LiveWidget(() { final ApiProviderTracker? provider = wallet.chain.provider()?.serviceProvider; - final bool supportCustomNode = - wallet.network is! AppXRPNetwork && wallet.network is! APPTVMNetwork; + return IconButton( tooltip: provider.message().tr, onPressed: () { @@ -27,9 +26,8 @@ class SelectProviderIcon extends StatelessWidget { (ctx) => _SelectProviderView( network: wallet.network, selectedProvider: provider, - supportCustomNode: supportCustomNode, ), content: (context) { - return supportCustomNode + return wallet.network.supportCustomNode ? [ WidgetConstant.width8, IconButton( @@ -74,18 +72,16 @@ class ProviderTrackerStatusView extends StatelessWidget { class _SelectProviderView extends StatelessWidget { const _SelectProviderView( - {required this.selectedProvider, - required this.network, - this.supportCustomNode = false}); + {required this.selectedProvider, required this.network}); final ApiProviderTracker? selectedProvider; final AppNetworkImpl network; - final bool supportCustomNode; bool get isTVM => network is APPTVMNetwork; @override Widget build(BuildContext context) { Set providers = { ...DefaultNodeProviders.getDefaultServices(network), - ...network.coinParam.providers.where((element) => element.protocol.platforms.contains(PlatformInterface.appPlatform)), + ...network.coinParam.providers.where((element) => + element.protocol.platforms.contains(PlatformInterface.appPlatform)), }; return SingleChildScrollView( @@ -153,7 +149,7 @@ class _SelectProviderView extends StatelessWidget { }, itemCount: providers.length, ), - ] else if (supportCustomNode) + ] else if (network.supportCustomNode) Row( children: [ Expanded( @@ -290,8 +286,11 @@ class _ProviderLogsViewState extends State<_ProviderLogsView> with SafeState { Text("url".tr, style: context.textTheme.titleSmall), ContainerWithBorder( backgroundColor: context.colors.secondary, - onRemoveIcon: - CopyTextIcon(dataToCopy: request.uri!), + onRemove: () {}, + onRemoveIcon: CopyTextIcon( + dataToCopy: request.uri!, + color: context.colors.onSecondary, + ), onTapWhenOnRemove: false, child: Text( request.uri!, @@ -307,8 +306,10 @@ class _ProviderLogsViewState extends State<_ProviderLogsView> with SafeState { ContainerWithBorder( backgroundColor: context.colors.secondary, onRemove: () {}, - onRemoveIcon: - CopyTextIcon(dataToCopy: request.params!), + onRemoveIcon: CopyTextIcon( + dataToCopy: request.params!, + color: context.colors.onSecondary, + ), onTapWhenOnRemove: false, child: Text( request.params!, @@ -336,8 +337,10 @@ class _ProviderLogsViewState extends State<_ProviderLogsView> with SafeState { ContainerWithBorder( backgroundColor: context.colors.secondary, onRemove: () {}, - onRemoveIcon: - CopyTextIcon(dataToCopy: request.response!), + onRemoveIcon: CopyTextIcon( + dataToCopy: request.response!, + color: context.colors.onSecondary, + ), onTapWhenOnRemove: false, child: Text( request.response!, diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/setup_amount.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/setup_amount.dart index 04f75be8..61aa7729 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/setup_amount.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/setup_amount.dart @@ -28,11 +28,16 @@ class SetupNetworkAmount extends StatefulWidget { class _SetupNetworkAmountState extends State with SafeState { + late final BigInt? maxValue = widget.max == null + ? null + : widget.max!.isNegative + ? BigInt.zero + : widget.max; final GlobalKey form = GlobalKey(debugLabel: "SetupNetworkAmount"); final GlobalKey textFieldKey = GlobalKey(); late final String? maxString = - PriceUtils.tryEncodePrice(widget.max, widget.token.decimal!); + PriceUtils.tryEncodePrice(maxValue, widget.token.decimal!); late final String? minString = PriceUtils.tryEncodePrice(widget.min, widget.token.decimal!); late final bool enableMin = (widget.min ?? BigInt.zero) > BigInt.zero; @@ -50,7 +55,7 @@ class _SetupNetworkAmountState extends State } return "decimal_int_validator".tr; } - if (widget.max != null && toBigit > widget.max!) { + if (maxValue != null && toBigit > maxValue!) { return "price_less_than".tr.replaceOne( PriceUtils.priceWithCoinName(maxString!, widget.token.symbolView)); } else if (widget.min != null && toBigit < widget.min!) { @@ -65,10 +70,10 @@ class _SetupNetworkAmountState extends State bool isMin = false; void onChanged(String v) { price = v; - if (widget.max == null && !enableMin) return; + if (maxValue == null && !enableMin) return; final toBigit = PriceUtils.tryDecodePrice(price, widget.token.decimal!); - final equal = toBigit == widget.max; + final equal = toBigit == maxValue; if (equal != isMax) { setState(() { isMax = equal; @@ -85,7 +90,7 @@ class _SetupNetworkAmountState extends State } void onTapMax() { - final p = PriceUtils.tryEncodePrice(widget.max, widget.token.decimal!); + final p = PriceUtils.tryEncodePrice(maxValue, widget.token.decimal!); if (p != null) { textFieldKey.currentState?.updateText(p); } @@ -171,7 +176,7 @@ class _SetupNetworkAmountState extends State ], ), ), - if (widget.max != null || enableMin) ...[ + if (maxValue != null || enableMin) ...[ Row( mainAxisAlignment: MainAxisAlignment.end, children: [ @@ -189,9 +194,9 @@ class _SetupNetworkAmountState extends State borderRadius: WidgetConstant.border8)), child: Text("min".tr), ), - if (widget.max != null) WidgetConstant.width8, + if (maxValue != null) WidgetConstant.width8, ], - if (widget.max != null) + if (maxValue != null) FilledButton( onPressed: onTapMax, style: TextButton.styleFrom( diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/token_details.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/token_details.dart index 0ec3bdfd..3933d572 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/token_details.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/token_details.dart @@ -1,28 +1,103 @@ import 'package:flutter/material.dart'; import 'package:mrt_wallet/app/core.dart'; +import 'package:mrt_wallet/future/pages/start_page/home.dart'; import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/address_details.dart'; +import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/update_tokens.dart'; import 'package:mrt_wallet/future/widgets/custom_widgets.dart'; +import 'package:mrt_wallet/main.dart'; import 'package:mrt_wallet/models/wallet_models/wallet_models.dart'; enum TokenAction { delete, transfer } class TokenDetailsModalView extends StatelessWidget { const TokenDetailsModalView( - {super.key, required this.token, required this.address}); + {super.key, + required this.token, + required this.address, + required this.transferPath}); final TokenCore token; final CryptoAccountAddress address; + final String transferPath; @override Widget build(BuildContext context) { - return Column( - children: [_RippleTokenView(token: token, address: address)], + final wallet = context.watch(StateIdsConst.main); + return CustomScrollView( + shrinkWrap: true, + slivers: [ + SliverAppBar( + title: Text("token_info".tr), + leading: WidgetConstant.sizedBox, + leadingWidth: 0, + pinned: true, + actions: [ + IconButton( + onPressed: () { + context + .openSliverBottomSheet( + "update_token".tr, + child: UpdateTokenDetailsView(token: token.token), + ) + .then((value) { + if (value != null) { + wallet + .updateToken( + token: token, + updatedToken: value, + address: address) + .then((value) { + if (value.hasError) return; + context.pop(); + }); + } + }); + }, + icon: const Icon(Icons.edit)), + IconButton( + onPressed: () { + context.openSliverDialog( + (ctx) => DialogTextView( + buttomWidget: AsyncDialogDoubleButtonView( + firstButtonPressed: () => wallet + .removeToken(token, address) + .then((value) { + if (value.hasError) return; + context.pop(); + }), + ), + text: "remove_token_from_account".tr), + "remove_token".tr); + }, + icon: Icon(Icons.delete, color: context.colors.error)), + const CloseButton(), + WidgetConstant.width8, + ], + ), + SliverToBoxAdapter( + child: ConstraintsBoxView( + padding: WidgetConstant.padding20, + child: _TokenDetailsView( + token: token, + address: address, + wallet: wallet, + transferPath: transferPath, + ), + ), + ), + ], ); } } -class _RippleTokenView extends StatelessWidget { - const _RippleTokenView({required this.token, required this.address}); +class _TokenDetailsView extends StatelessWidget { + const _TokenDetailsView( + {required this.token, + required this.address, + required this.wallet, + required this.transferPath}); final TokenCore token; final CryptoAccountAddress address; + final WalletProvider wallet; + final String transferPath; @override Widget build(BuildContext context) { @@ -53,7 +128,7 @@ class _RippleTokenView extends StatelessWidget { children: [ FloatingActionButton( onPressed: () { - context.pop(TokenAction.transfer); + context.offTo(transferPath, argruments: token); }, child: const Icon(Icons.upload), ), diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/transaction_amount.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/transaction_amount.dart index f598bcba..3aa7054d 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/transaction_amount.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/transaction_amount.dart @@ -10,6 +10,7 @@ class TransactionAmountView extends StatelessWidget { required this.amount, required this.token, required this.onTap, + this.onRemoveIcon, this.title, this.subtitle, this.validate = true, @@ -21,6 +22,7 @@ class TransactionAmountView extends StatelessWidget { final String? validateError; final String? subtitle; final String? title; + final Widget? onRemoveIcon; @override Widget build(BuildContext context) { bool hasAmount = amount != null && !amount!.isZero; @@ -35,8 +37,8 @@ class TransactionAmountView extends StatelessWidget { validate: hasAmount && validate, onRemove: onTap, validateText: validateError, - onRemoveIcon: - hasAmount ? const Icon(Icons.edit) : const Icon(Icons.add), + onRemoveIcon: onRemoveIcon ?? + (hasAmount ? const Icon(Icons.edit) : const Icon(Icons.add)), child: hasAmount ? CoinPriceView( token: token, diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/update_tokens.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/update_tokens.dart new file mode 100644 index 00000000..455883a5 --- /dev/null +++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/update_tokens.dart @@ -0,0 +1,96 @@ +import 'package:flutter/widgets.dart'; +import 'package:mrt_wallet/app/core.dart'; +import 'package:mrt_wallet/future/widgets/custom_widgets.dart'; +import 'package:mrt_wallet/models/wallet_models/network/network_models.dart'; + +class UpdateTokenDetailsView extends StatefulWidget { + const UpdateTokenDetailsView({super.key, required this.token}); + final Token token; + + @override + State createState() => _UpdateTokenDetailsViewState(); +} + +class _UpdateTokenDetailsViewState extends State + with SafeState { + final GlobalKey nameTextFieldKey = + GlobalKey(debugLabel: "_UpdateTokenDetailsViewState_nameTextFieldKey"); + final GlobalKey symbolTextFieldKey = + GlobalKey(debugLabel: "_UpdateTokenDetailsViewState_symbolTextFieldKey"); + final GlobalKey formKey = + GlobalKey(debugLabel: "_UpdateTokenDetailsViewState"); + late String tokenName = widget.token.name; + late String tokenSymbol = widget.token.name; + void onTokenNameChange(String v) { + tokenName = v; + } + + void onTokenSymbolChange(String v) { + tokenSymbol = v; + } + + String? tokenNamevalidator(String? v) { + final val = v?.trim() ?? ""; + if (val.length < 3) { + return "token_name_validator".tr; + } + return null; + } + + void onPressed() { + if (!(formKey.currentState?.validate() ?? false)) return; + if (context.mounted) { + context.pop(widget.token.copyWith(name: tokenName, symbol: tokenSymbol)); + } + } + + String? tokenSymbolvalidator(String? v) { + final val = v?.trim() ?? ""; + if (val.length < 2) { + return "token_symbol_validator".tr; + } + return null; + } + + @override + Widget build(BuildContext context) { + return Form( + key: formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + PageTitleSubtitle( + title: "update_token_information".tr, + body: Text("update_token_desc".tr)), + WidgetConstant.height20, + AppTextField( + label: "name".tr, + minlines: 1, + initialValue: tokenName, + validator: tokenNamevalidator, + onChanged: onTokenNameChange, + key: nameTextFieldKey), + WidgetConstant.height20, + AppTextField( + label: "symbol".tr, + minlines: 1, + initialValue: tokenName, + validator: tokenSymbolvalidator, + onChanged: onTokenSymbolChange, + key: symbolTextFieldKey), + WidgetConstant.height20, + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FixedElevatedButton( + padding: WidgetConstant.paddingVertical20, + onPressed: onPressed, + child: Text("update_token".tr), + ) + ], + ) + ], + ), + ); + } +} diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/wallet_signing_password.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/wallet_signing_password.dart index 5f3172cb..714eb830 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/wallet_signing_password.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/wallet_signing_password.dart @@ -135,11 +135,13 @@ class _WalletSigningPasswordState extends State key: ValueKey(showAllAddresses), child: showAllAddresses ? Column( + crossAxisAlignment: CrossAxisAlignment.start, children: List.generate(addresses.length, (index) { final address = addresses.elementAt(index); final bool isLastIndex = index == addresses.length - 1; return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ AddressDetailsView(address: address), if (!isLastIndex) diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/bitcoin_pages/setup_address.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/bitcoin_pages/setup_address.dart index 9f48a9da..c3c9d288 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/bitcoin_pages/setup_address.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/bitcoin_pages/setup_address.dart @@ -155,10 +155,12 @@ class _SetupBitcoinAddressViewState extends State super.didChangeDependencies(); } - AddressDerivationIndex? derivationkey() { + AddressDerivationIndex? derivationkey(CryptoCoins coin) { if (selectedCustomKey != null) { return ImportedAddressIndex( - accountId: selectedCustomKey!.id, bip32KeyIndex: customKeyIndex); + accountId: selectedCustomKey!.id, + bip32KeyIndex: customKeyIndex, + currencyCoin: coin); } return customKeyIndex; } @@ -180,7 +182,8 @@ class _SetupBitcoinAddressViewState extends State } else { selectedType = selected.first; } - final keyIndex = derivationkey() ?? chainAccount.account.nextDrive(coin); + final keyIndex = + derivationkey(coin) ?? chainAccount.account.nextDrive(coin); NewAccountParams newAccount; if (network is AppBitcoinCashNetwork) { newAccount = BitcoinCashNewAddressParams( @@ -200,8 +203,7 @@ class _SetupBitcoinAddressViewState extends State buttomText: "generate_new_address".tr, buttomWidget: ContainerWithBorder( margin: WidgetConstant.paddingVertical8, - child: AddressDetailsView( - address: result.result)), + child: AddressDetailsView(address: result.result)), onPressed: () { if (mounted) { pageProgressKey.backToIdle(); diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/bitcoin_pages/update_provider/import_electrum_provider.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/bitcoin_pages/update_provider/import_electrum_provider.dart index 9c186bda..2c967cb9 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/bitcoin_pages/update_provider/import_electrum_provider.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/bitcoin_pages/update_provider/import_electrum_provider.dart @@ -57,8 +57,7 @@ class __ImportElectrumProviderState extends State<_ImportElectrumProvider> { final GlobalKey pageProgressKey = GlobalKey(); final GlobalKey uriFieldKey = GlobalKey(); late List evmNetworks; - late String symbol = widget.network.coinParam.token.symbol; - late String networkName = widget.network.coinParam.token.name; + String rpcUrl = ""; ElectrumServerInfos? serverInfo; bool validGnesis = false; @@ -236,7 +235,7 @@ class __ImportElectrumProviderState extends State<_ImportElectrumProvider> { } } - void onAddChain() async { + void onAddProvider() async { if ((providers.isEmpty && defaultProviders.isEmpty) || selectedProvider != null) return; if (!(formKey.currentState?.validate() ?? false)) return; @@ -246,10 +245,7 @@ class __ImportElectrumProviderState extends State<_ImportElectrumProvider> { final services = providers.map((e) => e.serviceProvider.provider).toList(); final updatedNetwork = network.copyWith( - coinParam: network.coinParam.copyWith( - providers: services, - token: network.coinParam.token - .copyWith(name: networkName, symbol: symbol))); + coinParam: network.coinParam.copyWith(providers: services)); return await wallet.updateImportNetwork(updatedNetwork); }); if (result.hasError) { @@ -411,7 +407,7 @@ class __ImportElectrumProviderState extends State<_ImportElectrumProvider> { WidgetConstant.paddingVertical20, onPressed: enableUpdateButton ? null - : onAddChain, + : onAddProvider, child: Text( "network_update_network_providers" .tr), diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/account_page.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/account_page.dart deleted file mode 100644 index 8126a38b..00000000 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/account_page.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:mrt_wallet/models/wallet_models/wallet_models.dart'; - -class CardanoAccountPageView extends StatelessWidget { - const CardanoAccountPageView({required this.chainAccount, super.key}); - final AppChain chainAccount; - @override - Widget build(BuildContext context) { - return const TabBarView(children: []); - } -} diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/setup_address_page.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/setup_address_page.dart index 60b8b670..52b3992e 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/setup_address_page.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/setup_address_page.dart @@ -226,10 +226,12 @@ class _SetupCardanoAddressViewState extends State super.didChangeDependencies(); } - AddressDerivationIndex? derivationkey() { + AddressDerivationIndex? derivationkey(CryptoCoins coin) { if (selectedCustomKey != null) { return ImportedAddressIndex( - accountId: selectedCustomKey!.id, bip32KeyIndex: customKeyIndex); + accountId: selectedCustomKey!.id, + bip32KeyIndex: customKeyIndex, + currencyCoin: coin); } return customKeyIndex; } @@ -238,7 +240,7 @@ class _SetupCardanoAddressViewState extends State if (!(form.currentState?.validate() ?? false)) return; pageProgressKey.progressText("generating_new_addr".tr); final model = context.watch(StateIdsConst.main); - final keyIndex = derivationkey() ?? + final keyIndex = derivationkey(coin) ?? chainAccount.account.nextDrive(coin, seedGeneration: seedGenerationType, masterKeyGeneration: diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/fee_impl.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/fee_impl.dart index a0652cc8..962b89b8 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/fee_impl.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/fee_impl.dart @@ -17,18 +17,17 @@ mixin CardanoTransactionFeeImpl on CardanoTransactionImpl { NoneDecimalBalance.zero(network.coinParam.decimal); late final NoneDecimalBalance _networkRequiredFee = NoneDecimalBalance.zero(network.coinParam.decimal); - NoneDecimalBalance get networkRequiredFee => _networkRequiredFee; - @override - NoneDecimalBalance get transactionFee => _feeRate; CardanoFeeRateType _feeRateType = CardanoFeeRateType.basic; - CardanoFeeRateType get feeRateType => _feeRateType; - bool get hasFee => !transactionFee.isZero; - String? _feeError; - String? get feeError => _feeError; @override int get coinsPerUtxoSize => _protocolParams!.coinsPerUtxoSize; + String? get feeError => _feeError; + CardanoFeeRateType get feeRateType => _feeRateType; + bool get hasFee => !transactionFee.isZero; + NoneDecimalBalance get networkRequiredFee => _networkRequiredFee; + @override + NoneDecimalBalance get transactionFee => _feeRate; @override Future calculateFee() async { diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/memo_impl.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/memo_impl.dart index dfdc1d2c..005cc882 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/memo_impl.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/memo_impl.dart @@ -6,21 +6,26 @@ typedef OnAddCardanoMemo = Future<(String, BigInt)?> Function( List existsLabel, String? currentTxt); mixin CardanoTransactionMemoImpl on CardanoTransactionImpl { - final Map _metadata = {}; + Map _metadata = + Map.unmodifiable({}); Map get metadatas => _metadata; @override GeneralTransactionMetadata? get transactionMemo => _metadata.isEmpty ? null : GeneralTransactionMetadata(metadata: _metadata); + Future addMetaData(OnAddCardanoMemo addMemo, {BigInt? current}) async { try { final memo = _metadata[current]?.value; final labels = List.from(_metadata.keys.toList()) ..removeWhere((element) => element == current); final m = await addMemo(labels, memo); - _metadata.remove(current); - if (m == null) return; - _metadata[m.$2] = TransactionMetadataText(value: m.$1); + final meta = Map.from(_metadata); + meta.remove(current); + if (m != null) { + meta[m.$2] = TransactionMetadataText(value: m.$1); + } + _metadata = Map.unmodifiable(meta); } finally { notify(); calculateFee(); diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/transaction.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/transaction.dart index 9db39240..dd751d98 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/transaction.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/transaction.dart @@ -16,28 +16,13 @@ import 'package:on_chain/on_chain.dart'; enum CardanoTransactionPages { account, utxo, send } abstract class CardanoTransactionImpl extends StateController { - Future calculateFee(); - GeneralTransactionMetadata? get transactionMemo; - NoneDecimalBalance get transactionFee; - int get coinsPerUtxoSize; - final WalletProvider walletProvider; - final AppChain chainAccount; - NetworkAccountCore get account => chainAccount.account; - APPCardanoNetwork get network => chainAccount.network.toNetwork(); - CardanoApiProvider get providers => chainAccount.provider()!; - ICardanoAddress get address => - chainAccount.account.address as ICardanoAddress; - final GlobalKey progressKey = - GlobalKey(debugLabel: "CardanoTransactionImpl"); - List get addresses => chainAccount.account.addresses.cast(); - CardanoTransactionImpl( - {required this.walletProvider, required this.chainAccount}); late final NoneDecimalBalance spendableAmount = NoneDecimalBalance.zero(network.coinParam.decimal); late final NoneDecimalBalance setupAmount = NoneDecimalBalance.zero(network.coinParam.decimal); late final NoneDecimalBalance sumOfSelectedUtxo = NoneDecimalBalance.zero(network.coinParam.decimal); + late final CardanoOutputWithBalance _changeADAOutput = CardanoOutputWithBalance( address: ReceiptAddress( @@ -46,6 +31,8 @@ abstract class CardanoTransactionImpl extends StateController { networkAddress: address.networkAddress), network: network); CardanoOutputWithBalance get changeADAOutput => _changeADAOutput; + NoneDecimalBalance get remindAmount => changeADAOutput.balance; + late final CardanoOutputWithBalance _changeAssetOutput = CardanoOutputWithBalance( address: ReceiptAddress( @@ -55,9 +42,62 @@ abstract class CardanoTransactionImpl extends StateController { network: network); CardanoOutputWithBalance get changeAssetOutput => _changeAssetOutput; + final GlobalKey progressKey = + GlobalKey(debugLabel: "CardanoTransactionImpl"); + final WalletProvider walletProvider; + + final AppChain chainAccount; + NetworkAccountCore get account => chainAccount.account; + APPCardanoNetwork get network => chainAccount.network.toNetwork(); + CardanoApiProvider get providers => chainAccount.provider()!; + ICardanoAddress get address => + chainAccount.account.address as ICardanoAddress; + List get addresses => chainAccount.account.addresses.cast(); + + GeneralTransactionMetadata? get transactionMemo; + NoneDecimalBalance get transactionFee; + int get coinsPerUtxoSize; + Future calculateFee(); + + CardanoTransactionImpl( + {required this.walletProvider, required this.chainAccount}); + bool _trReady = false; bool get trReady => _trReady; + CardanoTransactionPages _page = CardanoTransactionPages.account; + CardanoTransactionPages get page => _page; + bool get inUtxoPage => _page == CardanoTransactionPages.utxo; + bool get inSendPage => _page == CardanoTransactionPages.send; + + UtxoMultiAsset _totalAsset = UtxoMultiAsset.empty; + UtxoMultiAsset get totalAssets => _totalAsset; + bool get hasAsset => _totalAsset.hasAsset; + + final Map> _fetchedUtxos = {}; + + final Map _accountUtxos = {}; + List get utxos => _accountUtxos.values.toList(); + + final List _selectedUtxos = []; + List get selectedUtxos => _selectedUtxos; + bool get allUtxosSelected => _selectedUtxos.length == _utxosCount; + bool utxoSelected(CardanoUtxo utxo) => _selectedUtxos.contains(utxo); + bool get canBuildTransaction => _selectedUtxos.isNotEmpty; + + int _utxosCount = 0; + + bool get haveUtxos => _utxosCount > 0; + + final List _addresses = []; + bool addressSelected(ICardanoAddress addr) => + _addresses.contains(addr.networkAddress); + List get spenders => _addresses; + bool get hasSpender => spenders.isNotEmpty; + + final Map _receivers = {}; + List get receivers => _receivers.values.toList(); + void changeOutputAddress(ICardanoAddress? changeAddr) { if (changeAddr == null || changeAddr.address.toAddress == _changeADAOutput.address.view) return; @@ -78,11 +118,6 @@ abstract class CardanoTransactionImpl extends StateController { notify(); } - CardanoTransactionPages _page = CardanoTransactionPages.account; - CardanoTransactionPages get page => _page; - UtxoMultiAsset _totalAsset = UtxoMultiAsset.empty; - UtxoMultiAsset get totalAssets => _totalAsset; - bool get hasAsset => _totalAsset.hasAsset; void onSetupUtxo() { _totalAsset = selectedUtxos.fold(UtxoMultiAsset({}), (previousValue, element) => previousValue + element.utxo.multiAsset); @@ -98,16 +133,6 @@ abstract class CardanoTransactionImpl extends StateController { notify(); } - bool get inUtxoPage => _page == CardanoTransactionPages.utxo; - bool get inSendPage => _page == CardanoTransactionPages.send; - - final Map> _fetchedUtxos = {}; - final Map _accountUtxos = {}; - final List _selectedUtxos = []; - List get selectedUtxos => _selectedUtxos; - bool get canBuildTransaction => _selectedUtxos.isNotEmpty; - - int _utxosCount = 0; void _countUtxos() { _utxosCount = 0; for (final i in _accountUtxos.values) { @@ -115,13 +140,6 @@ abstract class CardanoTransactionImpl extends StateController { } } - bool get allUtxosSelected => _selectedUtxos.length == _utxosCount; - bool get haveUtxos => _utxosCount > 0; - - List get utxos => _accountUtxos.values.toList(); - final List _addresses = []; - List get spenders => _addresses; - bool get hasSpender => spenders.isNotEmpty; void addSpender(ICardanoAddress address) { final r = _addresses.remove(address.networkAddress); if (!r) { @@ -161,11 +179,6 @@ abstract class CardanoTransactionImpl extends StateController { } } - bool utxoSelected(CardanoUtxo utxo) => _selectedUtxos.contains(utxo); - - bool addressSelected(ICardanoAddress addr) => - _addresses.contains(addr.networkAddress); - Future fetchUtxos() async { if (_addresses.isEmpty) return; progressKey.progressText("retreiving_account_utxos".tr); @@ -200,10 +213,6 @@ abstract class CardanoTransactionImpl extends StateController { progressKey.success(); } - final Map _receivers = {}; - List get receivers => _receivers.values.toList(); - NoneDecimalBalance get remindAmount => changeADAOutput.balance; - void removeReceiver(ReceiptAddress? addr) { if (addr == null) return; final re = _receivers.remove(addr.networkAddress.address); diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/setup_address.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/setup_address.dart index 5a3aa266..6deb8fc3 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/setup_address.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/setup_address.dart @@ -32,12 +32,6 @@ class _SetupCosmosAddressViewState extends State final GlobalKey visibleXAddressDetails = GlobalKey(debugLabel: "visibleContinue"); - // EllipticCurveTypes algorithm = EllipticCurveTypes.secp256k1; - // void onChangeAlgorithm(EllipticCurveTypes algo) { - // algorithm = algo; - // setState(() {}); - // } - AddressDerivationMode? selectedDerivationMode; EncryptedCustomKey? selectedCustomKey; bool inAddressPage = false; @@ -103,10 +97,12 @@ class _SetupCosmosAddressViewState extends State super.didChangeDependencies(); } - AddressDerivationIndex? derivationkey() { + AddressDerivationIndex? derivationkey(CryptoCoins coin) { if (selectedCustomKey != null) { return ImportedAddressIndex( - accountId: selectedCustomKey!.id, bip32KeyIndex: customKeyIndex); + accountId: selectedCustomKey!.id, + bip32KeyIndex: customKeyIndex, + currencyCoin: coin); } return customKeyIndex; } @@ -120,7 +116,8 @@ class _SetupCosmosAddressViewState extends State pageProgressKey.progressText("generating_new_addr".tr); final model = context.watch(StateIdsConst.main); - final keyIndex = derivationkey() ?? chainAccount.account.nextDrive(coin); + final keyIndex = + derivationkey(coin) ?? chainAccount.account.nextDrive(coin); final newAccount = CosmosNewAddressParams(coin: coin, deriveIndex: keyIndex); @@ -319,47 +316,3 @@ class _GenerateAddress extends StatelessWidget { ); } } - -// class _ChooseAddressGenerationAlgorithm extends StatelessWidget { -// const _ChooseAddressGenerationAlgorithm( -// {required this.onChageAlgorithm, -// required this.algo, -// required this.onChange}); -// final _OnAddressAlgorithm onChageAlgorithm; -// final EllipticCurveTypes algo; -// final _OnChangePage onChange; -// @override -// Widget build(BuildContext context) { -// return Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// Text("elliptic_curve_options".tr, style: context.textTheme.titleMedium), -// Text("address_generation_algorithm".tr), -// WidgetConstant.height20, -// AppRadioListTile( -// title: const Text("Secp256k1"), -// groupValue: algo, -// value: EllipticCurveTypes.secp256k1, -// onChanged: (value) => onChageAlgorithm(EllipticCurveTypes.secp256k1), -// ), -// AppRadioListTile( -// title: const Text("Nist256p1"), -// groupValue: algo, -// value: EllipticCurveTypes.nist256p1, -// onChanged: (value) => onChageAlgorithm(EllipticCurveTypes.nist256p1), -// ), -// Row( -// mainAxisAlignment: MainAxisAlignment.center, -// children: [ -// FixedElevatedButton( -// padding: WidgetConstant.paddingVertical20, -// child: Text("continue".tr), -// onPressed: () { -// onChange(_Page.generationAddress); -// }), -// ], -// ) -// ], -// ); -// } -// } diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/controller.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/controller.dart index f4404e7a..8f191ee0 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/controller.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/controller.dart @@ -17,10 +17,15 @@ class CosomosTransactionStateController extends CosmosTransactiomImpl required super.address, required super.apiProvider, required super.validator}); + bool _trIsReady = false; bool get trIsReady => _trIsReady; + String? _error; String? get error => _error; + + String? _lastestUpdateHashCode; + @override Future onTapMemo(OnAddCosmosMemo onAddMemo) async { final String? currentMemo = memo; @@ -34,8 +39,6 @@ class CosomosTransactionStateController extends CosmosTransactiomImpl buildTransaction(); } - String? _lastestUpdateHashCode; - void _onReadyValidator(String hashCode) { if (_lastestUpdateHashCode == hashCode && hasFee) return; _lastestUpdateHashCode = hashCode; diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/impl/fee.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/impl/fee.dart index b1832335..4067ac60 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/impl/fee.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/impl/fee.dart @@ -16,23 +16,26 @@ enum CosmosFeeTypes { } mixin CosmosTransactionFeeImpl on CosmosTransactiomImpl { - final Cancelable _cancelable = Cancelable(); - CosmosFeeTypes _feeType = CosmosFeeTypes.basic; - CosmosFeeTypes get feeType => _feeType; - Fee? _fee; late final NoneDecimalBalance _feeAmount = NoneDecimalBalance.zero(network.coinParam.decimal); late final NoneDecimalBalance _networkFeeRate = NoneDecimalBalance.zero(network.coinParam.decimal); + + CosmosFeeTypes _feeType = CosmosFeeTypes.basic; + CosmosFeeTypes get feeType => _feeType; + Fee? _fee; + @override + Fee? get fee => _fee; + bool get hasFee => _fee != null; NoneDecimalBalance get feeAmount => _feeAmount; + final GlobalKey feeProgressKey = GlobalKey(debugLabel: "CosmosTransactionFeeImpl"); + String? _feeError; String? get feeError => _feeError; - @override - Fee? get fee => _fee; - bool get hasFee => _fee != null; + final Cancelable _cancelable = Cancelable(); Future _simulateTr() async { final messages = validator.validator.messages(address.networkAddress); diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/impl/transaction.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/impl/transaction.dart index d96da98e..662227f0 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/impl/transaction.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/impl/transaction.dart @@ -16,6 +16,7 @@ abstract class CosmosTransactiomImpl extends StateController { required this.address, required this.apiProvider, required this.validator}); + final WalletProvider walletProvider; final NetworkAccountCore account; final APPCosmosNetwork network; @@ -26,6 +27,7 @@ abstract class CosmosTransactiomImpl extends StateController { GlobalKey(debugLabel: "CosmosTransactiomImpl"); late final NoneDecimalBalance remindAmount = NoneDecimalBalance.zero(network.coinParam.decimal); + BaseAccount get ownerAccount; GetLatestBlockResponse get latestBlock; ThorNodeNetworkConstants get thorNodeNetworkConstants; diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/fields/thor_swap.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/fields/thor_swap.dart new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/fields/thor_swap.dart @@ -0,0 +1 @@ + diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/ethereum_account_page_view.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/ethereum_account_page_view.dart index d42f8cac..70bfcff9 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/ethereum_account_page_view.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/ethereum_account_page_view.dart @@ -1,9 +1,7 @@ import 'package:flutter/material.dart'; import 'package:mrt_wallet/app/core.dart'; -import 'package:mrt_wallet/future/pages/start_page/controller/wallet_provider.dart'; import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/wallet_global_pages.dart'; import 'package:mrt_wallet/future/widgets/custom_widgets.dart'; -import 'package:mrt_wallet/main.dart'; import 'package:mrt_wallet/models/wallet_models/wallet_models.dart'; class ETHAccountPageView extends StatelessWidget { @@ -23,7 +21,6 @@ class _EthereumTokenView extends StatelessWidget { @override Widget build(BuildContext context) { - final wallet = context.watch(StateIdsConst.main); final tokens = account.tokens; if (tokens.isEmpty) { @@ -65,40 +62,13 @@ class _EthereumTokenView extends StatelessWidget { final ETHERC20Token token = account.tokens[index]; return ContainerWithBorder( onRemove: () { - context - .openSliverDialog( - (ctx) => TokenDetailsModalView( - token: token, - address: account, - ), - content: (ctx) => [ - IconButton( - onPressed: () { - ctx.pop(TokenAction.delete); - }, - icon: Icon(Icons.delete, - color: context.colors.error)) - ], - "token_info".tr) - .then((value) { - switch (value) { - case TokenAction.delete: - context.openSliverDialog( - (ctx) => DialogTextView( - buttomWidget: AsyncDialogDoubleButtonView( - firstButtonPressed: () => - wallet.removeToken(token, account), - ), - text: "remove_token_from_account".tr), - "remove_token".tr); - break; - case TokenAction.transfer: - context.to(PagePathConst.ethereumTransaction, - argruments: token); - break; - default: - } - }); + context.openDialogPage( + (ctx) => TokenDetailsModalView( + token: token, + address: account, + transferPath: PagePathConst.ethereumTransaction, + ), + "token_info".tr); }, onRemoveWidget: WidgetConstant.sizedBox, child: Row( diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/setup_address.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/setup_address.dart index b186781c..f91f19e8 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/setup_address.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/setup_address.dart @@ -101,10 +101,12 @@ class _SetupEthereumAddressViewState extends State super.didChangeDependencies(); } - AddressDerivationIndex? derivationkey() { + AddressDerivationIndex? derivationkey(CryptoCoins coin) { if (selectedCustomKey != null) { return ImportedAddressIndex( - accountId: selectedCustomKey!.id, bip32KeyIndex: customKeyIndex); + accountId: selectedCustomKey!.id, + bip32KeyIndex: customKeyIndex, + currencyCoin: coin); } return customKeyIndex; } @@ -120,7 +122,8 @@ class _SetupEthereumAddressViewState extends State final curve = selectedCustomKey?.type ?? EllipticCurveTypes.secp256k1; final coin = coins.firstWhere((element) => element.conf.type == curve); - final keyIndex = derivationkey() ?? chainAccount.account.nextDrive(coin); + final keyIndex = + derivationkey(coin) ?? chainAccount.account.nextDrive(coin); final newAccount = EthereumNewAddressParam(coin: coin, deriveIndex: keyIndex); diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/account_page.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/account_page.dart index 7b0a9130..953695f1 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/account_page.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/account_page.dart @@ -1,10 +1,7 @@ import 'package:flutter/material.dart'; import 'package:mrt_wallet/app/core.dart'; -import 'package:mrt_wallet/future/pages/start_page/controller/wallet_provider.dart'; import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/wallet_global_pages.dart'; - import 'package:mrt_wallet/future/widgets/custom_widgets.dart'; -import 'package:mrt_wallet/main.dart'; import 'package:mrt_wallet/models/wallet_models/wallet_models.dart'; import 'package:mrt_wallet/provider/transaction_validator/core/validator.dart'; import 'package:mrt_wallet/provider/transaction_validator/ripple/ripple.dart'; @@ -185,7 +182,6 @@ class _RippleTokensView extends StatelessWidget { @override Widget build(BuildContext context) { - final wallet = context.watch(StateIdsConst.main); final tokens = account.tokens; if (tokens.isEmpty) { return Center( @@ -226,40 +222,13 @@ class _RippleTokensView extends StatelessWidget { final RippleIssueToken token = account.tokens[index]; return ContainerWithBorder( onRemove: () { - context - .openSliverDialog( - (ctx) => TokenDetailsModalView( - token: token, - address: account, - ), - content: (ctx) => [ - IconButton( - onPressed: () { - ctx.pop(TokenAction.delete); - }, - icon: Icon(Icons.delete, - color: context.colors.error)) - ], - "token_info".tr) - .then((value) { - switch (value) { - case TokenAction.delete: - context.openSliverDialog( - (ctx) => DialogTextView( - buttomWidget: AsyncDialogDoubleButtonView( - firstButtonPressed: () => - wallet.removeToken(token, account), - ), - text: "remove_token_from_account".tr), - "remove_token".tr); - break; - case TokenAction.transfer: - context.to(PagePathConst.rippleTransfer, - argruments: token); - break; - default: - } - }); + context.openDialogPage( + (ctx) => TokenDetailsModalView( + token: token, + address: account, + transferPath: PagePathConst.rippleTransfer, + ), + "token_info".tr); }, onRemoveWidget: WidgetConstant.sizedBox, backgroundColor: Colors.transparent, diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/setup_address.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/setup_address.dart index 8c5b604b..a384b1ef 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/setup_address.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/setup_address.dart @@ -125,10 +125,12 @@ class _SetupRippleAddressViewState extends State super.didChangeDependencies(); } - AddressDerivationIndex? derivationkey() { + AddressDerivationIndex? derivationkey(CryptoCoins coin) { if (selectedCustomKey != null) { return ImportedAddressIndex( - accountId: selectedCustomKey!.id, bip32KeyIndex: customKeyIndex); + accountId: selectedCustomKey!.id, + bip32KeyIndex: customKeyIndex, + currencyCoin: coin); } return customKeyIndex; } @@ -140,7 +142,8 @@ class _SetupRippleAddressViewState extends State final curve = selectedCustomKey?.type ?? EllipticCurveTypes.secp256k1; final coin = coins.firstWhere((element) => element.conf.type == curve); - final keyIndex = derivationkey() ?? chainAccount.account.nextDrive(coin); + final keyIndex = + derivationkey(coin) ?? chainAccount.account.nextDrive(coin); final newAccount = RippleNewAddressParam( coin: coin, deriveIndex: keyIndex, diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/fields/payment_fields.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/fields/payment_fields.dart index 86e5c6fd..0ea6760e 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/fields/payment_fields.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/fields/payment_fields.dart @@ -116,7 +116,7 @@ class RipplePaymentFieldsView extends StatelessWidget { onRemove: () { context .openSliverBottomSheet( - validator.fieldsName.tr, + validator.validatorName.tr, child: StringWriterView( defaultValue: validator.invoiceId.value, maxLength: RippleConst.rippleTranactionHashLength, diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/fields/ripple_global_transaction_fields.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/fields/ripple_global_transaction_fields.dart index b66562f0..8c94b905 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/fields/ripple_global_transaction_fields.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/fields/ripple_global_transaction_fields.dart @@ -32,7 +32,7 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { onRemove: () { context .openSliverBottomSheet( - validator.fieldsName.tr, + validator.validatorName.tr, child: StringWriterView( defaultValue: field.value, maxLength: RippleConst.rippleTranactionHashLength, @@ -42,7 +42,7 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(field.subject.tr), + Text(field.subject!.tr), ], )), buttomText: "setup_input".tr, @@ -71,7 +71,7 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { onTap: () { context .openSliverBottomSheet( - validator.fieldsName.tr, + validator.validatorName.tr, maxExtend: 1, minExtent: 0.8, initialExtend: 0.9, @@ -83,7 +83,7 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(field.subject.tr), + Text(field.subject!.tr), ], )), ), @@ -99,7 +99,7 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { onRemove: () { context .openSliverBottomSheet( - validator.fieldsName.tr, + validator.validatorName.tr, child: NumberWriteView( defaultValue: field.value, max: RippleConst.max32UnsignedRational, @@ -110,7 +110,7 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(field.subject.tr), + Text(field.subject!.tr), ], )), buttomText: "setup_input".tr, @@ -145,7 +145,7 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { } context .openSliverBottomSheet( - validator.fieldsName.tr, + validator.validatorName.tr, child: NumberWriteView( defaultValue: field.value, max: max, @@ -156,7 +156,7 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(field.subject.tr), + Text(field.subject!.tr), ], )), buttomText: "setup_input".tr, @@ -179,7 +179,7 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { } context .openSliverBottomSheet( - validator.fieldsName.tr, + validator.validatorName.tr, child: StringWriterView( defaultValue: field.value, maxLength: maxLength, @@ -188,7 +188,7 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(field.subject.tr), + Text(field.subject!.tr), ], )), buttomText: "setup_input".tr, @@ -303,7 +303,7 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { bodyBuilder: (controller) => BuildRippleCurrencyAmountView( account: account, scrollController: controller, - title: validator.fieldsName.tr, + title: validator.validatorName.tr, acceptZero: true, supportXRP: field.id != "trust_set_limit_amount", ), @@ -383,7 +383,7 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { onRemove: () { context .openSliverBottomSheet( - validator.fieldsName.tr, + validator.validatorName.tr, child: StringWriterView( defaultValue: null, maxLength: RippleConst.rippleTranactionHashLength, @@ -393,7 +393,7 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(field.subject.tr), + Text(field.subject!.tr), ], )), buttomText: "setup_input".tr, @@ -415,13 +415,13 @@ class RippleGlobalTransactionFieldsView extends StatelessWidget { onRemove: () { context .openSliverBottomSheet( - validator.fieldsName.tr, + validator.validatorName.tr, child: SetupNetworkAmount( token: account.network.coinParam.token, max: account.address.address.balance.value.balance, min: BigInt.zero, subtitle: PageTitleSubtitle( - title: field.name.tr, body: Text(field.subject.tr)), + title: field.name.tr, body: Text(field.subject!.tr)), ), ) .then( diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/fields/signer_list_fields.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/fields/signer_list_fields.dart index dfdde8c8..d8b84232 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/fields/signer_list_fields.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/fields/signer_list_fields.dart @@ -41,7 +41,7 @@ class RippleSetSignerListFieldsView extends StatelessWidget { onTap: () { context .openSliverBottomSheet( - validator.fieldsName.tr, + validator.validatorName.tr, maxExtend: 1, minExtent: 0.8, initialExtend: 0.9, @@ -54,7 +54,7 @@ class RippleSetSignerListFieldsView extends StatelessWidget { WidgetConstant.height20, Text(validator.signerQuorum.name.tr, style: context.textTheme.titleMedium), - Text(validator.signerQuorum.subject.tr), + Text(validator.signerQuorum.subject!.tr), WidgetConstant.height8, ContainerWithBorder( validate: validator.signerQuorum.isCompleted, @@ -64,7 +64,7 @@ class RippleSetSignerListFieldsView extends StatelessWidget { onRemove: () { context .openSliverBottomSheet( - validator.fieldsName.tr, + validator.validatorName.tr, child: NumberWriteView( defaultValue: validator.signerQuorum.value, min: BigRational.zero, @@ -77,7 +77,7 @@ class RippleSetSignerListFieldsView extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ TextAndLinkView( - text: validator.signerQuorum.subject.tr, + text: validator.signerQuorum.subject!.tr, url: validator.helperUri), ], )), diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/ripple_tranaction_fields_view.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/ripple_tranaction_fields_view.dart index 49f5ba8f..fba6715e 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/ripple_tranaction_fields_view.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/ripple_pages/transaction/fields/ripple_tranaction_fields_view.dart @@ -76,7 +76,8 @@ class RippleTransactionFieldsView extends StatelessWidget { PageTitleSubtitle( title: validator.validator.name.tr, body: TextAndLinkView( - text: validator.validator.subject.tr, + text: validator + .validator.validatorDescription.tr, url: validator.validator.helperUri)), _RippleValidatorFields( validator: controller.validator, @@ -161,7 +162,7 @@ class _RippleValidatorFields extends StatelessWidget { children: [ Text(fields.fields[index].name.tr, style: context.textTheme.titleMedium), - Text(fields.fields[index].subject.tr), + Text(fields.fields[index].subject!.tr), WidgetConstant.height8, RippleGlobalTransactionFieldsView( field: field, diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/account_page.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/account_page.dart index 623ca63e..93f5ae84 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/account_page.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/account_page.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:mrt_wallet/app/core.dart'; -import 'package:mrt_wallet/future/pages/start_page/controller/wallet_provider.dart'; import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/token_details.dart'; import 'package:mrt_wallet/future/widgets/custom_widgets.dart'; -import 'package:mrt_wallet/main.dart'; import 'package:mrt_wallet/models/wallet_models/wallet_models.dart'; +import 'package:mrt_wallet/provider/transaction_validator/core/validator.dart'; +import 'package:mrt_wallet/provider/transaction_validator/solana/solana.dart'; class SolanaAccountPageView extends StatelessWidget { const SolanaAccountPageView({required this.chainAccount, super.key}); @@ -12,6 +12,7 @@ class SolanaAccountPageView extends StatelessWidget { @override Widget build(BuildContext context) { return TabBarView(children: [ + const _SolanaServices(), _SolanaTokenView(account: chainAccount.account.address as ISolanaAddress), ]); } @@ -23,7 +24,6 @@ class _SolanaTokenView extends StatelessWidget { @override Widget build(BuildContext context) { - final wallet = context.watch(StateIdsConst.main); final tokens = account.tokens; if (tokens.isEmpty) { @@ -65,40 +65,13 @@ class _SolanaTokenView extends StatelessWidget { final SolanaSPLToken token = account.tokens[index]; return ContainerWithBorder( onRemove: () { - context - .openSliverDialog( - (ctx) => TokenDetailsModalView( - token: token, - address: account, - ), - content: (ctx) => [ - IconButton( - onPressed: () { - ctx.pop(TokenAction.delete); - }, - icon: Icon(Icons.delete, - color: context.colors.error)) - ], - "token_info".tr) - .then((value) { - switch (value) { - case TokenAction.delete: - context.openSliverDialog( - (ctx) => DialogTextView( - buttomWidget: AsyncDialogDoubleButtonView( - firstButtonPressed: () => - wallet.removeToken(token, account), - ), - text: "remove_token_from_account".tr), - "remove_token".tr); - break; - case TokenAction.transfer: - context.to(PagePathConst.solanaTransfer, - argruments: token); - break; - default: - } - }); + context.openDialogPage( + (ctx) => TokenDetailsModalView( + token: token, + address: account, + transferPath: PagePathConst.solanaTransfer, + ), + "token_info".tr); }, onRemoveWidget: WidgetConstant.sizedBox, child: Row( @@ -132,3 +105,60 @@ class _SolanaTokenView extends StatelessWidget { ); } } + +class _SolanaServices extends StatelessWidget { + const _SolanaServices(); + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Column( + children: [ + AppListTile( + title: Text("associated_token_program".tr), + subtitle: Text("create_associated_token_account".tr), + onTap: () { + final validator = LiveTransactionValidator< + SolanaCreateAssociatedTokenAccountValidator>( + validator: SolanaCreateAssociatedTokenAccountValidator()); + context.to(PagePathConst.solanaTransaction, + argruments: validator); + }, + ), + AppListTile( + title: Text("create_account".tr), + subtitle: Text("solana_create_account_desc".tr), + onTap: () { + final validator = + LiveTransactionValidator( + validator: SolanaCreateAccountValidator()); + context.to(PagePathConst.solanaTransaction, + argruments: validator); + }, + ), + AppListTile( + title: Text("initialize_mint".tr), + subtitle: Text("initiailize_mint_desc".tr), + onTap: () { + final validator = + LiveTransactionValidator( + validator: SolanaInitializeMintValidator()); + context.to(PagePathConst.solanaTransaction, + argruments: validator); + }, + ), + AppListTile( + title: Text("mint_to".tr), + subtitle: Text("mint_to_desc".tr), + onTap: () { + final validator = LiveTransactionValidator( + validator: SolanaMintToValidator()); + context.to(PagePathConst.solanaTransaction, + argruments: validator); + }, + ), + ], + ), + ); + } +} diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/setup_address.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/setup_address.dart index 2dd6c6e5..429b43e6 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/setup_address.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/setup_address.dart @@ -106,10 +106,12 @@ class _SetupSolanaAddressViewState extends State super.didChangeDependencies(); } - AddressDerivationIndex? derivationkey() { + AddressDerivationIndex? derivationkey(CryptoCoins coin) { if (selectedCustomKey != null) { return ImportedAddressIndex( - accountId: selectedCustomKey!.id, bip32KeyIndex: customKeyIndex); + accountId: selectedCustomKey!.id, + bip32KeyIndex: customKeyIndex, + currencyCoin: coin); } return customKeyIndex; } @@ -121,7 +123,8 @@ class _SetupSolanaAddressViewState extends State final curve = selectedCustomKey?.type ?? EllipticCurveTypes.ed25519; final coin = coins.firstWhere((element) => element.conf.type == curve); - final keyIndex = derivationkey() ?? chainAccount.account.nextDrive(coin); + final keyIndex = + derivationkey(coin) ?? chainAccount.account.nextDrive(coin); final newAccount = SolanaNewAddressParam(coin: coin, deriveIndex: keyIndex); final result = await model.deriveNewAccount(newAccount); diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/fee_impl.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/fee_impl.dart index dbad6c41..ded804f4 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/fee_impl.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/fee_impl.dart @@ -1,32 +1,42 @@ import 'dart:async'; +import 'package:flutter/material.dart'; import 'package:mrt_wallet/app/core.dart'; +import 'package:mrt_wallet/future/widgets/progress_bar/progress.dart'; import 'package:mrt_wallet/models/wallet_models/wallet_models.dart'; import 'package:on_chain/solana/solana.dart'; import 'transaction_impl.dart'; mixin SolanaTransactionFeeImpl on SolanaTransactionImpl { + StreamSubscription? _onFee; late final NoneDecimalBalance _fee = NoneDecimalBalance.zero(network.coinParam.decimal); NoneDecimalBalance get fee => _fee; bool get hasFee => !_fee.isZero; SolAddress? _blockHash; final Cancelable _cancelable = Cancelable(); + final GlobalKey feeProgressKey = + GlobalKey(debugLabel: "SolanaTransactionFeeImpl_fee"); Future _calculateFees() async { - _blockHash ??= await apiProvider.getBlockHash(); - final transaction = SolanaTransaction( - payerKey: owner.networkAddress, - instructions: - await validator.validator.instructions(address.networkAddress), - recentBlockhash: _blockHash!); - return await apiProvider.getFee(transaction); + try { + _blockHash ??= await apiProvider.getBlockHash(); + final transaction = SolanaTransaction( + payerKey: owner.networkAddress, + instructions: + await validator.validator.instructions(address.networkAddress), + recentBlockhash: _blockHash!); + return await apiProvider.getFee(transaction); + } catch (e, s) { + WalletLogging.print("has error $e $s"); + rethrow; + } } - StreamSubscription? _onFee; Future calculateFees() async { if (hasFee || _onFee != null) return; + feeProgressKey.process(); _onFee = MethodCaller.prediocCaller(() async { - return await MethodCaller.call( + final call = await MethodCaller.call( () async { final result = await _calculateFees(); if (result == null) { @@ -35,16 +45,22 @@ mixin SolanaTransactionFeeImpl on SolanaTransactionImpl { return result; }, ); + WalletLogging.print("called $call"); + return call; }, canclable: _cancelable, closeOnSuccess: true) .listen( (event) { _fee.updateBalance(event); onChange(); + feeProgressKey.idle(); + _cancelable.cancel(); }, ); _onFee?.onDone(() { _onFee?.cancel(); _onFee = null; + feeProgressKey.idle(); + _cancelable.cancel(); }); } @@ -53,5 +69,6 @@ mixin SolanaTransactionFeeImpl on SolanaTransactionImpl { super.close(); _onFee?.cancel(); _onFee = null; + _cancelable.cancel(); } } diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/memo_impl.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/memo_impl.dart index b821f854..094e6268 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/memo_impl.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/memo_impl.dart @@ -3,12 +3,14 @@ import 'package:on_chain/solana/solana.dart'; import 'transaction_impl.dart'; typedef OnSetMemo = Future Function(String? memo); + mixin SolanaMemoImpl on SolanaTransactionImpl { MemoProgram? _memo; String? get memoStr => (_memo?.layout as MemoLayout?)?.memo; - bool get hasMemo => memoStr != null; + bool get hasMemo => _memo != null; @override MemoProgram? get memo => _memo; + void onTapMemo(OnSetMemo onTapMemo) async { final txt = await onTapMemo(memoStr); if (txt == null) { diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/signer_impl.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/signer_impl.dart index 66f8c92d..8b9eca6d 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/signer_impl.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/signer_impl.dart @@ -15,10 +15,22 @@ mixin SolanaSignerImpl on SolanaTransactionImpl { if (memo != null) memo!, ], recentBlockhash: bl.blockhash); + final signersAddresses = transaction.message.accountKeys + .sublist(0, transaction.message.header.numRequiredSignatures) + .map((e) => e.address) + .toList(); + final signerAccounts = account.addresses + .where((element) => + signersAddresses.contains(element.networkAddress.address)) + .toList(); + + if (signersAddresses.length != signerAccounts.length) { + throw WalletException("required_signer_account_missing".tr); + } final signedTr = await walletProvider.signSolanaTransaction( request: SolanaSigningRequest( network: network, - addresses: [owner], + addresses: signerAccounts, solanaTransaction: transaction)); if (signedTr.hasError) { throw signedTr.exception!; @@ -40,7 +52,8 @@ mixin SolanaSignerImpl on SolanaTransactionImpl { return await _buildAndSigneTransaction(); }); if (result.hasError) { - progressKey.errorText(result.error!.tr); + progressKey.errorText(result.error!.tr, + showBackButtom: true, backToIdle: false); } else { progressKey.success( progressWidget: diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/transaction_impl.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/transaction_impl.dart index defb40c6..fef27c32 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/transaction_impl.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/imp/transaction_impl.dart @@ -7,6 +7,7 @@ import 'package:mrt_wallet/models/wallet_models/wallet_models.dart'; import 'package:mrt_wallet/provider/api/api_provider.dart'; import 'package:mrt_wallet/provider/transaction_validator/core/live_validator.dart'; import 'package:mrt_wallet/provider/transaction_validator/solana/core/solana_transaction_validator.dart'; +import 'package:on_chain/solana/src/address/sol_address.dart'; import 'package:on_chain/solana/src/instructions/memo/program.dart'; abstract class SolanaTransactionImpl extends StateController { @@ -18,14 +19,15 @@ abstract class SolanaTransactionImpl extends StateController { required this.apiProvider, required this.validator}); final WalletProvider walletProvider; - final NetworkAccountCore account; + final NetworkAccountCore account; final APPSolanaNetwork network; final SolanaApiProvider apiProvider; final ISolanaAddress address; - ISolanaAddress get owner => address; final LiveTransactionValidator validator; - MemoProgram? get memo; + ISolanaAddress get owner => address; final GlobalKey progressKey = GlobalKey( debugLabel: "progressKey_SolanaTransactionImpl"); + void onChange(); + MemoProgram? get memo; } diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/solana_transaction_controller.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/solana_transaction_controller.dart index 2a0509aa..0e2ee945 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/solana_transaction_controller.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/controller/solana_transaction_controller.dart @@ -14,10 +14,6 @@ class SolanaTransactionStateController extends SolanaTransactionImpl required super.address, required super.apiProvider, required super.validator}); - - @override - String get repositoryId => "solana/transaction"; - NoneDecimalBalance? _remindTokenAmount; late final NoneDecimalBalance _remindAmount = NoneDecimalBalance.zero(network.coinParam.decimal); @@ -26,12 +22,15 @@ class SolanaTransactionStateController extends SolanaTransactionImpl String? get error => _error; bool _trReady = false; bool get transactionIsReady => _trReady; + bool _checkTransaction() { _error = validator.validator.validateError(); - final transactionValue = validator.validator.transferValue + fee.balance; _remindAmount.updateBalance( - account.address.address.balance.value.balance - transactionValue); + account.address.address.balance.value.balance - fee.balance); if (validator.validator.mode != SolanaTransactionType.spl) { + final transactionValue = validator.validator.transferValue + fee.balance; + _remindAmount.updateBalance( + account.address.address.balance.value.balance - transactionValue); remindAmount = (_remindAmount, network.coinParam.token); } else { final tokenTransferFiled = validator.validator as SolanaTransferValidator; @@ -99,4 +98,7 @@ class SolanaTransactionStateController extends SolanaTransactionImpl validator.validator.setProvider(null); super.close(); } + + @override + String get repositoryId => "solana/transaction"; } diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/fields/transaction.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/fields/transaction.dart index ee5097e6..90878818 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/fields/transaction.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/fields/transaction.dart @@ -1,3 +1,4 @@ +import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:flutter/material.dart'; import 'package:mrt_wallet/app/core.dart'; import 'package:mrt_wallet/future/pages/wallet_pages/account_pages/account_controller.dart'; @@ -9,20 +10,23 @@ import 'package:mrt_wallet/models/wallet_models/address/address.dart'; import 'package:mrt_wallet/models/wallet_models/currency_balance/currency_balance.dart'; import 'package:mrt_wallet/models/wallet_models/network/core/network.dart'; import 'package:mrt_wallet/provider/transaction_validator/core/live_validator.dart'; -import 'package:mrt_wallet/provider/transaction_validator/solana/core/solana_transaction_validator.dart'; -import 'package:mrt_wallet/provider/transaction_validator/solana/transfer/transfer.dart'; +import 'package:mrt_wallet/provider/transaction_validator/solana/solana.dart'; +import 'package:on_chain/solana/solana.dart'; class SolanaTransactionFieldsView extends StatelessWidget { - const SolanaTransactionFieldsView({super.key, required this.validator}); - final LiveTransactionValidator validator; + const SolanaTransactionFieldsView({super.key, this.field}); + final LiveTransactionValidator? field; @override Widget build(BuildContext context) { + final LiveTransactionValidator validator = + field ?? context.getArgruments(); return NetworkAccountControllerView( childBulder: (wallet, chain, address, network, switchAccount) { return MrtViewBuilder( controller: () => SolanaTransactionStateController( walletProvider: wallet, - account: chain.account, + account: chain.account + as NetworkAccountCore, network: network, address: address, apiProvider: chain.provider()!, @@ -66,33 +70,38 @@ class SolanaTransactionFieldsView extends StatelessWidget { ), WidgetConstant.height20, _SolanaTransactionFileds( - account: chain.account, - validator: controller.validator, - network: controller.network, - ), + validator: controller.validator, + controller: controller), AnimatedSize( duration: AppGlobalConst.animationDuraion, - child: !controller.hasFee - ? WidgetConstant.sizedBox - : Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - WidgetConstant.height20, - Text("transaction_fee".tr, - style: context - .textTheme.titleLarge), - WidgetConstant.height8, - ContainerWithBorder( - child: CoinPriceView( - token: controller - .network.coinParam.token, - balance: controller.fee, - style: - context.textTheme.titleLarge, - )), - ], - ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + WidgetConstant.height20, + Text("transaction_fee".tr, + style: context.textTheme.titleLarge), + WidgetConstant.height8, + ContainerWithBorder( + validate: controller.hasFee, + onRemove: () {}, + onTapWhenOnRemove: false, + onRemoveIcon: StreamWidget( + key: controller.feeProgressKey, + initialStatus: + StreamWidgetStatus.idle, + buttomWidget: Icon(Icons.circle, + color: + context.colors.transparent), + ), + child: CoinPriceView( + token: controller + .network.coinParam.token, + balance: controller.fee, + style: context.textTheme.titleLarge, + )), + ], + ), ), WidgetConstant.height20, Text("setup_memo".tr, @@ -139,6 +148,12 @@ class SolanaTransactionFieldsView extends StatelessWidget { ], )), WidgetConstant.height20, + InsufficientBalanceErrorView( + verticalMargin: + WidgetConstant.paddingVertical10, + balance: controller.remindAmount.$1, + token: controller.remindAmount.$2, + ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -160,35 +175,45 @@ class SolanaTransactionFieldsView extends StatelessWidget { }, ); }, - title: "build_transacation".tr); + title: validator.validator.name.tr); } } class _SolanaTransactionFileds extends StatelessWidget { const _SolanaTransactionFileds( - {required this.validator, required this.account, required this.network}); + {required this.validator, required this.controller}); final LiveTransactionValidator validator; - final NetworkAccountCore account; - final AppNetworkImpl network; + final SolanaTransactionStateController controller; @override Widget build(BuildContext context) { return LiveWidget(() { - final field = validator.value as SolanaTransferValidator; - return _SolanaTransferFields( - field: field, - account: account, - network: network, - ); + switch (validator.validator.mode) { + case SolanaTransactionType.createAssociatedTokenAccount: + final field = + validator.value as SolanaCreateAssociatedTokenAccountValidator; + return _CreateAssociatedTokenAccountFields( + field: field, controller: controller); + case SolanaTransactionType.createAccount: + final field = validator.value as SolanaCreateAccountValidator; + return _CreateAccountFields(field: field, controller: controller); + case SolanaTransactionType.initializeMint: + final field = validator.value as SolanaInitializeMintValidator; + return _InitializeMintFields(field: field, controller: controller); + case SolanaTransactionType.mintTo: + final field = validator.value as SolanaMintToValidator; + return _MintToFields(field: field, controller: controller); + default: + final field = validator.value as SolanaTransferValidator; + return _SolanaTransferFields(field: field, controller: controller); + } }); } } class _SolanaTransferFields extends StatelessWidget { - const _SolanaTransferFields( - {required this.field, required this.account, required this.network}); + const _SolanaTransferFields({required this.field, required this.controller}); final SolanaTransferValidator field; - final NetworkAccountCore account; - final AppNetworkImpl network; + final SolanaTransactionStateController controller; @override Widget build(BuildContext context) { return Column( @@ -216,8 +241,8 @@ class _SolanaTransferFields extends StatelessWidget { maxExtend: 1, minExtent: 0.8, initialExtend: 0.9, - bodyBuilder: (controller) => SelectRecipientAccountView( - account: account, scrollController: controller)) + bodyBuilder: (sc) => SelectRecipientAccountView( + account: controller.account, scrollController: sc)) .then( (value) { field.setValue(field.destination, value); @@ -226,16 +251,14 @@ class _SolanaTransferFields extends StatelessWidget { }, ), WidgetConstant.height20, - Text("recipient_info".tr, style: context.textTheme.titleMedium), + Text("destination_info".tr, style: context.textTheme.titleMedium), + Text("destination_info_desc".tr), WidgetConstant.height8, ContainerWithBorder( onRemoveIcon: StreamWidget( - buttomWidget: Icon( - Icons.circle, - color: context.colors.transparent, - ), - key: field.accountKey, - ), + buttomWidget: + Icon(Icons.circle, color: context.colors.transparent), + key: field.accountKey), onRemove: () { if (!field.hasErrpr) return; field.updateAccountInfo(); @@ -280,7 +303,7 @@ class _SolanaTransferFields extends StatelessWidget { validateError: field.showRequirementAmountAlert ? "amount_must_exceed".tr.replaceOne(PriceUtils.priceWithCoinName( SolanaConstants.systemProgramRent.price, - network.coinParam.token.symbol)) + controller.network.coinParam.token.symbol)) : null, onTap: () { context @@ -290,7 +313,8 @@ class _SolanaTransferFields extends StatelessWidget { token: field.token, max: field.isTokenTransfer ? field.splToken!.balance.value.balance - : account.address.address.balance.value.balance, + : controller.address.address.balance.value.balance - + controller.fee.balance, min: BigInt.zero, subtitle: field.destination.hasValue ? ReceiptAddressView( @@ -315,3 +339,548 @@ class _SolanaTransferFields extends StatelessWidget { ); } } + +class _CreateAssociatedTokenAccountFields extends StatelessWidget { + const _CreateAssociatedTokenAccountFields( + {required this.field, required this.controller}); + final SolanaCreateAssociatedTokenAccountValidator field; + final SolanaTransactionStateController controller; + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ReceiptAddressView( + address: field.ownerAddress.value, + title: "owner_address".tr, + subtitle: "owner_of_account".tr, + onTap: () { + context + .openSliverBottomSheet("owner_address".tr, + maxExtend: 1, + minExtent: 0.8, + initialExtend: 0.9, + bodyBuilder: (sc) => SelectRecipientAccountView( + account: controller.account, + scrollController: sc, + subtitle: PageTitleSubtitle( + title: "owner".tr, + body: Text("owner_of_account".tr)), + )) + .then( + (value) { + field.setValue(field.ownerAddress, value); + }, + ); + }, + ), + WidgetConstant.height20, + ReceiptAddressView( + address: field.mintAddress.value, + title: "mint_address".tr, + subtitle: "mint_address_desc".tr, + onTap: () { + context + .openSliverBottomSheet("mint_address".tr, + maxExtend: 1, + minExtent: 0.8, + initialExtend: 0.9, + bodyBuilder: (sc) => SelectRecipientAccountView( + account: controller.account, + scrollController: sc, + subtitle: PageTitleSubtitle( + title: "mint_address".tr, + body: Text("mint_address_desc".tr)), + )) + .then( + (value) { + field.setValue(field.mintAddress, value); + }, + ); + }, + ), + WidgetConstant.height20, + ReceiptAddressView( + address: field.tokenProgram.value, + subtitle: "program_address_desc".tr, + title: "program_address".tr, + onTap: () { + context + .openSliverBottomSheet("program_address".tr, + maxExtend: 1, + minExtent: 0.8, + initialExtend: 0.9, + bodyBuilder: (sc) => SelectRecipientAccountView( + account: controller.account, + scrollController: sc, + subtitle: PageTitleSubtitle( + title: "program_address".tr, + body: Text("program_address_desc".tr)), + )) + .then( + (value) { + field.setValue(field.tokenProgram, value); + }, + ); + }, + ), + AnimatedSize( + duration: AppGlobalConst.animationDuraion, + child: field.assosicatedAddress == null + ? WidgetConstant.sizedBox + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + WidgetConstant.height20, + Text("associated_token_address".tr, + style: context.textTheme.titleMedium), + WidgetConstant.height8, + ContainerWithBorder( + child: Text(field.assosicatedAddress?.address ?? ""), + ) + ], + ), + ) + ], + ); + } +} + +class _CreateAccountFields extends StatelessWidget { + const _CreateAccountFields({required this.field, required this.controller}); + final SolanaCreateAccountValidator field; + final SolanaTransactionStateController controller; + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ReceiptAddressView( + address: field.newAccountAddress.value, + title: "new_account_address".tr, + subtitle: "solana_new_account_desc".tr, + onTap: () { + context + .openSliverBottomSheet( + "select_account".tr, + child: SwitchOrSelectAccountView( + account: controller.account, + showMultiSig: true, + ), + minExtent: 0.5, + maxExtend: 0.9, + initialExtend: 0.7, + centerContent: false, + ) + .then(field.changeAssetOutputAddress); + }, + ), + WidgetConstant.height20, + ReceiptAddressView( + address: field.ownerAddress.value, + title: "owner".tr, + subtitle: "owner_of_account".tr, + onTap: () { + context + .openSliverBottomSheet("owner".tr, + maxExtend: 1, + minExtent: 0.8, + initialExtend: 0.9, + bodyBuilder: (sc) => SelectRecipientAccountView( + account: controller.account, + scrollController: sc, + subtitle: PageTitleSubtitle( + title: "owner".tr, + body: Text("owner_of_account".tr)), + )) + .then( + (value) { + if (value == null) return; + field.setValue(field.ownerAddress, value); + }, + ); + }, + ), + WidgetConstant.height20, + Text("account_size".tr, style: context.textTheme.titleMedium), + Text("solana_account_size_desc".tr), + WidgetConstant.height8, + ContainerWithBorder( + validate: field.space.hasValue, + onRemoveIcon: field.space.hasValue + ? const Icon(Icons.edit) + : const Icon(Icons.add), + onRemove: () { + context + .openSliverBottomSheet( + "account_size".tr, + child: NumberWriteView( + defaultValue: field.space.value, + allowDecimal: false, + max: SolanaConstants.maximumAccountSizeBytes, + min: BigRational.zero, + allowSign: false, + title: PageTitleSubtitle( + title: "account_size".tr, + body: Text("solana_account_size_desc".tr)), + buttomText: "setup_account_size".tr, + label: "account_size".tr, + ), + ) + .then(field.setSpace); + }, + child: Text(field.space.value?.toString().to3Digits ?? + "tap_to_input_value".tr), + ), + WidgetConstant.height20, + TransactionAmountView( + amount: field.lamports.value, + title: "lamports".tr, + subtitle: "solana_create_account_lamports_desc".tr, + validate: field.lamports.isCompleted, + onRemoveIcon: StreamWidget( + key: field.rentProgress, + buttomWidget: field.lamports.hasValue + ? const Icon(Icons.edit) + : const Icon(Icons.add)), + onTap: () { + if (field.rentProgress.inProgress) return; + context + .openSliverBottomSheet( + "lamports".tr, + child: SetupNetworkAmount( + token: controller.network.coinParam.token, + max: controller.address.address.balance.value.balance - + controller.fee.balance, + min: BigInt.zero, + subtitle: Text("solana_create_account_lamports_desc".tr), + ), + ) + .then(field.setLamports); + }, + token: controller.network.coinParam.token, + ), + ], + ); + } +} + +class _InitializeMintFields extends StatelessWidget { + const _InitializeMintFields({required this.field, required this.controller}); + final SolanaInitializeMintValidator field; + final SolanaTransactionStateController controller; + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ReceiptAddressView( + address: field.programId.value, + title: "program_id".tr, + subtitle: "solana_program_id_desc".tr, + onTap: () { + context + .openSliverBottomSheet("program_id".tr, + maxExtend: 1, + minExtent: 0.8, + initialExtend: 0.9, + bodyBuilder: (sc) => SelectRecipientAccountView( + account: controller.account, scrollController: sc)) + .then( + (value) { + if (value == null) return; + field.setValue(field.programId, value); + }, + ); + }, + ), + WidgetConstant.height20, + ReceiptAddressView( + address: field.mint.value, + title: "mint".tr, + subtitle: "mint_address_to_initialize".tr, + onTap: () { + context + .openSliverBottomSheet("mint".tr, + maxExtend: 1, + minExtent: 0.8, + initialExtend: 0.9, + bodyBuilder: (sc) => SelectRecipientAccountView( + account: controller.account, scrollController: sc)) + .then( + (value) { + if (value == null) return; + field.setValue(field.mint, value); + }, + ); + }, + ), + WidgetConstant.height20, + ReceiptAddressView( + address: field.mintAuthority.value, + title: "mint_authority".tr, + subtitle: "mint_authority_desc".tr, + onTap: () { + context + .openSliverBottomSheet("mint_authority".tr, + maxExtend: 1, + minExtent: 0.8, + initialExtend: 0.9, + bodyBuilder: (sc) => SelectRecipientAccountView( + account: controller.account, scrollController: sc)) + .then( + (value) { + if (value == null) return; + field.setValue(field.mintAuthority, value); + }, + ); + }, + ), + WidgetConstant.height20, + ReceiptAddressView( + address: field.freezAuthority.value, + validate: true, + title: "freeze_authority".tr, + subtitle: "freeze_authority_desc".tr, + onTap: () { + context + .openSliverBottomSheet("freeze_authority".tr, + maxExtend: 1, + minExtent: 0.8, + initialExtend: 0.9, + bodyBuilder: (sc) => SelectRecipientAccountView( + account: controller.account, scrollController: sc)) + .then( + (value) { + if (value == null) return; + field.setValue(field.freezAuthority, value); + }, + ); + }, + ), + WidgetConstant.height20, + Text("decimals".tr, style: context.textTheme.titleMedium), + Text("solana_mint_decimal_desc".tr), + WidgetConstant.height8, + ContainerWithBorder( + validate: field.decimals.hasValue, + onRemoveIcon: field.decimals.hasValue + ? const Icon(Icons.edit) + : const Icon(Icons.add), + onRemove: () { + context + .openSliverBottomSheet( + "decimals".tr, + child: NumberWriteView( + defaultValue: field.decimals.value, + allowDecimal: false, + max: SolanaConstants.maxSPLTokenDecimalPlaces, + min: BigRational.zero, + allowSign: false, + title: PageTitleSubtitle( + title: "decimals".tr, + body: Text("solana_mint_decimal_desc".tr)), + buttomText: "setup_token_decimal".tr, + label: "decimals".tr, + ), + ) + .then( + (value) { + field.setValue(field.decimals, value); + }, + ); + }, + child: Text(field.decimals.value?.toString().to3Digits ?? + "tap_to_input_value".tr), + ), + ], + ); + } +} + +class _MintToFields extends StatelessWidget { + const _MintToFields({required this.field, required this.controller}); + final SolanaMintToValidator field; + final SolanaTransactionStateController controller; + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ReceiptAddressView( + address: field.programId.value, + title: "program_id".tr, + subtitle: "solana_program_id_desc".tr, + onTap: () { + context + .openSliverBottomSheet("program_id".tr, + maxExtend: 1, + minExtent: 0.8, + initialExtend: 0.9, + bodyBuilder: (sc) => SelectRecipientAccountView( + account: controller.account, scrollController: sc)) + .then( + (value) { + if (value == null) return; + field.setValue(field.programId, value); + }, + ); + }, + ), + WidgetConstant.height20, + ReceiptAddressView( + address: field.mint.value, + title: "mint".tr, + subtitle: "mint_address_mint_desc".tr, + onTap: () { + context + .openSliverBottomSheet("mint".tr, + maxExtend: 1, + minExtent: 0.8, + initialExtend: 0.9, + bodyBuilder: (sc) => SelectRecipientAccountView( + account: controller.account, + scrollController: sc, + subtitle: PageTitleSubtitle( + title: "mint".tr, + body: Text("mint_address_mint_desc".tr)), + )) + .then( + (value) { + if (value == null) return; + field.setValue(field.mint, value); + }, + ); + }, + ), + WidgetConstant.height20, + ReceiptAddressView( + address: field.authority.value, + title: "authority".tr, + subtitle: "mint_to_authority_desc".tr, + onTap: () { + context + .openSliverBottomSheet("authority".tr, + maxExtend: 1, + minExtent: 0.8, + initialExtend: 0.9, + bodyBuilder: (sc) => SelectRecipientAccountView( + account: controller.account, + scrollController: sc, + subtitle: PageTitleSubtitle( + title: "authority".tr, + body: Text("mint_to_authority_desc".tr)), + )) + .then( + (value) { + if (value == null) return; + field.setValue(field.authority, value); + }, + ); + }, + ), + WidgetConstant.height20, + ReceiptAddressView( + address: field.destination.value, + validate: field.destination.hasValue, + title: "destination".tr, + subtitle: "use_owner_account_instead_pda_desc".tr, + onTap: () { + context + .openSliverBottomSheet>( + "destination".tr, + maxExtend: 1, + minExtent: 0.8, + initialExtend: 0.9, + bodyBuilder: (sc) => SelectRecipientAccountView( + account: controller.account, + scrollController: sc, + subtitle: PageTitleSubtitle( + title: "destination".tr, + body: Text("mint_to_destination_desc".tr)), + )) + .then( + (value) { + if (value == null) return; + field.setDestination(value); + }, + ); + }, + ), + WidgetConstant.height20, + Text("destination_info".tr, style: context.textTheme.titleMedium), + Text("destination_info_desc".tr), + WidgetConstant.height8, + ContainerWithBorder( + onRemoveIcon: StreamWidget( + buttomWidget: + Icon(Icons.circle, color: context.colors.transparent), + key: field.accountProgressKey), + onRemove: () { + if (!field.hasFetchingAccountError) return; + field.getDestinationAccountInfo(); + }, + child: !field.destination.hasValue + ? Text("no_account_chosen".tr) + : field.hasFetchingAccountError + ? Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + WidgetConstant.errorIcon, + WidgetConstant.width8, + Expanded( + child: Text( + "request_error".tr, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ) + : field.destinationAccount == null + ? Text("account_not_found".tr) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("owner".tr, + style: context.textTheme.labelLarge), + Text(field.destinationAccount!.owner.address), + Divider(color: context.colors.onPrimaryContainer), + Text("executable".tr, + style: context.textTheme.labelLarge), + Text(field.destinationAccount!.executable.tr), + ], + )), + WidgetConstant.height20, + TransactionAmountView( + amount: field.amount.value, + title: "amount".tr, + subtitle: "mint_to_amount_desc".tr, + validate: field.amount.isCompleted, + onTap: () { + context + .openSliverBottomSheet( + "amount".tr, + child: SetupNetworkAmount( + token: field.token, + max: maxU64, + min: BigInt.zero, + subtitle: PageTitleSubtitle( + title: "amount".tr, body: Text("mint_to_amount_desc".tr)), + ), + ) + .then((value) { + if (value == null) { + field.setValue(field.amount, null); + } else { + field.setValue(field.amount, + NoneDecimalBalance(value, field.token.decimal!)); + } + }); + }, + token: field.token, + ), + ], + ); + } +} diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/fields/transfer.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/fields/transfer.dart index 7f300519..347b9e62 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/fields/transfer.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/transaction/fields/transfer.dart @@ -15,7 +15,7 @@ class SolanaTransferTransactionView extends StatelessWidget { final SolanaSPLToken? splToken = context.getNullArgruments(); return SolanaTransactionFieldsView( - validator: LiveTransactionValidator( + field: LiveTransactionValidator( validator: SolanaTransferValidator( token: chain?.network.coinParam.token ?? splToken!.token, splToken: splToken))); diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/update_provider.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/update_provider.dart new file mode 100644 index 00000000..a5a00467 --- /dev/null +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/solana_pages/update_provider.dart @@ -0,0 +1,465 @@ +import 'package:flutter/material.dart'; +import 'package:mrt_wallet/app/core.dart'; +import 'package:mrt_wallet/future/pages/start_page/controller/wallet_provider.dart'; +import 'package:mrt_wallet/future/pages/wallet_pages/wallet_pages.dart'; +import 'package:mrt_wallet/future/widgets/custom_widgets.dart'; +import 'package:mrt_wallet/main.dart'; +import 'package:mrt_wallet/models/api/api_provider_tracker.dart'; +import 'package:mrt_wallet/models/wallet_models/chain/defauilt_node_providers.dart'; +import 'package:mrt_wallet/models/wallet_models/wallet_models.dart'; +import 'package:mrt_wallet/provider/api/api_provider.dart'; +import 'package:on_chain/solana/solana.dart'; + +class ImportSolanaProviderView extends StatelessWidget { + const ImportSolanaProviderView({super.key}); + + @override + Widget build(BuildContext context) { + final APPSolanaNetwork network = context.getArgruments(); + return _ImportSolanaProvider(network); + } +} + +class _ImportSolanaProvider extends StatefulWidget { + const _ImportSolanaProvider(this.network); + final APPSolanaNetwork network; + + @override + State<_ImportSolanaProvider> createState() => _ImportSolanaProviderState(); +} + +class _ImportSolanaProviderState extends State<_ImportSolanaProvider> { + late APPSolanaNetwork network = widget.network.copyWith(); + late final String? genesisHash = DefaultNodeProviders.getGnesisHash(network); + late final List providers = widget + .network.coinParam.providers + .map((e) => + ChainUtils.buildApiProvider(network, service: e) as SolanaApiProvider) + .toList(); + late final List defaultProviders = + List.unmodifiable( + DefaultNodeProviders.getDefaultServices(network) + .map((e) => ChainUtils.buildApiProvider(network, service: e) + as SolanaApiProvider) + .toList()); + SolanaApiProvider? selectedProvider; + bool hasAnyChange = false; + bool get enableUpdateButton => + !hasAnyChange || (providers.isEmpty && defaultProviders.isEmpty); + final GlobalKey formKey = GlobalKey(); + final GlobalKey pageProgressKey = GlobalKey(); + final GlobalKey uriFieldKey = GlobalKey(); + String rpcUrl = ""; + SolanaApiProviderService? service; + + void onSelectProvider(SolanaApiProvider? provider) { + if (provider == null || defaultProviders.contains(provider)) return; + + selectedProvider = provider; + service = selectedProvider!.serviceProvider.provider; + rpcUrl = service!.httpNodeUri; + setState(() {}); + } + + void discardChange() { + selectedProvider = null; + setState(() {}); + } + + void deleteProvider() { + providers.removeWhere((element) => element == selectedProvider); + selectedProvider = null; + hasAnyChange = true; + setState(() {}); + } + + void onDiscardProvider() { + _genesisHash = null; + verifyGenesis = false; + setState(() {}); + } + + SolanaApiProvider _buildSolanaRpc( + String url, String serviceName, String websiteurl) { + final service = SolanaApiProviderService( + serviceName: serviceName, websiteUri: websiteurl, httpNodeUri: url); + final tracker = ApiProviderTracker(provider: service); + return SolanaApiProvider( + provider: SolanaRPC(RPCHttpService(service.httpNodeUri, tracker)), + network: widget.network); + } + + void createNewRPC() { + if (selectedProvider != null) return; + selectedProvider = _buildSolanaRpc("", "", ""); + setState(() {}); + } + + void onPasteUri(String v) { + uriFieldKey.currentState?.updateText(v); + } + + void onChageUrl(String v) { + rpcUrl = v; + } + + String? validateRpcUrl(String? v) { + final path = AppStringUtility.validateUri(v, schame: ["http", "https"]); + if (path != null) return null; + return "network_websocket_address_validator".tr; + } + + void onAddProvider() async { + WalletLogging.print((providers.isEmpty && defaultProviders.isEmpty)); + if ((providers.isEmpty && defaultProviders.isEmpty) || + selectedProvider != null) return; + if (!(formKey.currentState?.validate() ?? false)) return; + pageProgressKey.progressText("updating_network".tr); + final result = await MethodCaller.call(() async { + final wallet = context.watch(StateIdsConst.main); + final services = + providers.map((e) => e.serviceProvider.provider).toList(); + final updatedNetwork = network.copyWith( + coinParam: network.coinParam.copyWith(providers: services)); + return await wallet.updateImportNetwork(updatedNetwork); + }); + if (result.hasError) { + pageProgressKey.errorText(result.error!.tr); + } else { + pageProgressKey.successText("network_updated_successfully".tr, + backToIdle: false); + } + } + + void addProvider() async { + if (selectedProvider == null || _genesisHash == null) return; + if (!verifyGenesis) { + final alert = await context.openSliverDialog( + (p0) => DialogTextView( + text: "network_electrum_incorrect_genesis_hash".tr, + buttomWidget: const DialogDoubleButtonView(), + ), + "network_security_issue".tr, + ); + if (alert != true) { + discardChange(); + return; + } + } + final currentProvider = providers.indexWhere((element) => + element.serviceProvider.provider.serviceName == service?.serviceName); + if (!currentProvider.isNegative) { + providers[currentProvider] = selectedProvider!; + } else { + providers.add(selectedProvider!); + } + + selectedProvider = null; + _genesisHash = null; + verifyGenesis = false; + rpcUrl = ''; + service = null; + hasAnyChange = true; + setState(() {}); + } + + String? _genesisHash; + bool verifyGenesis = false; + void checkingRpcStatus() async { + if (!(formKey.currentState?.validate() ?? false)) return; + verifyGenesis = false; + pageProgressKey.progressText("network_waiting_for_response".tr); + final result = await MethodCaller.call(() async { + final uniqueServiceName = AppStringUtility.addNumberToMakeUnique( + providers.map((e) => e.serviceProvider.provider.serviceName).toList() + ..removeWhere((element) => + element == + selectedProvider!.serviceProvider.provider.serviceName), + rpcUrl); + selectedProvider = _buildSolanaRpc(rpcUrl, uniqueServiceName, rpcUrl); + final serverBanner = await selectedProvider!.getGenesisHash(); + + return serverBanner; + }); + if (result.hasError) { + pageProgressKey.errorText(result.error!.tr); + } else { + _genesisHash = result.result; + if (_genesisHash == genesisHash) { + verifyGenesis = true; + } + pageProgressKey.success(); + } + } + + @override + Widget build(BuildContext context) { + return ScaffolPageView( + appBar: AppBar( + title: Text("network_update_node_provider".tr), + ), + child: PageProgress( + key: pageProgressKey, + backToIdle: AppGlobalConst.twoSecoundDuration, + child: () => CustomScrollView( + slivers: [ + SliverToBoxAdapter( + child: ConstraintsBoxView( + padding: WidgetConstant.padding20, + child: Form( + key: formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + PageTitleSubtitle( + title: "network_security_title".tr, + body: LargeTextView([ + "network_security_desc".tr, + "network_change_detect_desc".tr + ])), + Text("network".tr, + style: context.textTheme.titleMedium), + WidgetConstant.height8, + ContainerWithBorder( + child: Text(widget.network.coinParam.token.name)), + WidgetConstant.height20, + AnimatedSize( + duration: AppGlobalConst.animationDuraion, + child: selectedProvider == null + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("default_providers".tr, + style: context.textTheme.titleMedium), + WidgetConstant.height8, + ...List.generate(defaultProviders.length, + (index) { + final provider = defaultProviders[index]; + return ContainerWithBorder( + onRemove: () { + context.showAlert( + "network_unbale_change_providers" + .tr); + }, + onRemoveIcon: + ProviderTrackerStatusView( + provider: + provider.serviceProvider), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text(provider.serviceProvider + .provider.serviceName), + Text(provider.serviceProvider + .provider.websiteUri) + ], + )); + }), + WidgetConstant.height20, + Text("providers".tr, + style: context.textTheme.titleMedium), + Text("edit_or_add_evm_provider_desc".tr), + WidgetConstant.height8, + ...List.generate(providers.length, (index) { + final provider = providers[index]; + return ContainerWithBorder( + onRemove: () { + onSelectProvider(provider); + }, + onRemoveIcon: + ProviderTrackerStatusView( + provider: + provider.serviceProvider), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text(provider.serviceProvider + .provider.serviceName), + Text(provider.serviceProvider + .provider.websiteUri) + ], + )); + }), + ContainerWithBorder( + onRemove: createNewRPC, + validate: providers.isNotEmpty, + onTapWhenOnRemove: false, + onRemoveIcon: const Icon(Icons.add_box), + child: Text("create_new_provider".tr), + ), + Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + FixedElevatedButton( + padding: + WidgetConstant.paddingVertical20, + onPressed: enableUpdateButton + ? null + : onAddProvider, + child: Text( + "network_update_network_providers" + .tr), + ) + ], + ) + ], + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (providers + .contains(selectedProvider)) ...[ + Text("edit_provider_rpc_url".tr, + style: context.textTheme.titleMedium), + Text("edit_or_add_evm_provider_desc".tr), + WidgetConstant.height8, + ContainerWithBorder( + onRemove: () {}, + onRemoveIcon: + ProviderTrackerStatusView( + provider: selectedProvider! + .serviceProvider), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text(selectedProvider! + .serviceProvider + .provider + .serviceName), + Text(selectedProvider! + .serviceProvider + .provider + .websiteUri) + ], + )), + WidgetConstant.height20, + ], + AnimatedSize( + duration: AppGlobalConst.animationDuraion, + child: _genesisHash == null + ? Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text("rpc_url".tr, + style: context + .textTheme.titleMedium), + Text("rpc_url_desc".tr), + WidgetConstant.height8, + AppTextField( + key: uriFieldKey, + initialValue: rpcUrl, + onChanged: onChageUrl, + validator: validateRpcUrl, + suffixIcon: PasteTextIcon( + onPaste: onPasteUri), + label: "rpc_url".tr, + hint: + "https://api.mainnet.solana....", + ), + Padding( + padding: WidgetConstant + .paddingVertical20, + child: Row( + mainAxisAlignment: + MainAxisAlignment + .center, + children: [ + FixedElevatedButton.icon( + label: Text( + "network_verify_server_status" + .tr), + onPressed: + checkingRpcStatus, + icon: const Icon( + Icons.update), + ), + WidgetConstant.width8, + IconButton( + tooltip: + "discard_changes" + .tr, + icon: const Icon( + Icons.cancel), + onPressed: + discardChange), + WidgetConstant.width8, + IconButton( + tooltip: "remove".tr, + icon: const Icon( + Icons.delete), + onPressed: + deleteProvider), + ], + ), + ) + ], + ) + : Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + WidgetConstant.height20, + Text( + "network_electrum_genesis_hash" + .tr, + style: context + .textTheme.titleMedium, + ), + Text("gnesis_hash_desc".tr), + WidgetConstant.height8, + ContainerWithBorder( + child: Text(_genesisHash!)), + ErrorTextContainer( + error: !verifyGenesis + ? "network_genesis_hash_validator" + .tr + : null), + Padding( + padding: WidgetConstant + .paddingVertical20, + child: Row( + mainAxisAlignment: + MainAxisAlignment + .center, + children: [ + FixedElevatedButton.icon( + label: Text( + "network_add_to_providers" + .tr), + onPressed: addProvider, + icon: const Icon( + Icons.add_box), + ), + WidgetConstant.width8, + IconButton( + tooltip: + "discard_changes" + .tr, + icon: const Icon( + Icons.cancel), + onPressed: + onDiscardProvider), + ], + ), + ) + ], + ), + ) + ], + ), + ) + ], + ), + )), + ), + ], + ), + ), + ); + } +} diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/tron_pages/setup_address.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/tron_pages/setup_address.dart index a13a18bf..f3fbae33 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/tron_pages/setup_address.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/tron_pages/setup_address.dart @@ -105,10 +105,12 @@ class _SetupTronAddressViewState extends State super.didChangeDependencies(); } - AddressDerivationIndex? derivationkey() { + AddressDerivationIndex? derivationkey(CryptoCoins coin) { if (selectedCustomKey != null) { return ImportedAddressIndex( - accountId: selectedCustomKey!.id, bip32KeyIndex: customKeyIndex); + accountId: selectedCustomKey!.id, + bip32KeyIndex: customKeyIndex, + currencyCoin: coin); } return customKeyIndex; } @@ -120,7 +122,8 @@ class _SetupTronAddressViewState extends State final curve = selectedCustomKey?.type ?? EllipticCurveTypes.secp256k1; final coin = coins.firstWhere((element) => element.conf.type == curve); - final keyIndex = derivationkey() ?? chainAccount.account.nextDrive(coin); + final keyIndex = + derivationkey(coin) ?? chainAccount.account.nextDrive(coin); final newAccount = TronNewAddressParam(coin: coin, deriveIndex: keyIndex); final result = await model.deriveNewAccount(newAccount); diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/tron_pages/tron_account_page_view.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/tron_pages/tron_account_page_view.dart index 508425bb..b08a3051 100644 --- a/mrt_wallet/lib/future/pages/wallet_pages/network/tron_pages/tron_account_page_view.dart +++ b/mrt_wallet/lib/future/pages/wallet_pages/network/tron_pages/tron_account_page_view.dart @@ -1,9 +1,7 @@ import 'package:flutter/material.dart'; import 'package:mrt_wallet/app/core.dart'; -import 'package:mrt_wallet/future/pages/start_page/controller/wallet_provider.dart'; import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/token_details.dart'; import 'package:mrt_wallet/future/widgets/custom_widgets.dart'; -import 'package:mrt_wallet/main.dart'; import 'package:mrt_wallet/models/wallet_models/wallet_models.dart'; import 'package:mrt_wallet/provider/transaction_validator/transaction_validator.dart'; @@ -27,7 +25,6 @@ class _TronTokenView extends StatelessWidget { final bool isTrc10; @override Widget build(BuildContext context) { - final wallet = context.watch(StateIdsConst.main); final tokens = isTrc10 ? account.trc10Tokens : account.tokens; if (tokens.isEmpty) { @@ -73,40 +70,13 @@ class _TronTokenView extends StatelessWidget { final TokenCore token = tokens[index]; return ContainerWithBorder( onRemove: () { - context - .openSliverDialog( - (ctx) => TokenDetailsModalView( - token: token, - address: account, - ), - content: (ctx) => [ - IconButton( - onPressed: () { - ctx.pop(TokenAction.delete); - }, - icon: Icon(Icons.delete, - color: context.colors.error)) - ], - "token_info".tr) - .then((value) { - switch (value) { - case TokenAction.delete: - context.openSliverDialog( - (ctx) => DialogTextView( - buttomWidget: AsyncDialogDoubleButtonView( - firstButtonPressed: () => - wallet.removeToken(token, account), - ), - text: "remove_token_from_account".tr), - "remove_token".tr); - break; - case TokenAction.transfer: - context.to(PagePathConst.tronTransfer, - argruments: token); - break; - default: - } - }); + context.openDialogPage( + (ctx) => TokenDetailsModalView( + token: token, + address: account, + transferPath: PagePathConst.tronTransfer, + ), + "token_info".tr); }, onRemoveWidget: WidgetConstant.sizedBox, child: Row( diff --git a/mrt_wallet/lib/future/widgets/bottom_sheet.dart b/mrt_wallet/lib/future/widgets/bottom_sheet.dart index 24287692..d3fa4922 100644 --- a/mrt_wallet/lib/future/widgets/bottom_sheet.dart +++ b/mrt_wallet/lib/future/widgets/bottom_sheet.dart @@ -125,6 +125,7 @@ class _AppBottomSheetState extends State { ? null : const SizedBox(), title: Text(widget.label), + centerTitle: false, ), body: Column( children: [ diff --git a/mrt_wallet/lib/future/widgets/dialog_view.dart b/mrt_wallet/lib/future/widgets/dialog_view.dart index 122b43ce..671638ed 100644 --- a/mrt_wallet/lib/future/widgets/dialog_view.dart +++ b/mrt_wallet/lib/future/widgets/dialog_view.dart @@ -5,12 +5,14 @@ import 'package:mrt_wallet/types/typedef.dart'; class DialogView extends StatelessWidget { const DialogView( - {required this.child, + {this.widget, this.title, this.titleWidget, this.content = const [], + this.child, super.key}); - final Widget child; + final Widget? widget; + final Widget? child; final String? title; final Widget? titleWidget; final List content; @@ -25,27 +27,28 @@ class DialogView extends StatelessWidget { borderRadius: WidgetConstant.border8, child: Material( color: context.colors.background, - child: CustomScrollView( - shrinkWrap: true, - slivers: [ - SliverAppBar( - title: titleWidget ?? Text(title ?? ""), - leading: WidgetConstant.sizedBox, - leadingWidth: 0, - pinned: true, - actions: [ - ...content, - const CloseButton(), + child: child ?? + CustomScrollView( + shrinkWrap: true, + slivers: [ + SliverAppBar( + title: titleWidget ?? Text(title ?? ""), + leading: WidgetConstant.sizedBox, + leadingWidth: 0, + pinned: true, + actions: [ + ...content, + const CloseButton(), + ], + ), + SliverToBoxAdapter( + child: ConstraintsBoxView( + padding: WidgetConstant.padding20, + child: widget ?? WidgetConstant.sizedBox, + ), + ), ], ), - SliverToBoxAdapter( - child: ConstraintsBoxView( - padding: WidgetConstant.padding20, - child: child, - ), - ), - ], - ), ), ), ), diff --git a/mrt_wallet/lib/future/widgets/progress_bar/progress_widgets.dart b/mrt_wallet/lib/future/widgets/progress_bar/progress_widgets.dart index ecada460..c18a2062 100644 --- a/mrt_wallet/lib/future/widgets/progress_bar/progress_widgets.dart +++ b/mrt_wallet/lib/future/widgets/progress_bar/progress_widgets.dart @@ -28,27 +28,29 @@ class ErrorWithTextView extends StatelessWidget { maxHeight: 120, child: Container( padding: WidgetConstant.padding10, - decoration: BoxDecoration(boxShadow: const [ - BoxShadow(spreadRadius: 1, blurRadius: 5), - ], borderRadius: WidgetConstant.border8), + decoration: BoxDecoration( + borderRadius: WidgetConstant.border8, + color: context.colors.errorContainer), child: SingleChildScrollView( child: SelectableText( text, textAlign: TextAlign.center, + style: context.textTheme.bodyMedium + ?.copyWith(color: context.colors.onErrorContainer), ), ), ), ), if (progressKey != null) ...[ - WidgetConstant.height8, + WidgetConstant.height20, Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.center, children: [ FilledButton.icon( onPressed: () { progressKey?.backToIdle(); }, - icon: const Icon(Icons.close), + icon: const Icon(Icons.arrow_back), label: Text("back_to_the_page".tr)) ], ) diff --git a/mrt_wallet/lib/main.dart b/mrt_wallet/lib/main.dart index 5f42c061..8e2ee0a9 100644 --- a/mrt_wallet/lib/main.dart +++ b/mrt_wallet/lib/main.dart @@ -24,7 +24,9 @@ import 'package:mrt_wallet/future/pages/wallet_pages/network/ripple_pages/transa import 'package:mrt_wallet/future/pages/wallet_pages/network/ripple_pages/transaction/fields/transfer.dart'; import 'package:mrt_wallet/future/pages/wallet_pages/network/solana_pages/setup_address.dart'; import 'package:mrt_wallet/future/pages/wallet_pages/network/solana_pages/spl_token/account_spl_tokens_view.dart'; +import 'package:mrt_wallet/future/pages/wallet_pages/network/solana_pages/transaction/fields/transaction.dart'; import 'package:mrt_wallet/future/pages/wallet_pages/network/solana_pages/transaction/fields/transfer.dart'; +import 'package:mrt_wallet/future/pages/wallet_pages/network/solana_pages/update_provider.dart'; import 'package:mrt_wallet/future/pages/wallet_pages/network/tron_pages/setup_address.dart'; import 'package:mrt_wallet/future/pages/wallet_pages/network/tron_pages/setup_multisig_address.dart'; import 'package:mrt_wallet/future/pages/wallet_pages/network/tron_pages/token/import_trc10_tokens.dart'; @@ -246,6 +248,10 @@ class PageRouter { return const SetupCosmosAddressView(); case PagePathConst.cosmosTransaction: return const CosmosTransferTransactionView(); + case PagePathConst.solanaTransaction: + return const SolanaTransactionFieldsView(); + case PagePathConst.editSolanaNetwork: + return const ImportSolanaProviderView(); default: return const HomeScreen(); } diff --git a/mrt_wallet/lib/models/wallet_models/address/core/address.dart b/mrt_wallet/lib/models/wallet_models/address/core/address.dart index b3a97004..fffe8e3d 100644 --- a/mrt_wallet/lib/models/wallet_models/address/core/address.dart +++ b/mrt_wallet/lib/models/wallet_models/address/core/address.dart @@ -26,6 +26,7 @@ abstract class CryptoAccountAddress with CborSerializable { void removeNFT(NFTCore nft); void addToken(TokenCore newToken); void removeToken(TokenCore token); + void updateToken(TokenCore token, Token updatedToken); static CryptoAccountAddress fromCbor( AppNetworkImpl network, CborObject cbor) { diff --git a/mrt_wallet/lib/models/wallet_models/address/core/derivation/address_derivation.dart b/mrt_wallet/lib/models/wallet_models/address/core/derivation/address_derivation.dart index f08b9ab9..df496017 100644 --- a/mrt_wallet/lib/models/wallet_models/address/core/derivation/address_derivation.dart +++ b/mrt_wallet/lib/models/wallet_models/address/core/derivation/address_derivation.dart @@ -1,3 +1,4 @@ +import 'package:blockchain_utils/bip/bip/bip32/base/bip32_base.dart'; import 'package:blockchain_utils/bip/bip/conf/bip_coins.dart'; import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:mrt_wallet/app/error/exception/wallet_ex.dart'; @@ -7,10 +8,11 @@ import 'package:mrt_wallet/models/wallet_models/wallet_models.dart'; import 'package:mrt_wallet/provider/wallet/constant/constant.dart'; abstract class AddressDerivationIndex with CborSerializable, Equatable { - const AddressDerivationIndex(); String get path; EllipticCurveTypes? get curve; CryptoCoins? get currencyCoin; + const AddressDerivationIndex(); + static AddressDerivationIndex fromCborBytesOrObject( {List? bytes, CborObject? obj}) { final cbor = (obj ?? CborObject.fromCbor(bytes!)) as CborTagValue; @@ -30,7 +32,8 @@ abstract class AddressDerivationIndex with CborSerializable, Equatable { } } - T derive(T derivator, {Bip44Levels maxLevel = Bip44Levels.addressIndex}); + T derive(T derivator, + {Bip44Levels maxLevel = Bip44Levels.addressIndex}); String storageKey({Bip44Levels maxLevel = Bip44Levels.addressIndex}); diff --git a/mrt_wallet/lib/models/wallet_models/address/core/derivation/bip32_address_index.dart b/mrt_wallet/lib/models/wallet_models/address/core/derivation/bip32_address_index.dart index a63d5acd..96667e00 100644 --- a/mrt_wallet/lib/models/wallet_models/address/core/derivation/bip32_address_index.dart +++ b/mrt_wallet/lib/models/wallet_models/address/core/derivation/bip32_address_index.dart @@ -13,6 +13,28 @@ class Bip32AddressIndex extends AddressDerivationIndex final int accountLevel; final int changeLevel; final int addressIndex; + + @override + final String path; + + @override + final EllipticCurveTypes? curve; + @override + final SeedGenerationType seedGeneration; + @override + final CryptoCoins? currencyCoin; + + const Bip32AddressIndex._( + {required this.purpose, + required this.coin, + required this.accountLevel, + required this.changeLevel, + required this.addressIndex, + required this.curve, + required this.currencyCoin, + required this.seedGeneration, + required this.path}); + factory Bip32AddressIndex.fromCborBytesOrObject( {List? bytes, CborObject? obj}) { try { @@ -36,6 +58,13 @@ class Bip32AddressIndex extends AddressDerivationIndex changeLevel: changeLevel, purpose: purposeLevel, coin: coinLevel, + path: _toPath([ + purposeLevel, + coinLevel, + accountLevel, + changeLevel, + addressIndex + ]), curve: curve == null ? coin == null ? EllipticCurveTypes.secp256k1 @@ -49,24 +78,27 @@ class Bip32AddressIndex extends AddressDerivationIndex throw WalletExceptionConst.invalidAccountDetails; } } - Bip32AddressIndex._( - {required this.purpose, - required this.coin, - required this.accountLevel, - required this.changeLevel, - required this.addressIndex, - required this.curve, - required this.currencyCoin, - required this.seedGeneration}); - Bip32AddressIndex( - {required this.purpose, - required this.coin, - required this.accountLevel, - required this.changeLevel, - required this.addressIndex, - required this.currencyCoin, - required this.seedGeneration}) - : curve = null; + + factory Bip32AddressIndex( + {required int purpose, + required int coin, + required int accountLevel, + required int changeLevel, + required int addressIndex, + required CryptoCoins currencyCoin, + required SeedGenerationType seedGeneration}) { + return Bip32AddressIndex._( + purpose: purpose, + coin: coin, + path: _toPath([purpose, coin, accountLevel, changeLevel, addressIndex]), + curve: null, + accountLevel: accountLevel, + changeLevel: changeLevel, + addressIndex: addressIndex, + currencyCoin: currencyCoin, + seedGeneration: seedGeneration); + } + factory Bip32AddressIndex.fromBip44KeyIndexDetais( {required List indexes, required CryptoCoins currencyCoin, @@ -86,13 +118,12 @@ class Bip32AddressIndex extends AddressDerivationIndex final int addressIndex = indexes .firstWhere((element) => element.level == Bip44Levels.addressIndex) .index; - return Bip32AddressIndex._( + return Bip32AddressIndex( purpose: purpose, coin: coin, accountLevel: accountLevel, changeLevel: changeLevel, addressIndex: addressIndex, - curve: null, currencyCoin: currencyCoin, seedGeneration: seedGeneration); } @@ -133,14 +164,6 @@ class Bip32AddressIndex extends AddressDerivationIndex seedGeneration.name ]; - String? _cachedPath; - - @override - String get path { - _cachedPath ??= _toPath(indexes.map((e) => e.index).toList()); - return _cachedPath!; - } - static String _toPath(List indexses) { String path = "m/"; for (final i in indexses) { @@ -156,16 +179,8 @@ class Bip32AddressIndex extends AddressDerivationIndex } @override - String toString() { - return path; - } - - @override - T derive(T derivator, {Bip44Levels maxLevel = Bip44Levels.addressIndex}) { - if (derivator is! Bip32Base) { - throw WalletException.invalidArgruments( - ["Bip32Base", derivator.runtimeType.toString()]); - } + T derive(T derivator, + {Bip44Levels maxLevel = Bip44Levels.addressIndex}) { Bip32Base deriveToIndex = derivator; for (int i = 0; i < maxLevel.value; i++) { deriveToIndex = deriveToIndex.childKey(indexes.elementAt(i)); @@ -173,8 +188,6 @@ class Bip32AddressIndex extends AddressDerivationIndex return deriveToIndex as T; } - @override - final CryptoCoins? currencyCoin; List get indexes => [ Bip32KeyIndex(purpose), Bip32KeyIndex(coin), @@ -183,9 +196,6 @@ class Bip32AddressIndex extends AddressDerivationIndex Bip32KeyIndex(addressIndex) ]; - @override - final EllipticCurveTypes? curve; - @override String storageKey({Bip44Levels maxLevel = Bip44Levels.addressIndex}) => BytesUtils.toHexString(MD5.hash([ @@ -195,5 +205,7 @@ class Bip32AddressIndex extends AddressDerivationIndex ])); @override - final SeedGenerationType seedGeneration; + String toString() { + return path; + } } diff --git a/mrt_wallet/lib/models/wallet_models/address/core/derivation/byron_legacy_address_index.dart b/mrt_wallet/lib/models/wallet_models/address/core/derivation/byron_legacy_address_index.dart index bac8e660..eb92b370 100644 --- a/mrt_wallet/lib/models/wallet_models/address/core/derivation/byron_legacy_address_index.dart +++ b/mrt_wallet/lib/models/wallet_models/address/core/derivation/byron_legacy_address_index.dart @@ -11,6 +11,18 @@ class ByronLegacyAddressIndex extends AddressDerivationIndex final int firstIndex; final int secondIndex; + @override + final CryptoCoins? currencyCoin; + @override + final EllipticCurveTypes? curve = null; + @override + SeedGenerationType get seedGeneration => SeedGenerationType.byronLegacySeed; + + const ByronLegacyAddressIndex( + {required this.firstIndex, + required this.secondIndex, + required this.currencyCoin}); + factory ByronLegacyAddressIndex.fromCborBytesOrObject( {List? bytes, CborObject? obj}) { try { @@ -22,22 +34,12 @@ class ByronLegacyAddressIndex extends AddressDerivationIndex final String coinName = cbor.elementAt(3); final CryptoCoins? coin = CryptoCoins.getCoin(coinName, CryptoProposal.fromName(proposal)); - return ByronLegacyAddressIndex._( + return ByronLegacyAddressIndex( firstIndex: firstIndex, secondIndex: secondIndex, currencyCoin: coin); } catch (e) { throw WalletExceptionConst.invalidAccountDetails; } } - ByronLegacyAddressIndex._( - {required this.firstIndex, - required this.secondIndex, - required this.currencyCoin}) - : curve = null; - ByronLegacyAddressIndex( - {required this.firstIndex, - required this.secondIndex, - required this.currencyCoin}) - : curve = null; @override CborTagValue toCbor() { @@ -61,24 +63,11 @@ class ByronLegacyAddressIndex extends AddressDerivationIndex } @override - String toString() { - return path; - } - - @override - T derive(T derivator, {Bip44Levels maxLevel = Bip44Levels.addressIndex}) { - if (derivator is! Bip32Base) { - throw WalletException.invalidArgruments( - ["Bip32Base", derivator.runtimeType.toString()]); - } + T derive(T derivator, + {Bip44Levels maxLevel = Bip44Levels.addressIndex}) { return derivator.derivePath(path) as T; } - @override - final CryptoCoins? currencyCoin; - - @override - final EllipticCurveTypes? curve; @override String storageKey({Bip44Levels maxLevel = Bip44Levels.addressIndex}) => BytesUtils.toHexString(MD5.hash([ @@ -88,5 +77,7 @@ class ByronLegacyAddressIndex extends AddressDerivationIndex ])); @override - SeedGenerationType get seedGeneration => SeedGenerationType.byronLegacySeed; + String toString() { + return path; + } } diff --git a/mrt_wallet/lib/models/wallet_models/address/core/derivation/imported_address_index.dart b/mrt_wallet/lib/models/wallet_models/address/core/derivation/imported_address_index.dart index c0ddf4ac..ef0cb513 100644 --- a/mrt_wallet/lib/models/wallet_models/address/core/derivation/imported_address_index.dart +++ b/mrt_wallet/lib/models/wallet_models/address/core/derivation/imported_address_index.dart @@ -3,12 +3,22 @@ import 'package:blockchain_utils/bip/bip/conf/bip_coins.dart'; import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:mrt_wallet/app/error/exception/wallet_ex.dart'; import 'package:mrt_wallet/app/euqatable/equatable.dart'; +import 'package:mrt_wallet/app/extention/cbor.dart'; import 'package:mrt_wallet/models/serializable/serializable.dart'; import 'package:mrt_wallet/models/wallet_models/wallet_models.dart'; import 'package:mrt_wallet/provider/wallet/constant/constant.dart'; class ImportedAddressIndex with Equatable implements AddressDerivationIndex { - const ImportedAddressIndex({required this.accountId, this.bip32KeyIndex}); + const ImportedAddressIndex({ + required this.accountId, + required CryptoCoins this.currencyCoin, + this.bip32KeyIndex, + }); + const ImportedAddressIndex._({ + required this.accountId, + required this.currencyCoin, + this.bip32KeyIndex, + }); factory ImportedAddressIndex.fromCborBytesOrObject( {List? bytes, CborObject? obj}) { try { @@ -20,8 +30,14 @@ class ImportedAddressIndex with Equatable implements AddressDerivationIndex { keyIndex = Bip32AddressIndex.fromCborBytesOrObject(obj: cbor.value[0]); } final String accountId = cbor.value[1].value; - return ImportedAddressIndex( - accountId: accountId, bip32KeyIndex: keyIndex); + CryptoCoins? coin; + final String? proposalName = cbor.elementAt(2); + if (proposalName != null) { + final CryptoProposal proposal = CryptoProposal.fromName(proposalName); + coin = CryptoCoins.getCoin(cbor.elementAt(3), proposal)!; + } + return ImportedAddressIndex._( + accountId: accountId, bip32KeyIndex: keyIndex, currencyCoin: coin); } catch (e) { throw WalletExceptionConst.invalidAccountDetails; } @@ -29,14 +45,19 @@ class ImportedAddressIndex with Equatable implements AddressDerivationIndex { final String accountId; final AddressDerivationIndex? bip32KeyIndex; + @override + final EllipticCurveTypes? curve = null; + @override + final CryptoCoins? currencyCoin; + @override CborTagValue toCbor() { return CborTagValue( CborListValue.fixedLength([ - bip32KeyIndex == null - ? const CborNullValue() - : bip32KeyIndex!.toCbor(), - accountId + bip32KeyIndex?.toCbor() ?? const CborNullValue(), + accountId, + currencyCoin?.proposal ?? const CborNullValue(), + currencyCoin?.coinName ?? const CborNullValue() ]), WalletModelCborTagsConst.importedAccountKeyIndex); } @@ -49,11 +70,8 @@ class ImportedAddressIndex with Equatable implements AddressDerivationIndex { List get variabels => [accountId, bip32KeyIndex]; @override - T derive(T derivator, {Bip44Levels maxLevel = Bip44Levels.addressIndex}) { - if (derivator is! Bip32Base) { - throw WalletException.invalidArgruments( - ["Bip32Base", derivator.runtimeType.toString()]); - } + T derive(T derivator, + {Bip44Levels maxLevel = Bip44Levels.addressIndex}) { if (bip32KeyIndex != null) { return bip32KeyIndex!.derive(derivator); } @@ -61,12 +79,6 @@ class ImportedAddressIndex with Equatable implements AddressDerivationIndex { return derivator; } - @override - EllipticCurveTypes get curve => throw UnimplementedError(); - - @override - CryptoCoins get currencyCoin => throw UnimplementedError(); - @override String storageKey({Bip44Levels maxLevel = Bip44Levels.addressIndex}) => BytesUtils.toHexString(MD5.hash([ diff --git a/mrt_wallet/lib/models/wallet_models/address/core/derivation/multi_sig_address_index.dart b/mrt_wallet/lib/models/wallet_models/address/core/derivation/multi_sig_address_index.dart index 9a7ddf6d..d3e0636c 100644 --- a/mrt_wallet/lib/models/wallet_models/address/core/derivation/multi_sig_address_index.dart +++ b/mrt_wallet/lib/models/wallet_models/address/core/derivation/multi_sig_address_index.dart @@ -1,3 +1,4 @@ +import 'package:blockchain_utils/bip/bip/bip32/base/bip32_base.dart'; import 'package:blockchain_utils/bip/bip/conf/bip_coins.dart'; import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:mrt_wallet/app/error/exception/wallet_ex.dart'; @@ -5,9 +6,9 @@ import 'package:mrt_wallet/models/wallet_models/wallet_models.dart'; import 'package:mrt_wallet/provider/wallet/constant/constant.dart'; class MultiSigAddressIndex implements AddressDerivationIndex { - const MultiSigAddressIndex(); @override String get path => "multi_signature"; + const MultiSigAddressIndex(); @override CborTagValue toCbor() { @@ -16,7 +17,8 @@ class MultiSigAddressIndex implements AddressDerivationIndex { } @override - T derive(T derivator, {Bip44Levels maxLevel = Bip44Levels.addressIndex}) { + T derive(T derivator, + {Bip44Levels maxLevel = Bip44Levels.addressIndex}) { throw WalletExceptionConst.multiSigDerivationNotSuported; } diff --git a/mrt_wallet/lib/models/wallet_models/address/network_address/bitcoin/bitcoin_account.dart b/mrt_wallet/lib/models/wallet_models/address/network_address/bitcoin/bitcoin_account.dart index 7b5bc2ee..cd8519f1 100644 --- a/mrt_wallet/lib/models/wallet_models/address/network_address/bitcoin/bitcoin_account.dart +++ b/mrt_wallet/lib/models/wallet_models/address/network_address/bitcoin/bitcoin_account.dart @@ -182,6 +182,9 @@ class IBitcoinAddress @override String get orginalAddress => address.toAddress; + + @override + void updateToken(TokenCore token, Token updatedToken) {} } class IBitcoinMultiSigAddress extends IBitcoinAddress diff --git a/mrt_wallet/lib/models/wallet_models/address/network_address/cardano/cardano.dart b/mrt_wallet/lib/models/wallet_models/address/network_address/cardano/cardano.dart index 759b02fe..b54b6ed9 100644 --- a/mrt_wallet/lib/models/wallet_models/address/network_address/cardano/cardano.dart +++ b/mrt_wallet/lib/models/wallet_models/address/network_address/cardano/cardano.dart @@ -172,6 +172,8 @@ class ICardanoAddress _tokens = List.unmodifiable(existTokens); } + @override + void updateToken(TokenCore token, Token updatedToken) {} @override void addNFT(NFTCore newNft) {} diff --git a/mrt_wallet/lib/models/wallet_models/address/network_address/cosmos/cosmos.dart b/mrt_wallet/lib/models/wallet_models/address/network_address/cosmos/cosmos.dart index f45ec3ea..01e08048 100644 --- a/mrt_wallet/lib/models/wallet_models/address/network_address/cosmos/cosmos.dart +++ b/mrt_wallet/lib/models/wallet_models/address/network_address/cosmos/cosmos.dart @@ -170,7 +170,8 @@ class ICosmosAddress @override void removeNFT(NFTCore nft) {} - + @override + void updateToken(TokenCore token, Token updatedToken) {} SignerInfo get signerInfo => SignerInfo( publicKey: coin.conf.type == EllipticCurveTypes.nist256p1 ? CosmosSecp256R1PublicKey.fromBytes(publicKey) diff --git a/mrt_wallet/lib/models/wallet_models/address/network_address/ethereum/ethereum_account.dart b/mrt_wallet/lib/models/wallet_models/address/network_address/ethereum/ethereum_account.dart index 7db326e7..b74c90d6 100644 --- a/mrt_wallet/lib/models/wallet_models/address/network_address/ethereum/ethereum_account.dart +++ b/mrt_wallet/lib/models/wallet_models/address/network_address/ethereum/ethereum_account.dart @@ -171,6 +171,7 @@ class IEthAddress @override void removeToken(TokenCore token) { if (!tokens.contains(token)) return; + final existTokens = List.from(_tokens); existTokens.removeWhere((element) => element == token); _tokens = List.unmodifiable(existTokens); @@ -181,6 +182,19 @@ class IEthAddress @override void removeNFT(NFTCore nft) {} + @override + @override + void updateToken(TokenCore token, Token updatedToken) { + if (!tokens.contains(token)) return; + if (token is! ETHERC20Token) { + throw WalletExceptionConst.invalidArgruments( + "ETHERC20Token", "${token.runtimeType}"); + } + List existTokens = List.from(_tokens); + existTokens.removeWhere((element) => element == token); + existTokens = [token.updateToken(updatedToken), ...existTokens]; + _tokens = List.unmodifiable(existTokens); + } @override bool get multiSigAccount => false; diff --git a/mrt_wallet/lib/models/wallet_models/address/network_address/solana/solana_address.dart b/mrt_wallet/lib/models/wallet_models/address/network_address/solana/solana_address.dart index 77a4d86a..ec12dab4 100644 --- a/mrt_wallet/lib/models/wallet_models/address/network_address/solana/solana_address.dart +++ b/mrt_wallet/lib/models/wallet_models/address/network_address/solana/solana_address.dart @@ -167,6 +167,19 @@ class ISolanaAddress _tokens = List.unmodifiable([newToken, ..._tokens]); } + @override + void updateToken(TokenCore token, Token updatedToken) { + if (!tokens.contains(token)) return; + if (token is! SolanaSPLToken) { + throw WalletExceptionConst.invalidArgruments( + "SolanaSPLToken", "${token.runtimeType}"); + } + List existTokens = List.from(_tokens); + existTokens.removeWhere((element) => element == token); + existTokens = [token.updateToken(updatedToken), ...existTokens]; + _tokens = List.unmodifiable(existTokens); + } + @override void removeToken(TokenCore token) { if (!tokens.contains(token)) return; diff --git a/mrt_wallet/lib/models/wallet_models/address/network_address/tron/tron_account.dart b/mrt_wallet/lib/models/wallet_models/address/network_address/tron/tron_account.dart index a90fa913..bf41631c 100644 --- a/mrt_wallet/lib/models/wallet_models/address/network_address/tron/tron_account.dart +++ b/mrt_wallet/lib/models/wallet_models/address/network_address/tron/tron_account.dart @@ -183,7 +183,7 @@ class ITronAddress void addToken(TokenCore newToken) { if (newToken is! TronTRC20Token && newToken is! TronTRC10Token) { throw WalletExceptionConst.invalidArgruments( - "ETHERC20Token", "${newToken.runtimeType}"); + "TronTRC20Token, TronTRC10Token", "${newToken.runtimeType}"); } if (_trc20Token.contains(newToken)) { throw WalletExceptionConst.tokenAlreadyExist; @@ -198,6 +198,28 @@ class ITronAddress } } + @override + void updateToken(TokenCore token, Token updatedToken) { + if (token is! TronTRC20Token && token is! TronTRC10Token) { + throw WalletExceptionConst.invalidArgruments( + "TronTRC20Token, TronTRC10Token", "${token.runtimeType}"); + } + if (tokens.contains(token)) { + token as TronTRC20Token; + List existTokens = List.from(_trc20Token); + existTokens.removeWhere((element) => element == token); + existTokens = [token.updateToken(updatedToken), ...existTokens]; + _trc20Token = List.unmodifiable(existTokens); + } else if (_trc10Tokens.contains(token)) { + token as TronTRC10Token; + List existTokens = + List.from(_trc10Tokens); + existTokens.removeWhere((element) => element == token); + existTokens = [token.updateToken(updatedToken), ...existTokens]; + _trc10Tokens = List.unmodifiable(existTokens); + } + } + @override void removeToken(TokenCore token) { if (tokens.contains(token)) { diff --git a/mrt_wallet/lib/models/wallet_models/address/network_address/xrp/xrp_account.dart b/mrt_wallet/lib/models/wallet_models/address/network_address/xrp/xrp_account.dart index 9bbd5d6b..8045b47e 100644 --- a/mrt_wallet/lib/models/wallet_models/address/network_address/xrp/xrp_account.dart +++ b/mrt_wallet/lib/models/wallet_models/address/network_address/xrp/xrp_account.dart @@ -212,6 +212,19 @@ class IXRPAddress _tokens = List.unmodifiable([newToken, ..._tokens]); } + @override + void updateToken(TokenCore token, Token updatedToken) { + if (!tokens.contains(token)) return; + if (token is! RippleIssueToken) { + throw WalletExceptionConst.invalidArgruments( + "RippleIssueToken", "${token.runtimeType}"); + } + List existTokens = List.from(_tokens); + existTokens.removeWhere((element) => element == token); + existTokens = [token.updateToken(updatedToken), ...existTokens]; + _tokens = List.unmodifiable(existTokens); + } + @override void removeToken(TokenCore token) { if (!tokens.contains(token)) return; diff --git a/mrt_wallet/lib/models/wallet_models/chain/chain.dart b/mrt_wallet/lib/models/wallet_models/chain/chain.dart index 46541a56..b645cf80 100644 --- a/mrt_wallet/lib/models/wallet_models/chain/chain.dart +++ b/mrt_wallet/lib/models/wallet_models/chain/chain.dart @@ -23,8 +23,10 @@ class AppChain with CborSerializable { return ["services", "tokens"]; } else if (network is APPTVMNetwork) { return ["services", "trc20_tokens", "trc10_tokens"]; - } else if (network is APPEVMNetwork || network is APPSolanaNetwork) { + } else if (network is APPEVMNetwork) { return ["tokens"]; + } else if (network is APPSolanaNetwork) { + return ["services", "tokens"]; } return ["services"]; } diff --git a/mrt_wallet/lib/models/wallet_models/chain/defauilt_node_providers.dart b/mrt_wallet/lib/models/wallet_models/chain/defauilt_node_providers.dart index f510d079..5495f862 100644 --- a/mrt_wallet/lib/models/wallet_models/chain/defauilt_node_providers.dart +++ b/mrt_wallet/lib/models/wallet_models/chain/defauilt_node_providers.dart @@ -1,4 +1,5 @@ import 'package:mrt_native_support/platform_interface.dart'; +import 'package:mrt_wallet/app/core.dart'; import 'package:mrt_wallet/models/wallet_models/network/core/network.dart'; import 'package:mrt_wallet/provider/api/api_provider.dart'; @@ -14,6 +15,8 @@ class DefaultNodeProviders { 4: "00000ffd590b1485b3caadc19b22e6379c733355108f107a430458cdf3407ab6", 10: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", 11: "000000001dd410c49a788668ce26751718cc797474d3152a5fc073dd44fd9f7b", + 33: "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d", + 34: "4uhcVJyU9pJkvQyS88uRDiswHXSCkY3zQawwpjk2NsNY", }; static final Map> _providers = Map>.unmodifiable({ @@ -356,6 +359,7 @@ class DefaultNodeProviders { } static String? getGnesisHash(AppNetworkImpl network) { + WalletLogging.print("come ${network.value}"); return gnesisHash[network.value]; } } diff --git a/mrt_wallet/lib/models/wallet_models/network/core/network.dart b/mrt_wallet/lib/models/wallet_models/network/core/network.dart index 4f37c61c..bc8c6caa 100644 --- a/mrt_wallet/lib/models/wallet_models/network/core/network.dart +++ b/mrt_wallet/lib/models/wallet_models/network/core/network.dart @@ -13,6 +13,8 @@ abstract class AppNetworkImpl with Equatable, CborSerializable { const AppNetworkImpl(); abstract final int value; abstract final NetworkCoinParams coinParam; + bool get supportCustomNode; + List get coins; List get keyTypes => [EllipticCurveTypes.secp256k1]; @@ -163,6 +165,9 @@ class AppBitcoinNetwork extends AppNetworkImpl { BitcoinParams.fromCborBytesOrObject(obj: cbor.getCborTag(1)), ); } + + @override + bool get supportCustomNode => true; } class AppBitcoinCashNetwork extends AppBitcoinNetwork { @@ -231,6 +236,9 @@ class AppXRPNetwork extends AppNetworkImpl { @override List get variabels => [value]; + + @override + bool get supportCustomNode => false; } // @@ -273,6 +281,9 @@ class APPEVMNetwork extends AppNetworkImpl { CborListValue.fixedLength([value, coinParam.toCbor(), slip44]), WalletModelCborTagsConst.evmNetwork); } + + @override + bool get supportCustomNode => true; } class APPTVMNetwork extends AppNetworkImpl { @@ -307,10 +318,17 @@ class APPTVMNetwork extends AppNetworkImpl { TVMNetworkParams.fromCborBytesOrObject(obj: cbor.getCborTag(1)), ); } + + @override + bool get supportCustomNode => false; } class APPSolanaNetwork extends AppNetworkImpl { const APPSolanaNetwork(this.value, this.coinParam); + APPSolanaNetwork copyWith({int? value, SolanaNetworkParams? coinParam}) { + return APPSolanaNetwork(value ?? this.value, coinParam ?? this.coinParam); + } + @override final int value; @override @@ -344,6 +362,9 @@ class APPSolanaNetwork extends AppNetworkImpl { SolanaNetworkParams.fromCborBytesOrObject(obj: cbor.getCborTag(1)), ); } + + @override + bool get supportCustomNode => true; } class APPCardanoNetwork extends AppNetworkImpl { @@ -393,6 +414,9 @@ class APPCardanoNetwork extends AppNetworkImpl { CardanoNetworkParams.fromCborBytesOrObject(obj: cbor.getCborTag(1)), ); } + + @override + bool get supportCustomNode => false; } class APPCosmosNetwork extends AppNetworkImpl { @@ -430,4 +454,6 @@ class APPCosmosNetwork extends AppNetworkImpl { CosmosNetworkParams.fromCborBytesOrObject(obj: cbor.getCborTag(1)), ); } + @override + bool get supportCustomNode => false; } diff --git a/mrt_wallet/lib/models/wallet_models/network/params/networks/solana.dart b/mrt_wallet/lib/models/wallet_models/network/params/networks/solana.dart index 1083e013..04618c27 100644 --- a/mrt_wallet/lib/models/wallet_models/network/params/networks/solana.dart +++ b/mrt_wallet/lib/models/wallet_models/network/params/networks/solana.dart @@ -19,7 +19,7 @@ class SolanaNetworkParams with CborSerializable implements NetworkCoinParams { addressExplorer: cbor.elementAt(1), token: Token.fromCborBytesOrObject(obj: cbor.getCborTag(2)), providers: (cbor.elementAt(3) as List) - .map((e) => TronApiProviderService.fromCborBytesOrObject(obj: e)) + .map((e) => SolanaApiProviderService.fromCborBytesOrObject(obj: e)) .toList(), mainnet: cbor.elementAt(4)); } @@ -30,6 +30,22 @@ class SolanaNetworkParams with CborSerializable implements NetworkCoinParams { required this.providers, required this.mainnet}); + SolanaNetworkParams copyWith({ + bool? mainnet, + String? transactionExplorer, + String? addressExplorer, + Token? token, + List? providers, + }) { + return SolanaNetworkParams( + mainnet: mainnet ?? this.mainnet, + transactionExplorer: transactionExplorer ?? this.transactionExplorer, + addressExplorer: addressExplorer ?? this.addressExplorer, + token: token ?? this.token, + providers: providers ?? this.providers, + ); + } + final bool mainnet; @override @@ -46,6 +62,8 @@ class SolanaNetworkParams with CborSerializable implements NetworkCoinParams { @override final Token token; + @override + final List providers; @override String? getAccountExplorer(String address) { @@ -57,9 +75,6 @@ class SolanaNetworkParams with CborSerializable implements NetworkCoinParams { return transactionExplorer?.replaceAll(_txIdArgs, txId); } - @override - final List providers; - @override CborTagValue toCbor() { return CborTagValue( diff --git a/mrt_wallet/lib/models/wallet_models/signing_request/networks/solana/solana.dart b/mrt_wallet/lib/models/wallet_models/signing_request/networks/solana/solana.dart index 923dbc7d..ea1dcfae 100644 --- a/mrt_wallet/lib/models/wallet_models/signing_request/networks/solana/solana.dart +++ b/mrt_wallet/lib/models/wallet_models/signing_request/networks/solana/solana.dart @@ -18,5 +18,6 @@ class SolanaSigningRequest implements SigningRequest { AppNetworkImpl network; @override - List get signers => [addresses.first.keyIndex]; + List get signers => + addresses.map((e) => e.keyIndex).toList(); } diff --git a/mrt_wallet/lib/models/wallet_models/token/core/core.dart b/mrt_wallet/lib/models/wallet_models/token/core/core.dart index 072fc97c..f34ca5fd 100644 --- a/mrt_wallet/lib/models/wallet_models/token/core/core.dart +++ b/mrt_wallet/lib/models/wallet_models/token/core/core.dart @@ -13,5 +13,5 @@ abstract class TokenCore with CborSerializable { } abstract class SolidityToken implements TokenCore { - String toHex(); + String toHexAddress(); } diff --git a/mrt_wallet/lib/models/wallet_models/token/networks/ethereum/erc20_token.dart b/mrt_wallet/lib/models/wallet_models/token/networks/ethereum/erc20_token.dart index 9dc3af2d..ef8d4207 100644 --- a/mrt_wallet/lib/models/wallet_models/token/networks/ethereum/erc20_token.dart +++ b/mrt_wallet/lib/models/wallet_models/token/networks/ethereum/erc20_token.dart @@ -35,6 +35,10 @@ class ETHERC20Token with Equatable implements SolidityToken { } } + ETHERC20Token updateToken(Token updateToken) { + return ETHERC20Token._(balance, updateToken, contractAddress, _updated); + } + @override final Live balance; @@ -66,7 +70,7 @@ class ETHERC20Token with Equatable implements SolidityToken { } @override - List get variabels => [token, contractAddress.address]; + List get variabels => [contractAddress.address]; @override final Token token; @@ -75,7 +79,7 @@ class ETHERC20Token with Equatable implements SolidityToken { String? get issuer => contractAddress.address; @override - String toHex() { + String toHexAddress() { return contractAddress.toHex(); } diff --git a/mrt_wallet/lib/models/wallet_models/token/networks/ripple/ripple_issue_token.dart b/mrt_wallet/lib/models/wallet_models/token/networks/ripple/ripple_issue_token.dart index 53e8d97f..c46e47a8 100644 --- a/mrt_wallet/lib/models/wallet_models/token/networks/ripple/ripple_issue_token.dart +++ b/mrt_wallet/lib/models/wallet_models/token/networks/ripple/ripple_issue_token.dart @@ -32,6 +32,9 @@ class RippleIssueToken with Equatable implements TokenCore { throw WalletExceptionConst.invalidTokenInformation; } } + RippleIssueToken updateToken(Token updateToken) { + return RippleIssueToken._(balance, updateToken, issuer, _updated); + } @override final Live balance; @@ -65,7 +68,7 @@ class RippleIssueToken with Equatable implements TokenCore { } @override - List get variabels => [token, issuer]; + List get variabels => [issuer]; @override final Token token; diff --git a/mrt_wallet/lib/models/wallet_models/token/networks/solana/spl_token.dart b/mrt_wallet/lib/models/wallet_models/token/networks/solana/spl_token.dart index cb052495..108a9177 100644 --- a/mrt_wallet/lib/models/wallet_models/token/networks/solana/spl_token.dart +++ b/mrt_wallet/lib/models/wallet_models/token/networks/solana/spl_token.dart @@ -48,6 +48,11 @@ class SolanaSPLToken with Equatable implements TokenCore { } } + SolanaSPLToken updateToken(Token updateToken) { + return SolanaSPLToken._( + balance, updateToken, mint, tokenAccount, _updated, tokenOwner); + } + @override final Live balance; @@ -83,7 +88,7 @@ class SolanaSPLToken with Equatable implements TokenCore { } @override - List get variabels => [token, mint.address, tokenAccount.address]; + List get variabels => [mint.address, tokenAccount.address]; @override final Token token; diff --git a/mrt_wallet/lib/models/wallet_models/token/networks/tron/trc10_token.dart b/mrt_wallet/lib/models/wallet_models/token/networks/tron/trc10_token.dart index 5fa2e36b..60981e8a 100644 --- a/mrt_wallet/lib/models/wallet_models/token/networks/tron/trc10_token.dart +++ b/mrt_wallet/lib/models/wallet_models/token/networks/tron/trc10_token.dart @@ -32,6 +32,9 @@ class TronTRC10Token with Equatable implements TokenCore { throw WalletExceptionConst.invalidTokenInformation; } } + TronTRC10Token updateToken(Token updateToken) { + return TronTRC10Token._(balance, updateToken, tokenID, _updated); + } @override final Live balance; @@ -64,7 +67,7 @@ class TronTRC10Token with Equatable implements TokenCore { } @override - List get variabels => [token, tokenID]; + List get variabels => [tokenID]; @override final Token token; diff --git a/mrt_wallet/lib/models/wallet_models/token/networks/tron/trc20_token.dart b/mrt_wallet/lib/models/wallet_models/token/networks/tron/trc20_token.dart index d4d042e9..1b6e261c 100644 --- a/mrt_wallet/lib/models/wallet_models/token/networks/tron/trc20_token.dart +++ b/mrt_wallet/lib/models/wallet_models/token/networks/tron/trc20_token.dart @@ -35,6 +35,9 @@ class TronTRC20Token with Equatable implements SolidityToken { throw WalletExceptionConst.invalidTokenInformation; } } + TronTRC20Token updateToken(Token updateToken) { + return TronTRC20Token._(balance, updateToken, contractAddress, _updated); + } @override final Live balance; @@ -67,7 +70,7 @@ class TronTRC20Token with Equatable implements SolidityToken { } @override - List get variabels => [token, contractAddress.toAddress()]; + List get variabels => [contractAddress.toAddress()]; @override final Token token; @@ -76,7 +79,7 @@ class TronTRC20Token with Equatable implements SolidityToken { String? get issuer => contractAddress.toAddress(); @override - String toHex() { + String toHexAddress() { return contractAddress.toAddress(false); } diff --git a/mrt_wallet/lib/provider/api/http_services/solana.dart b/mrt_wallet/lib/provider/api/http_services/solana.dart index 4edcd29a..ad472e21 100644 --- a/mrt_wallet/lib/provider/api/http_services/solana.dart +++ b/mrt_wallet/lib/provider/api/http_services/solana.dart @@ -1,30 +1,22 @@ -import 'dart:convert'; -import 'package:http/http.dart'; import 'package:mrt_wallet/models/api/api_provider_tracker.dart'; import 'package:mrt_wallet/provider/api/api_provider.dart'; import 'package:on_chain/solana/solana.dart'; class RPCHttpService extends HttpProvider implements SolanaJSONRPCService { - RPCHttpService(this.url, this.provider, - {Client? client, this.defaultTimeOut = const Duration(seconds: 30)}) - : client = client ?? Client(); - @override final String url; @override - final Client client; - @override final Duration defaultTimeOut; + RPCHttpService(this.url, this.provider, + {this.defaultTimeOut = const Duration(seconds: 30)}); + @override Future> call(SolanaRequestDetails params, [Duration? timeout]) async { - final response = await client - .post(Uri.parse(url), - headers: {'Content-Type': 'application/json'}, - body: params.toRequestBody()) - .timeout(timeout ?? defaultTimeOut); - final data = json.decode(response.body) as Map; - return data; + final response = await providerPOST>( + url, params.toRequestBody(), + headers: {'Content-Type': 'application/json'}); + return response; } @override diff --git a/mrt_wallet/lib/provider/api/networks/ethereum/evm_api_providr.dart b/mrt_wallet/lib/provider/api/networks/ethereum/evm_api_providr.dart index 007fd45f..2c7670de 100644 --- a/mrt_wallet/lib/provider/api/networks/ethereum/evm_api_providr.dart +++ b/mrt_wallet/lib/provider/api/networks/ethereum/evm_api_providr.dart @@ -82,8 +82,8 @@ class EVMApiProvider implements NetworkApiProvider { Future updateTokenBalance( SolidityAddress account, SolidityToken token) async { - final balance = - await provider.request(RPCERC20TokenBalance(token.toHex(), account)); + final balance = await provider + .request(RPCERC20TokenBalance(token.toHexAddress(), account)); token.updateBalance(balance); } diff --git a/mrt_wallet/lib/provider/api/networks/solana/api_provider.dart b/mrt_wallet/lib/provider/api/networks/solana/api_provider.dart index 78e26aa2..86f52aaf 100644 --- a/mrt_wallet/lib/provider/api/networks/solana/api_provider.dart +++ b/mrt_wallet/lib/provider/api/networks/solana/api_provider.dart @@ -48,6 +48,16 @@ class SolanaApiProvider implements NetworkApiProvider { return blockHash.blockhash; } + Future getGenesisHash() async { + final gnesisHash = await provider.request(SolanaRPCGetGenesisHash()); + return gnesisHash; + } + + Future> clusterNodes() async { + final gnesisHash = await provider.request(SolanaRPCGetClusterNodes()); + return gnesisHash; + } + Future updateAccounts(ISolanaAddress address) async { for (final i in address.tokens) { try { diff --git a/mrt_wallet/lib/provider/transaction_validator/core/transaction_validator_core.dart b/mrt_wallet/lib/provider/transaction_validator/core/transaction_validator_core.dart index fc3db23c..6d24451a 100644 --- a/mrt_wallet/lib/provider/transaction_validator/core/transaction_validator_core.dart +++ b/mrt_wallet/lib/provider/transaction_validator/core/transaction_validator_core.dart @@ -5,14 +5,8 @@ typedef OnChageValidatorField = void Function(ValidatorField, T?); abstract class TransactionValidator { String? validateError(); - bool get isValid; - String get helperUri; - String get subject; String get name; - String get fieldsName; List get fields; OnChangeValidator? onChanged; void setValue(ValidatorField? field, T? value); - void setListValue(ValidatorField> field, T? value); - void removeIndex(ValidatorField> field, int index); } diff --git a/mrt_wallet/lib/provider/transaction_validator/core/validator_fields.dart b/mrt_wallet/lib/provider/transaction_validator/core/validator_fields.dart index 34548d8d..b07a7c7e 100644 --- a/mrt_wallet/lib/provider/transaction_validator/core/validator_fields.dart +++ b/mrt_wallet/lib/provider/transaction_validator/core/validator_fields.dart @@ -1,20 +1,18 @@ import 'package:mrt_wallet/types/typedef.dart'; class ValidatorField { - ValidatorField( - {required this.name, - required this.id, - required this.subject, - required this.onChangeValidator, - T? value, - this.optional = true, - this.show = true}) - : _value = value; + ValidatorField({ + required this.name, + this.id, + this.subject, + required this.onChangeValidator, + T? value, + this.optional = true, + }) : _value = value; final String name; - final String id; - final String subject; + final String? id; + final String? subject; final bool optional; - final bool show; T? _value; T? get value => _value; bool get hasValue => _value != null; diff --git a/mrt_wallet/lib/provider/transaction_validator/cosmos/transaction_validator/swap/swap.dart b/mrt_wallet/lib/provider/transaction_validator/cosmos/transaction_validator/swap/swap.dart new file mode 100644 index 00000000..82a678ef --- /dev/null +++ b/mrt_wallet/lib/provider/transaction_validator/cosmos/transaction_validator/swap/swap.dart @@ -0,0 +1,32 @@ +import 'package:cosmos_sdk/cosmos_sdk.dart'; +import 'package:mrt_wallet/models/wallet_models/address/network_address/cosmos/cosmos.dart'; +import 'package:mrt_wallet/provider/transaction_validator/core/live_validator.dart'; +import 'package:mrt_wallet/provider/transaction_validator/core/validator_fields.dart'; +import 'package:mrt_wallet/provider/transaction_validator/cosmos/transaction_validator/core/cosmos_field_validator.dart'; + +class ThorChainSwapValidator extends CosmosTransactionValidator { + @override + OnChangeValidator? onChanged; + + @override + BigInt get callValue => throw UnimplementedError(); + + @override + List get fields => throw UnimplementedError(); + + @override + List messages(CosmosBaseAddress signer) { + throw UnimplementedError(); + } + + @override + String get name => throw UnimplementedError(); + + @override + void setValue(ValidatorField? field, T? value) {} + + @override + String? validateError({ICosmosAddress? account}) { + throw UnimplementedError(); + } +} diff --git a/mrt_wallet/lib/provider/transaction_validator/cosmos/transaction_validator/transfer/transfer.dart b/mrt_wallet/lib/provider/transaction_validator/cosmos/transaction_validator/transfer/transfer.dart index 8d0e4e26..9920eaea 100644 --- a/mrt_wallet/lib/provider/transaction_validator/cosmos/transaction_validator/transfer/transfer.dart +++ b/mrt_wallet/lib/provider/transaction_validator/cosmos/transaction_validator/transfer/transfer.dart @@ -19,13 +19,11 @@ class CosmosTransferValidator extends CosmosTransactionValidator { final APPCosmosNetwork network; final ValidatorField> destination = ValidatorField( - id: "receiver", name: "destination", optional: false, onChangeValidator: (p0) { return p0; - }, - subject: ""); + }); @override OnChangeValidator? onChanged; @@ -33,22 +31,9 @@ class CosmosTransferValidator extends CosmosTransactionValidator { @override List get fields => [destination]; - @override - String get fieldsName => throw UnimplementedError(); - - @override - String get helperUri => throw UnimplementedError(); - - @override - bool get isValid => validateError() == null; - @override String get name => "transfer"; - @override - void removeIndex(ValidatorField> field, int index) {} - - @override void setListValue(ValidatorField> field, T? value, {DynamicVoid? onExists}) { if (value == null) return; @@ -132,9 +117,6 @@ class CosmosTransferValidator extends CosmosTransactionValidator { } } - @override - String get subject => throw UnimplementedError(); - @override String? validateError({ICosmosAddress? account}) { if (destination.value?.isEmpty ?? true) { diff --git a/mrt_wallet/lib/provider/transaction_validator/ethereum/transaction_validator/transfer/transfer.dart b/mrt_wallet/lib/provider/transaction_validator/ethereum/transaction_validator/transfer/transfer.dart index 2702780a..74f20190 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ethereum/transaction_validator/transfer/transfer.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ethereum/transaction_validator/transfer/transfer.dart @@ -20,18 +20,14 @@ class EthereumTransferValidator extends EthereumTransactionValidator { final Token token; final ETHERC20Token? erc20Token; final ValidatorField> destination = ValidatorField( - id: "receiver", name: "destination", optional: false, onChangeValidator: (p0) { return p0; - }, - subject: ""); + }); final ValidatorField amount = ValidatorField( name: "amount", - subject: "", optional: false, - id: "", onChangeValidator: (v) { try { if (v!.isZero || v.isNegative) return null; @@ -48,24 +44,9 @@ class EthereumTransferValidator extends EthereumTransactionValidator { @override List get fields => [destination, amount]; - @override - String get fieldsName => throw UnimplementedError(); - - @override - String get helperUri => throw UnimplementedError(); - - @override - bool get isValid => validateError() == null; - @override String get name => erc20Token != null ? "transfer_erc20" : "transfer"; - @override - void removeIndex(ValidatorField> field, int index) {} - - @override - void setListValue(ValidatorField> field, T? value) {} - @override void setValue(ValidatorField? field, T? value) { if (field == null) return; @@ -76,14 +57,11 @@ class EthereumTransferValidator extends EthereumTransactionValidator { } void _checkEstimate() { - if (isValid && erc20Token != null) { + if (validateError() == null && erc20Token != null) { onStimateChanged?.call(); } } - @override - String get subject => throw UnimplementedError(); - @override String? validateError({IEthAddress? account}) { for (final i in fields) { diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/account_set/account_set_validator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/account_set/account_set_validator.dart index 1495bbea..528e2712 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/account_set/account_set_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/account_set/account_set_validator.dart @@ -107,9 +107,6 @@ class RippleAccountSetValidator implements RippleTransactionValidator { return null; } - @override - bool get isValid => validateError() == null; - @override String? validateError({IXRPAddress? account}) { for (final i in fields) { @@ -174,7 +171,7 @@ class RippleAccountSetValidator implements RippleTransactionValidator { String get name => "account_set"; @override - String get fieldsName => "account_set_fields"; + String get validatorName => "account_set_fields"; @override void removeIndex(ValidatorField> field, int index) {} @@ -186,5 +183,5 @@ class RippleAccountSetValidator implements RippleTransactionValidator { XRPLTransactionType get transactionType => XRPLTransactionType.accountSet; @override - String get subject => "account_set_desc"; + String get validatorDescription => "account_set_desc"; } diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/core/ripple_field_validator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/core/ripple_field_validator.dart index 164b24db..2edee5c6 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/core/ripple_field_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/core/ripple_field_validator.dart @@ -7,8 +7,12 @@ abstract class RippleTransactionValidator implements TransactionValidator { {List memos = const [], String signerPublicKey = "", BigInt? fee}); - + String get helperUri; XRPLTransactionType get transactionType; @override String? validateError({IXRPAddress? account}); + String get validatorName; + String get validatorDescription; + void removeIndex(ValidatorField> field, int index); + void setListValue(ValidatorField> field, T? value); } diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/escrow/ripple_escrow_cancel_validator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/escrow/ripple_escrow_cancel_validator.dart index f2956fa0..f150169b 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/escrow/ripple_escrow_cancel_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/escrow/ripple_escrow_cancel_validator.dart @@ -27,9 +27,6 @@ class RippleEscrowCancelValidator implements RippleTransactionValidator { }, ); - @override - bool get isValid => validateError() == null; - @override String? validateError({IXRPAddress? account}) { for (final i in fields) { @@ -73,15 +70,16 @@ class RippleEscrowCancelValidator implements RippleTransactionValidator { @override String get helperUri => RippleConst.aboutScrowCancel; @override - String get fieldsName => "ripple_escrow_cancel_fields"; + String get validatorName => "ripple_escrow_cancel_fields"; @override void removeIndex(ValidatorField> field, int index) {} @override void setListValue(ValidatorField> field, T? value) {} + @override - String get subject => "ripple_escrow_cancel_desc"; + String get validatorDescription => "ripple_escrow_cancel_desc"; @override XRPLTransactionType get transactionType => XRPLTransactionType.escrowCancel; diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/escrow/ripple_escrow_create_validator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/escrow/ripple_escrow_create_validator.dart index c6eddd3d..cd30be1c 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/escrow/ripple_escrow_create_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/escrow/ripple_escrow_create_validator.dart @@ -74,8 +74,6 @@ class RippleEscrowCreateValidator implements RippleTransactionValidator { } }, ); - @override - bool get isValid => validateError() == null; @override String? validateError({IXRPAddress? account}) { @@ -132,15 +130,16 @@ class RippleEscrowCreateValidator implements RippleTransactionValidator { String get name => "EscrowCreate"; @override - String get fieldsName => "ripple_escrow_create_fields"; + String get validatorName => "ripple_escrow_create_fields"; @override - String get subject => "ripple_escrow_create_desc"; + String get validatorDescription => "ripple_escrow_create_desc"; @override void removeIndex(ValidatorField> field, int index) {} @override void setListValue(ValidatorField> field, T? value) {} + @override XRPLTransactionType get transactionType => XRPLTransactionType.escrowCreate; } diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/escrow/ripple_escrow_finish_validator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/escrow/ripple_escrow_finish_validator.dart index 11542460..50d344bb 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/escrow/ripple_escrow_finish_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/escrow/ripple_escrow_finish_validator.dart @@ -51,8 +51,6 @@ class RippleEscrowFinishValidator implements RippleTransactionValidator { } }, ); - @override - bool get isValid => validateError() == null; @override String? validateError({IXRPAddress? account}) { @@ -103,7 +101,7 @@ class RippleEscrowFinishValidator implements RippleTransactionValidator { String get name => "EscrowFinish"; @override - String get fieldsName => "ripple_escrow_finish_fields"; + String get validatorName => "ripple_escrow_finish_fields"; @override String get helperUri => RippleConst.aboutScrowfinish; @@ -112,9 +110,10 @@ class RippleEscrowFinishValidator implements RippleTransactionValidator { @override void setListValue(ValidatorField> field, T? value) {} + @override XRPLTransactionType get transactionType => XRPLTransactionType.escrowFinish; @override - String get subject => "ripple_escrow_finish_desc"; + String get validatorDescription => "ripple_escrow_finish_desc"; } diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_accept_offer_validator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_accept_offer_validator.dart index 77cd480b..23f3bc75 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_accept_offer_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_accept_offer_validator.dart @@ -33,9 +33,6 @@ class RippleAcceptNFTOfferValidator implements RippleTransactionValidator { }, ); - @override - bool get isValid => validateError() == null; - @override String? validateError({IXRPAddress? account}) { for (final i in fields) { @@ -79,12 +76,12 @@ class RippleAcceptNFTOfferValidator implements RippleTransactionValidator { @override String get name => "NFTokenAcceptOffer"; @override - String get fieldsName => "ripple_nftoken_accept_offer_fields"; + String get validatorName => "ripple_nftoken_accept_offer_fields"; @override String get helperUri => RippleConst.aboutNftAcceptOffer; @override - String get subject => "ripple_accept_offer_desc"; + String get validatorDescription => "ripple_accept_offer_desc"; @override void removeIndex(ValidatorField> field, int index) {} diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_burn_token_validator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_burn_token_validator.dart index cfd25c13..7a74cdbf 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_burn_token_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_burn_token_validator.dart @@ -31,9 +31,6 @@ class RippeBurnTokenValidator implements RippleTransactionValidator { }, ); - @override - bool get isValid => validateError() == null; - @override String? validateError({IXRPAddress? account}) { for (final i in fields) { @@ -76,11 +73,11 @@ class RippeBurnTokenValidator implements RippleTransactionValidator { String get name => "NFTokenBurn"; @override - String get fieldsName => "ripple_nftoken_burn_fields"; + String get validatorName => "ripple_nftoken_burn_fields"; @override String get helperUri => RippleConst.aboutNftokenBurn; @override - String get subject => "ripple_nftoken_burn_desc"; + String get validatorDescription => "ripple_nftoken_burn_desc"; @override void removeIndex(ValidatorField> field, int index) {} diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_cancel_offer_valiator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_cancel_offer_valiator.dart index 05b42349..0b6c2d00 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_cancel_offer_valiator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_cancel_offer_valiator.dart @@ -20,9 +20,6 @@ class RippleCancelOfferValidator implements RippleTransactionValidator { }, ); - @override - bool get isValid => validateError() == null; - @override String? validateError({IXRPAddress? account}) { for (final i in fields) { @@ -65,10 +62,10 @@ class RippleCancelOfferValidator implements RippleTransactionValidator { @override String get helperUri => RippleConst.abountNftokenCancelOffer; @override - String get fieldsName => "ripple_nftoken_cancel_offer_fields"; + String get validatorName => "ripple_nftoken_cancel_offer_fields"; @override - String get subject => "ripple_nftoken_cancel_offer_desc"; + String get validatorDescription => "ripple_nftoken_cancel_offer_desc"; @override void removeIndex(ValidatorField> field, int index) { diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_create_offer_validator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_create_offer_validator.dart index 2cdfa19a..9fb2751b 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_create_offer_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_create_offer_validator.dart @@ -72,9 +72,6 @@ class RippleCreateOfferValidator implements RippleTransactionValidator { }, ); - @override - bool get isValid => validateError() == null; - @override String? validateError({IXRPAddress? account}) { for (final i in fields) { @@ -125,10 +122,10 @@ class RippleCreateOfferValidator implements RippleTransactionValidator { @override String get name => "NFTokenCreateOffer"; @override - String get fieldsName => "ripple_nftoken_create_offer_fields"; + String get validatorName => "ripple_nftoken_create_offer_fields"; @override - String get subject => "ripple_create_nftoken_offer_desc"; + String get validatorDescription => "ripple_create_nftoken_offer_desc"; @override void removeIndex(ValidatorField> field, int index) {} diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_mint_token_validator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_mint_token_validator.dart index 2258e87a..40fb7827 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_mint_token_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/nft/ripple_mint_token_validator.dart @@ -54,8 +54,6 @@ class RippleMintTokenValidator implements RippleTransactionValidator { return v; }, ); - @override - bool get isValid => validateError() == null; @override String? validateError({IXRPAddress? account}) { @@ -102,11 +100,11 @@ class RippleMintTokenValidator implements RippleTransactionValidator { @override String get name => "NFTokenMint"; @override - String get fieldsName => "ripple_nfttoken_fields"; + String get validatorName => "ripple_nfttoken_fields"; @override String get helperUri => RippleConst.aboutNftoken; @override - String get subject => "ripple_mint_nftoken_desc"; + String get validatorDescription => "ripple_mint_nftoken_desc"; @override void removeIndex(ValidatorField> field, int index) {} diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/payment/ripple_payment_validator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/payment/ripple_payment_validator.dart index 328365f7..e0024d81 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/payment/ripple_payment_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/payment/ripple_payment_validator.dart @@ -53,9 +53,6 @@ class RipplePaymentValidator implements RippleTransactionValidator { }, ); - @override - bool get isValid => validateError() == null; - @override String? validateError({IXRPAddress? account}) { for (final i in fields) { @@ -113,11 +110,11 @@ class RipplePaymentValidator implements RippleTransactionValidator { String get name => "Payment"; @override - String get fieldsName => "ripple_payment_fields"; + String get validatorName => "ripple_payment_fields"; @override String get helperUri => RippleConst.aboutRipplePayment; @override - String get subject => "ripple_payment_desc"; + String get validatorDescription => "ripple_payment_desc"; @override void removeIndex(ValidatorField> field, int index) {} diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/regular_key/ripple_regular_key_validator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/regular_key/ripple_regular_key_validator.dart index 52186018..5f058d44 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/regular_key/ripple_regular_key_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/regular_key/ripple_regular_key_validator.dart @@ -16,9 +16,6 @@ class RippleRegularKeyValidator implements RippleTransactionValidator { }, ); - @override - bool get isValid => validateError() == null; - @override String? validateError({IXRPAddress? account}) { for (final i in fields) { @@ -61,7 +58,7 @@ class RippleRegularKeyValidator implements RippleTransactionValidator { @override String get helperUri => RippleConst.aboutRegularKey; @override - String get fieldsName => "ripple_set_regular_key_fields"; + String get validatorName => "ripple_set_regular_key_fields"; @override void removeIndex(ValidatorField> field, int index) {} @@ -69,7 +66,7 @@ class RippleRegularKeyValidator implements RippleTransactionValidator { @override void setListValue(ValidatorField> field, T? value) {} @override - String get subject => "ripple_regular_key_desc"; + String get validatorDescription => "ripple_regular_key_desc"; @override XRPLTransactionType get transactionType => XRPLTransactionType.setRegularKey; diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/signer_list/ripple_signer_list_validator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/signer_list/ripple_signer_list_validator.dart index b7b7f4cd..f1c8910b 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/signer_list/ripple_signer_list_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/signer_list/ripple_signer_list_validator.dart @@ -27,9 +27,6 @@ class RippleSignerListValidator implements RippleTransactionValidator { }, ); - @override - bool get isValid => validateError() == null; - @override String? validateError({IXRPAddress? account}) { for (final i in fields) { @@ -83,7 +80,7 @@ class RippleSignerListValidator implements RippleTransactionValidator { @override String get helperUri => RippleConst.aboutSignerList; @override - String get fieldsName => "ripple_signer_list_fields"; + String get validatorName => "ripple_signer_list_fields"; @override void removeIndex(ValidatorField> field, int index) { @@ -105,7 +102,7 @@ class RippleSignerListValidator implements RippleTransactionValidator { } @override - String get subject => "ripple_set_signer_list_desc"; + String get validatorDescription => "ripple_set_signer_list_desc"; @override XRPLTransactionType get transactionType => XRPLTransactionType.signerListSet; diff --git a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/trust_set/ripple_trust_set_validator.dart b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/trust_set/ripple_trust_set_validator.dart index 93d7f137..9c9ba206 100644 --- a/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/trust_set/ripple_trust_set_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/ripple/transaction_validator/trust_set/ripple_trust_set_validator.dart @@ -47,9 +47,6 @@ class RippleTrustSetValidator implements RippleTransactionValidator { }, ); - @override - bool get isValid => validateError() == null; - @override String? validateError({IXRPAddress? account}) { for (final i in fields) { @@ -94,9 +91,9 @@ class RippleTrustSetValidator implements RippleTransactionValidator { String get name => "trust_set"; @override - String get fieldsName => "trust_set_fields"; + String get validatorName => "trust_set_fields"; @override - String get subject => "ripple_trust_set_desc"; + String get validatorDescription => "ripple_trust_set_desc"; @override void removeIndex(ValidatorField> field, int index) {} diff --git a/mrt_wallet/lib/provider/transaction_validator/solana/core/solana_transaction_type.dart b/mrt_wallet/lib/provider/transaction_validator/solana/core/solana_transaction_type.dart index da1fe46f..b90a7889 100644 --- a/mrt_wallet/lib/provider/transaction_validator/solana/core/solana_transaction_type.dart +++ b/mrt_wallet/lib/provider/transaction_validator/solana/core/solana_transaction_type.dart @@ -1 +1,8 @@ -enum SolanaTransactionType { native, spl } +enum SolanaTransactionType { + native, + spl, + createAssociatedTokenAccount, + createAccount, + initializeMint, + mintTo; +} diff --git a/mrt_wallet/lib/provider/transaction_validator/solana/solana.dart b/mrt_wallet/lib/provider/transaction_validator/solana/solana.dart index a74fc8cb..83a9ca85 100644 --- a/mrt_wallet/lib/provider/transaction_validator/solana/solana.dart +++ b/mrt_wallet/lib/provider/transaction_validator/solana/solana.dart @@ -1,3 +1,7 @@ export 'core/solana_transaction_type.dart'; export 'core/solana_transaction_validator.dart'; export 'transfer/transfer.dart'; +export 'transfer/create_associated_token_account_validator.dart'; +export 'transfer/create_account.dart'; +export 'transfer/initialize_mint.dart'; +export 'transfer/mint_to.dart'; diff --git a/mrt_wallet/lib/provider/transaction_validator/solana/transfer/create_account.dart b/mrt_wallet/lib/provider/transaction_validator/solana/transfer/create_account.dart new file mode 100644 index 00000000..e418175e --- /dev/null +++ b/mrt_wallet/lib/provider/transaction_validator/solana/transfer/create_account.dart @@ -0,0 +1,146 @@ +import 'package:blockchain_utils/numbers/big_rational.dart'; +import 'package:flutter/material.dart'; +import 'package:mrt_wallet/app/core.dart'; +import 'package:mrt_wallet/future/widgets/progress_bar/progress.dart'; +import 'package:mrt_wallet/models/wallet_models/address/address/crypto_address.dart'; +import 'package:mrt_wallet/models/wallet_models/address/network_address/solana/solana_address.dart'; +import 'package:mrt_wallet/models/wallet_models/currency_balance/currency_balance.dart'; +import 'package:mrt_wallet/provider/transaction_validator/core/live_validator.dart'; +import 'package:mrt_wallet/provider/transaction_validator/core/validator_fields.dart'; +import 'package:mrt_wallet/provider/transaction_validator/solana/core/solana_transaction_type.dart'; +import 'package:mrt_wallet/provider/transaction_validator/solana/core/solana_transaction_validator.dart'; +import 'package:on_chain/solana/src/address/sol_address.dart'; +import 'package:on_chain/solana/src/instructions/instructions.dart'; +import 'package:on_chain/solana/src/models/transaction/instruction.dart'; + +class SolanaCreateAccountValidator extends SolanaTransactionValidator { + bool _manuallyLamports = false; + final GlobalKey rentProgress = + GlobalKey( + debugLabel: "SolanaCreateAccountValidator_rentProgress"); + + final ValidatorField lamports = ValidatorField( + name: "lamports", + optional: false, + onChangeValidator: (p0) { + return p0; + }); + final ValidatorField> newAccountAddress = + ValidatorField( + name: "new_account_address", + optional: false, + onChangeValidator: (p0) { + return p0; + }); + final ValidatorField> ownerAddress = + ValidatorField( + name: "owner", + optional: false, + value: ReceiptAddress( + view: SystemProgramConst.programId.address, + type: null, + networkAddress: SPLTokenProgramConst.tokenProgramId), + onChangeValidator: (p0) { + return p0; + }); + final ValidatorField space = ValidatorField( + name: "account_size", + optional: false, + onChangeValidator: (p0) { + return p0; + }); + @override + OnChangeValidator? onChanged; + + @override + List get fields => + [newAccountAddress, ownerAddress, space, lamports]; + + final Cancelable _cancelable = Cancelable(); + + void changeAssetOutputAddress(ISolanaAddress? changeAddr) { + if (changeAddr == null || + changeAddr.address.toAddress == + newAccountAddress.value?.networkAddress.address) return; + + setValue( + newAccountAddress, + ReceiptAddress( + view: changeAddr.address.toAddress, + type: changeAddr.type, + networkAddress: changeAddr.networkAddress)); + } + + Future _getLamportsForRent() async { + if (_manuallyLamports) return; + _cancelable.cancel(); + rentProgress.process(); + final lamp = await MethodCaller.call(() async { + return await provider!.getRent(space.value!.toBigInt().toInt()); + }); + if (lamp.hasResult) { + setValue( + lamports, NoneDecimalBalance(lamp.result, SolanaConstants.decimal)); + } + rentProgress.idle(); + } + + @override + Future> instructions(SolAddress owner) async { + final account = SystemProgram.createAccount( + from: owner, + newAccountPubKey: newAccountAddress.value!.networkAddress, + layout: SystemCreateLayout( + lamports: lamports.value!.balance, + space: space.value!.toBigInt(), + programId: ownerAddress.value!.networkAddress)); + return [account]; + } + + @override + SolanaTransactionType get mode => SolanaTransactionType.createAccount; + + @override + String get name => "create_account"; + + @override + void setValue(ValidatorField? field, T? value) { + if (field == null) return; + if (field.setValue(value)) { + onChanged?.call(); + } + } + + void setSpace(BigRational? val) { + if (val == null) return; + if (val.toBigInt() == space.value?.toBigInt()) return; + setValue( + lamports, NoneDecimalBalance(BigInt.zero, SolanaConstants.decimal)); + setValue(space, val); + _getLamportsForRent(); + } + + void setLamports(BigInt? val) { + if (val == null) { + setValue(lamports, null); + _manuallyLamports = false; + return; + } + setValue(lamports, NoneDecimalBalance(val, SolanaConstants.decimal)); + _manuallyLamports = true; + } + + @override + BigInt get transferValue => lamports.value?.balance ?? BigInt.zero; + + @override + String? validateError({ISolanaAddress? account}) { + WalletLogging.print(lamports.hasValue); + for (final i in fields) { + if (!i.optional && !i.hasValue) { + return "field_is_req".tr.replaceOne(i.name.tr); + } + } + return null; + } +} diff --git a/mrt_wallet/lib/provider/transaction_validator/solana/transfer/create_associated_token_account_validator.dart b/mrt_wallet/lib/provider/transaction_validator/solana/transfer/create_associated_token_account_validator.dart new file mode 100644 index 00000000..5b6459a7 --- /dev/null +++ b/mrt_wallet/lib/provider/transaction_validator/solana/transfer/create_associated_token_account_validator.dart @@ -0,0 +1,106 @@ +import 'package:mrt_wallet/app/extention/extention.dart'; +import 'package:mrt_wallet/models/wallet_models/address/address/crypto_address.dart'; +import 'package:mrt_wallet/models/wallet_models/address/network_address/solana/solana_address.dart'; +import 'package:mrt_wallet/provider/transaction_validator/core/live_validator.dart'; +import 'package:mrt_wallet/provider/transaction_validator/core/validator_fields.dart'; +import 'package:mrt_wallet/provider/transaction_validator/solana/core/solana_transaction_type.dart'; +import 'package:mrt_wallet/provider/transaction_validator/solana/core/solana_transaction_validator.dart'; +import 'package:on_chain/solana/src/address/sol_address.dart'; +import 'package:on_chain/solana/src/instructions/instructions.dart'; +import 'package:on_chain/solana/src/models/transaction/instruction.dart'; + +class SolanaCreateAssociatedTokenAccountValidator + extends SolanaTransactionValidator { + SolAddress? _assosicatedAddress; + SolAddress? get assosicatedAddress => _assosicatedAddress; + + void _validate() { + final error = validateError(); + if (error != null) { + _assosicatedAddress = null; + } else { + _assosicatedAddress = + AssociatedTokenAccountProgramUtils.associatedTokenAccount( + mint: mintAddress.value!.networkAddress, + owner: ownerAddress.value!.networkAddress, + tokenProgramId: tokenProgram.value!.networkAddress) + .address; + } + onChanged?.call(); + } + + final ValidatorField> ownerAddress = + ValidatorField( + name: "owner", + optional: false, + onChangeValidator: (p0) { + return p0; + }); + final ValidatorField> mintAddress = ValidatorField( + name: "mint", + optional: false, + onChangeValidator: (p0) { + return p0; + }); + final ValidatorField> tokenProgram = + ValidatorField( + name: "token_program", + optional: false, + value: ReceiptAddress( + view: SPLTokenProgramConst.tokenProgramId.address, + type: null, + networkAddress: SPLTokenProgramConst.tokenProgramId), + onChangeValidator: (p0) { + return p0; + }); + + @override + OnChangeValidator? onChanged; + + @override + List get fields => [ownerAddress, mintAddress, tokenProgram]; + + @override + Future> instructions(SolAddress owner) async { + final create = AssociatedTokenAccountProgram.associatedTokenAccount( + payer: owner, + tokenProgramId: tokenProgram.value!.networkAddress, + associatedToken: + AssociatedTokenAccountProgramUtils.associatedTokenAccount( + mint: mintAddress.value!.networkAddress, + owner: ownerAddress.value!.networkAddress, + tokenProgramId: tokenProgram.value!.networkAddress) + .address, + owner: ownerAddress.value!.networkAddress, + mint: mintAddress.value!.networkAddress); + return [create]; + } + + @override + SolanaTransactionType get mode => + SolanaTransactionType.createAssociatedTokenAccount; + + @override + String get name => "create_associated_token_account"; + + @override + void setValue(ValidatorField? field, T? value) { + if (field == null) return; + if (field.setValue(value)) { + _validate(); + } + } + + @override + BigInt get transferValue => BigInt.zero; + + @override + String? validateError({ISolanaAddress? account}) { + for (final i in fields) { + if (!i.optional && !i.hasValue) { + return "field_is_req".tr.replaceOne(i.name.tr); + } + } + return null; + } +} diff --git a/mrt_wallet/lib/provider/transaction_validator/solana/transfer/initialize_mint.dart b/mrt_wallet/lib/provider/transaction_validator/solana/transfer/initialize_mint.dart new file mode 100644 index 00000000..4d5ca3db --- /dev/null +++ b/mrt_wallet/lib/provider/transaction_validator/solana/transfer/initialize_mint.dart @@ -0,0 +1,98 @@ +import 'package:blockchain_utils/numbers/big_rational.dart'; +import 'package:mrt_wallet/app/extention/extention.dart'; +import 'package:mrt_wallet/models/wallet_models/address/address/crypto_address.dart'; +import 'package:mrt_wallet/models/wallet_models/address/network_address/solana/solana_address.dart'; +import 'package:mrt_wallet/provider/transaction_validator/core/live_validator.dart'; +import 'package:mrt_wallet/provider/transaction_validator/core/validator_fields.dart'; +import 'package:mrt_wallet/provider/transaction_validator/solana/core/solana_transaction_type.dart'; +import 'package:mrt_wallet/provider/transaction_validator/solana/core/solana_transaction_validator.dart'; +import 'package:on_chain/solana/src/address/sol_address.dart'; +import 'package:on_chain/solana/src/instructions/instructions.dart'; +import 'package:on_chain/solana/src/models/transaction/instruction.dart'; + +class SolanaInitializeMintValidator extends SolanaTransactionValidator { + final ValidatorField> programId = ValidatorField( + name: "program_id", + value: ReceiptAddress( + view: SPLTokenProgramConst.token2022ProgramId.address, + type: null, + networkAddress: SPLTokenProgramConst.token2022ProgramId), + optional: false, + onChangeValidator: (p0) { + return p0; + }); + final ValidatorField> mint = ValidatorField( + name: "mint", + optional: false, + onChangeValidator: (p0) { + return p0; + }); + final ValidatorField> mintAuthority = + ValidatorField( + name: "mint_authority", + optional: false, + onChangeValidator: (p0) { + return p0; + }); + final ValidatorField decimals = ValidatorField( + name: "decimals", + optional: false, + onChangeValidator: (p0) { + if (p0 == null) return null; + if (p0.isNegative) return null; + + return p0; + }); + + final ValidatorField> freezAuthority = + ValidatorField( + name: "freeze_authority", + onChangeValidator: (p0) { + return p0; + }); + @override + OnChangeValidator? onChanged; + + @override + List get fields => + [mint, mintAuthority, decimals, freezAuthority]; + + @override + Future> instructions(SolAddress owner) async { + final instruction = SPLTokenProgram.initializeMint2( + layout: SPLTokenInitializeMint2Layout( + decimals: decimals.value!.toBigInt().toInt(), + mintAuthority: mintAuthority.value!.networkAddress, + freezeAuthority: freezAuthority.value?.networkAddress), + mint: mint.value!.networkAddress, + ); + return [instruction]; + } + + @override + SolanaTransactionType get mode => SolanaTransactionType.initializeMint; + + @override + String get name => "initialize_mint"; + + @override + void setValue(ValidatorField? field, T? value) { + if (field == null) return; + if (field.setValue(value)) { + onChanged?.call(); + } + } + + @override + BigInt get transferValue => BigInt.zero; + + @override + String? validateError({ISolanaAddress? account}) { + for (final i in fields) { + if (!i.optional && !i.hasValue) { + return "field_is_req".tr.replaceOne(i.name.tr); + } + } + return null; + } +} diff --git a/mrt_wallet/lib/provider/transaction_validator/solana/transfer/mint_to.dart b/mrt_wallet/lib/provider/transaction_validator/solana/transfer/mint_to.dart new file mode 100644 index 00000000..7c6243a7 --- /dev/null +++ b/mrt_wallet/lib/provider/transaction_validator/solana/transfer/mint_to.dart @@ -0,0 +1,188 @@ +import 'package:flutter/material.dart'; +import 'package:mrt_wallet/app/core.dart'; +import 'package:mrt_wallet/future/widgets/progress_bar/progress.dart'; +import 'package:mrt_wallet/models/wallet_models/wallet_models.dart'; +import 'package:mrt_wallet/provider/transaction_validator/core/live_validator.dart'; +import 'package:mrt_wallet/provider/transaction_validator/core/validator_fields.dart'; +import 'package:mrt_wallet/provider/transaction_validator/solana/solana.dart'; +import 'package:on_chain/solana/solana.dart'; + +class SolanaMintToValidator extends SolanaTransactionValidator { + Token _token = + Token(name: "unknown_token".tr, symbol: "unknown_token".tr, decimal: 0); + Token get token => _token; + void _updateToken() { + if (mint.hasValue) { + _token = + _token.copyWith(name: mint.value!.view, symbol: mint.value!.view); + } else { + _token = + _token.copyWith(name: "unknown_token".tr, symbol: "unknown_token".tr); + } + } + + final ValidatorField> mint = ValidatorField( + name: "mint", + optional: false, + onChangeValidator: (p0) { + return p0; + }); + final ValidatorField> destination = ValidatorField( + name: "destination", + optional: false, + onChangeValidator: (p0) { + return p0; + }); + final ValidatorField> authority = ValidatorField( + name: "authority", + optional: false, + onChangeValidator: (p0) { + return p0; + }); + final ValidatorField> programId = ValidatorField( + name: "program_id", + optional: false, + value: ReceiptAddress( + networkAddress: SPLTokenProgramConst.tokenProgramId, + view: SPLTokenProgramConst.tokenProgramId.address, + type: null), + onChangeValidator: (p0) { + return p0; + }); + + final ValidatorField amount = ValidatorField( + name: "amount", + optional: false, + onChangeValidator: (p0) { + return p0; + }); + @override + OnChangeValidator? onChanged; + + @override + List get fields => + [mint, destination, authority, programId, amount]; + + SolanaAccountInfo? _destinationAccount; + SolanaAccountInfo? get destinationAccount => _destinationAccount; + + final Cancelable _cancelable = Cancelable(); + final GlobalKey accountProgressKey = + GlobalKey( + debugLabel: "SolanaMintToValidator_progressKey"); + + String? _fetchingAccountError; + + String? get error => _fetchingAccountError; + bool get hasFetchingAccountError => _fetchingAccountError != null; + + void stopFetchingAccount() { + _cancelable.cancel(); + _fetchingAccountError = null; + _destinationAccount = null; + accountProgressKey.idle(); + } + + Future getDestinationAccountInfo() async { + stopFetchingAccount(); + if (!mint.hasValue || !destination.hasValue) { + return; + } + accountProgressKey.process(); + final result = await MethodCaller.call(() async { + final pda = AssociatedTokenAccountProgramUtils.associatedTokenAccount( + mint: mint.value!.networkAddress, + owner: destination.value!.networkAddress); + final info = await provider!.getAccountInfo(pda.address); + if (info == null) return info; + }, cancelable: _cancelable); + if (result.hasError) { + _fetchingAccountError = result.error!.tr; + } else { + _destinationAccount = result.result; + } + accountProgressKey.idle(); + onChanged?.call(); + } + + @override + Future> instructions(SolAddress owner) async { + final pda = AssociatedTokenAccountProgramUtils.associatedTokenAccount( + mint: mint.value!.networkAddress, + owner: destination.value!.networkAddress); + final mintTo = SPLTokenProgram.mintTo( + layout: SPLTokenMintToLayout(amount: amount.value!.balance), + mint: mint.value!.networkAddress, + destination: pda.address, + authority: authority.value!.networkAddress); + final List instructions = [ + if (_destinationAccount == null) + AssociatedTokenAccountProgram.associatedTokenAccount( + payer: owner, + associatedToken: pda.address, + owner: destination.value!.networkAddress, + mint: mint.value!.networkAddress, + tokenProgramId: programId.value!.networkAddress), + mintTo, + ]; + return instructions; + } + + @override + SolanaTransactionType get mode => SolanaTransactionType.mintTo; + + @override + String get name => "mint_to"; + + @override + void setValue(ValidatorField? field, T? value) { + if (field == null) return; + if (field.setValue(value)) { + _updateToken(); + onChanged?.call(); + } + } + + void setDestination(ReceiptAddress? destinationAccount) { + if (destinationAccount == null) { + stopFetchingAccount(); + setValue(destination, destinationAccount); + return; + } + if (destinationAccount.networkAddress.address == + destination.value?.networkAddress.address) { + return; + } + setValue(destination, destinationAccount); + getDestinationAccountInfo(); + } + + void setMintAccount(ReceiptAddress? mintAcc) { + if (mintAcc == null) { + stopFetchingAccount(); + setValue(mint, mintAcc); + return; + } + if (mintAcc.networkAddress.address == mint.value?.networkAddress.address) { + return; + } + setValue(mint, mintAcc); + getDestinationAccountInfo(); + } + + @override + BigInt get transferValue => BigInt.zero; + + @override + String? validateError({ISolanaAddress? account}) { + if (hasFetchingAccountError) { + return _fetchingAccountError; + } + for (final i in fields) { + if (!i.optional && !i.hasValue) { + return "field_is_req".tr.replaceOne(i.name.tr); + } + } + return null; + } +} diff --git a/mrt_wallet/lib/provider/transaction_validator/solana/transfer/transfer.dart b/mrt_wallet/lib/provider/transaction_validator/solana/transfer/transfer.dart index 923c9c6e..1e04dab5 100644 --- a/mrt_wallet/lib/provider/transaction_validator/solana/transfer/transfer.dart +++ b/mrt_wallet/lib/provider/transaction_validator/solana/transfer/transfer.dart @@ -27,18 +27,14 @@ class SolanaTransferValidator extends SolanaTransactionValidator { amount.value!.balance < SolanaConstants.systemProgramRent.balance); final ValidatorField> destination = ValidatorField( - id: "receiver", name: "destination", optional: false, onChangeValidator: (p0) { return p0; - }, - subject: ""); + }); final ValidatorField amount = ValidatorField( name: "amount", - subject: "", optional: false, - id: "", onChangeValidator: (v) { try { if (v!.isZero || v.isNegative) return null; @@ -57,22 +53,7 @@ class SolanaTransferValidator extends SolanaTransactionValidator { List get fields => [destination, amount]; @override - String get fieldsName => throw UnimplementedError(); - - @override - String get helperUri => throw UnimplementedError(); - - @override - bool get isValid => throw UnimplementedError(); - - @override - String get name => throw UnimplementedError(); - - @override - void removeIndex(ValidatorField> field, int index) {} - - @override - void setListValue(ValidatorField> field, T? value) {} + String get name => "transfer_symbol".tr.replaceOne(token.symbol); @override void setValue(ValidatorField? field, T? value) { @@ -110,9 +91,6 @@ class SolanaTransferValidator extends SolanaTransactionValidator { onChanged?.call(); } - @override - String get subject => throw UnimplementedError(); - @override BigInt get transferValue => amount.value?.balance ?? BigInt.zero; diff --git a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/account/account_update_contract_permission_validator.dart b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/account/account_update_contract_permission_validator.dart index 1f47bc74..d257d373 100644 --- a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/account/account_update_contract_permission_validator.dart +++ b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/account/account_update_contract_permission_validator.dart @@ -223,24 +223,9 @@ class TronAccountUpdatePermissionValidator extends TronTransactionValidator { @override List get fields => []; - @override - String get fieldsName => throw UnimplementedError(); - - @override - String get helperUri => throw UnimplementedError(); - - @override - bool get isValid => validateError() == null; - @override late final String name = "update_account_permission"; - @override - void removeIndex(ValidatorField> field, int index) {} - - @override - void setListValue(ValidatorField> field, T? value) {} - @override void setValue(ValidatorField? field, T? value) { if (field == null) return; @@ -251,14 +236,11 @@ class TronAccountUpdatePermissionValidator extends TronTransactionValidator { } void _checkEstimate() { - if (isValid) { + if (validateError() == null) { onStimateChanged?.call(); } } - @override - String get subject => throw UnimplementedError(); - @override String? validateError({ITronAddress? account}) { if (_selectedPermission != null) { diff --git a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/account/update_account.dart b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/account/update_account.dart index 5e5c54be..95e75a46 100644 --- a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/account/update_account.dart +++ b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/account/update_account.dart @@ -16,9 +16,7 @@ class TronUpdateAccountValidator extends TronTransactionValidator { late final ValidatorField accountName = ValidatorField( name: "account_name", - subject: "", optional: false, - id: "", onChangeValidator: (v) { try { return v; @@ -34,24 +32,9 @@ class TronUpdateAccountValidator extends TronTransactionValidator { @override List get fields => [accountName]; - @override - String get fieldsName => throw UnimplementedError(); - - @override - String get helperUri => throw UnimplementedError(); - - @override - bool get isValid => validateError() == null; - @override late final String name = "update_account"; - @override - void removeIndex(ValidatorField> field, int index) {} - - @override - void setListValue(ValidatorField> field, T? value) {} - @override void setValue(ValidatorField? field, T? value) { if (field == null) return; @@ -62,14 +45,11 @@ class TronUpdateAccountValidator extends TronTransactionValidator { } void _checkEstimate() { - if (isValid) { + if (validateError() == null) { onStimateChanged?.call(); } } - @override - String get subject => throw UnimplementedError(); - @override String? validateError({ITronAddress? account}) { for (final i in fields) { diff --git a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/delegated_resource.dart b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/delegated_resource.dart index 831126a0..59bc101b 100644 --- a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/delegated_resource.dart +++ b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/delegated_resource.dart @@ -18,9 +18,7 @@ class TronDelegatedResourceV2Validator extends TronTransactionValidator { final ValidatorField amount = ValidatorField( name: "delegatable_amount", - subject: "", optional: false, - id: "", onChangeValidator: (v) { try { if (v!.isZero || v.isNegative) return null; @@ -32,18 +30,14 @@ class TronDelegatedResourceV2Validator extends TronTransactionValidator { ); final ValidatorField> destination = ValidatorField( - id: "", name: "receiver_address", optional: false, onChangeValidator: (p0) { return p0; - }, - subject: ""); + }); late final ValidatorField resource = ValidatorField( name: "resource", - subject: "", optional: false, - id: "", onChangeValidator: (v) { try { if (v == ResourceCode.tronPower) return null; @@ -55,17 +49,13 @@ class TronDelegatedResourceV2Validator extends TronTransactionValidator { ); final ValidatorField lock = ValidatorField( name: "lock", - subject: "", optional: true, - id: "", onChangeValidator: (v) { return v; }, ); final ValidatorField lockPeriod = ValidatorField( name: "lock_period", - subject: "", - id: "", onChangeValidator: (v) { try { if (v!.isNegative || v.isZero || v.isDecimal) return null; @@ -90,24 +80,9 @@ class TronDelegatedResourceV2Validator extends TronTransactionValidator { @override List get fields => [amount, destination, resource]; - @override - String get fieldsName => throw UnimplementedError(); - - @override - String get helperUri => throw UnimplementedError(); - - @override - bool get isValid => validateError() == null; - @override late final String name = "delegated_resource"; - @override - void removeIndex(ValidatorField> field, int index) {} - - @override - void setListValue(ValidatorField> field, T? value) {} - void setLockPerid(bool? value) { if (lock.setValue(value ?? false)) { lockPeriod.setValue(TronUtils.defaultDelegateLockPeriod); @@ -126,14 +101,11 @@ class TronDelegatedResourceV2Validator extends TronTransactionValidator { } void _checkEstimate() { - if (isValid) { + if (validateError() == null) { onStimateChanged?.call(); } } - @override - String get subject => throw UnimplementedError(); - @override String? validateError({ITronAddress? account}) { for (final i in fields) { diff --git a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/freez_balance_v2.dart b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/freez_balance_v2.dart index 16d9cabc..94aeeec1 100644 --- a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/freez_balance_v2.dart +++ b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/freez_balance_v2.dart @@ -16,9 +16,7 @@ class TronFreezBalanceV2Validator extends TronTransactionValidator { late final ValidatorField amount = ValidatorField( name: "frozen_balance", - subject: "trx_stake_amount", optional: false, - id: "frozen_balance", onChangeValidator: (v) { try { if (v!.isZero || v.isNegative) return null; @@ -30,9 +28,7 @@ class TronFreezBalanceV2Validator extends TronTransactionValidator { ); late final ValidatorField resource = ValidatorField( name: "resource", - subject: "", optional: false, - id: "", onChangeValidator: (v) { try { if (v == ResourceCode.tronPower) return null; @@ -49,24 +45,9 @@ class TronFreezBalanceV2Validator extends TronTransactionValidator { @override List get fields => [amount, resource]; - @override - String get fieldsName => throw UnimplementedError(); - - @override - String get helperUri => throw UnimplementedError(); - - @override - bool get isValid => validateError() == null; - @override late final String name = "tron_stack_v2"; - @override - void removeIndex(ValidatorField> field, int index) {} - - @override - void setListValue(ValidatorField> field, T? value) {} - @override void setValue(ValidatorField? field, T? value) { if (field == null) return; @@ -77,14 +58,11 @@ class TronFreezBalanceV2Validator extends TronTransactionValidator { } void _checkEstimate() { - if (isValid) { + if (validateError() == null) { onStimateChanged?.call(); } } - @override - String get subject => throw UnimplementedError(); - @override String? validateError({ITronAddress? account}) { for (final i in fields) { diff --git a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/undelegated_resource.dart b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/undelegated_resource.dart index 13025d36..2ceee607 100644 --- a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/undelegated_resource.dart +++ b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/undelegated_resource.dart @@ -18,9 +18,7 @@ class TronUnDelegatedResourceV2Validator extends TronTransactionValidator { final ValidatorField balance = ValidatorField( name: "balance", - subject: "", optional: false, - id: "", onChangeValidator: (v) { try { if (v!.isZero || v.isNegative) return null; @@ -33,13 +31,11 @@ class TronUnDelegatedResourceV2Validator extends TronTransactionValidator { ); final ValidatorField> destination = ValidatorField( - id: "", name: "resource_receiver_address", optional: false, onChangeValidator: (p0) { return p0; - }, - subject: ""); + }); void onChangeResource(ReceiptAddress? resource) { if (resource == null) return; @@ -108,24 +104,9 @@ class TronUnDelegatedResourceV2Validator extends TronTransactionValidator { @override List get fields => [balance, destination]; - @override - String get fieldsName => throw UnimplementedError(); - - @override - String get helperUri => throw UnimplementedError(); - - @override - bool get isValid => validateError() == null; - @override late final String name = "undelegated_resource"; - @override - void removeIndex(ValidatorField> field, int index) {} - - @override - void setListValue(ValidatorField> field, T? value) {} - @override void setValue(ValidatorField? field, T? value) { if (field == null) return; @@ -136,14 +117,11 @@ class TronUnDelegatedResourceV2Validator extends TronTransactionValidator { } void _checkEstimate() { - if (isValid) { + if (validateError() == null) { onStimateChanged?.call(); } } - @override - String get subject => throw UnimplementedError(); - @override String? validateError({ITronAddress? account}) { if (_selectedResource == null) { diff --git a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/unfreez_balance_v2.dart b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/unfreez_balance_v2.dart index 24256f64..c6699802 100644 --- a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/unfreez_balance_v2.dart +++ b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/resource_v2/unfreez_balance_v2.dart @@ -19,9 +19,7 @@ class TronUnFreezBalanceV2Validator extends TronTransactionValidator { late final ValidatorField amount = ValidatorField( name: "unfreeze_balance", - subject: "trx_unstake_amount", optional: false, - id: "unfreeze_balance", onChangeValidator: (v) { try { if (v!.isZero || v.isNegative) return null; @@ -34,9 +32,7 @@ class TronUnFreezBalanceV2Validator extends TronTransactionValidator { late final ValidatorField resource = ValidatorField( name: "resource", - subject: "trx_stake_type", optional: false, - id: "resource", onChangeValidator: (v) { try { if (v == ResourceCode.tronPower) return null; @@ -53,24 +49,9 @@ class TronUnFreezBalanceV2Validator extends TronTransactionValidator { @override List get fields => [resource, amount]; - @override - String get fieldsName => throw UnimplementedError(); - - @override - String get helperUri => throw UnimplementedError(); - - @override - bool get isValid => validateError() == null; - @override late final String name = "tron_unstack_v2"; - @override - void removeIndex(ValidatorField> field, int index) {} - - @override - void setListValue(ValidatorField> field, T? value) {} - final NoneDecimalBalance stackedBalance = NoneDecimalBalance.zero(TronUtils.decimal); @@ -95,14 +76,11 @@ class TronUnFreezBalanceV2Validator extends TronTransactionValidator { } void _checkEstimate() { - if (isValid) { + if (validateError() == null) { onStimateChanged?.call(); } } - @override - String get subject => throw UnimplementedError(); - @override String? validateError({ITronAddress? account}) { for (final i in fields) { diff --git a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/transfer/transfer.dart b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/transfer/transfer.dart index e3847d22..78288454 100644 --- a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/transfer/transfer.dart +++ b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/transfer/transfer.dart @@ -34,18 +34,15 @@ class TronTransferValidator extends TronTransactionValidator { final ValidatorField> destination = ValidatorField( - id: "receiver", - name: "destination", - optional: false, - onChangeValidator: (p0) { - return p0; - }, - subject: ""); + name: "destination", + optional: false, + onChangeValidator: (p0) { + return p0; + }, + ); late final ValidatorField amount = ValidatorField( name: "amount", - subject: "", optional: false, - id: "", onChangeValidator: (v) { try { if (v!.isZero || v.isNegative) return null; @@ -62,15 +59,6 @@ class TronTransferValidator extends TronTransactionValidator { @override List get fields => [destination, amount]; - @override - String get fieldsName => throw UnimplementedError(); - - @override - String get helperUri => throw UnimplementedError(); - - @override - bool get isValid => validateError() == null; - @override late final String name = _trc10Token != null ? "transfer_trc10" @@ -78,12 +66,6 @@ class TronTransferValidator extends TronTransactionValidator { ? "transfer_trc20" : "transfer"; - @override - void removeIndex(ValidatorField> field, int index) {} - - @override - void setListValue(ValidatorField> field, T? value) {} - @override void setValue(ValidatorField? field, T? value) { if (field == null) return; @@ -94,14 +76,11 @@ class TronTransferValidator extends TronTransactionValidator { } void _checkEstimate() { - if (isValid) { + if (validateError() == null) { onStimateChanged?.call(); } } - @override - String get subject => throw UnimplementedError(); - @override String? validateError({ITronAddress? account}) { for (final i in fields) { diff --git a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/vote_sr/create_witness.dart b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/vote_sr/create_witness.dart index adb12899..1686d851 100644 --- a/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/vote_sr/create_witness.dart +++ b/mrt_wallet/lib/provider/transaction_validator/tron/transaction_validator/vote_sr/create_witness.dart @@ -16,9 +16,7 @@ class TronCreateWitnessValidator extends TronTransactionValidator { late final ValidatorField url = ValidatorField( name: "url", - subject: "", optional: false, - id: "", onChangeValidator: (v) { try { return v; @@ -34,24 +32,9 @@ class TronCreateWitnessValidator extends TronTransactionValidator { @override List get fields => [url]; - @override - String get fieldsName => throw UnimplementedError(); - - @override - String get helperUri => throw UnimplementedError(); - - @override - bool get isValid => validateError() == null; - @override late final String name = "create_witness"; - @override - void removeIndex(ValidatorField> field, int index) {} - - @override - void setListValue(ValidatorField> field, T? value) {} - @override void setValue(ValidatorField? field, T? value) { if (field == null) return; @@ -62,14 +45,11 @@ class TronCreateWitnessValidator extends TronTransactionValidator { } void _checkEstimate() { - if (isValid) { + if (validateError() == null) { onStimateChanged?.call(); } } - @override - String get subject => throw UnimplementedError(); - @override String? validateError({ITronAddress? account}) { for (final i in fields) { diff --git a/mrt_wallet/lib/provider/wallet/core/core.dart b/mrt_wallet/lib/provider/wallet/core/core.dart index 33e79883..542e29f9 100644 --- a/mrt_wallet/lib/provider/wallet/core/core.dart +++ b/mrt_wallet/lib/provider/wallet/core/core.dart @@ -144,6 +144,22 @@ abstract class WalletCore extends _WalletCore with WalletStatusImpl { } } + Future> updateToken({ + required TokenCore token, + required Token updatedToken, + required CryptoAccountAddress address, + }) async { + try { + final result = await _callSynchronized( + () async => await _updateToken( + token: token, address: address, updatedToken: updatedToken), + conditionStatus: WalletStatus.unlock); + return result; + } finally { + notify(); + } + } + Future> addNewNFT( NFTCore nft, CryptoAccountAddress address) async { try { diff --git a/mrt_wallet/lib/provider/wallet/network/network_imp.dart b/mrt_wallet/lib/provider/wallet/network/network_imp.dart index 50f253de..ff9f2e14 100644 --- a/mrt_wallet/lib/provider/wallet/network/network_imp.dart +++ b/mrt_wallet/lib/provider/wallet/network/network_imp.dart @@ -75,6 +75,20 @@ mixin WalletNetworkImpl on WalletCryptoImpl, WalletStorageImpl, MasterKeyImpl { await _saveAccount(acc); } + Future _updateToken({ + required TokenCore token, + required Token updatedToken, + required CryptoAccountAddress address, + }) async { + final acc = chain; + final currentAccount = acc.account; + if (!currentAccount.addresses.contains(address)) { + throw WalletExceptionConst.accountDoesNotFound; + } + address.updateToken(token, updatedToken); + await _saveAccount(acc); + } + Future _addNewNFT(NFTCore nft, CryptoAccountAddress address) async { final acc = chain; final currentAccount = acc.account; diff --git a/mrt_wallet/lib/provider/wallet/signer/signer_impl.dart b/mrt_wallet/lib/provider/wallet/signer/signer_impl.dart index aea141fc..eb6bd5d1 100644 --- a/mrt_wallet/lib/provider/wallet/signer/signer_impl.dart +++ b/mrt_wallet/lib/provider/wallet/signer/signer_impl.dart @@ -127,12 +127,17 @@ mixin Signer on MasterKeyImpl { SolanaTransaction _signSolanaTransaction( {required SolanaSigningRequest request, required List password}) { - final bipKey = _getPrivateKey(password, request.signers.first); - final solanaPrivateKey = SolanaPrivateKey.fromSeed(bipKey.privateKey.raw); - final signature = - solanaPrivateKey.sign(request.solanaTransaction.serializeMessage()); - request.solanaTransaction - .addSignature(request.addresses.first.networkAddress, signature); + WalletLogging.print("signers len ${request.signers.length}"); + for (int i = 0; i < request.signers.length; i++) { + final signier = request.signers.elementAt(i); + final addr = request.addresses.elementAt(i).networkAddress; + final bipKey = _getPrivateKey(password, signier); + final solanaPrivateKey = SolanaPrivateKey.fromSeed(bipKey.privateKey.raw); + final signature = + solanaPrivateKey.sign(request.solanaTransaction.serializeMessage()); + request.solanaTransaction.addSignature(addr, signature); + } + return request.solanaTransaction; } diff --git a/mrt_wallet/pubspec.lock b/mrt_wallet/pubspec.lock index 6bc7f6a5..59a03855 100644 --- a/mrt_wallet/pubspec.lock +++ b/mrt_wallet/pubspec.lock @@ -101,10 +101,10 @@ packages: dependency: "direct main" description: name: cosmos_sdk - sha256: c847e96abd5b5d279540c3864ce653894c53961064f2fc2eeb51359d4c3dceaa + sha256: d0edde91fbc5c2771bd4b3f95122e81583385b659b96d7bf757ac59670357a86 url: "https://pub.dev" source: hosted - version: "0.0.4" + version: "0.0.5" crypto: dependency: transitive description: diff --git a/mrt_wallet/pubspec.yaml b/mrt_wallet/pubspec.yaml index e56c4cd7..206ab2ac 100644 --- a/mrt_wallet/pubspec.yaml +++ b/mrt_wallet/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 5.0.0+6 +version: 5.1.0+7 homepage: "https://github.com/mrtnetwork/mrtwallet" repository: "https://github.com/mrtnetwork/mrtwallet" @@ -49,7 +49,7 @@ dependencies: bitcoin_base: ^4.2.1 xrpl_dart: ^4.1.2 on_chain: ^3.1.0 - cosmos_sdk: ^0.0.4 + cosmos_sdk: ^0.0.5 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2