diff --git a/.DS_Store b/.DS_Store
index a2a4a785..dcca6016 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f12c0fce..cae59d2e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,45 +1 @@
# MRT Wallet Changelog
-
-## Version 4.0.0
-
-### Bitcoin (mainnet, testnet):
-- **Features:** Comprehensive support for Bitcoin transactions.
-- **Highlights:**
- - Robust support for P2TR, P2WPKH, P2WSH, P2SH, P2PKH, and multisignature functionalities.
- - Enhanced control over transactions, allowing you to effortlessly create, sign, and send transactions from multiple UTXOs and addresses.
-
-### Bitcoin Cash (mainnet, testnet):
-- **Features:** Comprehensive support for Bitcoin Cash transactions.
-- **Highlights:**
- - P2SH, P2SH32, P2PKH and token-aware addresses.
- - Enhanced control over transactions, supporting the creation, signing, minting and sending of Cash tokens.
-
-### Dogecoin:
-- **Features:** Seamless transaction creation and management on the Dogecoin network.
-- **Highlights:** Extends capabilities to the playful realm of Dogecoin, ensuring a smooth and secure user experience.
-
-### Dash:
-- **Features:** Exploration of the fast and efficient world of Dash.
-- **Highlights:** Easy creation, signing, and sending of transactions with support for various Dash network functionalities.
-
-### Bitcoin SV:
-- **Features:** Effortless navigation of Bitcoin SV transactions.
-- **Highlights:**
- - User-friendly interface for smooth and secure transaction creation and management.
- - Support for handling P2PKH addresses, simplifying the Bitcoin SV experience.
-
-### Litecoin:
-- **Features:** Support for Litecoin transactions.
-- **Highlights:** Dive into the silver to Bitcoin's gold with MRT Wallet, managing Litecoin transactions effortlessly with confidence.
-
-### Ripple:
-- **Features:** Unlocking the potential of the Ripple network.
-- **Highlights:** Comprehensive support for advanced cryptographic algorithms, NFTs, tokens, multisignature transactions, account settings, trust settings, escrow transactions, regular key settings, and more.
-
-### Ethereum:
-- **Features:** Support for Ethereum transactions.
-- **Highlights:** Compatibility with both legacy and EIP-1559 transactions. Import and manage ERC-20 assets effortlessly, and execute ERC-20 token transfers with ease.
-
-### Tron:
-- **Features:** Seamless interaction with the Tron blockchain.
-- **Highlights:** Confidence in sending TRX, TRC-20, and TRC-10 tokens. Support for native contracts, including multi-signature transactions. Control over updating account permissions, managing accounts, unstaking (v2), delegating resources, and creating/updating witnesses.
\ No newline at end of file
diff --git a/README.md b/README.md
index ea6f5101..6f6227a6 100644
--- a/README.md
+++ b/README.md
@@ -1,52 +1,93 @@
# About MRT Wallet
-Welcome to MRT Wallet, the open-source wallet designed for the decentralized future of finance. Our mission is to empower users with a secure and versatile solution that supports both Bitcoin mainnet and testnet, as well as networks such as
-Ethereum, Tron, Ripple, Dogecoin, Litecoin, and Dash, with a roadmap set to embrace a broad spectrum of cryptocurrencies.
+Welcome to MRT Wallet, the open-source wallet designed for the decentralized future of finance. Our mission is to empower users with a secure and versatile solution that supports both Bitcoin mainnet and testnet, as well as networks such as
+Ethereum, Tron, Ripple, Dogecoin, Litecoin, Solana, Cardano, Cosmos and Dash, with a roadmap set to embrace a broad spectrum of cryptocurrencies.
## Networks
-### Bitcoin (mainnet, testnet):
+### Bitcoin (mainnet, testnet)
+
- **Features:** Comprehensive support for Bitcoin transactions.
- **Highlights:**
- Robust support for P2TR, P2WPKH, P2WSH, P2SH, P2PKH, and multisignature functionalities.
- Enhanced control over transactions, allowing you to effortlessly create, sign, and send transactions from multiple UTXOs and addresses.
+ - Allows for multiple account transactions.
+
+### Bitcoin Cash (mainnet, testnet)
-### Bitcoin Cash (mainnet, testnet):
- **Features:** Comprehensive support for Bitcoin Cash transactions.
- **Highlights:**
- P2SH, P2SH32, P2PKH and token-aware addresses.
- Enhanced control over transactions, supporting the creation, signing, minting and sending of Cash tokens.
+ - Allows for multiple account transactions.
+
+### Dogecoin
-### Dogecoin:
- **Features:** Seamless transaction creation and management on the Dogecoin network.
- **Highlights:** Extends capabilities to the playful realm of Dogecoin, ensuring a smooth and secure user experience.
+- Allows for multiple account transactions.
+
+### Dash
-### Dash:
- **Features:** Exploration of the fast and efficient world of Dash.
- **Highlights:** Easy creation, signing, and sending of transactions with support for various Dash network functionalities.
+- Allows for multiple account transactions.
+
+### Bitcoin SV
-### Bitcoin SV:
- **Features:** Effortless navigation of Bitcoin SV transactions.
- **Highlights:**
- User-friendly interface for smooth and secure transaction creation and management.
- Support for handling P2PKH addresses, simplifying the Bitcoin SV experience.
+ - Allows for multiple account transactions.
+
+### Litecoin
-### Litecoin:
- **Features:** Support for Litecoin transactions.
- **Highlights:** Dive into the silver to Bitcoin's gold with MRT Wallet, managing Litecoin transactions effortlessly with confidence.
+- Allows for multiple account transactions.
+
+### Ripple
-### Ripple:
- **Features:** Unlocking the potential of the Ripple network.
- **Highlights:** Comprehensive support for advanced cryptographic algorithms, NFTs, tokens, multisignature transactions, account settings, trust settings, escrow transactions, regular key settings, and more.
-### Ethereum:
+### Solana (Mainnet, Testnet)
+
+- **Features:** Seamless support for Solana transactions.
+- **Highlights:**
+ - SPLToken transfer, account creation and token minting.
+
+### Cardano (Mainnet, Preproad)
+
+- **Features:** Streamlined support for Cardano transactions.
+- **Highlights:**
+ - Full compatibility with Shelley and Byron addresses and transactions.
+ - Facilitates minting and transfer of assets.
+ - Integration for stake certificates.
+ - Allows for multiple account transactions.
+
+### Ethereum
+
- **Features:** Support for Ethereum transactions.
- **Highlights:** Compatibility with both legacy and EIP-1559 transactions. Import and manage ERC-20 assets effortlessly, and execute ERC-20 token transfers with ease.
-### Tron:
+### Tron
+
- **Features:** Seamless interaction with the Tron blockchain.
- **Highlights:** Confidence in sending TRX, TRC-20, and TRC-10 tokens. Support for native contracts, including multi-signature transactions. Control over updating account permissions, managing accounts, unstaking (v2), delegating resources, and creating/updating witnesses.
+### Cosmos (Mainnet)
+
+- **Features:** Seamless support for Cosmos transactions.
+
+### Thor (Mainnet)
+
+- **Features:** Seamless support for Thor transactions.
+
+### Maya (Mainnet)
+
+- **Features:** Seamless support for Maya transactions.
## Decentralized, Secure, and Open Source
@@ -54,7 +95,6 @@ At MRT Wallet, we believe in the power of decentralization. Our commitment to de
We take pride in being fully open source. You can explore and audit our code on [GitHub](https://github.com/mrtnetwork/mrtwallet) under the Apache License 2.0. This commitment to transparency means that every line of code is accessible, empowering the community to verify the security and integrity of our wallet.
-
## Platform Support
MRT Wallet is available on multiple platforms to provide a seamless experience:
@@ -63,6 +103,8 @@ MRT Wallet is available on multiple platforms to provide a seamless experience:
- **Windows:** Enjoy the convenience of MRT Wallet on your desktop. Our Windows version brings the power of decentralized finance to your fingertips.
+- **Macos:** Enjoy the convenience of MRT Wallet on your desktop. Our Mac version brings the power of decentralized finance to your fingertips.
+
- **Web:** Access your wallet from any web browser with our web platform. Manage your assets with ease, all while enjoying the security and privacy MRT Wallet provides.
## Roadmap: Embracing a Diverse Crypto Landscape
@@ -75,59 +117,66 @@ MRT Wallet is not just a wallet; it's a community-driven project. We welcome col
## Build Instructions
-
Clone the repository and build using Flutter:
-**WEB**
+- **WEB**
- you can view the web version of MRT Wallet at https://mrtnetwork.github.io/mrtwallet/.
+ you can view the web version of MRT Wallet at .
-```
+```shell
gh repo clone mrtnetwork/mrtwallet
cd mrt_wallet
flutter pub get
flutter build web --release
```
-**Android**
-```
+- **Android**
+
+```shell
gh repo clone mrtnetwork/mrtwallet
cd mrt_wallet
flutter pub get
-flutter build apk
+flutter build apk
```
-**Windows**
-```
+- **Windows**
+
+```shell
gh repo clone mrtnetwork/mrtwallet
cd mrt_wallet
flutter pub get
-flutter build windows
+flutter build windows --release
```
+- **Macos**
-## Contributing
+```shell
+gh repo clone mrtnetwork/mrtwallet
+cd mrt_wallet
+flutter pub get
+flutter build macos --release
+```
+## Contributing
Contributions are welcome! Please follow these guidelines:
- - Fork the repository and create a new branch.
- - Make your changes and ensure tests pass.
- - Submit a pull request with a detailed description of your changes.
-## Feature requests and bugs
+- Fork the repository and create a new branch.
+- Make your changes and ensure tests pass.
+- Submit a pull request with a detailed description of your changes.
+## Feature requests and bugs
Please file feature requests and bugs in the issue tracker.
## Get Involved
-
Join us on our mission to redefine the landscape of decentralized finance. Contribute to our open-source project on [GitHub](https://github.com/mrtnetwork/mrtwallet) or connect with our community on [Telegram](https://t.me/blockchain_web3_solidity).
Thank you for choosing MRT Wallet as your trusted partner in the world of decentralized finance.
-
## Support
+
1KMRGUzRFCuR9y73gUnjxfC1Dte8Ua3vcp
bc1q92fvc5jm4k8e5wegzmhzdv72gwe43sgfnuspgzfmj7llkd8xhmusgd44qf
diff --git a/mrt_wallet/lib/app/constant/page_path.dart b/mrt_wallet/lib/app/constant/page_path.dart
index 3243d05b..331d4bdb 100644
--- a/mrt_wallet/lib/app/constant/page_path.dart
+++ b/mrt_wallet/lib/app/constant/page_path.dart
@@ -27,13 +27,10 @@ class PagePathConst {
static const String cardanoTransaction = "/cardano/transaction";
static const String cosmosTransaction = "/cosmos/transaction";
- static const String setupRippleAddress = "/ripple/setup_address";
+ // static const String setupRippleAddress = "/ripple/setup_address";
static const String setupBitcoinAddress = "/bitcoin/setup_address";
- static const String setupEthAddress = "/ethereum/setup_address";
- static const String setupTronAddress = "/tron/setup_address";
- static const String setupSolanaAddress = "/solana/setup_address";
+ static const String setupGenericAddress = "/networks/setup_address";
static const String setupCardanoAddress = "/cardano/setup_address";
- static const String setupCosmosAddress = "/cosmos/setup_address";
static const String setupBitcoinMultsig = "/bitcoin/setup_multisig_address";
@@ -78,17 +75,12 @@ class PagePathConst {
static String setupAddressPage(AppNetworkImpl network) {
if (network is AppBitcoinNetwork) return setupBitcoinAddress;
- if (network is APPEVMNetwork) return setupEthAddress;
- if (network is APPTVMNetwork) return setupTronAddress;
- if (network is APPSolanaNetwork) return setupSolanaAddress;
if (network is APPCardanoNetwork) return setupCardanoAddress;
- if (network is APPCosmosNetwork) return setupCosmosAddress;
- return setupRippleAddress;
+ return setupGenericAddress;
}
static const String importERC20Token = "ethereum/import_token";
static const String importTRC20Token = "tron/import_token";
static const String importTrc10Token = "tron/import_trc10_token";
-
static const String importSPLTokens = "solana/import_spl_tokens";
}
diff --git a/mrt_wallet/lib/app/error/exception/wallet_ex.dart b/mrt_wallet/lib/app/error/exception/wallet_ex.dart
index 5eebefc4..aec5cf47 100644
--- a/mrt_wallet/lib/app/error/exception/wallet_ex.dart
+++ b/mrt_wallet/lib/app/error/exception/wallet_ex.dart
@@ -66,6 +66,8 @@ class WalletExceptionConst {
WalletException("invalid_balance");
static final WalletException unsuportedFeature =
WalletException("unsuported_feature");
+ static final WalletException featureUnavailableForMultiSignature =
+ WalletException("feature__unavailable_for_multi_signature");
static final WalletException condition = WalletException("message");
static final WalletException emptyThrow = WalletException("");
diff --git a/mrt_wallet/lib/app/extention/context.dart b/mrt_wallet/lib/app/extention/context.dart
index a476b937..94f4a03e 100644
--- a/mrt_wallet/lib/app/extention/context.dart
+++ b/mrt_wallet/lib/app/extention/context.dart
@@ -68,6 +68,7 @@ extension QuickContextAccsess on BuildContext {
BodyBuilder? bodyBuilder,
List appbarActions = const [],
bool centerContent = true}) async {
+ if (!mounted) return null;
return await showModalBottomSheet(
context: this,
constraints: const BoxConstraints(maxWidth: 900),
@@ -93,6 +94,7 @@ extension QuickContextAccsess on BuildContext {
return await showAdaptiveDialog(
context: this,
useRootNavigator: true,
+ barrierDismissible: true,
builder: (context) {
return DialogView(
title: label,
@@ -103,17 +105,22 @@ extension QuickContextAccsess on BuildContext {
);
}
- Future openDialogPage(WidgetContext child, String label,
- {List Function(BuildContext)? content}) async {
+ Future openDialogPage(
+ String label, {
+ WidgetContext? child,
+ List Function(BuildContext)? content,
+ Widget? fullWidget,
+ }) async {
return await showAdaptiveDialog(
context: this,
useRootNavigator: true,
+ barrierDismissible: true,
builder: (context) {
- return DialogView(
- title: label,
- content: content?.call(context) ?? const [],
- child: child(context),
- );
+ return fullWidget ??
+ DialogView(
+ title: label,
+ content: content?.call(context) ?? const [],
+ child: child?.call(context) ?? WidgetConstant.sizedBox);
},
);
}
diff --git a/mrt_wallet/lib/app/extention/string.dart b/mrt_wallet/lib/app/extention/string.dart
index b06601dc..c6e225b2 100644
--- a/mrt_wallet/lib/app/extention/string.dart
+++ b/mrt_wallet/lib/app/extention/string.dart
@@ -25,6 +25,7 @@ extension Translate on String {
}
String get orEmpty => trim().isEmpty ? "value_is_empty".tr : this;
+ String or(String or) => trim().isEmpty ? or : this;
String? get nullOnEmpty => trim().isEmpty ? null : this;
String get to3Digits => AppStringUtility.to3Digits(this, separator: ",");
}
diff --git a/mrt_wallet/lib/app/localization/localization.dart b/mrt_wallet/lib/app/localization/localization.dart
index 8432c9f7..db14e36c 100644
--- a/mrt_wallet/lib/app/localization/localization.dart
+++ b/mrt_wallet/lib/app/localization/localization.dart
@@ -77,7 +77,7 @@ class Localization {
"unlock": "Unlock",
"derive_network_address": "Deriving ___1__ Addresses",
"generate_from_hd_wallet":
- "Generating an address based on your HD wallet seed.",
+ "Creating an address from your HD wallet seed or imported keys.",
"generate_from_imported_keys":
"Generating an address based on your imported keys",
"generate_from_imported_key_desc1":
@@ -133,6 +133,7 @@ class Localization {
"hardened_index": "Hardened key with an index of ___1__.",
"path": "Path",
"setup_derivation_path": "Setup Derivation path",
+ "setup_derivation": "Setup Derivation",
"generate_address": "Generate address",
"invalid_argruments":
"Invalid arguments expected ___1__ but got ___2__",
@@ -805,7 +806,7 @@ class Localization {
"apply_for_condition": "Apply for condition.",
"saved_fulfillment_desc":
"Are you certain that the fulfillment and conditions have been securely saved?",
- "ripple_key_type": "Ripple key type",
+ "key_algorithm": "Key algorithm",
"invalid_ripple_privatekey_algorithm":
"Invalid Ripple private key encryption algorithm.",
"ed25519_support_derivation_desc":
@@ -1422,8 +1423,7 @@ class Localization {
"back_to_the_page": "Back to the page",
"label": "Label",
"metadatum_label": "Metadatum label",
- "enther_valid_un_label":
- "Please enter a valid unsigned number for the label.",
+ "enther_valid_un_label": "Please enter a valid unsigned number.",
"label_already_exists": "The label you entered already exists.",
"no_account_chosen": "No account has been chosen.",
"associated_token_program": "Associated Token Program",
@@ -1487,7 +1487,93 @@ class Localization {
"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"
+ "The genesis hash is the unique identifier for the initial block in a blockchain network, often used for network bootstrapping and verifying network state",
+ "policy_id": "Policy ID",
+ "utxos_amount": "UTXOs amount",
+ "create_a_new_token": "Create a new token",
+ "ada_asset_name_validator": "Please provide a name for the asset.",
+ "ada_create_new_token_desc":
+ "Kindly specify the asset name and total supply for your new token.",
+ "asset_name": "Asset name",
+ "name_of_token": "Name of token",
+ "total_supply_desc":
+ "Please specify the initial token supply amount.",
+ "setup_supply": "Setup supply",
+ "tap_to_input_total_supply": "Tap to input total supply",
+ "owner_of_token": "The owner of token",
+ "tap_to_select_owner": "Tap to select accout",
+ "setup_mint": "Setup mint",
+ "byron_does_not_support_minting_token":
+ "The Byron address does not support the initialization of minting tokens.",
+ "certificates": "Certificates",
+ "add_certificate_to_transaction":
+ "Add certificates to the transaction",
+ "tap_to_add_certificate": "Tap to add certificate",
+ "deregistration": "Deregistration",
+ "registration": "Registration",
+ "delegation": "Delegation",
+ "certificate_type": "Certificate type",
+ "add_certificate_to_transaction_desc":
+ "Please choose the certificate you would like to include in the transaction.",
+ "certificate": "Certificate",
+ "stake_address": "Stake address",
+ "setup_certificate": "Setup certificate",
+ "stake_registration": "Stake Registration",
+ "stake_address_validator":
+ "The account does not possess a stake address",
+ "stake_deregistration": "Stake Deregistration",
+ "stake_delegation": "Stake Delegation",
+ "deposit": "Deposit",
+ "transaction_deposits_list": "List of required transaction deposits",
+ "refund_deposit": "Refund deposit",
+ "unable_to_spend_from_stake_address":
+ "Unable to spend from a stake address.",
+ "cannot_send_ada_to_stake_address":
+ "Sending ADA or assets to a stake address is not allowed.",
+ "stake_key_derivation": "Stake key derivation",
+ "ada_base_stake_key_same_error":
+ "ensure that the base key and stake key are not generated using the same key.",
+ "feature__unavailable_for_multi_signature":
+ "The feature is unavailable for multi-signature addresses.",
+ "select_creation_type": "Select creation type",
+ "setup_address_derivation_keys_desc":
+ "In the setup derivation, you can select imported keys if they exist.",
+ "please_following_steps_to_generate_address":
+ "Please follow these steps to generate an address.",
+ "stake_key": "Stake key",
+ "main_key": "Main key",
+ "base_key": "Base key",
+ "switch_between_keys":
+ "Please switch between keys to view information about each one.",
+ "retrieve_the_public":
+ "Please wait while we retrieve the public key of the account.",
+ "public_keys": "Public keys",
+ "Invalid_coin_default_path": "Invalid coin default path",
+ "invalid_hd_wallet_derivation_path":
+ "Invalid HD wallet derivation path",
+ "derivation_path": "Derivation path",
+ "hd_wallet_path_max_indeqxes":
+ "only supports up to ___1__ HD wallet indexes.",
+ "hd_wallet_hardened_desc":
+ "For hardened indices, append ' or h to the end of the index.",
+ "imported_": "Imported(___1__)",
+ "hd_path": "HD Path",
+ "hd_path_key": "HD Path key",
+ "byron_legacy_hd_path_desc":
+ "Please set up the HD Path and HD Path key, or disable manual configuration to generate them automatically from the key.",
+ "invalid_byron_legacy_hd_path_key":
+ "Invalid byron legacy HD path key",
+ "byron_legacy_hd_wallet_length_desc":
+ "Byron Legacy only supports the first two HD wallet indexes, such as m/1/2.",
+ "byron_legacy_hd_path_key_desc":
+ "Invalid HD Path key bytes. Please provide the HD path key in hexadecimal format.",
+ "byron_legacy_hd_path_key_length_desc":
+ "The HD path key should be 32 bytes in length.",
+ "byron_legacy_hd_path_key_desc2":
+ "Please provide the HD path key in hexadecimal format.",
+ "manually_set_hd_path": "Manually set HD path details.",
+ "byron_legacy_hd_path_generate_from_master_key_desc":
+ "Do not toggle on for generating from master key.",
}
};
}
diff --git a/mrt_wallet/lib/app/utility/blockchain_constant/constant.dart b/mrt_wallet/lib/app/utility/blockchain_constant/constant.dart
new file mode 100644
index 00000000..a573add7
--- /dev/null
+++ b/mrt_wallet/lib/app/utility/blockchain_constant/constant.dart
@@ -0,0 +1,4 @@
+class BlockchainConstant {
+ static const int maxBip32LevelIndex = 5;
+ static const int maxByronLegacyBip32LevelIndex = 2;
+}
diff --git a/mrt_wallet/lib/app/utility/blockchin_utils/blockchaain_utils.dart b/mrt_wallet/lib/app/utility/blockchin_utils/blockchaain_utils.dart
index a8cd1671..0ae053d9 100644
--- a/mrt_wallet/lib/app/utility/blockchin_utils/blockchaain_utils.dart
+++ b/mrt_wallet/lib/app/utility/blockchin_utils/blockchaain_utils.dart
@@ -3,33 +3,38 @@ import 'package:blockchain_utils/bip/bip/bip44/base/bip44_base_ex.dart';
import 'package:blockchain_utils/bip/bip/conf/bip_coins.dart';
import 'package:blockchain_utils/bip/mnemonic/mnemonic.dart';
import 'package:blockchain_utils/blockchain_utils.dart';
-import 'package:mrt_wallet/app/error/exception/wallet_ex.dart';
-import 'package:mrt_wallet/app/utility/blockchin_utils/ripple/ripple_utils.dart';
-import 'package:mrt_wallet/app/utility/compute/compute.dart';
-import 'package:mrt_wallet/models/wallet_models/address/core/core.dart';
-import 'package:mrt_wallet/models/wallet_models/keys/keys.dart';
-import 'package:mrt_wallet/models/wallet_models/network/network_models.dart';
-import 'package:xrpl_dart/xrpl_dart.dart';
+import 'package:mrt_wallet/app/core.dart';
+import 'package:mrt_wallet/models/wallet_models/wallet_models.dart';
class BlockchainUtils {
- static Bip32Base privteKeyToBip32(
- List privateKeyBytes, EllipticCurveTypes curve,
- {bool icarus = false}) {
+ static Bip32Base privteKeyToBip32(List privateKeyBytes, CryptoCoins coin,
+ {Bip32KeyNetVersions? keyNetVar}) {
try {
- switch (curve) {
+ if (coin.proposal == CustomProposal.cip0019) {
+ return CardanoByronLegacyBip32.fromPrivateKey(
+ privateKeyBytes, null, keyNetVar);
+ }
+ switch (coin.conf.type) {
case EllipticCurveTypes.secp256k1:
- return Bip32Slip10Secp256k1.fromPrivateKey(privateKeyBytes);
+ return Bip32Slip10Secp256k1.fromPrivateKey(privateKeyBytes,
+ keyNetVer: keyNetVar);
case EllipticCurveTypes.ed25519:
- return Bip32Slip10Ed25519.fromPrivateKey(privateKeyBytes);
+ return Bip32Slip10Ed25519.fromPrivateKey(privateKeyBytes,
+ keyNetVer: keyNetVar);
case EllipticCurveTypes.ed25519Kholaw:
+ final bool icarus = coin.conf.addrParams["is_icarus"] ?? false;
if (icarus) {
- return CardanoIcarusBip32.fromPrivateKey(privateKeyBytes);
+ return CardanoIcarusBip32.fromPrivateKey(privateKeyBytes,
+ keyNetVer: keyNetVar);
}
- return Bip32KholawEd25519.fromPrivateKey(privateKeyBytes);
+ return Bip32KholawEd25519.fromPrivateKey(privateKeyBytes,
+ keyNetVer: keyNetVar);
case EllipticCurveTypes.ed25519Blake2b:
- return Bip32Slip10Ed25519Blake2b.fromPrivateKey(privateKeyBytes);
+ return Bip32Slip10Ed25519Blake2b.fromPrivateKey(privateKeyBytes,
+ keyNetVer: keyNetVar);
case EllipticCurveTypes.nist256p1:
- return Bip32Slip10Nist256p1.fromPrivateKey(privateKeyBytes);
+ return Bip32Slip10Nist256p1.fromPrivateKey(privateKeyBytes,
+ keyNetVer: keyNetVar);
default:
throw WalletExceptionConst.invalidPrivateKey;
}
@@ -39,23 +44,32 @@ class BlockchainUtils {
}
static Bip32Base extendedKeyToBip32(
- String extendedKey, EllipticCurveTypes curve,
- {bool icarus = false}) {
+ {required String extendedKey, required CryptoCoins coin}) {
try {
- switch (curve) {
+ if (coin.proposal == CustomProposal.cip0019) {
+ return CardanoByronLegacyBip32.fromExtendedKey(
+ extendedKey, coin.conf.keyNetVer);
+ }
+ switch (coin.conf.type) {
case EllipticCurveTypes.secp256k1:
- return Bip32Slip10Secp256k1.fromExtendedKey(extendedKey);
+ return Bip32Slip10Secp256k1.fromExtendedKey(
+ extendedKey, coin.conf.keyNetVer);
case EllipticCurveTypes.ed25519:
- return Bip32Slip10Ed25519.fromExtendedKey(extendedKey);
+ return Bip32Slip10Ed25519.fromExtendedKey(
+ extendedKey, coin.conf.keyNetVer);
case EllipticCurveTypes.ed25519Kholaw:
- if (icarus) {
- return CardanoIcarusBip32.fromExtendedKey(extendedKey);
+ if (coin.conf.addrParams["is_icarus"] == true) {
+ return CardanoIcarusBip32.fromExtendedKey(
+ extendedKey, coin.conf.keyNetVer);
}
- return Bip32KholawEd25519.fromExtendedKey(extendedKey);
+ return Bip32KholawEd25519.fromExtendedKey(
+ extendedKey, coin.conf.keyNetVer);
case EllipticCurveTypes.ed25519Blake2b:
- return Bip32Slip10Ed25519Blake2b.fromExtendedKey(extendedKey);
+ return Bip32Slip10Ed25519Blake2b.fromExtendedKey(
+ extendedKey, coin.conf.keyNetVer);
case EllipticCurveTypes.nist256p1:
- return Bip32Slip10Nist256p1.fromExtendedKey(extendedKey);
+ return Bip32Slip10Nist256p1.fromExtendedKey(
+ extendedKey, coin.conf.keyNetVer);
default:
throw WalletExceptionConst.invalidPrivateKey;
}
@@ -68,7 +82,7 @@ class BlockchainUtils {
try {
final keyBytes =
WifDecoder.decode(wifKey, netVer: coin.conf.wifNetVer!).item1;
- return privteKeyToBip32(keyBytes, coin.conf.type);
+ return privteKeyToBip32(keyBytes, coin);
} on WalletException {
rethrow;
} catch (e) {
@@ -95,109 +109,9 @@ class BlockchainUtils {
return seed;
}
- static Bip44Base privateKeyToBip44(String key, CryptoCoins coin) {
- final privateKey = BytesUtils.fromHexString(key);
- switch (coin.proposal) {
- case BipProposal.bip44:
- return Bip44.fromPrivateKey(privateKey, coin as Bip44Coins);
- case BipProposal.bip49:
- return Bip49.fromPrivateKey(privateKey, coin as Bip49Coins);
- case BipProposal.bip84:
- return Bip84.fromPrivateKey(privateKey, coin as Bip84Coins);
- case BipProposal.bip86:
- return Bip86.fromPrivateKey(privateKey, coin as Bip86Coins);
- case CipProposal.cip1852:
- return Cip1852.fromPrivateKey(privateKey, coin as Cip1852Coins);
- default:
- throw WalletExceptionConst.invalidPrivateKey;
- }
- }
-
- static Bip44Base extendedKeyToBip44(String key, CryptoCoins coin) {
- switch (coin.proposal) {
- case BipProposal.bip44:
- return Bip44.fromExtendedKey(key, coin as Bip44Coins);
- case BipProposal.bip49:
- return Bip49.fromExtendedKey(key, coin as Bip49Coins);
- case BipProposal.bip84:
- return Bip84.fromExtendedKey(key, coin as Bip84Coins);
- case BipProposal.bip86:
- return Bip86.fromExtendedKey(key, coin as Bip86Coins);
- default:
- throw WalletExceptionConst.invalidPrivateKey;
- }
- }
-
- static String exportPrivateKey(String privateKey, CryptoCoins coin) {
- switch (coin) {
- case Bip44Coins.rippleEd25519:
- case Bip44Coins.ripple:
- case Bip44Coins.rippleTestnet:
- case Bip44Coins.rippleTestnetED25519:
- final prv = XRPPrivateKey.fromHex(privateKey,
- algorithm: XRPKeyAlgorithm.values
- .firstWhere((element) => element.curveType == coin.conf.type));
- return prv.toHex();
- default:
- return privateKey;
- }
- }
-
- static String extendedKeyToPrivateKey(String privateKey, CryptoCoins coin) {
- final bip32 = extendedKeyToBip32(privateKey, coin.conf.type);
- return BytesUtils.toHexString(bip32.privateKey.raw);
- }
-
- static ExportedPublicKey? exportPublicKey(
- List pubkeyBytes, CryptoCoins coin, AppNetworkImpl network) {
- final Bip44Base account;
- try {
- switch (coin.proposal) {
- case BipProposal.bip44:
- account = Bip44.fromPublicKey(pubkeyBytes, coin as Bip44Coins);
- break;
- case BipProposal.bip49:
- account = Bip49.fromPublicKey(pubkeyBytes, coin as Bip49Coins);
- break;
- case BipProposal.bip84:
- account = Bip84.fromPublicKey(pubkeyBytes, coin as Bip84Coins);
- break;
- case BipProposal.bip86:
- account = Bip86.fromPublicKey(pubkeyBytes, coin as Bip86Coins);
- break;
- case CipProposal.cip1852:
- account = Cip1852.fromPublicKey(pubkeyBytes, coin as Cip1852Coins);
- break;
- default:
- return null;
- }
- } catch (e) {
- return null;
- }
- String extendedKey = account.publicKey.toExtended;
- List comprossed = account.publicKey.compressed;
- List? unComprossed = account.publicKey.uncompressed;
- String pubKey;
- String? unComprossedPubKey;
- if (network is AppXRPNetwork) {
- pubKey =
- RippleUtils.toRipplePublicKey(BytesUtils.toHexString(comprossed));
- } else {
- pubKey = BytesUtils.toHexString(comprossed);
- }
- if (!bytesEqual(unComprossed, comprossed)) {
- unComprossedPubKey = BytesUtils.toHexString(unComprossed);
- }
- return ExportedPublicKey(
- extendedKey: extendedKey,
- comprossed: pubKey,
- uncomprossed: unComprossedPubKey);
- }
-
- static Bip32Base extendedToBip32(
- String exKeyStr, {
- CryptoCoins? coin,
- EllipticCurveTypes? type,
+ static Bip32Base seedToBip32({
+ required List seedBytes,
+ required CryptoCoins coin,
}) {
Bip32Base validate(Bip32Base bip32Obj) {
int depth = bip32Obj.depth.depth;
@@ -219,79 +133,31 @@ class BlockchainUtils {
}
Bip32Base bip;
- final conf = coin?.conf;
- switch (conf?.type ?? type) {
+ final conf = coin.conf;
+ switch (conf.type) {
case EllipticCurveTypes.secp256k1:
- bip = Bip32Slip10Secp256k1.fromExtendedKey(exKeyStr, conf?.keyNetVer);
+ bip = Bip32Slip10Secp256k1.fromSeed(seedBytes, conf.keyNetVer);
break;
case EllipticCurveTypes.ed25519:
- bip = Bip32Slip10Ed25519.fromExtendedKey(exKeyStr, conf?.keyNetVer);
+ bip = Bip32Slip10Ed25519.fromSeed(seedBytes, conf.keyNetVer);
break;
case EllipticCurveTypes.ed25519Kholaw:
- if (conf?.addrParams["is_icarus"] == true) {
- bip = CardanoIcarusBip32.fromExtendedKey(exKeyStr, conf?.keyNetVer);
+ if (coin.proposal == CustomProposal.cip0019) {
+ bip =
+ CardanoByronLegacyBip32.fromSeed(seedBytes, coin.conf.keyNetVer);
break;
}
- bip = Bip32KholawEd25519.fromExtendedKey(exKeyStr, conf?.keyNetVer);
- break;
- case EllipticCurveTypes.ed25519Blake2b:
- bip = Bip32Slip10Ed25519Blake2b.fromExtendedKey(
- exKeyStr, conf?.keyNetVer);
- break;
- case EllipticCurveTypes.nist256p1:
- bip = Bip32Slip10Nist256p1.fromExtendedKey(exKeyStr, conf?.keyNetVer);
- break;
- default:
- throw const ArgumentException("invaid type");
- }
- return validate(bip);
- }
-
- static Bip32Base seedToBip32(
- List seedBytes, {
- CryptoCoins? coin,
- EllipticCurveTypes? type,
- }) {
- Bip32Base validate(Bip32Base bip32Obj) {
- int depth = bip32Obj.depth.depth;
-
- if (bip32Obj.isPublicOnly) {
- if (depth < Bip44Levels.account.value ||
- depth > Bip44Levels.addressIndex.value) {
- throw Bip44DepthError(
- "Depth of the public-only Bip object ($depth) is below account level or beyond address index level");
- }
- } else {
- if (depth < 0 || depth > Bip44Levels.addressIndex.value) {
- throw Bip44DepthError(
- "Depth of the Bip object ($depth) is invalid or beyond address index level");
- }
- }
-
- return bip32Obj;
- }
-
- Bip32Base bip;
- final conf = coin?.conf;
- switch (conf?.type ?? type) {
- case EllipticCurveTypes.secp256k1:
- bip = Bip32Slip10Secp256k1.fromSeed(seedBytes, conf?.keyNetVer);
- break;
- case EllipticCurveTypes.ed25519:
- bip = Bip32Slip10Ed25519.fromSeed(seedBytes, conf?.keyNetVer);
- break;
- case EllipticCurveTypes.ed25519Kholaw:
- if (conf?.addrParams["is_icarus"] == true) {
- bip = CardanoIcarusBip32.fromSeed(seedBytes, conf?.keyNetVer);
+ if (conf.addrParams["is_icarus"] == true) {
+ bip = CardanoIcarusBip32.fromSeed(seedBytes, conf.keyNetVer);
break;
}
- bip = Bip32KholawEd25519.fromSeed(seedBytes, conf?.keyNetVer);
+ bip = Bip32KholawEd25519.fromSeed(seedBytes, conf.keyNetVer);
break;
case EllipticCurveTypes.ed25519Blake2b:
- bip = Bip32Slip10Ed25519Blake2b.fromSeed(seedBytes, conf?.keyNetVer);
+ bip = Bip32Slip10Ed25519Blake2b.fromSeed(seedBytes, conf.keyNetVer);
break;
case EllipticCurveTypes.nist256p1:
- bip = Bip32Slip10Nist256p1.fromSeed(seedBytes, conf?.keyNetVer);
+ bip = Bip32Slip10Nist256p1.fromSeed(seedBytes, conf.keyNetVer);
break;
default:
throw const ArgumentException("invaid type");
@@ -300,50 +166,97 @@ class BlockchainUtils {
return validate(bip);
}
+ static Bip32AddressIndex generateAccountNextKeyIndex(
+ {required CryptoCoins coin,
+ required List addresses,
+ required SeedGenerationType seedGenerationType}) {
+ if (coin.proposal == CustomProposal.cip0019) {
+ return findNextByronLegacyIndex(coin: coin, addresses: addresses);
+ }
+ return findNextBip32Index(
+ coin: coin,
+ addresses: addresses,
+ seedGenerationType: seedGenerationType);
+ }
+
static Bip32AddressIndex findNextBip32Index(
{required CryptoCoins coin,
required List addresses,
required SeedGenerationType seedGenerationType}) {
- final List addressIndex = addresses
+ final List existsIndexes = addresses
.map((e) => e.keyIndex)
.whereType()
.toList();
final int purposeIndex = coin.proposal.purpose.index;
final int coinIndex = Bip32KeyIndex.hardenIndex(coin.conf.coinIdx).index;
- final int accountLevel = coin.conf.type == EllipticCurveTypes.ed25519
- ? Bip32KeyIndex.hardenIndex(0).index
- : 0;
+ final def = Bip32PathParser.parse(coin.conf.defPath);
+ if (def.elems.isEmpty) {
+ throw WalletException("Invalid_coin_default_path");
+ }
+
+ List indexKeyes = List.from([
+ def.elems.elementAtOrNull(0)!.index,
+ def.elems.elementAtOrNull(1)?.index,
+ def.elems.elementAtOrNull(2)?.index,
+ ], growable: false);
+ int? getCorrectIndex(int elemIndex, int elemValidIndex, int index) {
+ if (elemIndex == elemValidIndex) return index;
+ return indexKeyes[elemIndex];
+ }
- for (int i = accountLevel; i < Bip32KeyDataConst.keyIndexMaxVal; i++) {
+ final validIndex = indexKeyes.lastIndexWhere((element) => element != null);
+ final startIndex = def.elems.elementAt(validIndex).index;
+ for (int i = startIndex; i < Bip32KeyDataConst.keyIndexMaxVal; i++) {
final newKeyIndex = Bip32AddressIndex(
- purpose: purposeIndex,
- coin: coinIndex,
- accountLevel: accountLevel,
- changeLevel: accountLevel,
- addressIndex: i,
- currencyCoin: coin,
- seedGeneration: seedGenerationType);
- if (!addressIndex.contains(newKeyIndex)) {
+ purpose: purposeIndex,
+ coin: coinIndex,
+ accountLevel: getCorrectIndex(0, validIndex, i),
+ changeLevel: getCorrectIndex(1, validIndex, i),
+ addressIndex: getCorrectIndex(2, validIndex, i),
+ currencyCoin: coin,
+ seedGeneration: seedGenerationType,
+ );
+ if (!existsIndexes.contains(newKeyIndex)) {
return newKeyIndex;
}
}
throw WalletExceptionConst.tooManyAccounts;
}
- static ByronLegacyAddressIndex findNextByronLegacyIndex(
+ static Bip32AddressIndex findNextByronLegacyIndex(
{required CryptoCoins coin, required List addresses}) {
- final List addressIndex = addresses
+ final List addressIndex = addresses
.map((e) => e.keyIndex)
- .whereType()
+ .whereType()
.toList();
for (int i = 0; i < Bip32KeyDataConst.keyIndexMaxVal; i++) {
- final newKeyIndex = ByronLegacyAddressIndex(
- firstIndex: 0, secondIndex: i, currencyCoin: coin);
+ final newKeyIndex = Bip32AddressIndex.byronLegacy(
+ firstIndex: 0, secoundIndex: i, currencyCoin: coin);
if (!addressIndex.contains(newKeyIndex)) {
return newKeyIndex;
}
}
throw WalletExceptionConst.tooManyAccounts;
}
+
+ static String createCustomKeyChecksum(Bip32Base bip32) {
+ return BytesUtils.toHexString(MD5.hash([
+ ...bip32.publicKey.compressed,
+ ...bip32.chainCode.toBytes()
+ ]).sublist(0, 8));
+ }
+
+ static String validateHdPathKey(String path, {int? maxIndex}) {
+ try {
+ final parser = Bip32PathParser.parse(path);
+ if (maxIndex != null && parser.length() != maxIndex) {
+ throw WalletException(
+ "hd_wallet_path_max_indeqxes".tr.replaceOne(maxIndex.toString()));
+ }
+ return path;
+ } catch (e) {
+ throw WalletException("invalid_hd_wallet_derivation_path");
+ }
+ }
}
diff --git a/mrt_wallet/lib/app/utility/blockchin_utils/cardano/cardano_utils.dart b/mrt_wallet/lib/app/utility/blockchin_utils/cardano/cardano_utils.dart
new file mode 100644
index 00000000..552dbc61
--- /dev/null
+++ b/mrt_wallet/lib/app/utility/blockchin_utils/cardano/cardano_utils.dart
@@ -0,0 +1,20 @@
+import 'package:blockchain_utils/blockchain_utils.dart';
+import 'package:on_chain/ada/src/address/address.dart';
+
+class CardanoUtils {
+ static const int decimal = 6;
+ static const int bip32StakeChangeLevel = 2;
+ static const int bip32StakeAddressLevel = 0;
+ static const int byronAddressHdPathKeyLengthBytes = 32;
+ static const String hdPathHint = "m/1/2";
+ static ADARewardAddress? extractRewardAddress(ADAAddress addr) {
+ switch (addr.addressType) {
+ case ADAAddressType.base:
+ return (addr as ADABaseAddress).stakeAddress();
+ case ADAAddressType.reward:
+ return addr as ADARewardAddress;
+ default:
+ return null;
+ }
+ }
+}
diff --git a/mrt_wallet/lib/app/utility/blockchin_utils/coins/coins.dart b/mrt_wallet/lib/app/utility/blockchin_utils/coins/coins.dart
new file mode 100644
index 00000000..18790b22
--- /dev/null
+++ b/mrt_wallet/lib/app/utility/blockchin_utils/coins/coins.dart
@@ -0,0 +1,2 @@
+export 'custom_currency_coins.dart';
+export 'custom_currency_conf.dart';
diff --git a/mrt_wallet/lib/app/utility/blockchin_utils/coins/custom_currency_coins.dart b/mrt_wallet/lib/app/utility/blockchin_utils/coins/custom_currency_coins.dart
new file mode 100644
index 00000000..9f9f2650
--- /dev/null
+++ b/mrt_wallet/lib/app/utility/blockchin_utils/coins/custom_currency_coins.dart
@@ -0,0 +1,79 @@
+import 'package:blockchain_utils/bip/bip/bip32/bip32_key_data.dart';
+import 'package:blockchain_utils/bip/bip/conf/bip_coin_conf.dart';
+import 'package:blockchain_utils/bip/bip/conf/bip_coins.dart';
+import 'package:blockchain_utils/exception/exception.dart';
+
+import 'custom_currency_conf.dart';
+
+class CustomCoins extends CryptoCoins {
+ CustomCoins._(this.name, this.conf);
+ final String name;
+ @override
+ String get coinName => name;
+
+ @override
+ final CoinConfig conf;
+
+ @override
+ CryptoProposal get proposal => CustomProposal.cip0019;
+
+ @override
+ CryptoCoins get value => this;
+
+ static final CustomCoins byronLegacy =
+ CustomCoins._("Byron legacy", CustomCurrencyConf.byronLegacy);
+ static final CustomCoins byronLegacyTestnet = CustomCoins._(
+ "Byron legacy testnet", CustomCurrencyConf.byronLegacyTestnet);
+ static final List values = [byronLegacy, byronLegacyTestnet];
+
+ static CryptoCoins? getCoin(String name, CryptoProposal proposal) {
+ switch (proposal) {
+ case CustomProposal.cip0019:
+ return CustomCoins.fromName(name);
+ default:
+ return CryptoCoins.getCoin(name, proposal);
+ }
+ }
+
+ static CustomCoins? fromName(String name) {
+ try {
+ return values.firstWhere((element) => element.name == name);
+ } on StateError {
+ return null;
+ }
+ }
+}
+
+class CustomProposal implements CryptoProposal {
+ static const CustomProposal cip0019 = CustomProposal._('custom');
+
+ const CustomProposal._(this.name);
+ final String name;
+
+ @override
+ String get specName => name;
+ @override
+ CustomProposal get value => this;
+
+ static const List values = [cip0019];
+
+ @override
+ Bip32KeyIndex get purpose => Bip32KeyIndex(0);
+
+ static CryptoProposal fromName(String name) {
+ try {
+ return values.firstWhere(
+ (element) => element.specName == name,
+ orElse: () =>
+ BipProposal.values.firstWhere((element) => element.name == name),
+ );
+ } on StateError {
+ return CipProposal.values.firstWhere(
+ (element) => element.name == name,
+ orElse: () => throw MessageException(
+ "Unable to locate a proposal with the given name.",
+ details: {"Name": name}),
+ );
+ }
+ }
+}
diff --git a/mrt_wallet/lib/app/utility/blockchin_utils/coins/custom_currency_conf.dart b/mrt_wallet/lib/app/utility/blockchin_utils/coins/custom_currency_conf.dart
new file mode 100644
index 00000000..0469dbdb
--- /dev/null
+++ b/mrt_wallet/lib/app/utility/blockchin_utils/coins/custom_currency_conf.dart
@@ -0,0 +1,29 @@
+import 'package:blockchain_utils/bip/bip/conf/bip_coin_conf.dart';
+import 'package:blockchain_utils/bip/coin_conf/coins_name.dart';
+import 'package:blockchain_utils/bip/slip/slip44/slip44.dart';
+import 'package:blockchain_utils/blockchain_utils.dart';
+
+class CustomCurrencyConf {
+ static CoinConfig byronLegacy = CoinConfig(
+ coinNames: const CoinNames("Byron legacy", "ADA"),
+ coinIdx: 0,
+ isTestnet: false,
+ defPath: "0/0",
+ keyNetVer: Bip32Const.kholawKeyNetVersions,
+ wifNetVer: null,
+ type: EllipticCurveTypes.ed25519Kholaw,
+ addressEncoder: ([dynamic kwargs]) => AdaByronLegacyAddrEncoder(),
+ addrParams: {"chain_code": true},
+ );
+ static CoinConfig byronLegacyTestnet = CoinConfig(
+ coinNames: const CoinNames("Byron legacy testnet", "ADA"),
+ coinIdx: Slip44.testnet,
+ isTestnet: true,
+ defPath: "",
+ keyNetVer: Bip32Const.kholawKeyNetVersions,
+ wifNetVer: null,
+ type: EllipticCurveTypes.ed25519Kholaw,
+ addressEncoder: ([dynamic kwargs]) => AdaByronLegacyAddrEncoder(),
+ addrParams: {"chain_code": true},
+ );
+}
diff --git a/mrt_wallet/lib/app/utility/blockchin_utils/ripple/ripple_utils.dart b/mrt_wallet/lib/app/utility/blockchin_utils/ripple/ripple_utils.dart
index ff9db513..26169b97 100644
--- a/mrt_wallet/lib/app/utility/blockchin_utils/ripple/ripple_utils.dart
+++ b/mrt_wallet/lib/app/utility/blockchin_utils/ripple/ripple_utils.dart
@@ -1,9 +1,11 @@
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/constant/network_constant/ripple_const.dart';
import 'package:mrt_wallet/app/error/exception/wallet_ex.dart';
import 'package:mrt_wallet/app/utility/bytes_utils/quick_bytes.dart';
import 'package:mrt_wallet/models/wallet_models/address/network_address/xrp/xrp_account.dart';
+import 'package:mrt_wallet/models/wallet_models/network/core/network.dart';
import 'package:xrpl_dart/xrpl_dart.dart';
import '../blockchaain_utils.dart';
@@ -213,11 +215,13 @@ class RippleUtils {
}
}
- static Bip32Base rippleSeedToBip32(String seed) {
+ static Bip32Base rippleSeedToBip32(String seed, AppNetworkImpl network) {
try {
final ripplePrivateKey = XRPPrivateKey.fromSeed(seed);
return BlockchainUtils.privteKeyToBip32(
- ripplePrivateKey.toBytes(), ripplePrivateKey.algorithm.curveType);
+ ripplePrivateKey.toBytes(),
+ network.coins.firstWhere((element) =>
+ element.conf.type == ripplePrivateKey.algorithm.curveType));
} on WalletException {
rethrow;
} catch (e) {
@@ -226,15 +230,15 @@ class RippleUtils {
}
static Bip32Base ripplePrivateKeyToBip32(
- String privateKey, EllipticCurveTypes curve) {
+ String privateKey, CryptoCoins coin) {
try {
final ripplePrivateKey = XRPPrivateKey.fromBytes(
BytesUtils.fromHexString(privateKey),
- algorithm: curve == EllipticCurveTypes.ed25519
+ algorithm: coin.conf.type == EllipticCurveTypes.ed25519
? XRPKeyAlgorithm.ed25519
: XRPKeyAlgorithm.secp256k1);
- return BlockchainUtils.privteKeyToBip32(
- ripplePrivateKey.toBytes(), ripplePrivateKey.algorithm.curveType);
+
+ return BlockchainUtils.privteKeyToBip32(ripplePrivateKey.toBytes(), coin);
} on WalletException {
rethrow;
} catch (e) {
@@ -242,15 +246,13 @@ class RippleUtils {
}
}
- static Bip32Base rippleEntropyToBip32(
- String entropy, EllipticCurveTypes algorithm) {
+ static Bip32Base rippleEntropyToBip32(String entropy, CryptoCoins coin) {
try {
final ripplePrivateKey = XRPPrivateKey.fromEntropy(entropy,
- algorithm: algorithm == EllipticCurveTypes.ed25519
+ algorithm: coin.conf.type == EllipticCurveTypes.ed25519
? XRPKeyAlgorithm.ed25519
: XRPKeyAlgorithm.secp256k1);
- return BlockchainUtils.privteKeyToBip32(
- ripplePrivateKey.toBytes(), ripplePrivateKey.algorithm.curveType);
+ return BlockchainUtils.privteKeyToBip32(ripplePrivateKey.toBytes(), coin);
} on WalletException {
rethrow;
} catch (e) {
diff --git a/mrt_wallet/lib/app/utility/blockchin_utils/utils.dart b/mrt_wallet/lib/app/utility/blockchin_utils/utils.dart
index 5afa6425..89af62f0 100644
--- a/mrt_wallet/lib/app/utility/blockchin_utils/utils.dart
+++ b/mrt_wallet/lib/app/utility/blockchin_utils/utils.dart
@@ -7,3 +7,5 @@ export 'blockchain_addr_utils.dart';
export 'bitcoin/bitcoin.dart';
export 'bitcoin_cash/bitcoin_cash_utils.dart';
export 'solana/solana.dart';
+export 'cardano/cardano_utils.dart';
+export 'coins/coins.dart';
diff --git a/mrt_wallet/lib/app/utility/string_utility.dart b/mrt_wallet/lib/app/utility/string_utility.dart
index c9cc9aaa..df38fc27 100644
--- a/mrt_wallet/lib/app/utility/string_utility.dart
+++ b/mrt_wallet/lib/app/utility/string_utility.dart
@@ -158,7 +158,7 @@ class AppStringUtility {
static bool isValidIPv4WithPort(String ipv4) {
// Regular expression to match IPv4 address with optional port
final RegExp ipv4WithPortRegex = RegExp(r'^(\d{1,3}\.){3}\d{1,3}:\d+$');
-
+
// Check if the input matches the pattern
return ipv4WithPortRegex.hasMatch(ipv4);
}
diff --git a/mrt_wallet/lib/app/utility/utility.dart b/mrt_wallet/lib/app/utility/utility.dart
index e5d76755..3365ff4c 100644
--- a/mrt_wallet/lib/app/utility/utility.dart
+++ b/mrt_wallet/lib/app/utility/utility.dart
@@ -13,3 +13,4 @@ export 'numeric_utils/numeric_utils.dart';
export 'lifecycle_listener/core.dart';
export 'file/file.dart';
export 'bytes_utils/quick_bytes.dart';
+export 'blockchain_constant/constant.dart';
diff --git a/mrt_wallet/lib/future/pages/start_page/account_page.dart b/mrt_wallet/lib/future/pages/start_page/account_page.dart
index 991b8629..ff529113 100644
--- a/mrt_wallet/lib/future/pages/start_page/account_page.dart
+++ b/mrt_wallet/lib/future/pages/start_page/account_page.dart
@@ -4,6 +4,7 @@ import 'package:mrt_wallet/future/pages/start_page/home.dart';
import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/wallet_global_pages.dart';
import 'package:mrt_wallet/future/pages/wallet_pages/network/bitcoin_cash_pages/account_page.dart';
import 'package:mrt_wallet/future/pages/wallet_pages/network/bitcoin_pages/account_page.dart';
+import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/account_page.dart';
import 'package:mrt_wallet/future/pages/wallet_pages/network/ethereum_pages/ethereum_account_page_view.dart';
import 'package:mrt_wallet/future/pages/wallet_pages/network/ripple_pages/account_page.dart';
import 'package:mrt_wallet/future/pages/wallet_pages/network/solana_pages/account_page.dart';
@@ -308,6 +309,8 @@ class _AccountPageView extends StatelessWidget {
return ETHAccountPageView(chainAccount: chainAccount);
case APPTVMNetwork:
return TronAccountPageView(chainAccount: chainAccount);
+ case APPCardanoNetwork:
+ return CardanoAccountPage(chainAccount: chainAccount);
default:
return const SizedBox();
}
diff --git a/mrt_wallet/lib/future/pages/start_page/home_screen.dart b/mrt_wallet/lib/future/pages/start_page/home_screen.dart
index 604e1ada..0dbc82be 100644
--- a/mrt_wallet/lib/future/pages/start_page/home_screen.dart
+++ b/mrt_wallet/lib/future/pages/start_page/home_screen.dart
@@ -196,15 +196,14 @@ class _BottomAppBar extends StatelessWidget {
IconButton(
tooltip: "switch_network".tr,
onPressed: () async {
- await showAdaptiveDialog(
- context: context,
- useRootNavigator: false,
- builder: (context) {
- return SwitchNetworkView(
- selectedNetwork: model.network,
- );
- },
- ).then(
+ context
+ .openDialogPage(
+ "switch_network".tr,
+ fullWidget: SwitchNetworkView(
+ selectedNetwork: model.network,
+ ),
+ )
+ .then(
(value) {
if (value == null) return;
if (value.isNegative) {
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/account_pages/show_public_key.dart b/mrt_wallet/lib/future/pages/wallet_pages/account_pages/show_public_key.dart
index 7ed2b8dd..e42c3b6d 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/account_pages/show_public_key.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/account_pages/show_public_key.dart
@@ -1,7 +1,10 @@
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/wallet_pages.dart';
import 'package:mrt_wallet/future/widgets/custom_widgets.dart';
+import 'package:mrt_wallet/main.dart';
+import 'package:mrt_wallet/models/wallet_models/address/network_address/cardano/cardano.dart';
import 'package:mrt_wallet/models/wallet_models/wallet_models.dart';
class AccountPublicKeyView extends StatelessWidget {
@@ -27,77 +30,163 @@ class _BipAccountPublicKey extends StatefulWidget {
}
class __BipAccountPublicKeyState extends State<_BipAccountPublicKey> {
- ExportedPublicKey? publicKey;
+ final List pubKeys = [];
+ bool get hasMultipleKey => pubKeys.length > 1;
+ late AccessPubliKeyResponse publicKey;
+ final GlobalKey progressKey = GlobalKey();
+ bool inited = false;
+ void initPubKey() async {
+ if (inited) return;
+ inited = true;
+ final wallet = context.watch(StateIdsConst.main);
+ final result = await wallet.getAccountPubKys(account: widget.account);
+ if (result.hasResult) {
+ pubKeys.addAll(result.result);
+ progressKey.success();
+ publicKey = pubKeys.first;
+ } else {
+ progressKey.errorText("cannot_export_public_key".tr, backToIdle: false);
+ }
+ }
+
+ late final ICardanoAddress? adaLegacyAddress = isAdaLegacy();
+
+ ICardanoAddress? isAdaLegacy() {
+ if (widget.account is ICardanoAddress) {
+ if ((widget.account as ICardanoAddress).addressDetails.isLegacy) {
+ return widget.account as ICardanoAddress;
+ }
+ }
+ return null;
+ }
- void initPubKey() {
- publicKey = BlockchainUtils.exportPublicKey(
- widget.account.publicKey, widget.account.coin, widget.network);
+ void onChangeKey(AccessPubliKeyResponse? changeKey) {
+ if (publicKey == changeKey || changeKey == null) return;
+ publicKey = changeKey;
+ setState(() {});
}
@override
- void initState() {
- super.initState();
+ void didChangeDependencies() {
+ super.didChangeDependencies();
initPubKey();
}
@override
Widget build(BuildContext context) {
- if (publicKey == null) {
- return Column(
+ return PageProgress(
+ key: progressKey,
+ initialStatus: StreamWidgetStatus.progress,
+ backToIdle: AppGlobalConst.oneSecoundDuration,
+ initialWidget: ProgressWithTextView(text: "retrieve_the_public".tr),
+ child: () => Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
- WidgetConstant.errorIconLarge,
- WidgetConstant.height8,
- Text("cannot_export_public_key".tr)
+ PageTitleSubtitle(
+ title: "export_public_key".tr,
+ body: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [Text("export_public_key_desc1".tr)],
+ )),
+ if (hasMultipleKey) ...[
+ Text("public_keys".tr, style: context.textTheme.titleMedium),
+ Text("switch_between_keys".tr),
+ WidgetConstant.height8,
+ AppDropDownBottom(
+ onChanged: onChangeKey,
+ items: {for (final i in pubKeys) i: Text(i.keyName.tr)},
+ label: "key_name".tr,
+ value: publicKey,
+ ),
+ WidgetConstant.height20,
+ ],
+ if (!hasMultipleKey) ...[
+ Text("address_details".tr, style: context.textTheme.titleMedium),
+ WidgetConstant.height8,
+ ContainerWithBorder(
+ child: CopyTextWithBarcode(
+ dataToCopy: widget.account.address.toAddress,
+ widget: AddressDetailsView(address: widget.account),
+ barcodeTitle: "address_sharing".tr),
+ ),
+ WidgetConstant.height20
+ ],
+ _HDPathDetails(byronLegacy: adaLegacyAddress),
+ AnimatedSwitcher(
+ duration: AppGlobalConst.animationDuraion,
+ child: Column(
+ key: UniqueKey(),
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text("extended_public_key".tr,
+ style: context.textTheme.titleMedium),
+ WidgetConstant.height8,
+ ContainerWithBorder(
+ child: CopyTextWithBarcode(
+ dataToCopy: publicKey.extendedKey,
+ barcodeTitle: "extended_public_key".tr,
+ widget: SelectableText(publicKey.extendedKey),
+ )),
+ WidgetConstant.height20,
+ Text("comperessed_public_key".tr,
+ style: context.textTheme.titleMedium),
+ WidgetConstant.height8,
+ ContainerWithBorder(
+ child: CopyTextWithBarcode(
+ barcodeTitle: "comperessed_public_key".tr,
+ dataToCopy: publicKey.comprossed,
+ widget: SelectableText(publicKey.comprossed),
+ )),
+ if (publicKey.uncomprossed != null) ...[
+ WidgetConstant.height20,
+ Text("uncomperessed_public_key".tr,
+ style: context.textTheme.titleMedium),
+ WidgetConstant.height8,
+ ContainerWithBorder(
+ child: CopyTextWithBarcode(
+ dataToCopy: publicKey.uncomprossed!,
+ barcodeTitle: "uncomperessed_public_key".tr,
+ widget: SelectableText(publicKey.uncomprossed!),
+ )),
+ ],
+ ],
+ ),
+ )
],
- );
- }
+ ),
+ );
+ }
+}
+
+class _HDPathDetails extends StatelessWidget {
+ const _HDPathDetails({this.byronLegacy});
+ final ICardanoAddress? byronLegacy;
+
+ @override
+ Widget build(BuildContext context) {
+ if (byronLegacy == null) return WidgetConstant.sizedBox;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- PageTitleSubtitle(
- title: "export_public_key".tr,
- body: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [Text("export_public_key_desc1".tr)],
- )),
- Text("address_details".tr, style: context.textTheme.titleMedium),
+ Text("hd_path".tr, style: context.textTheme.titleMedium),
WidgetConstant.height8,
ContainerWithBorder(
- child: CopyTextWithBarcode(
- dataToCopy: widget.account.address.toAddress,
- widget: AddressDetailsView(address: widget.account),
- barcodeTitle: "address_sharing".tr),
+ onRemove: () {},
+ onRemoveIcon:
+ CopyTextIcon(dataToCopy: byronLegacy!.addressDetails.hdPath!),
+ child:
+ Text(byronLegacy!.addressDetails.hdPath!.or("non_derivation".tr)),
),
WidgetConstant.height20,
- Text("extended_public_key".tr, style: context.textTheme.titleMedium),
+ Text("hd_path_key".tr, style: context.textTheme.titleMedium),
WidgetConstant.height8,
ContainerWithBorder(
- child: CopyTextWithBarcode(
- dataToCopy: publicKey!.extendedKey,
- barcodeTitle: "extended_public_key".tr,
- widget: SelectableText(publicKey!.extendedKey),
- )),
- WidgetConstant.height20,
- Text("comperessed_public_key".tr, style: context.textTheme.titleMedium),
- WidgetConstant.height8,
- ContainerWithBorder(
- child: CopyTextWithBarcode(
- barcodeTitle: "comperessed_public_key".tr,
- dataToCopy: publicKey!.comprossed,
- widget: SelectableText(publicKey!.comprossed),
- )),
- if (publicKey!.uncomprossed != null) ...[
- WidgetConstant.height20,
- Text("uncomperessed_public_key".tr,
- style: context.textTheme.titleMedium),
- WidgetConstant.height8,
- ContainerWithBorder(
- child: CopyTextWithBarcode(
- dataToCopy: publicKey!.uncomprossed!,
- barcodeTitle: "uncomperessed_public_key".tr,
- widget: SelectableText(publicKey!.uncomprossed!),
- )),
- ]
+ onRemove: () {},
+ onRemoveIcon: CopyTextIcon(
+ dataToCopy: byronLegacy!.addressDetails.hdPathKeyHex!),
+ child: Text(byronLegacy!.addressDetails.hdPathKeyHex!),
+ ),
+ WidgetConstant.height20
],
);
}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation/address_derivation_view.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation/address_derivation_view.dart
new file mode 100644
index 00000000..3f5fda24
--- /dev/null
+++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation/address_derivation_view.dart
@@ -0,0 +1,72 @@
+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_derivation/generic.dart';
+import 'package:mrt_wallet/future/widgets/custom_widgets.dart';
+import 'package:mrt_wallet/main.dart';
+import 'controller.dart';
+
+class NetworkGenericAddressDerivationView extends StatelessWidget {
+ const NetworkGenericAddressDerivationView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final wallet = context.watch(StateIdsConst.main);
+ return MrtViewBuilder(
+ controller: () => AddressDerivationController(
+ chainAccount: wallet.chain, network: wallet.network, wallet: wallet),
+ builder: (controller) => Scaffold(
+ appBar: AppBar(
+ title: Text("setup_address".tr),
+ ),
+ body: PageProgress(
+ key: controller.pageProgressKey,
+ backToIdle: AppGlobalConst.oneSecoundDuration,
+ initialStatus: PageProgressStatus.idle,
+ child: () => UnfocusableChild(
+ child: Center(
+ child: CustomScrollView(
+ shrinkWrap: true,
+ slivers: [
+ SliverToBoxAdapter(
+ child: ConstraintsBoxView(
+ padding: WidgetConstant.paddingHorizontal20,
+ child: AnimatedSwitcher(
+ duration: AppGlobalConst.animationDuraion,
+ child: Form(
+ key: controller.form,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ key: const ValueKey(true),
+ children: [
+ PageTitleSubtitle(
+ title: "setup_network_address".tr.replaceOne(
+ controller.network.coinParam.token.name),
+ body: Column(
+ crossAxisAlignment:
+ CrossAxisAlignment.start,
+ children: [
+ Text("disable_standard_derivation".tr),
+ WidgetConstant.height8,
+ Text("setup_address_derivation_keys_desc"
+ .tr),
+ WidgetConstant.height8,
+ Text(
+ "please_following_steps_to_generate_address"
+ .tr),
+ ],
+ )),
+ SetupGenericAddressView(controller: controller)
+ ],
+ ),
+ )),
+ ))
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation/controller.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation/controller.dart
new file mode 100644
index 00000000..7ac76fc0
--- /dev/null
+++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation/controller.dart
@@ -0,0 +1,103 @@
+import 'package:blockchain_utils/bip/bip/conf/bip_coins.dart';
+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_derivation/setup_address_derivation_mode.dart';
+import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/address_details.dart';
+import 'package:mrt_wallet/future/widgets/custom_widgets.dart';
+import 'package:mrt_wallet/models/wallet_models/wallet_models.dart';
+
+typedef OnGenerateDerivation = Future Function();
+
+enum AddressDerivationMode {
+ hdWallet,
+ importedKey;
+
+ bool get isCustomKey => this == AddressDerivationMode.importedKey;
+}
+
+typedef OnSelectDerivation = void Function(
+ AddressDerivationMode mode, EncryptedCustomKey? selectedKey);
+
+class AddressDerivationController extends StateController {
+ AddressDerivationController({
+ required this.wallet,
+ required this.network,
+ required this.chainAccount,
+ });
+ final WalletProvider wallet;
+ final GlobalKey visibleContinue =
+ GlobalKey(debugLabel: "visibleGenerateAddress");
+ final AppNetworkImpl network;
+
+ bool showCustomKes = false;
+ bool showSetupPage = false;
+
+ final GlobalKey pageProgressKey =
+ GlobalKey(debugLabel: "SetupEthereumAddressView");
+ final GlobalKey form = GlobalKey();
+ final GlobalKey visibleGenerateAddress =
+ GlobalKey(debugLabel: "visibleContinue");
+ final GlobalKey visibleXAddressDetails =
+ GlobalKey(debugLabel: "visibleContinue");
+
+ final AppChain chainAccount;
+ NetworkAccountCore get networkAccounts => chainAccount.account;
+ List get coins => network.coins;
+ CryptoCoins get coin => coins.first;
+
+ Bip32AddressIndex? customKeyIndex;
+ bool get derivationStandard => customKeyIndex == null;
+
+ bool inited = false;
+
+ void onChangeDerivation(OnGenerateDerivation onGenerateDerivation) async {
+ if (derivationStandard) {
+ customKeyIndex = await onGenerateDerivation();
+ } else {
+ customKeyIndex = null;
+ }
+ notify();
+ }
+
+ AddressDerivationIndex get nextDerivation {
+ return chainAccount.account.nextDerive(coin);
+ }
+
+ Future getCoin(BuildContext context) async {
+ if (!(form.currentState?.validate() ?? true)) return null;
+ return await context.openSliverBottomSheet(
+ "setup_derivation".tr,
+ child: SetupDerivationModeView(coin: coin, chainAccout: chainAccount));
+ }
+
+ void generateAddress(NewAccountParams newAccount) async {
+ if (!(form.currentState?.validate() ?? false)) return;
+ pageProgressKey.progressText("generating_new_addr".tr);
+ final result = await MethodCaller.call(() async {
+ final result = await wallet.deriveNewAccount(newAccount);
+ result.rethrowIfError();
+ return result.result;
+ });
+ if (result.hasError) {
+ pageProgressKey.errorText(result.error!.tr);
+ } else {
+ pageProgressKey.success(
+ backToIdle: false,
+ progressWidget: SuccessWithButtomView(
+ buttomText: "generate_new_address".tr,
+ buttomWidget: ContainerWithBorder(
+ margin: WidgetConstant.paddingVertical8,
+ child: AddressDetailsView(address: result.result)),
+ onPressed: () {
+ pageProgressKey.backToIdle();
+ },
+ text: "address_added_success".tr,
+ ));
+ }
+ notify();
+ }
+
+ @override
+ String get repositoryId => "address_derivation";
+}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation/generic.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation/generic.dart
new file mode 100644
index 00000000..73a030e7
--- /dev/null
+++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation/generic.dart
@@ -0,0 +1,68 @@
+import 'package:flutter/material.dart';
+import 'package:mrt_wallet/app/core.dart';
+import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/address_derivation/controller.dart';
+import 'package:mrt_wallet/future/pages/wallet_pages/network/ripple_pages/setup_address.dart';
+import 'package:mrt_wallet/future/widgets/button.dart';
+import 'package:mrt_wallet/future/widgets/widget_constant.dart';
+import 'package:mrt_wallet/models/wallet_models/wallet_models.dart';
+
+class SetupGenericAddressView extends StatelessWidget {
+ const SetupGenericAddressView({super.key, required this.controller});
+ final AddressDerivationController controller;
+
+ @override
+ Widget build(BuildContext context) {
+ switch (controller.network.runtimeType) {
+ case AppXRPNetwork:
+ return SetupRippleAddressView(
+ controller: controller,
+ );
+ default:
+ return _GenericNetworkAddressGenerationView(controller: controller);
+ }
+ }
+}
+
+class _GenericNetworkAddressGenerationView extends StatelessWidget {
+ const _GenericNetworkAddressGenerationView({required this.controller});
+ final AddressDerivationController controller;
+ static NewAccountParams getnerateAccoutParams(
+ Bip32AddressIndex keyIndex, AppNetworkImpl network) {
+ switch (network.runtimeType) {
+ case APPEVMNetwork:
+ return EthereumNewAddressParam(deriveIndex: keyIndex);
+ case APPSolanaNetwork:
+ return SolanaNewAddressParam(deriveIndex: keyIndex);
+ case APPCosmosNetwork:
+ return CosmosNewAddressParams(deriveIndex: keyIndex);
+ case APPTVMNetwork:
+ return TronNewAddressParam(deriveIndex: keyIndex);
+ default:
+ throw UnimplementedError();
+ }
+ }
+
+ static void generateAddress(
+ BuildContext context, AddressDerivationController controller) async {
+ final keyIndex = await controller.getCoin(context);
+ if (keyIndex == null) return;
+ final newAccountParam = getnerateAccoutParams(keyIndex, controller.network);
+ controller.generateAddress(newAccountParam);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ FixedElevatedButton(
+ padding: WidgetConstant.paddingVertical20,
+ onPressed: () {
+ generateAddress(context, controller);
+ },
+ child: Text("generate_address".tr),
+ ),
+ ],
+ );
+ }
+}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation/setup_address_derivation_mode.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation/setup_address_derivation_mode.dart
new file mode 100644
index 00000000..d91576a0
--- /dev/null
+++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation/setup_address_derivation_mode.dart
@@ -0,0 +1,211 @@
+import 'package:blockchain_utils/bip/bip/conf/bip_coins.dart';
+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/bip32_derivation.dart';
+import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/byron_legacy_derivation.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';
+
+typedef _OnGenerateDerivation = Future Function();
+
+class SetupDerivationModeView extends StatefulWidget {
+ final CryptoCoins coin;
+ final AppChain chainAccout;
+ final AddressDerivationIndex? defaultDerivation;
+ final Widget? title;
+ const SetupDerivationModeView(
+ {super.key,
+ required this.coin,
+ required this.chainAccout,
+ this.defaultDerivation,
+ this.title});
+
+ @override
+ State createState() =>
+ _SetupDerivationModeView2State();
+}
+
+class _SetupDerivationModeView2State extends State
+ with SafeState {
+ EncryptedCustomKey? selectedCustomKey;
+ AppNetworkImpl get network => chainAccount.network;
+ AppChain get chainAccount => widget.chainAccout;
+ late final bool useByronLegacyDeriavation =
+ widget.coin.proposal == CustomProposal.cip0019;
+
+ AddressDerivationIndex derivationkey(CryptoCoins coin) {
+ if (selectedCustomKey != null) {
+ return (customKeyIndex ?? Bip32AddressIndex(currencyCoin: coin))
+ .copyWith(importedKeyId: selectedCustomKey!.id);
+ }
+ return customKeyIndex ?? nextDerivation;
+ }
+
+ AddressDerivationIndex get nextDerivation {
+ return widget.defaultDerivation ??
+ chainAccount.account.nextDerive(widget.coin);
+ }
+
+ void onChangeCustomKey(EncryptedCustomKey? newSelected) {
+ selectedCustomKey = newSelected;
+ setState(() {});
+ }
+
+ List customKeys = [];
+ bool _inited = false;
+ void _setupIAccount() {
+ if (!_inited) {
+ _inited = true;
+ final model = context.watch(StateIdsConst.main);
+ customKeys = model.getCustomKeysForCoin(widget.coin);
+ }
+ }
+
+ bool get derivationStandard => customKeyIndex == null;
+ Bip32AddressIndex? customKeyIndex;
+
+ void onChangeDerivation(_OnGenerateDerivation onGenerateDerivation) async {
+ if (derivationStandard) {
+ customKeyIndex = await onGenerateDerivation();
+ } else {
+ customKeyIndex = null;
+ }
+ setState(() {});
+ }
+
+ @override
+ void didChangeDependencies() {
+ _setupIAccount();
+ super.didChangeDependencies();
+ }
+
+ void onSubmit() {
+ final key = derivationkey(widget.coin);
+ context.pop(key);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ widget.title ??
+ PageTitleSubtitle(
+ title: "derive_network_address"
+ .tr
+ .replaceOne(network.coinParam.token.name),
+ body: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [Text("disable_standard_derivation".tr)],
+ )),
+ Text(
+ "derivation_path".tr,
+ style: context.textTheme.titleMedium,
+ ),
+ WidgetConstant.height8,
+ ContainerWithBorder(
+ onRemove: () {
+ onChangeDerivation(
+ () async {
+ if (useByronLegacyDeriavation) {
+ return context.openSliverBottomSheet(
+ "key_derivation".tr,
+ child: ByronLegacyKeyDerivationView(
+ coin: widget.coin,
+ curve: widget.coin.conf.type,
+ ));
+ }
+ return context.openSliverBottomSheet(
+ "key_derivation".tr,
+ child: Bip32KeyDerivationView(
+ coin: widget.coin,
+ curve: widget.coin.conf.type,
+ network: network,
+ defaultPath: nextDerivation.hdPath,
+ ));
+ },
+ );
+ },
+ onRemoveIcon: derivationStandard
+ ? const Icon(Icons.edit)
+ : const Icon(Icons.remove_circle),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ selectedCustomKey == null
+ ? Text(
+ derivationStandard
+ ? "standard_derivation".tr
+ : "custom_derivation".tr,
+ style: context.textTheme.labelLarge,
+ )
+ : Text(
+ customKeyIndex == null
+ ? "non_derivation".tr
+ : "custom_derivation".tr,
+ style: context.textTheme.labelLarge,
+ ),
+ selectedCustomKey == null
+ ? Text(
+ customKeyIndex?.toString() ?? nextDerivation.toString(),
+ )
+ : Text(
+ customKeyIndex?.toString() ??
+ "import_key_derivation_desc2".tr,
+ )
+ ],
+ )),
+ WidgetConstant.height20,
+ Text(
+ "select_creation_type".tr,
+ style: context.textTheme.titleMedium,
+ ),
+ Text("generate_from_hd_wallet".tr),
+ WidgetConstant.height8,
+ RadioListTile(
+ value: null,
+ groupValue: selectedCustomKey,
+ onChanged: onChangeCustomKey,
+ title: Text("hd_wallet".tr),
+ subtitle: Text("generate_from_hd_wallet".tr),
+ ),
+ Column(
+ children: List.generate(customKeys.length, (index) {
+ final key = customKeys[index];
+ return RadioListTile(
+ value: key,
+ groupValue: selectedCustomKey,
+ onChanged: onChangeCustomKey,
+ title: OneLineTextWidget(key.networkPubKey(network)),
+ subtitle: RichText(
+ text:
+ TextSpan(style: context.textTheme.bodyMedium, children: [
+ if (key.name != null) ...[
+ TextSpan(text: key.name),
+ TextSpan(
+ text: " (${key.created.toDateAndTime()}) ",
+ style: context.textTheme.bodySmall)
+ ] else
+ TextSpan(
+ text: "imported_at".tr.replaceOne(key.created.toString()),
+ style: context.textTheme.bodyMedium),
+ ])),
+ );
+ }),
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ FixedElevatedButton(
+ padding: WidgetConstant.paddingVertical20,
+ onPressed: onSubmit,
+ child: Text("generate_address".tr),
+ )
+ ],
+ )
+ ],
+ );
+ }
+}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation_type.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation_type.dart
deleted file mode 100644
index d1c1bd06..00000000
--- a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_derivation_type.dart
+++ /dev/null
@@ -1,193 +0,0 @@
-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/widgets/custom_widgets.dart';
-import 'package:mrt_wallet/main.dart';
-import 'package:mrt_wallet/models/wallet_models/wallet_models.dart';
-
-enum AddressDerivationMode { hdWallet, importedKey }
-
-typedef OnSelectDerivation = void Function(
- AddressDerivationMode mode, EncryptedCustomKey? selectedKey);
-
-class SetupAddressDerivation extends StatefulWidget {
- const SetupAddressDerivation(this.onSelectDerivation, {super.key});
- final OnSelectDerivation onSelectDerivation;
- @override
- State createState() =>
- _SetupAddressDerivationViewState();
-}
-
-class _SetupAddressDerivationViewState extends State
- with SafeState {
- String? _error;
- final GlobalKey visibleContinue =
- GlobalKey(debugLabel: "visibleGenerateAddress");
- late final AppNetworkImpl network;
- AddressDerivationMode? selectedDerivationMode;
- EncryptedCustomKey? selectedCustomKey;
- bool showCustomKes = false;
- bool showSetupPage = false;
- bool inAddressPage = false;
-
- void onChangeCustomKey(EncryptedCustomKey? newSelected) {
- selectedCustomKey = newSelected;
- if (selectedCustomKey != null && showCustomKes) {
- showSetupPage = true;
- } else {
- showSetupPage = false;
- }
- setState(() {});
- }
-
- late final Map derivationModes = {
- AddressDerivationMode.hdWallet: Text("hd_wallet".tr),
- AddressDerivationMode.importedKey: Text("imported_key".tr)
- };
-
- void onChangeDerivationMode(AddressDerivationMode? mode) async {
- if (mode == selectedDerivationMode) return;
- selectedDerivationMode = mode ?? selectedDerivationMode;
- _error = null;
- showCustomKes = false;
- showSetupPage = false;
- selectedCustomKey = null;
-
- try {
- if (selectedDerivationMode == AddressDerivationMode.importedKey) {
- if (customKeys.isEmpty) {
- _error = "empty_custom_key_desc".tr;
- } else {
- showCustomKes = true;
- selectedCustomKey = customKeys.first;
- showSetupPage = true;
- }
- } else {
- showSetupPage = true;
- }
- setState(() {});
- } finally {
- if (showSetupPage) {
- ensureKeyVisible(key: visibleContinue);
- }
- }
- }
-
- List customKeys = [];
- bool _inited = false;
- void _setupIAccount() {
- if (!_inited) {
- _inited = true;
- final model = context.watch(StateIdsConst.main);
- customKeys = model.getNetworkImportedKeys();
- network = model.chain.network;
- }
- }
-
- @override
- void didChangeDependencies() {
- _setupIAccount();
- super.didChangeDependencies();
- }
-
- void onSubmitDerivation() {
- widget.onSelectDerivation(selectedDerivationMode!, selectedCustomKey);
- }
-
- @override
- Widget build(BuildContext context) {
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text("select_derivation_type".tr, style: context.textTheme.titleMedium),
- Text("select_derivation_desc".tr),
- WidgetConstant.height8,
- AppDropDownBottom(
- items: derivationModes,
- onChanged: onChangeDerivationMode,
- label: "derivation_type".tr,
- value: selectedDerivationMode,
- error: _error,
- ),
- WidgetConstant.height20,
- AnimatedSize(
- duration: AppGlobalConst.animationDuraion,
- child: showCustomKes
- ? _SelectCustomKeys(
- existsKeys: customKeys,
- selectedKey: selectedCustomKey,
- onChangeCustomKey: onChangeCustomKey,
- network: network,
- )
- : const SizedBox(),
- ),
- AnimatedSwitcher(
- duration: AppGlobalConst.animationDuraion,
- child: showSetupPage
- ? Row(mainAxisAlignment: MainAxisAlignment.center, children: [
- FixedElevatedButton(
- padding: WidgetConstant.paddingVertical20,
- onPressed: onSubmitDerivation,
- key: visibleContinue,
- child: Text("continue".tr),
- )
- ])
- : const SizedBox(),
- )
- ],
- );
- }
-}
-
-typedef _OnChangeCustomKey = void Function(EncryptedCustomKey?);
-
-class _SelectCustomKeys extends StatelessWidget {
- const _SelectCustomKeys(
- {required this.existsKeys,
- required this.selectedKey,
- required this.onChangeCustomKey,
- required this.network});
- final List existsKeys;
- final EncryptedCustomKey? selectedKey;
- final _OnChangeCustomKey onChangeCustomKey;
- final AppNetworkImpl network;
-
- @override
- Widget build(BuildContext context) {
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text("choose_public_key".tr, style: context.textTheme.titleMedium),
- Text("generate_from_imported_keys".tr),
- Text("select_imported_key_desc".tr),
- WidgetConstant.height8,
- Column(
- children: List.generate(existsKeys.length, (index) {
- return RadioListTile(
- value: existsKeys[index],
- groupValue: selectedKey,
- onChanged: onChangeCustomKey,
- title:
- OneLineTextWidget(existsKeys[index].networkPubKey(network)),
- subtitle: RichText(
- text:
- TextSpan(style: context.textTheme.bodyMedium, children: [
- if (existsKeys[index].name != null) ...[
- TextSpan(text: existsKeys[index].name),
- TextSpan(
- text: " (${existsKeys[index].created.toDateAndTime()}) ",
- style: context.textTheme.bodySmall)
- ] else
- TextSpan(
- text: "imported_at"
- .tr
- .replaceOne(existsKeys[index].created.toString()),
- style: context.textTheme.bodyMedium),
- ])),
- );
- }),
- ),
- ],
- );
- }
-}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_details.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_details.dart
index a7bf1152..a8353aeb 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_details.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/address_details.dart
@@ -15,7 +15,6 @@ class AddressDetailsView extends StatelessWidget {
});
final CryptoAccountAddress address;
-
final bool showBalance;
final Color? color;
@@ -47,7 +46,7 @@ class AddressDetailsView extends StatelessWidget {
context.textTheme.labelLarge?.copyWith(color: color)),
OneLineTextWidget(address.address.toAddress,
style: context.textTheme.bodyMedium?.copyWith(color: color)),
- OneLineTextWidget(address.keyIndex.path.tr,
+ OneLineTextWidget(address.keyIndex.toString(),
style: context.textTheme.bodyMedium?.copyWith(color: color)),
if (showBalance)
CoinPriceView(
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/bip32_derivation.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/bip32_derivation.dart
index a1bfa95d..683b94b6 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/bip32_derivation.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/bip32_derivation.dart
@@ -7,9 +7,17 @@ import 'package:mrt_wallet/models/wallet_models/wallet_models.dart';
class Bip32KeyDerivationView extends StatefulWidget {
const Bip32KeyDerivationView(
- {super.key, required this.coin, required this.curve});
+ {super.key,
+ required this.coin,
+ required this.curve,
+ required this.network,
+ required this.defaultPath,
+ this.seedGeneration = SeedGenerationType.bip39});
final CryptoCoins coin;
final EllipticCurveTypes curve;
+ final SeedGenerationType seedGeneration;
+ final AppNetworkImpl network;
+ final String? defaultPath;
@override
State createState() => _Bip32KeyDerivationViewState();
@@ -17,110 +25,56 @@ class Bip32KeyDerivationView extends StatefulWidget {
class _Bip32KeyDerivationViewState extends State {
final GlobalKey form =
- GlobalKey(debugLabel: "_AddressTypePathSetupState");
- final Map> levelStateKeys = {
- Bip44Levels.purpose: GlobalKey(
- debugLabel: "_AddressTypePathSetupState_1"),
- Bip44Levels.coin: GlobalKey(
- debugLabel: "_AddressTypePathSetupState_2"),
- Bip44Levels.account: GlobalKey(
- debugLabel: "_AddressTypePathSetupState_3"),
- Bip44Levels.change: GlobalKey(
- debugLabel: "_AddressTypePathSetupState_4"),
- Bip44Levels.addressIndex: GlobalKey(
- debugLabel: "_AddressTypePathSetupState_5"),
- };
-
+ GlobalKey(debugLabel: "_Bip32KeyDerivationViewState_form");
+ final GlobalKey pathTextFieldKey =
+ GlobalKey(
+ debugLabel: "_Bip32KeyDerivationViewState_pathTextFieldKey");
late final bool isSupportNoneHardend;
- late final int minIndex;
-
- String? validate(String? v, Bip44Levels level) {
- if (levels[level] == null) {
- return "bip32_key_index_validate".tr;
- }
- return null;
- }
-
- final Map levels = {
- Bip44Levels.purpose: null,
- Bip44Levels.coin: null,
- Bip44Levels.account: null,
- Bip44Levels.change: null,
- Bip44Levels.addressIndex: null,
- };
- void onChangedValue(String? v, Bip44Levels level) {
- if (v == null) return;
- try {
- final index = Bip44LevelsDetails.fromIntIndex(int.parse(v), level);
- if (!index.isHardened && !isSupportNoneHardend) return;
- levels[level] = Bip44LevelsDetails.fromIntIndex(int.parse(v), level);
- } on Exception {
- levels[level] = null;
- } finally {
- path = calculatePath();
- setState(() {});
- }
- }
-
- String? helperText(Bip44Levels level) {
- if (levels[level]?.isHardened ?? false) {
- return "hardened_index"
- .tr
- .replaceOne(levels[level]!.unHardendValue.toString());
- }
- return null;
- }
-
- Color? hardenedColor(Bip44Levels level) {
- return (levels[level]?.isHardened ?? false)
- ? context.theme.iconTheme.color
- : null;
- }
-
- bool isHardened(Bip44Levels level) {
- return (levels[level]?.isHardened ?? false);
- }
void onSubmit() {
if (!(form.currentState?.validate() ?? false)) return;
- final keyIndex = Bip32AddressIndex.fromBip44KeyIndexDetais(
- indexes: levels.values.toList().cast(),
- currencyCoin: widget.coin,
- seedGeneration: SeedGenerationType.bip39);
+ final keyIndex = Bip32AddressIndex.fromPath(
+ path: path,
+ currencyCoin: widget.coin,
+ seedGeneration: widget.seedGeneration,
+ );
context.pop(keyIndex);
}
- void onTapHardened(Bip44Levels level) {
- if (levels[level]?.isHardened ?? true) return;
- stateKey(level)
- .currentState
- ?.changeIndex(Bip32KeyIndex.hardenIndex(levels[level]!.index).index);
- }
+ late String path = widget.defaultPath ?? "";
- GlobalKey stateKey(Bip44Levels level) {
- return levelStateKeys[level]!;
+ @override
+ void initState() {
+ super.initState();
+ isSupportNoneHardend = widget.curve != EllipticCurveTypes.ed25519;
}
- String path = "";
+ void onChangePath(String v) {
+ path = v;
+ }
- String calculatePath() {
- String p = "m";
- for (final i in levels.values) {
- if (i == null) {
- p += "/***";
- } else {
- p += "/${i.path}";
+ String? validator(String? v) {
+ if (path.trim().isEmpty) return null;
+ try {
+ final parse = Bip32PathParser.parse(path);
+ if (parse.elems.isEmpty) return null;
+ if (!isSupportNoneHardend &&
+ parse.elems.any((element) => !element.isHardened)) {
+ return "ed25519_support_derivation_desc".tr;
+ }
+ if (parse.elems.length > BlockchainConstant.maxBip32LevelIndex) {
+ throw WalletException("hd_wallet_path_max_indeqxes"
+ .tr
+ .replaceOne(BlockchainConstant.maxBip32LevelIndex.toString()));
}
+ } catch (e) {
+ return "invalid_hd_wallet_derivation_path".tr;
}
- return p;
+ return null;
}
- @override
- void initState() {
- super.initState();
- isSupportNoneHardend = widget.curve != EllipticCurveTypes.ed25519;
- minIndex =
- isSupportNoneHardend ? 0 : Bip32KeyDataConst.hardenKeyIndexMinValue;
+ void onPaste(String v) {
+ pathTextFieldKey.currentState?.updateText(v);
}
@override
@@ -144,106 +98,17 @@ class _Bip32KeyDerivationViewState extends State {
])
],
)),
- PageTitleSubtitle(
- title: "choose_index_each_level".tr,
- body: Text("bip32_level_desc".tr)),
- Text("path".tr, style: context.textTheme.titleMedium),
+ Text("derivation_path".tr, style: context.textTheme.titleMedium),
+ Text("hd_wallet_hardened_desc".tr),
WidgetConstant.height8,
- ContainerWithBorder(
- child: Text(
- path,
- style: context.textTheme.bodyLarge,
- )),
- WidgetConstant.height20,
- NumberTextField(
- label: "p_level".tr,
- max: Bip32KeyDataConst.keyIndexMaxVal,
- defaultValue: widget.coin.proposal.purpose.index,
- helperText: helperText(Bip44Levels.purpose),
- suffixIcon: _HardenIconView(
- isHarden: (level) => isHardened(level),
- level: Bip44Levels.purpose,
- onTap: (level) => onTapHardened(level),
- ),
- key: stateKey(Bip44Levels.purpose),
- min: minIndex,
- onChange: (v) {
- onChangedValue(v, Bip44Levels.purpose);
- },
- validator: (v) => validate(v, Bip44Levels.purpose),
- ),
- Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Expanded(
- child: NumberTextField(
- label: "c_level".tr,
- max: Bip32KeyDataConst.keyIndexMaxVal,
- helperText: helperText(Bip44Levels.coin),
- key: stateKey(Bip44Levels.coin),
- defaultValue:
- Bip32KeyIndex.hardenIndex(widget.coin.conf.coinIdx).index,
- suffixIcon: _HardenIconView(
- isHarden: (level) => isHardened(level),
- level: Bip44Levels.coin,
- onTap: (level) => onTapHardened(level),
- ),
- min: minIndex,
- onChange: (v) {
- onChangedValue(v, Bip44Levels.coin);
- },
- validator: (v) => validate(v, Bip44Levels.coin),
- ),
- ),
- ],
- ),
- NumberTextField(
- label: "a_level".tr,
- max: Bip32KeyDataConst.keyIndexMaxVal,
- helperText: helperText(Bip44Levels.account),
- key: stateKey(Bip44Levels.account),
- min: minIndex,
- onChange: (v) {
- onChangedValue(v, Bip44Levels.account);
- },
- validator: (v) => validate(v, Bip44Levels.account),
- suffixIcon: _HardenIconView(
- isHarden: (level) => isHardened(level),
- level: Bip44Levels.account,
- onTap: (level) => onTapHardened(level),
- ),
- ),
- NumberTextField(
- label: "change_level".tr,
- max: Bip32KeyDataConst.keyIndexMaxVal,
- helperText: helperText(Bip44Levels.change),
- key: stateKey(Bip44Levels.change),
- suffixIcon: _HardenIconView(
- isHarden: (level) => isHardened(level),
- level: Bip44Levels.change,
- onTap: (level) => onTapHardened(level),
- ),
- min: minIndex,
- onChange: (v) {
- onChangedValue(v, Bip44Levels.change);
- },
- validator: (v) => validate(v, Bip44Levels.change),
- ),
- NumberTextField(
- label: "address_index".tr,
- max: Bip32KeyDataConst.keyIndexMaxVal,
- helperText: helperText(Bip44Levels.addressIndex),
- key: stateKey(Bip44Levels.addressIndex),
- suffixIcon: _HardenIconView(
- isHarden: (level) => isHardened(level),
- level: Bip44Levels.addressIndex,
- onTap: (level) => onTapHardened(level),
- ),
- min: minIndex,
- onChange: (v) {
- onChangedValue(v, Bip44Levels.addressIndex);
- },
- validator: (v) => validate(v, Bip44Levels.addressIndex),
+ AppTextField(
+ onChanged: onChangePath,
+ initialValue: path,
+ suffixIcon: PasteTextIcon(onPaste: onPaste),
+ validator: validator,
+ key: pathTextFieldKey,
+ label: "derivation_path".tr,
+ hint: "derivation_path".tr,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
@@ -260,33 +125,3 @@ class _Bip32KeyDerivationViewState extends State {
);
}
}
-
-typedef _IsHarden = bool Function(Bip44Levels);
-typedef _OnTapLevel = void Function(Bip44Levels);
-
-class _HardenIconView extends StatelessWidget {
- const _HardenIconView(
- {required this.level, required this.isHarden, required this.onTap});
- final Bip44Levels level;
- final _IsHarden isHarden;
- final _OnTapLevel onTap;
- @override
- Widget build(BuildContext context) {
- return InkWell(
- borderRadius: WidgetConstant.border8,
- onTap: () => onTap(level),
- child: IgnorePointer(
- ignoring: true,
- child: Padding(
- padding: WidgetConstant.padding5,
- child: Column(
- children: [
- Text("harden".tr, style: context.textTheme.bodySmall),
- Checkbox(value: isHarden(level), onChanged: (v) {})
- ],
- ),
- ),
- ),
- );
- }
-}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/byron_legacy_derivation.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/byron_legacy_derivation.dart
index 5798357b..7c710102 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/byron_legacy_derivation.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/byron_legacy_derivation.dart
@@ -76,10 +76,11 @@ class _ByronLegacyKeyDerivationViewState
void onSubmit() {
if (!(form.currentState?.validate() ?? false)) return;
- final keyIndex = ByronLegacyAddressIndex(
- firstIndex: levels[Bip44Levels.change]!.index,
- secondIndex: levels[Bip44Levels.addressIndex]!.index,
- currencyCoin: widget.coin);
+ final keyIndex = Bip32AddressIndex.byronLegacy(
+ firstIndex: levels[Bip44Levels.change]!.index,
+ secoundIndex: levels[Bip44Levels.addressIndex]!.index,
+ currencyCoin: widget.coin,
+ );
context.pop(keyIndex);
}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/receipt_address_view.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/receipt_address_view.dart
index 7e4ef675..2c7c6b58 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/receipt_address_view.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/receipt_address_view.dart
@@ -12,13 +12,15 @@ class ReceiptAddressView extends StatelessWidget {
super.key,
this.subtitle,
this.validate,
- this.onEditIcon});
+ this.onEditIcon,
+ this.onTapWhenOnRemove = true});
final ReceiptAddress? address;
final DynamicVoid? onTap;
final String? title;
final String? subtitle;
final bool? validate;
final Icon? onEditIcon;
+ final bool onTapWhenOnRemove;
@override
Widget build(BuildContext context) {
return Column(
@@ -33,6 +35,7 @@ class ReceiptAddressView extends StatelessWidget {
ContainerWithBorder(
validate: validate ?? (address != null),
onRemove: onTap,
+ onTapWhenOnRemove: onTapWhenOnRemove,
onRemoveIcon: address == null
? const Icon(Icons.add)
: onEditIcon ?? const Icon(Icons.edit),
@@ -61,7 +64,7 @@ class ReceiptAddressDetailsView extends StatelessWidget {
Text(address.contact!.name,
style: context.textTheme.labelSmall?.copyWith(color: color))
else if (address.isAccount)
- Text(address.account!.keyIndex.path.tr,
+ Text(address.account!.keyIndex.toString(),
style: context.textTheme.labelSmall?.copyWith(color: color)),
OneLineTextWidget(
address.view,
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/select_account_or_contact.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/select_account_or_contact.dart
index e27874bf..92544774 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/select_account_or_contact.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/select_account_or_contact.dart
@@ -16,10 +16,12 @@ class SelectRecipientAccountView extends StatefulWidget {
{super.key,
required this.account,
required this.scrollController,
- this.subtitle});
+ this.subtitle,
+ this.multipleSelect = true});
final NetworkAccountCore account;
final ScrollController scrollController;
final Widget? subtitle;
+ final bool multipleSelect;
@override
State createState() =>
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/wallet_global_pages.dart b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/wallet_global_pages.dart
index 069bca25..24d1ad2e 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/global_pages/wallet_global_pages.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/global_pages/wallet_global_pages.dart
@@ -7,7 +7,6 @@ export 'switch_network.dart';
export 'wallet_signing_password.dart';
export 'select_provider.dart';
export 'add_to_contact_list.dart';
-export 'address_derivation_type.dart';
export 'bip32_derivation.dart';
export 'receipt_address_view.dart';
export 'select_account_or_contact.dart';
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 714eb830..3806cb17 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
@@ -186,7 +186,7 @@ class _WalletSigningPasswordState extends State
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- _KeyIndexDetails(keyIndex: keyIndex),
+ _HDWalletDerivationDetails(keyIndex: keyIndex),
if (!isLastIndex)
Divider(
color: context.colors.onPrimaryContainer)
@@ -227,40 +227,6 @@ class _WalletSigningPasswordState extends State
}
}
-class _KeyIndexDetails extends StatelessWidget {
- const _KeyIndexDetails({required this.keyIndex});
- final AddressDerivationIndex keyIndex;
- @override
- Widget build(BuildContext context) {
- switch (keyIndex.runtimeType) {
- case ImportedAddressIndex:
- return _ImportedKeyDerivationDetails(
- keyIndex: keyIndex as ImportedAddressIndex);
- default:
- return _HDWalletDerivationDetails(keyIndex: keyIndex);
- }
- }
-}
-
-class _ImportedKeyDerivationDetails extends StatelessWidget {
- const _ImportedKeyDerivationDetails({required this.keyIndex});
- final ImportedAddressIndex keyIndex;
- @override
- Widget build(BuildContext context) {
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text("imported".tr, style: context.textTheme.labelLarge),
- Text(keyIndex.accountId),
- if (keyIndex.bip32KeyIndex != null) ...[
- Text(keyIndex.bip32KeyIndex!.toString(),
- style: context.textTheme.bodySmall)
- ]
- ],
- );
- }
-}
-
class _HDWalletDerivationDetails extends StatelessWidget {
const _HDWalletDerivationDetails({required this.keyIndex});
final AddressDerivationIndex keyIndex;
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 c3c9d288..b5a1d566 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
@@ -1,14 +1,13 @@
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:blockchain_utils/bip/bip/conf/bip_coins.dart';
-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/start_page/home.dart';
+import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/address_derivation/setup_address_derivation_mode.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/types/typedef.dart';
class SetupBitcoinAddressView extends StatefulWidget {
@@ -25,39 +24,11 @@ class _SetupBitcoinAddressViewState extends State
GlobalKey(debugLabel: "SetupBitcoinAddressView");
late final AppChain chainAccount;
final GlobalKey visibleGenerateAddress =
- GlobalKey(debugLabel: "visibleContinue");
-
- AddressDerivationMode? selectedDerivationMode;
- EncryptedCustomKey? selectedCustomKey;
- bool inAddressPage = false;
-
- void goToAddressPage(
- AddressDerivationMode derivationMode, EncryptedCustomKey? customKey) {
- if (derivationMode == AddressDerivationMode.importedKey &&
- customKey == null) return;
- selectedDerivationMode = derivationMode;
- selectedCustomKey = customKey;
- inAddressPage = true;
- setState(() {});
- ensureKeyVisible(key: visibleGenerateAddress);
- }
-
- void _onBackButton() {
- if (pageProgressKey.isSuccess) return;
- if (inAddressPage) {
- selectedDerivationMode = null;
- selectedCustomKey = null;
- inAddressPage = false;
- p2shType = _defaultP2sh();
- customKeyIndex = null;
- }
- setState(() {});
- }
+ GlobalKey(debugLabel: "_SetupBitcoinAddressViewState_visibleContinue");
AppBitcoinNetwork get network => chainAccount.network as AppBitcoinNetwork;
List get coins => network.coins;
bool inited = false;
- Bip32AddressIndex? customKeyIndex;
late final List p2shTypes;
late final List p2pkhTypes;
late final List supportAddressTypes;
@@ -114,23 +85,11 @@ class _SetupBitcoinAddressViewState extends State
selected = value;
p2shType = _defaultP2sh();
p2pkhType = P2pkhAddressType.p2pkh;
- customKeyIndex = null;
setState(() {});
}
- bool get derivationStandard => customKeyIndex == null;
late P2shAddressType p2shType;
P2pkhAddressType p2pkhType = P2pkhAddressType.p2pkh;
- void onChangeDerivation(bool? val, DynamicVoid onFalse) {
- if (val == null) return;
- if (derivationStandard) {
- onFalse();
- return;
- } else {
- customKeyIndex = null;
- setState(() {});
- }
- }
void onChageSegwit(P2shAddressType? val) {
if (!p2shTypes.contains(val)) return;
@@ -144,34 +103,7 @@ class _SetupBitcoinAddressViewState extends State
setState(() {});
}
- void setupKeyIndex(Bip32AddressIndex? newKeyIndex) {
- customKeyIndex = newKeyIndex;
- setState(() {});
- }
-
- @override
- void didChangeDependencies() {
- _setupIAccount();
- super.didChangeDependencies();
- }
-
- AddressDerivationIndex? derivationkey(CryptoCoins coin) {
- if (selectedCustomKey != null) {
- return ImportedAddressIndex(
- accountId: selectedCustomKey!.id,
- bip32KeyIndex: customKeyIndex,
- currencyCoin: coin);
- }
- return customKeyIndex;
- }
-
- AddressDerivationIndex get standardDerivation {
- final coin = findCoin();
- return chainAccount.account.nextDrive(coin);
- }
-
void generateAddress() async {
- pageProgressKey.progressText("generating_new_addr".tr);
final wallet = context.watch(StateIdsConst.main);
final coin = findCoin();
BitcoinAddressType selectedType;
@@ -182,15 +114,22 @@ class _SetupBitcoinAddressViewState extends State
} else {
selectedType = selected.first;
}
- final keyIndex =
- derivationkey(coin) ?? chainAccount.account.nextDrive(coin);
+
+ final keyIndex = await context.openSliverBottomSheet(
+ "setup_derivation".tr,
+ child: SetupDerivationModeView(
+ coin: coin,
+ chainAccout: chainAccount,
+ ));
+ if (keyIndex == null) return;
+ pageProgressKey.progressText("generating_new_addr".tr);
NewAccountParams newAccount;
if (network is AppBitcoinCashNetwork) {
newAccount = BitcoinCashNewAddressParams(
- coin: coin, deriveIndex: keyIndex, bitcoinAddressType: selectedType);
+ deriveIndex: keyIndex, bitcoinAddressType: selectedType);
} else {
newAccount = BitcoinNewAddressParams(
- coin: coin, deriveIndex: keyIndex, bitcoinAddressType: selectedType);
+ deriveIndex: keyIndex, bitcoinAddressType: selectedType);
}
final result = await wallet.deriveNewAccount(newAccount);
@@ -215,95 +154,66 @@ class _SetupBitcoinAddressViewState extends State
setState(() {});
}
+ @override
+ void didChangeDependencies() {
+ _setupIAccount();
+ super.didChangeDependencies();
+ }
+
@override
Widget build(BuildContext context) {
- return PopScope(
- canPop: !inAddressPage || pageProgressKey.isSuccess,
- onPopInvoked: (didPop) {
- if (!didPop) {
- _onBackButton();
- }
- },
- child: Scaffold(
- appBar: AppBar(
- title: Text("setup_address".tr),
- ),
- body: PageProgress(
- key: pageProgressKey,
- backToIdle: AppGlobalConst.oneSecoundDuration,
- initialStatus: PageProgressStatus.idle,
- child: () => UnfocusableChild(
- child: Center(
- child: CustomScrollView(
- shrinkWrap: true,
- slivers: [
- SliverToBoxAdapter(
- child: ConstraintsBoxView(
- padding: WidgetConstant.paddingHorizontal20,
- child: AnimatedSwitcher(
- duration: AppGlobalConst.animationDuraion,
- child: inAddressPage
- ? Column(
- key: const ValueKey(true),
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- _DriveFromHdWallet(
- customKeyIndex: customKeyIndex,
- onVisibleGenerateAddress:
- visibleGenerateAddress,
- nextStandartIndex: standardDerivation,
- onChangeDeravation: (p0) {
- onChangeDerivation(
- p0,
- () {
- context
- .openSliverBottomSheet<
- Bip32AddressIndex>(
- "key_derivation".tr,
- child: Bip32KeyDerivationView(
- coin: findCoin(),
- curve: EllipticCurveTypes
- .secp256k1))
- .then(setupKeyIndex);
- },
- );
- },
- derivationStandard: derivationStandard,
- typesToSelect: typesToSelect,
- generateAddress: generateAddress,
- p2shTypes: p2shTypes,
- p2pkhTypes: p2pkhTypes,
- onChageSegwit: onChageSegwit,
- onChangeSelected: onChangeSelected,
- selected: selected,
- selectedP2shType: p2shType,
- customKey: selectedCustomKey,
- onChangeP2pkh: onChangeP2pkh,
- selectedP2pkhType: p2pkhType,
- ),
- ],
- )
- : Column(
- children: [
- WidgetConstant.height20,
- PageTitleSubtitle(
- title: "derive_network_address"
- .tr
- .replaceOne(network.coinParam.token.name),
- body: LargeTextView([
- "bip44_desc".tr,
- "bip49_desc".tr,
- if (isSupportSegwit) "bip84_desc".tr,
- if (isSupportP2tr) "bip86_desc".tr
- ]),
- ),
- SetupAddressDerivation(goToAddressPage)
- ],
- ),
- ),
- ))
- ],
- ),
+ return Scaffold(
+ appBar: AppBar(
+ title: Text("setup_address".tr),
+ ),
+ body: PageProgress(
+ key: pageProgressKey,
+ backToIdle: AppGlobalConst.oneSecoundDuration,
+ initialStatus: PageProgressStatus.idle,
+ child: () => UnfocusableChild(
+ child: Center(
+ child: CustomScrollView(
+ shrinkWrap: true,
+ slivers: [
+ SliverToBoxAdapter(
+ child: ConstraintsBoxView(
+ padding: WidgetConstant.paddingHorizontal20,
+ child: Column(
+ key: const ValueKey(true),
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ PageTitleSubtitle(
+ title: "setup_network_address"
+ .tr
+ .replaceOne(network.coinParam.token.name),
+ body: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text("disable_standard_derivation".tr),
+ WidgetConstant.height8,
+ Text("setup_address_derivation_keys_desc".tr),
+ WidgetConstant.height8,
+ Text("please_following_steps_to_generate_address"
+ .tr),
+ ],
+ )),
+ _DriveFromHdWallet(
+ onVisibleGenerateAddress: visibleGenerateAddress,
+ typesToSelect: typesToSelect,
+ generateAddress: generateAddress,
+ p2shTypes: p2shTypes,
+ p2pkhTypes: p2pkhTypes,
+ onChageSegwit: onChageSegwit,
+ onChangeSelected: onChangeSelected,
+ selected: selected,
+ selectedP2shType: p2shType,
+ onChangeP2pkh: onChangeP2pkh,
+ selectedP2pkhType: p2pkhType,
+ ),
+ ],
+ ),
+ ))
+ ],
),
),
),
@@ -315,35 +225,27 @@ class _SetupBitcoinAddressViewState extends State
class _DriveFromHdWallet extends StatelessWidget {
const _DriveFromHdWallet(
{required this.selected,
- required this.customKeyIndex,
- required this.onChangeDeravation,
required this.generateAddress,
- required this.derivationStandard,
required this.p2shTypes,
required this.onChageSegwit,
required this.onChangeSelected,
required this.selectedP2shType,
required this.onVisibleGenerateAddress,
required this.typesToSelect,
- required this.nextStandartIndex,
+ // required this.nextStandartIndex,
required this.p2pkhTypes,
required this.onChangeP2pkh,
- required this.selectedP2pkhType,
- this.customKey});
- final AddressDerivationIndex nextStandartIndex;
- final AddressDerivationIndex? customKeyIndex;
+ required this.selectedP2pkhType});
+
final Set selected;
final _OnChangeP2shType onChageSegwit;
final DynamicVoid generateAddress;
final VoidSetT onChangeSelected;
- final bool derivationStandard;
final List p2shTypes;
final List p2pkhTypes;
final P2shAddressType selectedP2shType;
final P2pkhAddressType selectedP2pkhType;
final _OnChangeP2pkhTypes onChangeP2pkh;
- final NullBoolVoid onChangeDeravation;
- final EncryptedCustomKey? customKey;
final GlobalKey onVisibleGenerateAddress;
final Map typesToSelect;
@@ -356,67 +258,34 @@ class _DriveFromHdWallet extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- PageTitleSubtitle(
- title: "choose_bitcoin_address_type".tr,
- body: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text("choose_bitcoin_address_type_desc".tr),
- WidgetConstant.height8,
- if (supportP2trOrSegwit) Text("bitcoin_type_recomended".tr),
- WidgetConstant.height8,
- if (customKey != null) ...[
- Text("generate_from_imported_keys".tr),
- WidgetConstant.height8,
- Text("generate_from_imported_key_desc1".tr)
- ] else ...[
- Text("generate_from_hd_wallet".tr),
- ]
- ],
- )),
- AppSwitchListTile(
- value: derivationStandard,
- onChanged: onChangeDeravation,
- title: customKey == null
- ? Text(derivationStandard
- ? "standard_derivation".tr
- : "custom_derivation".tr)
- : Text(customKeyIndex == null
- ? "non_derivation".tr
- : "custom_derivation".tr),
- subtitle: customKey == null
- ? Text(customKeyIndex?.path ?? nextStandartIndex.path)
- : Text(customKeyIndex?.path ?? "import_key_derivation_desc2".tr),
- ),
+ Text("choose_bitcoin_address_type".tr,
+ style: context.textTheme.titleMedium),
+ Text("bitcoin_type_recomended".tr),
WidgetConstant.height8,
- SizedBox(
- width: context.mediaQuery.size.width,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- AppSegmentedButton(
- items: typesToSelect,
- onChangeSelected: onChangeSelected,
- selected: selected),
- WidgetConstant.height20,
- _AddressTypeOPtion(
- select: selected.first,
- deriveStandard: derivationStandard,
- p2shTypes: p2shTypes,
- selectedP2shType: selectedP2shType,
- onChangeP2shSegwit: onChageSegwit,
- p2pkhTypes: p2pkhTypes,
- onChangeP2pkhAddress: onChangeP2pkh,
- selectP2pkhType: selectedP2pkhType,
- ),
- FixedElevatedButton(
- padding: WidgetConstant.paddingVertical20,
- onPressed: generateAddress,
- key: onVisibleGenerateAddress,
- child: Text("generate_address".tr),
- )
- ],
- ),
+ AppSegmentedButton(
+ items: typesToSelect,
+ onChangeSelected: onChangeSelected,
+ selected: selected),
+ WidgetConstant.height20,
+ _AddressTypeOPtion(
+ select: selected.first,
+ p2shTypes: p2shTypes,
+ selectedP2shType: selectedP2shType,
+ onChangeP2shSegwit: onChageSegwit,
+ p2pkhTypes: p2pkhTypes,
+ onChangeP2pkhAddress: onChangeP2pkh,
+ selectP2pkhType: selectedP2pkhType,
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ FixedElevatedButton(
+ padding: WidgetConstant.paddingVertical20,
+ onPressed: generateAddress,
+ key: onVisibleGenerateAddress,
+ child: Text("setup_derivation".tr),
+ ),
+ ],
)
],
);
@@ -430,7 +299,6 @@ class _AddressTypeOPtion extends StatelessWidget {
const _AddressTypeOPtion(
{required this.select,
required this.p2pkhTypes,
- required this.deriveStandard,
required this.selectedP2shType,
required this.onChangeP2shSegwit,
required this.p2shTypes,
@@ -439,7 +307,6 @@ class _AddressTypeOPtion extends StatelessWidget {
final List p2shTypes;
final List p2pkhTypes;
final BitcoinAddressType select;
- final bool deriveStandard;
final P2shAddressType selectedP2shType;
final P2pkhAddressType selectP2pkhType;
final _OnChangeP2shType onChangeP2shSegwit;
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
new file mode 100644
index 00000000..96419b69
--- /dev/null
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/account_page.dart
@@ -0,0 +1,57 @@
+import 'package:flutter/material.dart';
+import 'package:mrt_wallet/app/core.dart';
+import 'package:mrt_wallet/future/widgets/custom_widgets.dart';
+import 'package:mrt_wallet/models/wallet_models/address/network_address/cardano/cardano.dart';
+import 'package:mrt_wallet/models/wallet_models/wallet_models.dart';
+import 'package:on_chain/on_chain.dart';
+
+class CardanoAccountPage extends StatelessWidget {
+ const CardanoAccountPage({required this.chainAccount, super.key});
+ final AppChain chainAccount;
+ @override
+ Widget build(BuildContext context) {
+ return TabBarView(children: [
+ _CardanoAccountPage(
+ chainAccount: chainAccount.account.address as ICardanoAddress),
+ ]);
+ }
+}
+
+class _CardanoAccountPage extends StatelessWidget {
+ const _CardanoAccountPage({required this.chainAccount});
+ final ICardanoAddress chainAccount;
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [_ShowRewardAddress(chainAccount: chainAccount)],
+ );
+ }
+}
+
+class _ShowRewardAddress extends StatelessWidget {
+ const _ShowRewardAddress({required this.chainAccount});
+ final ICardanoAddress chainAccount;
+ @override
+ Widget build(BuildContext context) {
+ final ADARewardAddress? rewardAddress = chainAccount.rewardAddress;
+ if (rewardAddress == null) return WidgetConstant.sizedBox;
+
+ return ContainerWithBorder(
+ onRemove: () {},
+ onTapWhenOnRemove: false,
+ onRemoveWidget: CopyTextIcon(dataToCopy: rewardAddress.address),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(rewardAddress.addressType.name,
+ style: context.textTheme.labelLarge),
+ Text(
+ rewardAddress.address,
+ maxLines: 1,
+ ),
+ ],
+ ),
+ );
+ }
+}
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 52b3992e..c944338f 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
@@ -3,17 +3,25 @@ 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/start_page/home.dart';
-import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/byron_legacy_derivation.dart';
+import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/address_derivation/setup_address_derivation_mode.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/types/typedef.dart';
-typedef _OnChangeDerivation = void Function(bool? val, DynamicVoid onFalse);
-typedef _SetupKeyIndex = void Function(AddressDerivationIndex? newKeyIndex);
typedef _OnChangeShellyAddrType = void Function(ADAAddressType? addrType);
+enum _Bip32DerivationMode {
+ customDerivation("custom_derivation"),
+ standardDerivation("standard_derivation");
+
+ const _Bip32DerivationMode(this.viewName);
+ final String viewName;
+ bool get isStandard => this == _Bip32DerivationMode.standardDerivation;
+ bool get isCustom => this == _Bip32DerivationMode.customDerivation;
+}
+
enum _AdaEra {
shelly("shelly"),
byron("byron");
@@ -21,6 +29,48 @@ enum _AdaEra {
final String name;
const _AdaEra(this.name);
bool get isShelly => this == _AdaEra.shelly;
+ CryptoCoins getRelatedIcarusCardanoCoin(APPCardanoNetwork network) {
+ if (isShelly) {
+ if (network.coinParam.mainnet) {
+ return Cip1852Coins.cardanoIcarus;
+ } else {
+ return Cip1852Coins.cardanoIcarusTestnet;
+ }
+ } else {
+ if (network.coinParam.mainnet) {
+ return Bip44Coins.cardanoByronIcarus;
+ } else {
+ return Bip44Coins.cardanoByronIcarusTestnet;
+ }
+ }
+ }
+
+ CryptoCoins getRelatedLedgerCardanoCoin(APPCardanoNetwork network) {
+ if (isShelly) {
+ if (network.coinParam.mainnet) {
+ return Cip1852Coins.cardanoLedger;
+ } else {
+ return Cip1852Coins.cardanoLedgerTestnet;
+ }
+ } else {
+ if (network.coinParam.mainnet) {
+ return Bip44Coins.cardanoByronLedger;
+ } else {
+ return Bip44Coins.cardanoByronLedgerTestnet;
+ }
+ }
+ }
+
+ CryptoCoins getRelatedByronLegacy(APPCardanoNetwork network) {
+ if (isShelly) {
+ throw WalletException.invalidArgruments(["byron", "shelly"]);
+ }
+ if (network.coinParam.mainnet) {
+ return CustomCoins.byronLegacy;
+ } else {
+ return CustomCoins.byronLegacyTestnet;
+ }
+ }
}
enum _CardanoMasterKeyGenerationType {
@@ -40,7 +90,6 @@ enum _GenerateAddressPage {
generateAddress
}
-/// add testnet coin
class SetupCardanoAddressView extends StatefulWidget {
const SetupCardanoAddressView({super.key});
@@ -53,32 +102,81 @@ class _SetupCardanoAddressViewState extends State
with SafeState {
final GlobalKey pageProgressKey =
GlobalKey(debugLabel: "SetupEthereumAddressView");
- final GlobalKey form = GlobalKey();
- late final AppChain chainAccount;
- AddressDerivationIndex get standardDerivation {
- return chainAccount.account.nextDrive(coin,
- masterKeyGeneration:
- keyGenerationType == _CardanoMasterKeyGenerationType.byronLegacy
- ? SeedGenerationType.byronLegacySeed
- : SeedGenerationType.bip39,
- seedGeneration: seedGenerationType);
- }
-
- NetworkAccountCore get networkAccounts => chainAccount.account;
final GlobalKey visibleGenerateAddress =
GlobalKey(debugLabel: "visibleContinue");
final GlobalKey visibleXAddressDetails =
GlobalKey(debugLabel: "visibleContinue");
- AddressDerivationMode? selectedDerivationMode;
- EncryptedCustomKey? selectedCustomKey;
+ final GlobalKey form = GlobalKey();
+ final GlobalKey hdPathKeyKey =
+ GlobalKey(debugLabel: "hdPathKey");
+ final GlobalKey hdPathKey =
+ GlobalKey(debugLabel: "hdPath");
+
+ late final AppChain chainAccount;
+ NetworkAccountCore get networkAccounts => chainAccount.account;
+ APPCardanoNetwork get network => networkAccounts.network as APPCardanoNetwork;
+ List get coins => network.coins;
+ late CryptoCoins coin = coins.first;
+
+ bool inited = false;
+
_AdaEra era = _AdaEra.shelly;
_GenerateAddressPage page = _GenerateAddressPage.seedGeneration;
- bool byronLegacy = false;
- void changeByronLegacy(bool? change) {
- byronLegacy = !byronLegacy;
+ _CardanoMasterKeyGenerationType keyGenerationType =
+ _CardanoMasterKeyGenerationType.icarus;
+ SeedGenerationType seedGenerationType = SeedGenerationType.icarus;
+
+ ADAAddressType addrType = ADAAddressType.base;
+
+ String? manuallyHdPath;
+ String? manuallyHdPathKey;
+ bool manuallySetLegacyHdPathKey = false;
+
+ void onChangeManuallySetHdPathKey() {
+ manuallySetLegacyHdPathKey = !manuallySetLegacyHdPathKey;
+ if (!manuallySetLegacyHdPathKey) {
+ manuallyHdPath = null;
+ manuallyHdPathKey = null;
+ }
setState(() {});
}
+ void onChageHdPath(String path) {
+ manuallyHdPath = path;
+ }
+
+ void onChangeHdPathKey(String v) {
+ manuallyHdPathKey = v;
+ }
+
+ String? onValidateHdPath(String? v) {
+ try {
+ final parse = Bip32PathParser.parse(manuallyHdPath!);
+ if (parse.elems.length !=
+ BlockchainConstant.maxByronLegacyBip32LevelIndex) {
+ return "byron_legacy_hd_wallet_length_desc".tr;
+ }
+ } catch (e) {
+ return "invalid_byron_legacy_hd_path_key".tr;
+ }
+ return null;
+ }
+
+ String? onValidateHdPathKey(String? v) {
+ try {
+ final inBytes = BytesUtils.tryFromHexString(manuallyHdPathKey);
+ if (inBytes == null) {
+ return "byron_legacy_hd_path_key_desc".tr;
+ }
+ if (inBytes.length != CardanoUtils.byronAddressHdPathKeyLengthBytes) {
+ return "byron_legacy_hd_path_key_length_desc".tr;
+ }
+ } catch (e) {
+ return "byron_legacy_hd_path_key_desc".tr;
+ }
+ return null;
+ }
+
void onChangeEra(_AdaEra? e) {
era = e ?? era;
setState(() {});
@@ -100,59 +198,40 @@ class _SetupCardanoAddressViewState extends State
setState(() {});
}
- _CardanoMasterKeyGenerationType keyGenerationType =
- _CardanoMasterKeyGenerationType.icarus;
- void onChangeMasterKeyGeneration(_CardanoMasterKeyGenerationType? e) {
- keyGenerationType = e ?? keyGenerationType;
+ bool get showLegacy =>
+ !era.isShelly &&
+ (seedGenerationType == SeedGenerationType.byronLegacySeed ||
+ seedGenerationType == SeedGenerationType.none);
+ void onChangeMasterKeyGeneration(
+ _CardanoMasterKeyGenerationType? masterKeyGeneration) {
+ if (masterKeyGeneration == null) return;
+ if (era.isShelly && masterKeyGeneration.isLegacy) return;
+ keyGenerationType = masterKeyGeneration;
setState(() {});
}
- SeedGenerationType seedGenerationType = SeedGenerationType.icarus;
- void onChangeSeedGeneration(SeedGenerationType? e) {
- if (e == SeedGenerationType.bip39) return;
- seedGenerationType = e ?? seedGenerationType;
+ void onChangeSeedGeneration(SeedGenerationType? seedType) {
+ if (seedType == SeedGenerationType.bip39) return;
+ seedGenerationType = seedType ?? seedGenerationType;
setState(() {});
}
void onContinueFromMasterkeyGeneration() {
- page = _GenerateAddressPage.generateAddress;
switch (keyGenerationType) {
case _CardanoMasterKeyGenerationType.icarus:
- if (era.isShelly) {
- if (network.coinParam.mainnet) {
- coin = Cip1852Coins.cardanoIcarus;
- } else {
- coin = Cip1852Coins.cardanoIcarusTestnet;
- }
- } else {
- if (network.coinParam.mainnet) {
- coin = Bip44Coins.cardanoByronIcarus;
- } else {
- coin = Bip44Coins.cardanoByronIcarusTestnet;
- }
- }
+ coin = era.getRelatedIcarusCardanoCoin(network);
+ break;
+ case _CardanoMasterKeyGenerationType.byronLegacy:
+ coin = era.getRelatedByronLegacy(network);
break;
default:
- if (era.isShelly) {
- if (network.coinParam.mainnet) {
- coin = Cip1852Coins.cardanoLedger;
- } else {
- coin = Cip1852Coins.cardanoLedgerTestnet;
- }
- } else {
- if (network.coinParam.mainnet) {
- coin = Bip44Coins.cardanoByronLedger;
- } else {
- coin = Bip44Coins.cardanoByronLedgerTestnet;
- }
- }
+ coin = era.getRelatedLedgerCardanoCoin(network);
break;
}
+ page = _GenerateAddressPage.generateAddress;
setState(() {});
}
- ADAAddressType addrType = ADAAddressType.base;
-
void onChangeShellyddrType(ADAAddressType? type) {
if (type == null) return;
if (era == _AdaEra.byron) return;
@@ -161,109 +240,98 @@ class _SetupCardanoAddressViewState extends State
setState(() {});
}
- bool inAddressPage = false;
-
- void goToAddressPage(
- AddressDerivationMode derivationMode, EncryptedCustomKey? customKey) {
- if (derivationMode == AddressDerivationMode.importedKey &&
- customKey == null) return;
- selectedDerivationMode = derivationMode;
- selectedCustomKey = customKey;
- inAddressPage = true;
- setState(() {});
- ensureKeyVisible(key: visibleGenerateAddress);
- }
-
- void _onBackButton() {
- if (pageProgressKey.isSuccess) return;
- if (inAddressPage) {
- selectedDerivationMode = null;
- selectedCustomKey = null;
- inAddressPage = false;
- customKeyIndex = null;
- page = _GenerateAddressPage.seedGeneration;
- keyGenerationType = _CardanoMasterKeyGenerationType.icarus;
- addrType = ADAAddressType.base;
- era = _AdaEra.shelly;
- }
- setState(() {});
- }
-
- APPCardanoNetwork get network => networkAccounts.network as APPCardanoNetwork;
- List get coins => network.coins;
- late CryptoCoins coin = coins.firstWhere((element) =>
- element.conf.type ==
- (selectedCustomKey?.type ?? EllipticCurveTypes.ed25519Kholaw));
- bool inited = false;
- AddressDerivationIndex? customKeyIndex;
-
void _setupIAccount() {
if (inited) return;
final model = context.watch(StateIdsConst.main);
chainAccount = model.chain;
}
- bool get derivationStandard => customKeyIndex == null;
- void onChangeDerivation(bool? val, DynamicVoid onFalse) {
- if (val == null) return;
- if (derivationStandard) {
- onFalse();
- return;
- } else {
- customKeyIndex = null;
- setState(() {});
- }
- }
-
- void setupKeyIndex(AddressDerivationIndex? newKeyIndex) {
- customKeyIndex = newKeyIndex;
- setState(() {});
- }
-
- @override
- void didChangeDependencies() {
- _setupIAccount();
- super.didChangeDependencies();
- }
-
- AddressDerivationIndex? derivationkey(CryptoCoins coin) {
- if (selectedCustomKey != null) {
- return ImportedAddressIndex(
- accountId: selectedCustomKey!.id,
- bip32KeyIndex: customKeyIndex,
- currencyCoin: coin);
- }
- return customKeyIndex;
- }
-
void generateAddress() async {
if (!(form.currentState?.validate() ?? false)) return;
- pageProgressKey.progressText("generating_new_addr".tr);
- final model = context.watch(StateIdsConst.main);
- final keyIndex = derivationkey(coin) ??
- chainAccount.account.nextDrive(coin,
- seedGeneration: seedGenerationType,
- masterKeyGeneration:
- keyGenerationType == _CardanoMasterKeyGenerationType.byronLegacy
- ? SeedGenerationType.byronLegacySeed
- : SeedGenerationType.bip39);
-
- final newAccount = CardanoNewAddressParams(
- coin: coin,
+ final result = await MethodCaller.call(() async {
+ pageProgressKey.progressText("generating_new_addr".tr);
+ final model = context.watch(StateIdsConst.main);
+ Bip32AddressIndex? keyIndex = await context
+ .openSliverBottomSheet("setup_derivation".tr,
+ child: SetupDerivationModeView(
+ coin: coin,
+ chainAccout: chainAccount,
+ ));
+ if (keyIndex == null) {
+ return null;
+ }
+ keyIndex = keyIndex.copyWith(keyName: "base_key");
+ Bip32AddressIndex? stakeDerivation;
+ if (addrType == ADAAddressType.base) {
+ final defaultStakeKey = keyIndex.copyWith(
+ changeLevel: CardanoUtils.bip32StakeChangeLevel,
+ addressIndex: CardanoUtils.bip32StakeAddressLevel);
+ // ignore: use_build_context_synchronously
+ stakeDerivation = await context
+ .openSliverBottomSheet("setup_derivation".tr,
+ child: SetupDerivationModeView(
+ coin: coin,
+ chainAccout: chainAccount,
+ defaultDerivation: defaultStakeKey,
+ title: PageTitleSubtitle(
+ title: "derive_network_address"
+ .tr
+ .replaceOne(network.coinParam.token.name),
+ body: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text("disable_standard_derivation".tr),
+ WidgetConstant.height8,
+ Text("stake_key_derivation".tr),
+ WidgetConstant.height8,
+ Text("ada_base_stake_key_same_error".tr)
+ ],
+ )),
+ ));
+ if (stakeDerivation == null) return null;
+ stakeDerivation = stakeDerivation.copyWith(keyName: "stake_key");
+ }
+ if (addrType == ADAAddressType.base && keyIndex == stakeDerivation) {
+ throw WalletException("ada_base_stake_key_same_error");
+ }
+ String? hdPath;
+ List? hdPathKey;
+ if (keyGenerationType.isLegacy) {
+ if (manuallySetLegacyHdPathKey) {
+ hdPath = BlockchainUtils.validateHdPathKey(manuallyHdPath!,
+ maxIndex: BlockchainConstant.maxByronLegacyBip32LevelIndex);
+ hdPathKey = BytesUtils.tryFromHexString(manuallyHdPathKey!);
+ } else {
+ if (keyIndex.hdPath == null) {
+ hdPath = "";
+ hdPathKey = List.filled(32, 0);
+ }
+ }
+ }
+
+ final newAccount = CardanoNewAddressParams(
deriveIndex: keyIndex,
addressType: addrType,
- byronLegacy: era.isShelly ? null : byronLegacy);
+ rewardKeyIndex: stakeDerivation,
+ customHdPath: hdPath,
+ customHdPathKey: hdPathKey,
+ );
+ final result = await model.deriveNewAccount(newAccount);
+ if (result.hasError) throw result.exception!;
+ return result.result;
+ });
- final result = await model.deriveNewAccount(newAccount);
if (result.hasError) {
pageProgressKey.errorText(result.error!.tr);
+ } else if (result.result == null) {
+ pageProgressKey.backToIdle();
} else {
pageProgressKey.success(
backToIdle: false,
progressWidget: SuccessWithButtomView(
buttomWidget: ContainerWithBorder(
margin: WidgetConstant.paddingVertical8,
- child: AddressDetailsView(address: result.result)),
+ child: AddressDetailsView(address: result.result!)),
buttomText: "generate_new_address".tr,
onPressed: () {
if (mounted) {
@@ -275,29 +343,22 @@ class _SetupCardanoAddressViewState extends State
setState(() {});
}
- String? byronLegacyDerivationValidator(String? v, int index) {
- final int? parse = int.tryParse(v ?? "");
- if (parse == null) return "invalid_derivation_index".tr;
- if (parse.isNegative || parse > Bip32KeyDataConst.keyIndexMaxVal) {
- return "invalid_derivation_index".tr;
- }
- return null;
+ @override
+ void didChangeDependencies() {
+ _setupIAccount();
+ super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
return PopScope(
- canPop: !inAddressPage || pageProgressKey.isSuccess,
- onPopInvoked: (didPop) {
- if (!didPop) {
- _onBackButton();
- }
- },
+ canPop: true,
+ onPopInvoked: (didPop) {},
child: Scaffold(
appBar: AppBar(title: Text("setup_address".tr)),
body: PageProgress(
key: pageProgressKey,
- backToIdle: AppGlobalConst.oneSecoundDuration,
+ backToIdle: AppGlobalConst.twoSecoundDuration,
initialStatus: PageProgressStatus.idle,
child: () => UnfocusableChild(
child: Center(
@@ -307,85 +368,81 @@ class _SetupCardanoAddressViewState extends State
SliverToBoxAdapter(
child: ConstraintsBoxView(
padding: WidgetConstant.paddingHorizontal20,
- child: AnimatedSwitcher(
- duration: AppGlobalConst.animationDuraion,
- child: inAddressPage
- ? Form(
- key: form,
- child: Column(
+ child: Form(
+ key: form,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ key: const ValueKey(true),
+ children: [
+ PageTitleSubtitle(
+ title: "setup_network_address"
+ .tr
+ .replaceOne(network.coinParam.token.name),
+ body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
- key: const ValueKey(true),
children: [
- AnimatedSwitcher(
- duration: AppGlobalConst.animationDuraion,
- child: page ==
- _GenerateAddressPage.seedGeneration
- ? _SelectSeedGenerationType(
- seedGenerationType:
- seedGenerationType,
- onChageSeedGeneration:
- onChangeSeedGeneration,
- onContinue:
- onContinueFromSeedGeneration)
- : page == _GenerateAddressPage.era
- ? _SelectEra(
- era: era,
- onChangeEra: onChangeEra,
- onContinue: onContinueFromEra)
- : page ==
- _GenerateAddressPage
- .masterKeyGeneration
- ? _SelectMasterKeyGeneration(
- keyGenerationType:
- keyGenerationType,
- era: era,
- onChangeKeyGeneration:
- onChangeMasterKeyGeneration,
- onContinue:
- onContinueFromMasterkeyGeneration,
- seedGeneration:
- seedGenerationType,
- )
- : _GenerateAddress(
- network: network,
- addrType: addrType,
- generateAddress:
- generateAddress,
- coin: coin,
- derivationStandard:
- derivationStandard,
- era: era,
- onChangeDerivation:
- onChangeDerivation,
- onChangeShellyddrType:
- onChangeShellyddrType,
- setupKeyIndex:
- setupKeyIndex,
- standardDerivation:
- standardDerivation,
- customKeyIndex:
- customKeyIndex,
- selectedCustomKey:
- selectedCustomKey,
- masterKeyGenerationType:
- keyGenerationType),
- ),
+ Text("disable_standard_derivation".tr),
+ WidgetConstant.height8,
+ Text("setup_address_derivation_keys_desc".tr),
+ WidgetConstant.height8,
+ Text(
+ "please_following_steps_to_generate_address"
+ .tr),
],
- ),
- )
- : Column(
- children: [
- WidgetConstant.height20,
- PageTitleSubtitle(
- title: "derive_network_address"
- .tr
- .replaceOne(network.coinParam.token.name),
- body: LargeTextView(
- ["bip44_derivation_desc".tr]),
- ),
- SetupAddressDerivation(goToAddressPage)
- ],
- ),
+ )),
+ AnimatedSwitcher(
+ duration: AppGlobalConst.animationDuraion,
+ child: page == _GenerateAddressPage.seedGeneration
+ ? _SelectSeedGenerationType(
+ seedGenerationType: seedGenerationType,
+ onChageSeedGeneration:
+ onChangeSeedGeneration,
+ onContinue: onContinueFromSeedGeneration)
+ : page == _GenerateAddressPage.era
+ ? _SelectEra(
+ era: era,
+ onChangeEra: onChangeEra,
+ onContinue: onContinueFromEra)
+ : page ==
+ _GenerateAddressPage
+ .masterKeyGeneration
+ ? _SelectMasterKeyGeneration(
+ keyGenerationType:
+ keyGenerationType,
+ era: era,
+ onChangeKeyGeneration:
+ onChangeMasterKeyGeneration,
+ onContinue:
+ onContinueFromMasterkeyGeneration,
+ seedGeneration: seedGenerationType,
+ )
+ : _GenerateAddress(
+ network: network,
+ addrType: addrType,
+ generateAddress: generateAddress,
+ coin: coin,
+ era: era,
+ hdPathKeyKey: hdPathKeyKey,
+ keyGeneratorType: keyGenerationType,
+ hdpathKey: hdPathKey,
+ onChangedHdPath: onChageHdPath,
+ onChangedHdPathKey:
+ onChangeHdPathKey,
+ validatorHdPath: onValidateHdPath,
+ validatorHdPathKey:
+ onValidateHdPathKey,
+ onChangeShellyddrType:
+ onChangeShellyddrType,
+ hdPath: manuallyHdPath,
+ hdPathKey: manuallyHdPathKey,
+ manuallySetHdPathKey:
+ manuallySetLegacyHdPathKey,
+ onChangeManuallySetHdPathKey:
+ onChangeManuallySetHdPathKey,
+ ),
+ ),
+ ],
+ ),
),
))
],
@@ -410,10 +467,12 @@ class _SelectEra extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
PageTitleSubtitle(
title: "cardano_era".tr,
body: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("select_era_for_generate_addr".tr),
WidgetConstant.height8,
@@ -433,7 +492,13 @@ class _SelectEra extends StatelessWidget {
onChanged: onChangeEra,
),
WidgetConstant.height20,
- ElevatedButton(onPressed: onContinue, child: Text("continue".tr))
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ FixedElevatedButton(
+ onPressed: onContinue, child: Text("continue".tr)),
+ ],
+ )
],
);
}
@@ -454,14 +519,20 @@ class _SelectMasterKeyGeneration extends StatelessWidget {
final DynamicVoid onContinue;
final _AdaEra era;
final SeedGenerationType seedGeneration;
+ bool get showLegacy =>
+ !era.isShelly &&
+ (seedGeneration == SeedGenerationType.byronLegacySeed ||
+ seedGeneration == SeedGenerationType.none);
@override
Widget build(BuildContext context) {
return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
PageTitleSubtitle(
title: "master_key_generation".tr,
body: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("cardano_bip32_master_key".tr),
WidgetConstant.height8,
@@ -480,8 +551,7 @@ class _SelectMasterKeyGeneration extends StatelessWidget {
title: Text("icarus".tr),
onChanged: onChangeKeyGeneration,
),
- if (!era.isShelly &&
- seedGeneration == SeedGenerationType.byronLegacySeed)
+ if (showLegacy)
AppRadioListTile(
groupValue: keyGenerationType,
value: _CardanoMasterKeyGenerationType.byronLegacy,
@@ -489,7 +559,13 @@ class _SelectMasterKeyGeneration extends StatelessWidget {
onChanged: onChangeKeyGeneration,
),
WidgetConstant.height20,
- ElevatedButton(onPressed: onContinue, child: Text("continue".tr))
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ FixedElevatedButton(
+ onPressed: onContinue, child: Text("continue".tr)),
+ ],
+ )
],
);
}
@@ -509,6 +585,7 @@ class _SelectSeedGenerationType extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
PageTitleSubtitle(
title: "seed_generation".tr,
@@ -530,132 +607,113 @@ class _SelectSeedGenerationType extends StatelessWidget {
onChanged: onChageSeedGeneration,
),
WidgetConstant.height20,
- ElevatedButton(onPressed: onContinue, child: Text("continue".tr))
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ FixedElevatedButton(
+ onPressed: onContinue, child: Text("continue".tr)),
+ ],
+ )
],
);
}
}
class _GenerateAddress extends StatelessWidget {
- const _GenerateAddress({
- required this.network,
- required this.addrType,
- required this.generateAddress,
- required this.coin,
- required this.derivationStandard,
- required this.era,
- required this.onChangeDerivation,
- required this.onChangeShellyddrType,
- required this.setupKeyIndex,
- required this.standardDerivation,
- required this.masterKeyGenerationType,
- this.selectedCustomKey,
- this.customKeyIndex,
- });
+ const _GenerateAddress(
+ {required this.network,
+ required this.addrType,
+ required this.generateAddress,
+ required this.coin,
+ required this.era,
+ required this.onChangeShellyddrType,
+ required this.hdpathKey,
+ required this.hdPathKeyKey,
+ required this.onChangedHdPath,
+ required this.validatorHdPath,
+ required this.onChangedHdPathKey,
+ required this.validatorHdPathKey,
+ required this.keyGeneratorType,
+ required this.hdPath,
+ required this.hdPathKey,
+ required this.manuallySetHdPathKey,
+ required this.onChangeManuallySetHdPathKey});
final APPCardanoNetwork network;
- final EncryptedCustomKey? selectedCustomKey;
- final AddressDerivationIndex? customKeyIndex;
- final bool derivationStandard;
final _AdaEra era;
final ADAAddressType addrType;
- final AddressDerivationIndex standardDerivation;
final CryptoCoins coin;
final _OnChangeShellyAddrType onChangeShellyddrType;
final DynamicVoid generateAddress;
- final _OnChangeDerivation onChangeDerivation;
- final _SetupKeyIndex setupKeyIndex;
- final _CardanoMasterKeyGenerationType masterKeyGenerationType;
+ final GlobalKey hdpathKey;
+ final GlobalKey hdPathKeyKey;
+ final StringVoid onChangedHdPath;
+ final NullStringString validatorHdPath;
+ final StringVoid onChangedHdPathKey;
+ final NullStringString validatorHdPathKey;
+ final _CardanoMasterKeyGenerationType keyGeneratorType;
+ final String? hdPath;
+ final String? hdPathKey;
+ final bool manuallySetHdPathKey;
+ final DynamicVoid onChangeManuallySetHdPathKey;
+ bool get isBaseAddress => addrType == ADAAddressType.base;
@override
Widget build(BuildContext context) {
return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
children: [
- PageTitleSubtitle(
- title: "derive_network_address"
- .tr
- .replaceOne(network.coinParam.token.name),
- body: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text("disable_standard_derivation".tr),
- WidgetConstant.height8,
- if (selectedCustomKey != null)
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
+ if (era.isShelly) ...[
+ WidgetConstant.height20,
+ Text("shelley_address_format".tr,
+ style: context.textTheme.titleMedium),
+ WidgetConstant.height8,
+ AppDropDownBottom(
+ items: {
+ ADAAddressType.base: Text("base".tr),
+ ADAAddressType.reward: Text("reward".tr),
+ ADAAddressType.enterprise: Text("enterprise".tr),
+ },
+ value: addrType,
+ onChanged: onChangeShellyddrType,
+ label: "shelley_address_format".tr),
+ WidgetConstant.height20,
+ ] else if (keyGeneratorType.isLegacy) ...[
+ AppSwitchListTile(
+ value: manuallySetHdPathKey,
+ title: Text("manually_set_hd_path".tr),
+ subtitle:
+ Text("byron_legacy_hd_path_generate_from_master_key_desc".tr),
+ onChanged: (p0) => onChangeManuallySetHdPathKey(),
+ ),
+ AnimatedSize(
+ duration: AppGlobalConst.animationDuraion,
+ alignment: Alignment.topCenter,
+ child: manuallySetHdPathKey
+ ? Column(
children: [
- Text("generate_from_imported_keys".tr),
WidgetConstant.height8,
- Text("generate_from_imported_key_desc1".tr)
+ AppTextField(
+ label: "hd_path".tr,
+ key: hdpathKey,
+ onChanged: onChangedHdPath,
+ validator: validatorHdPath,
+ hint: CardanoUtils.hdPathHint,
+ initialValue: hdPath,
+ ),
+ AppTextField(
+ label: "hd_path_key".tr,
+ key: hdPathKeyKey,
+ onChanged: onChangedHdPathKey,
+ validator: validatorHdPathKey,
+ helperText: "byron_legacy_hd_path_key_desc2".tr,
+ hint: "0x950163...",
+ initialValue: hdPathKey,
+ ),
],
)
- else
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text("generate_from_hd_wallet".tr),
- ],
- )
- ],
- )),
- if (era.isShelly)
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- WidgetConstant.height20,
- Text("shelley_address_format".tr,
- style: context.textTheme.titleMedium),
- WidgetConstant.height8,
- AppDropDownBottom(
- items: {
- ADAAddressType.base: Text("base".tr),
- ADAAddressType.reward: Text("reward".tr),
- ADAAddressType.enterprise: Text("enterprise".tr),
- },
- value: addrType,
- onChanged: onChangeShellyddrType,
- label: "shelley_address_format".tr),
- WidgetConstant.height20,
- ],
- ),
- AppSwitchListTile(
- value: derivationStandard,
- onChanged: (p0) {
- onChangeDerivation(
- p0,
- () {
- if (masterKeyGenerationType.isLegacy) {
- context
- .openSliverBottomSheet(
- "key_derivation".tr,
- child: ByronLegacyKeyDerivationView(
- coin: coin,
- curve: coin.conf.type,
- ))
- .then(setupKeyIndex);
- return;
- }
- context
- .openSliverBottomSheet(
- "key_derivation".tr,
- child: Bip32KeyDerivationView(
- coin: coin,
- curve: coin.conf.type,
- ))
- .then(setupKeyIndex);
- },
- );
- },
- title: selectedCustomKey == null
- ? Text(derivationStandard
- ? "standard_derivation".tr
- : "custom_derivation".tr)
- : Text(customKeyIndex == null
- ? "non_derivation".tr
- : "custom_derivation".tr),
- subtitle: selectedCustomKey == null
- ? Text(customKeyIndex?.path ?? standardDerivation.path)
- : Text(customKeyIndex?.path ?? "import_key_derivation_desc2".tr),
- ),
+ : WidgetConstant.sizedBox,
+ )
+ ],
WidgetConstant.height20,
Row(
mainAxisAlignment: MainAxisAlignment.center,
@@ -663,7 +721,7 @@ class _GenerateAddress extends StatelessWidget {
FixedElevatedButton(
padding: WidgetConstant.paddingVertical20,
onPressed: generateAddress,
- child: Text("generate_address".tr),
+ child: Text("setup_derivation".tr),
),
],
)
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/controller.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/controller.dart
index aaccc4c9..2496ca4b 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/controller.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/controller.dart
@@ -1,5 +1,7 @@
+import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/certificate_impl.dart';
import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/fee_impl.dart';
import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/memo_impl.dart';
+import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/minting_impl.dart';
import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/transaction.dart';
import 'impl/signer_impl.dart';
@@ -7,7 +9,9 @@ class CardanoTransactionStateController extends CardanoTransactionImpl
with
CardanoTransactionFeeImpl,
CardanoSignerImpl,
- CardanoTransactionMemoImpl {
+ CardanoTransactionMemoImpl,
+ CardanoMintingImpl,
+ CardanoCertificateImpl {
CardanoTransactionStateController(
{required super.walletProvider, required super.chainAccount});
@@ -15,8 +19,8 @@ class CardanoTransactionStateController extends CardanoTransactionImpl
String get repositoryId => "cardano";
@override
- void sendTransaction() {
+ void buildAndBroadcastTransaction() {
if (!trReady) return;
- super.sendTransaction();
+ super.buildAndBroadcastTransaction();
}
}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/certificate_impl.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/certificate_impl.dart
new file mode 100644
index 00000000..5c5510d0
--- /dev/null
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/certificate_impl.dart
@@ -0,0 +1,22 @@
+import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/transaction.dart';
+import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/cardano.dart';
+
+mixin CardanoCertificateImpl on CardanoTransactionImpl {
+ List _certificates = [];
+ @override
+ List get certificates => _certificates;
+ void addCertificate(ADATransactionCertificate? newCertificate) {
+ if (newCertificate == null) return;
+ _certificates = [newCertificate, ...certificates];
+ notify();
+ calculateFee();
+ }
+
+ void removeCertificate(ADATransactionCertificate? certificate) {
+ if (!_certificates.contains(certificate)) return;
+ _certificates = List.unmodifiable(
+ _certificates.where((element) => element != certificate));
+ notify();
+ calculateFee();
+ }
+}
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 962b89b8..5471d89a 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
@@ -21,7 +21,8 @@ mixin CardanoTransactionFeeImpl on CardanoTransactionImpl {
String? _feeError;
@override
- int get coinsPerUtxoSize => _protocolParams!.coinsPerUtxoSize;
+ ADAEpochParametersResponse get protocolParams => _protocolParams!;
+
String? get feeError => _feeError;
CardanoFeeRateType get feeRateType => _feeRateType;
bool get hasFee => !transactionFee.isZero;
@@ -31,14 +32,8 @@ mixin CardanoTransactionFeeImpl on CardanoTransactionImpl {
@override
Future calculateFee() async {
- final builder = ADATransactionBuilder(
- outputs: [
- ...receivers.map((e) => e.toOutput()).toList(),
- if (remindAmount.largerThanZero) changeADAOutput.toOutput(),
- if (changeAssetOutput.hasAssets) changeAssetOutput.toOutput()
- ],
- utxos: selectedUtxos.map((e) => e.utxo.toUtxoResponse()).toList(),
- metadata: transactionMemo);
+ super.calculateFee();
+ final builder = buildTransaction(transactionFee.balance);
final size = builder.estimateSize(
onChangeAddress: changeADAOutput.address.networkAddress);
final calcFee = _protocolParams!.calculateFee(size);
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/minting_impl.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/minting_impl.dart
new file mode 100644
index 00000000..e075b6a6
--- /dev/null
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/minting_impl.dart
@@ -0,0 +1,32 @@
+import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/transaction.dart';
+import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/cardano.dart';
+
+mixin CardanoMintingImpl on CardanoTransactionImpl {
+ List _mints = [];
+ @override
+ List get mints => _mints;
+
+ void setupMint(ADAMintInfo? mint) {
+ if (mint == null) return;
+ _mints = List.unmodifiable([mint, ..._mints]);
+ setTotalAssets(totalAssets + mint.toMultiAsset);
+ calculateFee();
+ }
+
+ void removeMint(ADAMintInfo? mint) {
+ if (!_mints.contains(mint)) return;
+ _mints = List.unmodifiable(
+ _mints.where((element) => element != mint));
+ _cleanUpUsedMint(mint!);
+ }
+
+ void _cleanUpUsedMint(ADAMintInfo mint) {
+ final mintingAsset = mint.toMultiAsset;
+ setTotalAssets(totalAssets - mintingAsset);
+ changeAssetOutput.setAsset(changeAssetOutput.asset - mintingAsset);
+ for (final i in receivers) {
+ i.setAsset(i.asset - mintingAsset);
+ }
+ calculateFee();
+ }
+}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/signer_impl.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/signer_impl.dart
index 7b090d32..74925c35 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/signer_impl.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/controller/impl/signer_impl.dart
@@ -6,48 +6,31 @@ import 'package:on_chain/ada/ada.dart';
import 'transaction.dart';
mixin CardanoSignerImpl on CardanoTransactionImpl {
- Future _sendTransaction() async {
- TransactionOutput? output;
- if (remindAmount.largerThanZero) {
- output = changeADAOutput.toOutput();
- output = output.copyWith(
- amount: output.amount.copyWith(coin: remindAmount.balance));
+ Future _signTransaction() async {
+ try {
+ final builder = buildTransaction(transactionFee.balance);
+ final signers = getTransactionSignerAccounts();
+ final signerKeyIndexes = getTransactionSignersKeysIndex();
+ final tr = await walletProvider.signCardanoTransaction(
+ request: CardanoSigningRequest(
+ addresses: signers,
+ network: network,
+ transaction: builder,
+ signers: signerKeyIndexes));
+ if (tr.hasError) {
+ throw tr.exception!;
+ }
+ return tr.result;
+ } catch (e) {
+ rethrow;
}
- TransactionOutput? assetOutput;
- if (changeAssetOutput.hasAssets) {
- assetOutput = changeAssetOutput.toOutput();
- }
-
- final builder = ADATransactionBuilder(
- outputs: [
- ...receivers.map((e) => e.toOutput()).toList(),
- if (output != null) output,
- if (assetOutput != null) assetOutput
- ],
- utxos: selectedUtxos.map((e) => e.utxo.toUtxoResponse()).toList(),
- metadata: transactionMemo);
- builder.setFee(transactionFee.balance);
- final signerAddrs =
- selectedUtxos.map((e) => e.utxo.address).toList().toSet();
- final signers = addresses
- .where(
- (element) => signerAddrs.contains(element.networkAddress.address))
- .toList();
-
- final tr = await walletProvider.signCardanoTransaction(
- request: CardanoSigningRequest(
- addresses: signers, network: network, transaction: builder));
- if (tr.hasError) {
- throw tr.exception!;
- }
- return tr.result;
}
- void sendTransaction() async {
+ void buildAndBroadcastTransaction() async {
progressKey.progressText(
"create_send_transaction".tr.replaceOne(network.coinParam.token.name));
final result = await MethodCaller.call(() async {
- final result = await _sendTransaction();
+ final result = await _signTransaction();
final ser = result.serialize();
final broadcast = await providers.broadcastTransaction(ser);
return broadcast;
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 dd751d98..d8262484 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
@@ -3,11 +3,8 @@ import 'package:mrt_wallet/app/core.dart';
import 'package:mrt_wallet/future/pages/start_page/controller/wallet_provider.dart';
import 'package:mrt_wallet/future/widgets/custom_widgets.dart';
import 'package:mrt_wallet/models/wallet_models/address/network_address/cardano/cardano.dart';
-import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/account_utxos.dart';
-import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/cardano_output.dart';
-import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/utxo.dart';
-import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/utxo_multi_asset.dart';
-import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/utxo_with_owner.dart';
+import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/utxos.dart';
+import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/cardano.dart';
import 'package:mrt_wallet/models/wallet_models/wallet_models.dart';
import 'package:mrt_wallet/provider/api/api_provider.dart';
import 'package:mrt_wallet/types/typedef.dart';
@@ -16,10 +13,35 @@ import 'package:on_chain/on_chain.dart';
enum CardanoTransactionPages { account, utxo, send }
abstract class CardanoTransactionImpl extends StateController {
+ List get mints;
+ List get certificates;
+ List _deposits = [];
+ List get deposits => _deposits;
+ bool get hasDeposit => deposits.isNotEmpty;
+ List _refundDepsit = [];
+ List get refundDeposit => _refundDepsit;
+ bool get hasRefundDeposit => refundDeposit.isNotEmpty;
+ void _findDeposits() {
+ List depositsValues = [];
+ List refund = [];
+ for (final i in certificates) {
+ if (i.type == ADATransactionCertificateType.registraction) {
+ depositsValues.add(ADATransactionDeposit.amount(
+ type: ADACustomFeeTypes.stakeRegistration,
+ fee: protocolParams.keyDeposit));
+ } else if (i.type == ADATransactionCertificateType.deregistration) {
+ refund.add(ADATransactionDeposit.amount(
+ type: ADACustomFeeTypes.stakeRegistration,
+ fee: protocolParams.keyDeposit));
+ }
+ }
+ _deposits = List.unmodifiable(depositsValues);
+ _refundDepsit = List.unmodifiable(refund);
+ }
+
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);
@@ -28,7 +50,8 @@ abstract class CardanoTransactionImpl extends StateController {
address: ReceiptAddress(
view: address.address.toAddress,
type: address.type,
- networkAddress: address.networkAddress),
+ networkAddress: address.networkAddress,
+ account: address),
network: network);
CardanoOutputWithBalance get changeADAOutput => _changeADAOutput;
NoneDecimalBalance get remindAmount => changeADAOutput.balance;
@@ -38,7 +61,8 @@ abstract class CardanoTransactionImpl extends StateController {
address: ReceiptAddress(
view: address.address.toAddress,
type: address.type,
- networkAddress: address.networkAddress),
+ networkAddress: address.networkAddress,
+ account: address),
network: network);
CardanoOutputWithBalance get changeAssetOutput => _changeAssetOutput;
@@ -56,8 +80,10 @@ abstract class CardanoTransactionImpl extends StateController {
GeneralTransactionMetadata? get transactionMemo;
NoneDecimalBalance get transactionFee;
- int get coinsPerUtxoSize;
- Future calculateFee();
+ ADAEpochParametersResponse get protocolParams;
+ Future calculateFee() async {
+ _findDeposits();
+ }
CardanoTransactionImpl(
{required this.walletProvider, required this.chainAccount});
@@ -98,35 +124,56 @@ abstract class CardanoTransactionImpl extends StateController {
final Map _receivers = {};
List get receivers => _receivers.values.toList();
+ void setTotalAssets(UtxoMultiAsset? assets) {
+ _totalAsset = assets ?? UtxoMultiAsset(const {});
+ }
+
void changeOutputAddress(ICardanoAddress? changeAddr) {
if (changeAddr == null ||
changeAddr.address.toAddress == _changeADAOutput.address.view) return;
- _changeADAOutput.setAddress(ReceiptAddress(
- view: changeAddr.address.toAddress,
- type: changeAddr.type,
- networkAddress: changeAddr.networkAddress));
+ final bool needRecalculationFee = changeAddr.networkAddress.addressType !=
+ _changeADAOutput.address.networkAddress.addressType;
+ final ReceiptAddress changeReceiptAddr =
+ ReceiptAddress(
+ view: changeAddr.address.toAddress,
+ type: changeAddr.type,
+ networkAddress: changeAddr.networkAddress,
+ account: changeAddr);
+ _changeADAOutput.setAddress(changeReceiptAddr,
+ coinsPerUtxoSize: protocolParams.coinsPerUtxoSize);
+ if (needRecalculationFee) {
+ calculateFee();
+ }
notify();
}
void changeAssetOutputAddress(ICardanoAddress? changeAddr) {
if (changeAddr == null ||
changeAddr.address.toAddress == _changeAssetOutput.address.view) return;
- _changeAssetOutput.setAddress(ReceiptAddress(
- view: changeAddr.address.toAddress,
- type: changeAddr.type,
- networkAddress: changeAddr.networkAddress));
+ final bool needRecalculationFee = changeAddr.networkAddress.addressType !=
+ _changeAssetOutput.address.networkAddress.addressType;
+ _changeAssetOutput.setAddress(
+ ReceiptAddress(
+ view: changeAddr.address.toAddress,
+ type: changeAddr.type,
+ networkAddress: changeAddr.networkAddress,
+ account: changeAddr),
+ coinsPerUtxoSize: protocolParams.coinsPerUtxoSize);
+ if (needRecalculationFee) {
+ calculateFee();
+ }
notify();
}
void onSetupUtxo() {
- _totalAsset = selectedUtxos.fold(UtxoMultiAsset({}),
+ final totalUtxosAsset = selectedUtxos.fold(UtxoMultiAsset({}),
(previousValue, element) => previousValue + element.utxo.multiAsset);
-
+ setTotalAssets(totalUtxosAsset);
onCalculateAmount();
if (hasAsset) {
changeAssetOutput.updateBalance(
- changeAssetOutput.minValue(coinsPerUtxoSize),
- coinsPerUtxoSize: coinsPerUtxoSize);
+ changeAssetOutput.minValue(protocolParams.coinsPerUtxoSize),
+ coinsPerUtxoSize: protocolParams.coinsPerUtxoSize);
onCalculateAmount();
}
_page = CardanoTransactionPages.send;
@@ -140,7 +187,11 @@ abstract class CardanoTransactionImpl extends StateController {
}
}
- void addSpender(ICardanoAddress address) {
+ void addSpender(ICardanoAddress address, StringVoid onError) {
+ if (address.networkAddress.isRewardAddress) {
+ onError("unable_to_spend_from_stake_address");
+ return;
+ }
final r = _addresses.remove(address.networkAddress);
if (!r) {
_addresses.add(address.networkAddress);
@@ -148,15 +199,20 @@ abstract class CardanoTransactionImpl extends StateController {
notify();
}
+ void _updateSelectedUtxosBalance() {
+ final BigInt totalUtxosBalances = _selectedUtxos.fold(
+ BigInt.zero,
+ (previousValue, element) =>
+ previousValue + element.utxoBalance.balance);
+ sumOfSelectedUtxo.updateBalance(totalUtxosBalances);
+ }
+
void addUtxo(CardanoUtxo utxo) {
final r = _selectedUtxos.remove(utxo);
if (!r) {
_selectedUtxos.add(utxo);
}
- sumOfSelectedUtxo.updateBalance(_selectedUtxos.fold(
- BigInt.zero,
- (previousValue, element) =>
- previousValue + element.utxoBalance.balance));
+ _updateSelectedUtxosBalance();
notify();
}
@@ -170,10 +226,7 @@ abstract class CardanoTransactionImpl extends StateController {
for (final i in _accountUtxos.values) {
_selectedUtxos.addAll(i.utxos ?? []);
}
- sumOfSelectedUtxo.updateBalance(_selectedUtxos.fold(
- BigInt.zero,
- (previousValue, element) =>
- previousValue + element.utxoBalance.balance));
+ _updateSelectedUtxosBalance();
} finally {
notify();
}
@@ -225,24 +278,24 @@ abstract class CardanoTransactionImpl extends StateController {
void setupAccountAmount(String address, BigInt? amount) async {
if (amount == null) return;
- _receivers[address]
- ?.updateBalance(amount, coinsPerUtxoSize: coinsPerUtxoSize);
+ _receivers[address]?.updateBalance(amount,
+ coinsPerUtxoSize: protocolParams.coinsPerUtxoSize);
bool isMax = amount == remindAmount.balance;
onCalculateAmount();
if (isMax) {
await calculateFee();
final fixedAmount = amount + remindAmount.balance;
- _receivers[address]
- ?.updateBalance(fixedAmount, coinsPerUtxoSize: coinsPerUtxoSize);
+ _receivers[address]?.updateBalance(fixedAmount,
+ coinsPerUtxoSize: protocolParams.coinsPerUtxoSize);
onCalculateAmount();
}
notify();
}
void changeAssetAdaAmount(BigInt? amount) async {
- if (amount == null || !hasAsset) return;
+ if (amount == null || !hasAsset || !_changeAssetOutput.hasAssets) return;
_changeAssetOutput.updateBalance(amount,
- coinsPerUtxoSize: coinsPerUtxoSize);
+ coinsPerUtxoSize: protocolParams.coinsPerUtxoSize);
onCalculateAmount();
notify();
}
@@ -256,35 +309,45 @@ abstract class CardanoTransactionImpl extends StateController {
}
bool _isReady() {
- final zeroOutput = receivers.any((element) => !element.hasAmount);
- return receivers.isNotEmpty &&
- !zeroOutput &&
+ final hasNotReadyOutput = receivers.any((element) => !element.isReady);
+ return !hasNotReadyOutput &&
!remindAmount.isNegative &&
- !setupAmount.isZero &&
transactionFee.largerThanZero;
}
void onCalculateAmount() {
+ final filledAsset = _receivers.values.fold(UtxoMultiAsset({}),
+ (previousValue, element) => previousValue + element.asset);
+ _changeAssetOutput.setAsset(_totalAsset - filledAsset);
final totalAmounts = receivers.fold(BigInt.zero,
(previousValue, element) => previousValue + element.balance.balance);
- setupAmount.updateBalance(totalAmounts + changeAssetOutput.balance.balance);
- final remind = sumOfSelectedUtxo.balance -
+ _findDeposits();
+
+ final BigInt depositsAmounts = deposits.fold(BigInt.zero,
+ (previousValue, element) => previousValue + element.fee.balance);
+ final BigInt refaunds = refundDeposit.fold(BigInt.zero,
+ (previousValue, element) => previousValue + element.fee.balance);
+ final remind = sumOfSelectedUtxo.balance +
+ refaunds -
totalAmounts -
changeAssetOutput.balance.balance -
- transactionFee.balance;
+ transactionFee.balance -
+ depositsAmounts;
remindAmount.updateBalance(remind);
- final filledAsset = _receivers.values.fold(UtxoMultiAsset({}),
- (previousValue, element) => previousValue + element.asset);
- _changeAssetOutput.setAsset(_totalAsset - filledAsset);
+
_trReady = _isReady();
notify();
}
void onAddRecever(
- ReceiptAddress? addr, DynamicVoid onAccountExists) {
+ ReceiptAddress? addr, StringVoid onAccountExists) {
if (addr == null) return;
+ if (addr.networkAddress.isRewardAddress) {
+ onAccountExists("cannot_send_ada_to_stake_address");
+ return;
+ }
if (_receivers.containsKey(addr.networkAddress.address)) {
- onAccountExists();
+ onAccountExists("address_already_exist");
return;
} else {
_receivers[addr.networkAddress.address] =
@@ -293,4 +356,74 @@ abstract class CardanoTransactionImpl extends StateController {
notify();
calculateFee();
}
+
+ List _getRemindOutputs() {
+ final List remindOutputs = [];
+ if (remindAmount.largerThanZero) {
+ TransactionOutput output = changeADAOutput.toOutput();
+ output = output.copyWith(
+ amount: output.amount.copyWith(coin: remindAmount.balance));
+ remindOutputs.add(output);
+ }
+ if (changeAssetOutput.hasAssets) {
+ TransactionOutput assetOutput = changeAssetOutput.toOutput();
+ remindOutputs.add(assetOutput);
+ }
+ return remindOutputs;
+ }
+
+ ADATransactionBuilder buildTransaction(BigInt fee) {
+ final transaction = ADATransactionBuilder(
+ outputs: [
+ ...receivers.map((e) => e.toOutput()).toList(),
+ ..._getRemindOutputs()
+ ],
+ utxos: selectedUtxos.map((e) => e.utxo.toUtxoResponse()).toList(),
+ metadata: transactionMemo,
+ certificates: certificates.map((e) => e.certificate).toList(),
+ deposits: deposits.map((e) => e.toDepositBuilder()).toList(),
+ refundDeposits: refundDeposit.map((e) => e.toDepositBuilder()).toList(),
+ mints: mints.map((e) => e.toMintBuilder()).toList())
+ ..setFee(fee);
+ return transaction;
+ }
+
+ Set _signerAddresses() {
+ return {
+ ...selectedUtxos.map((e) => e.utxo.toAdddress),
+ ...mints.map((e) => e.owner),
+ ...certificates
+ .where((element) => element.certificate.signer != null)
+ .map((e) => e.certificate.signer!)
+ };
+ }
+
+ List getTransactionSignerAccounts() {
+ final Set signerAddrs = _signerAddresses();
+ List signers = [];
+ for (final i in signerAddrs) {
+ final signer = addresses.firstWhere((element) {
+ return element.networkAddress == i || element.rewardAddress == i;
+ }, orElse: () => throw WalletExceptionConst.accountDoesNotFound);
+ signers.add(signer);
+ }
+ return signers;
+ }
+
+ List getTransactionSignersKeysIndex() {
+ final Set signerAddrs = _signerAddresses();
+ List signers = [];
+ for (final i in signerAddrs) {
+ final signer = addresses.firstWhere(
+ (element) =>
+ element.networkAddress == i || element.rewardAddress == i,
+ orElse: () => throw WalletExceptionConst.accountDoesNotFound);
+ if (signer.rewardAddress == i) {
+ signers.add(signer.rewardKeyIndex ?? signer.keyIndex);
+ } else {
+ signers.add(signer.keyIndex);
+ }
+ }
+ return signers;
+ }
}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/asset_info.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/asset_info.dart
new file mode 100644
index 00000000..47597f6d
--- /dev/null
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/asset_info.dart
@@ -0,0 +1,66 @@
+import 'package:flutter/material.dart';
+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/custom/cardano/utxo_multi_asset.dart';
+import 'package:mrt_wallet/models/wallet_models/network/params/core/token.dart';
+
+class CardanoAssetsInfoView extends StatelessWidget {
+ const CardanoAssetsInfoView({super.key, required this.asset});
+ final UtxoMultiAsset asset;
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: List.generate(asset.assets.length, (index) {
+ final pl = asset.assets.keys.toList()[index];
+ final assets = asset.assets[pl]!;
+
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ ...List.generate(assets.assets.length, (pos) {
+ final assetName = assets.assets.keys.toList()[pos];
+ final token = Token(name: assetName.name, symbol: assetName.name);
+ return Padding(
+ padding: WidgetConstant.padding5,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Flexible(
+ child: RichText(
+ maxLines: 1,
+ text: TextSpan(
+ style: context.textTheme.bodyMedium,
+ children: [
+ TextSpan(text: assetName.name),
+ const TextSpan(text: " "),
+ WidgetSpan(
+ child: ToolTipView(
+ waitDuration: AppGlobalConst.milliseconds100,
+ message: "${"policy_id".tr}: ${pl.toHex()}",
+ child: Text(
+ "(${pl.toHex().substring(0, 3)}...)",
+ style: context.textTheme.labelSmall,
+ ),
+ ),
+ )
+ ]),
+ ),
+ ),
+ Flexible(
+ child: CoinPriceView(
+ token: token,
+ balance: assets.assets[assetName],
+ style: context.textTheme.titleMedium,
+ ))
+ ],
+ ),
+ );
+ }),
+ // const Divider(),
+ ],
+ );
+ }),
+ );
+ }
+}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/build_transaction.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/build_transaction.dart
index e21f3e2e..ea65931f 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/build_transaction.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/build_transaction.dart
@@ -59,7 +59,7 @@ class SendCardanoTransactionView extends StatelessWidget {
)
],
)
- : SelectAccountUtxo(controller: controller),
+ : _SelectAccountUtxo(controller: controller),
),
),
),
@@ -73,15 +73,15 @@ class SendCardanoTransactionView extends StatelessWidget {
}
}
-class SelectAccountUtxo extends StatefulWidget {
- const SelectAccountUtxo({super.key, required this.controller});
+class _SelectAccountUtxo extends StatefulWidget {
+ const _SelectAccountUtxo({required this.controller});
final CardanoTransactionImpl controller;
@override
- State createState() => _SelectAccountUtxoState();
+ State<_SelectAccountUtxo> createState() => _SelectAccountUtxoState();
}
-class _SelectAccountUtxoState extends State {
+class _SelectAccountUtxoState extends State<_SelectAccountUtxo> {
late final List addresses =
List.from(widget.controller.addresses)
..sort(
@@ -97,9 +97,14 @@ class _SelectAccountUtxoState extends State {
if (!showAll) {
bool alert = false;
for (final i in addresses) {
- if (i == currentAccount) continue;
+ if (i == currentAccount || i.networkAddress.isRewardAddress) continue;
if (widget.controller.addressSelected(i)) {
- widget.controller.addSpender(i);
+ widget.controller.addSpender(
+ i,
+ (p0) {
+ context.showAlert(p0.tr);
+ },
+ );
alert = true;
}
}
@@ -159,17 +164,17 @@ class _SelectAccountUtxoState extends State {
checkColor: context.colors.secondary,
activeColor: context.colors.secondary,
value: widget.controller.addressSelected(currentAccount),
- onChanged:
- currentAccount.address.balance.value.balance > BigInt.zero
- ? (v) {
- widget.controller.addressSelected(currentAccount);
- }
- : null),
- onRemove: currentAccount.address.balance.value.balance > BigInt.zero
- ? () {
- widget.controller.addSpender(currentAccount);
- }
- : null,
+ onChanged: (v) {
+ widget.controller.addressSelected(currentAccount);
+ }),
+ onRemove: () {
+ widget.controller.addSpender(
+ currentAccount,
+ (p0) {
+ context.showAlert(p0.tr);
+ },
+ );
+ },
child: AddressDetailsView(
address: currentAccount,
color: context.colors.onSecondary,
@@ -192,11 +197,21 @@ class _SelectAccountUtxoState extends State {
value: widget.controller
.addressSelected(addresses[index]),
onChanged: (value) {
- widget.controller.addSpender(addresses[index]);
+ widget.controller.addSpender(
+ addresses[index],
+ (p0) {
+ context.showAlert(p0.tr);
+ },
+ );
},
),
onRemove: () {
- widget.controller.addSpender(addresses[index]);
+ widget.controller.addSpender(
+ addresses[index],
+ (p0) {
+ context.showAlert(p0.tr);
+ },
+ );
},
child: AddressDetailsView(address: addresses[index]));
}),
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/mint_token_view.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/mint_token_view.dart
new file mode 100644
index 00000000..2a1b2ce5
--- /dev/null
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/mint_token_view.dart
@@ -0,0 +1,196 @@
+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/wallet_pages.dart';
+import 'package:mrt_wallet/future/widgets/custom_widgets.dart';
+import 'package:mrt_wallet/models/wallet_models/address/network_address/cardano/cardano.dart';
+import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/mint_info.dart';
+
+import 'package:mrt_wallet/models/wallet_models/wallet_models.dart';
+import 'package:on_chain/on_chain.dart';
+
+class CardanoMintTokenView extends StatefulWidget {
+ final NetworkAccountCore account;
+ const CardanoMintTokenView(this.account, {super.key});
+ @override
+ State createState() => _CardanoMintTokenViewState();
+}
+
+class _CardanoMintTokenViewState extends State
+ with SafeState {
+ static BigRational maxSupply = BigRational(maxU64);
+ final GlobalKey textFieldKey =
+ GlobalKey(debugLabel: "CardanoMintTokenView");
+ final GlobalKey formKey =
+ GlobalKey(debugLabel: "CardanoMintTokenView");
+ ReceiptAddress? owmnerReceiptView;
+ ICardanoAddress? ownerAccount;
+
+ bool fieldsIsReady = false;
+
+ void checkFildsReady() {
+ fieldsIsReady = !totalSupply.isZero &&
+ owmnerReceiptView != null &&
+ (assetName.trim().isNotEmpty);
+ setState(() {});
+ }
+
+ bool validateShellyAddress(ADAAddress addr) {
+ if (addr.addressType == ADAAddressType.byron) {
+ context.showAlert("byron_does_not_support_minting_token".tr);
+ return false;
+ }
+ return true;
+ }
+
+ void setPolicyId(ICardanoAddress? addr) {
+ if (addr == null) return;
+ if (!validateShellyAddress(addr.networkAddress)) return;
+ ownerAccount = addr;
+ owmnerReceiptView = ReceiptAddress(
+ view: addr.networkAddress.address,
+ type: addr.type,
+ networkAddress: addr.networkAddress,
+ account: addr);
+ checkFildsReady();
+ }
+
+ String assetName = "";
+ BigRational totalSupply = BigRational.zero;
+
+ void setSupply(BigRational? supply) {
+ if (supply == null ||
+ supply.isNegative ||
+ supply.isZero ||
+ supply > maxSupply) return;
+ totalSupply = supply;
+ checkFildsReady();
+ }
+
+ void onChangeAssetsName(String v) {
+ assetName = v;
+ final isReady = !totalSupply.isZero &&
+ owmnerReceiptView != null &&
+ (assetName.trim().isNotEmpty);
+ if (isReady != fieldsIsReady) {
+ checkFildsReady();
+ }
+ }
+
+ String? validator(String? v) {
+ final int length = v?.length ?? 0;
+ if (length < 1) {
+ return "ada_asset_name_validator".tr;
+ }
+ return null;
+ }
+
+ void onPaste(String v) {
+ textFieldKey.currentState?.updateText(v);
+ }
+
+ ADAMintInfo buildAsset() {
+ return ADAMintInfo(
+ owner: ownerAccount!.networkAddress,
+ pubKeyBytes: ownerAccount!.addressDetails.publicKey,
+ assets:
+ Assets({AssetName.fromString(assetName): totalSupply.toBigInt()}),
+ script: ownerAccount!.addressDetails.toNativeScript());
+ }
+
+ void onSubmit() {
+ if (!(formKey.currentState?.validate() ?? false)) return;
+ checkFildsReady();
+ if (!fieldsIsReady) return;
+ context.pop(buildAsset());
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Form(
+ key: formKey,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ PageTitleSubtitle(
+ title: "create_a_new_token".tr,
+ body: Text("ada_create_new_token_desc".tr)),
+ WidgetConstant.height20,
+ ReceiptAddressView(
+ title: "owner".tr,
+ subtitle: "owner_of_token".tr,
+ onTap: () {
+ context
+ .openSliverBottomSheet(
+ "select_account".tr,
+ child: SwitchOrSelectAccountView(
+ account: widget.account,
+ showMultiSig: true,
+ ),
+ minExtent: 0.5,
+ maxExtend: 0.9,
+ initialExtend: 0.7,
+ centerContent: false,
+ )
+ .then(setPolicyId);
+ },
+ address: owmnerReceiptView,
+ ),
+ WidgetConstant.height20,
+ Text("asset_name".tr, style: context.textTheme.titleMedium),
+ Text("name_of_token".tr),
+ WidgetConstant.height8,
+ AppTextField(
+ label: "asset_name".tr,
+ initialValue: assetName,
+ validator: validator,
+ suffixIcon: PasteTextIcon(onPaste: onPaste),
+ onChanged: onChangeAssetsName,
+ key: textFieldKey,
+ ),
+ WidgetConstant.height20,
+ Text("total_supply".tr, style: context.textTheme.titleMedium),
+ Text("total_supply_desc".tr),
+ WidgetConstant.height8,
+ ContainerWithBorder(
+ onRemoveIcon: totalSupply.isZero
+ ? const Icon(Icons.add)
+ : const Icon(Icons.edit),
+ validate: !totalSupply.isZero,
+ child: Text(totalSupply.isZero
+ ? "tap_to_input_total_supply".tr
+ : totalSupply.toDecimal()),
+ onRemove: () {
+ context
+ .openSliverBottomSheet(
+ "create_a_new_token".tr,
+ child: NumberWriteView(
+ allowDecimal: false,
+ max: _CardanoMintTokenViewState.maxSupply,
+ min: BigRational.one,
+ allowSign: false,
+ title: PageTitleSubtitle(
+ title: "total_supply".tr,
+ body: Text("total_supply_desc".tr)),
+ buttomText: "setup_supply".tr,
+ label: "create_a_new_token".tr,
+ ),
+ )
+ .then(setSupply);
+ },
+ ),
+ WidgetConstant.height20,
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ FixedElevatedButton(
+ onPressed: fieldsIsReady ? onSubmit : null,
+ child: Text("setup_mint".tr),
+ )
+ ],
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/send_transaction.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/send_transaction.dart
index f653f0f9..f48945c9 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/send_transaction.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/send_transaction.dart
@@ -1,16 +1,19 @@
import 'package:flutter/material.dart';
import 'package:mrt_wallet/app/core.dart';
import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/transaction/controller/controller.dart';
-import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/transaction/pages/cardano_transaction_asset_selector.dart';
+import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/transaction/pages/asset_info.dart';
+import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/transaction/pages/mint_token_view.dart';
+import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/transaction/pages/transaction_asset_selector.dart';
import 'package:mrt_wallet/future/pages/wallet_pages/network/cardano_pages/transaction/pages/memo_write_view.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/models/wallet_models/address/network_address/cardano/cardano.dart';
import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/cardano.dart';
-import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/utxo_multi_asset.dart';
import 'package:mrt_wallet/models/wallet_models/wallet_models.dart';
import 'package:on_chain/on_chain.dart';
+import 'transaction_certificate_view.dart';
+
class CardanoBuildTransactionView extends StatelessWidget {
const CardanoBuildTransactionView({super.key, required this.controller});
final CardanoTransactionStateController controller;
@@ -38,6 +41,73 @@ class CardanoBuildTransactionView extends StatelessWidget {
),
),
WidgetConstant.height20,
+ Text("mint".tr, style: context.textTheme.titleMedium),
+ Text("create_a_new_token".tr),
+ WidgetConstant.height8,
+ ...List.generate(controller.mints.length, (index) {
+ final assets = controller.mints[index].toUtxoAssets;
+ return Column(
+ children: List.generate(assets.assets.length, (pos) {
+ final assetName = assets.assets.keys.toList()[pos];
+ final balance = assets.assets[assetName]!;
+ final toToken =
+ Token(name: assetName.name, symbol: assetName.name);
+ return ContainerWithBorder(
+ onRemove: () =>
+ controller.removeMint(controller.mints[index]),
+ child: CoinPriceView(
+ token: toToken,
+ balance: balance,
+ style: context.textTheme.titleMedium));
+ }),
+ );
+ }),
+ ContainerWithBorder(
+ onRemoveIcon: const Icon(Icons.edit),
+ child: Text("tap_to_create_token".tr),
+ onRemove: () {
+ context
+ .openSliverBottomSheet("mint".tr,
+ child: CardanoMintTokenView(controller.account))
+ .then(controller.setupMint);
+ },
+ ),
+ WidgetConstant.height20,
+ Text("certificates".tr, style: context.textTheme.titleMedium),
+ Text("add_certificate_to_transaction".tr),
+ WidgetConstant.height8,
+ ...List.generate(controller.certificates.length, (index) {
+ final certificate = controller.certificates[index];
+ return ContainerWithBorder(
+ onRemove: () {
+ controller.removeCertificate(certificate);
+ },
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ // ADD
+ Text(certificate.type.viewName.tr,
+ style: context.textTheme.titleMedium),
+ Divider(
+ color: context.colors.onPrimaryContainer,
+ ),
+ ReceiptAddressDetailsView(address: certificate.rewardAccount)
+ ],
+ ));
+ }),
+ ContainerWithBorder(
+ onRemoveIcon: const Icon(Icons.edit),
+ child: Text("tap_to_add_certificate".tr),
+ onRemove: () {
+ context
+ .openSliverBottomSheet(
+ "certificate".tr,
+ child: CardanoTransactionCertificateView(controller.account),
+ )
+ .then(controller.addCertificate);
+ },
+ ),
+ WidgetConstant.height20,
Text("list_of_recipients".tr, style: context.textTheme.titleMedium),
Text("amount_for_each_output".tr),
WidgetConstant.height8,
@@ -57,6 +127,8 @@ class CardanoBuildTransactionView extends StatelessWidget {
children: [
ContainerWithBorder(
backgroundColor: context.colors.secondary,
+ validate: !receiver.isRewardAddress,
+ validateText: "cannot_send_ada_to_stake_address".tr,
child: ReceiptAddressDetailsView(
address: receiver.address,
color: context.colors.onSecondary,
@@ -142,11 +214,27 @@ class CardanoBuildTransactionView extends StatelessWidget {
? Text("tap_to_add_assets_for_recipient".tr,
style: context.textTheme.bodyMedium
?.copyWith(color: context.colors.onSecondary))
- : Text(
- "n_asset".tr.replaceOne(
- receiver.asset.totalAssets.toString()),
- style: context.textTheme.bodyMedium
- ?.copyWith(color: context.colors.onSecondary),
+ : Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ "n_asset".tr.replaceOne(
+ receiver.asset.totalAssets.toString()),
+ style: context.textTheme.bodyMedium?.copyWith(
+ color: context.colors.onSecondary),
+ ),
+ IconButton(
+ onPressed: () {
+ context.openSliverDialog(
+ (p0) => CardanoAssetsInfoView(
+ asset: receiver.asset),
+ "assets".tr);
+ },
+ icon: Icon(
+ Icons.remove_red_eye,
+ color: context.colors.onSecondary,
+ ))
+ ],
),
)
],
@@ -155,7 +243,6 @@ class CardanoBuildTransactionView extends StatelessWidget {
}),
),
ContainerWithBorder(
- validate: controller.receivers.isNotEmpty,
onRemove: () {
context
.openSliverBottomSheet>(
@@ -167,8 +254,8 @@ class CardanoBuildTransactionView extends StatelessWidget {
initialExtend: 0.9)
.then(
(value) {
- controller.onAddRecever(value, () {
- context.showAlert("address_already_exist".tr);
+ controller.onAddRecever(value, (s) {
+ context.showAlert(s.tr);
});
},
);
@@ -185,40 +272,34 @@ class CardanoBuildTransactionView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ContainerWithBorder(
- validate: !controller.remindAmount.isNegative,
- onRemoveIcon: Icon(Icons.edit, color: context.colors.onSecondary),
- backgroundColor: context.colors.secondary,
- validateText: "transaction_Insufficient_balance".tr,
- onRemove: () {
- context
- .openSliverBottomSheet(
- "select_account".tr,
- child: SwitchOrSelectAccountView(
- account: controller.account,
- showMultiSig: true,
- ),
- minExtent: 0.5,
- maxExtend: 0.9,
- initialExtend: 0.7,
- centerContent: false,
- )
- .then(controller.changeOutputAddress);
- },
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(controller.changeADAOutput.address.type ?? "",
- style: context.textTheme.labelLarge
- ?.copyWith(color: context.colors.onSecondary)),
- OneLineTextWidget(
- controller.changeADAOutput.address.view,
- style: context.textTheme.bodyMedium
- ?.copyWith(color: context.colors.onSecondary),
- )
- ],
- ),
- ),
+ // validate: !controller.remindAmount.isNegative,
+ onRemoveIcon:
+ Icon(Icons.edit, color: context.colors.onSecondary),
+ backgroundColor: context.colors.secondary,
+ validate: !controller.changeADAOutput.isRewardAddress,
+ validateText: "cannot_send_ada_to_stake_address".tr,
+ onRemove: () {
+ context
+ .openSliverBottomSheet(
+ "select_account".tr,
+ child: SwitchOrSelectAccountView(
+ account: controller.account,
+ showMultiSig: true,
+ ),
+ minExtent: 0.5,
+ maxExtend: 0.9,
+ initialExtend: 0.7,
+ centerContent: false,
+ )
+ .then(controller.changeOutputAddress);
+ },
+ child: ReceiptAddressDetailsView(
+ address: controller.changeADAOutput.address,
+ color: context.colors.onSecondary,
+ )),
ContainerWithBorder(
+ validate: !controller.remindAmount.isNegative,
+ validateText: "transaction_Insufficient_balance".tr,
backgroundColor: context.colors.secondary,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -242,160 +323,140 @@ class CardanoBuildTransactionView extends StatelessWidget {
],
)),
if (controller.hasAsset) ...[
- WidgetConstant.height20,
- Text("remaining_asset_amount".tr,
- style: context.textTheme.titleMedium),
- Text("remaining_asset_amount_and_receiver".tr),
- WidgetConstant.height8,
- ContainerWithBorder(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- ContainerWithBorder(
- validate: !controller.remindAmount.isNegative,
- onRemoveIcon:
- Icon(Icons.edit, color: context.colors.onSecondary),
- backgroundColor: context.colors.secondary,
- validateText: "transaction_Insufficient_balance".tr,
- onRemove: () {
- context
- .openSliverBottomSheet(
- "select_account".tr,
- child: SwitchOrSelectAccountView(
- account: controller.account,
- showMultiSig: true,
- ),
- minExtent: 0.5,
- maxExtend: 0.9,
- initialExtend: 0.7,
- centerContent: false,
- )
- .then(controller.changeAssetOutputAddress);
- },
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(controller.changeAssetOutput.address.type ?? "",
- style: context.textTheme.labelLarge
- ?.copyWith(color: context.colors.onSecondary)),
- OneLineTextWidget(
- controller.changeAssetOutput.address.view,
- style: context.textTheme.bodyMedium
- ?.copyWith(color: context.colors.onSecondary),
- )
- ],
- ),
- ),
- ContainerWithBorder(
- backgroundColor: context.colors.secondary,
- validate: controller.changeAssetOutput.hasAmount,
- onRemoveIcon:
- Icon(Icons.edit, color: context.colors.onSecondary),
- onRemove: () {
- context
- .openSliverBottomSheet(
- "setup_output_amount".tr,
- child: SetupNetworkAmount(
- token: controller.network.coinParam.token,
- max: controller.remindAmount.balance +
- controller.changeAssetOutput.balance.balance,
- min: BigInt.zero,
- subtitle: PageTitleSubtitle(
- title: "receiver".tr,
- body: ContainerWithBorder(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- controller.changeAssetOutput.address
- .networkAddress.addressType.name,
- style: context.textTheme.labelLarge),
- OneLineTextWidget(
- controller.changeAssetOutput.address.view)
- ],
- ))),
- ),
- )
- .then((amount) {
- controller.changeAssetAdaAmount(amount);
- });
- },
- child: Column(
+ AnimatedSize(
+ duration: AppGlobalConst.animationDuraion,
+ alignment: Alignment.topCenter,
+ child: controller.changeAssetOutput.hasAssets
+ ? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- CoinPriceView(
- balance: controller.changeAssetOutput.balance,
- token: controller.network.coinParam.token,
- symbolColor: context.colors.onSecondary,
- style: context.textTheme.titleLarge
- ?.copyWith(color: context.colors.onSecondary),
- ),
- if (controller.changeAssetOutput.minAdaRequired)
- ErrorTextContainer(
- showErrorIcon: false,
- error: "amount_must_exceed".tr.replaceOne(
- PriceUtils.priceWithCoinName(
- controller
- .changeAssetOutput.minAdaValue.price,
- controller.network.coinParam.token.symbol)))
+ WidgetConstant.height20,
+ Text("remaining_asset_amount".tr,
+ style: context.textTheme.titleMedium),
+ Text("remaining_asset_amount_and_receiver".tr),
+ WidgetConstant.height8,
+ ContainerWithBorder(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ ContainerWithBorder(
+ validate:
+ !controller.changeAssetOutput.isRewardAddress,
+ validateText:
+ "cannot_send_ada_to_stake_address".tr,
+ onRemoveIcon: Icon(Icons.edit,
+ color: context.colors.onSecondary),
+ backgroundColor: context.colors.secondary,
+ onRemove: () {
+ context
+ .openSliverBottomSheet(
+ "select_account".tr,
+ child: SwitchOrSelectAccountView(
+ account: controller.account,
+ showMultiSig: true,
+ ),
+ minExtent: 0.5,
+ maxExtend: 0.9,
+ initialExtend: 0.7,
+ centerContent: false,
+ )
+ .then(controller.changeAssetOutputAddress);
+ },
+ child: ReceiptAddressDetailsView(
+ address: controller.changeAssetOutput.address,
+ color: context.colors.onSecondary,
+ )),
+ ContainerWithBorder(
+ backgroundColor: context.colors.secondary,
+ validate: controller.changeAssetOutput.hasAmount,
+ onRemoveIcon: Icon(Icons.edit,
+ color: context.colors.onSecondary),
+ onRemove: () {
+ context
+ .openSliverBottomSheet(
+ "setup_output_amount".tr,
+ child: SetupNetworkAmount(
+ token: controller.network.coinParam.token,
+ max: controller.remindAmount.balance +
+ controller
+ .changeAssetOutput.balance.balance,
+ min: BigInt.zero,
+ subtitle: PageTitleSubtitle(
+ title: "receiver".tr,
+ body: ContainerWithBorder(
+ child: Column(
+ crossAxisAlignment:
+ CrossAxisAlignment.start,
+ children: [
+ Text(
+ controller
+ .changeAssetOutput
+ .address
+ .networkAddress
+ .addressType
+ .name,
+ style: context
+ .textTheme.labelLarge),
+ OneLineTextWidget(controller
+ .changeAssetOutput.address.view)
+ ],
+ ))),
+ ),
+ )
+ .then((amount) {
+ controller.changeAssetAdaAmount(amount);
+ });
+ },
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ CoinPriceView(
+ balance:
+ controller.changeAssetOutput.balance,
+ token: controller.network.coinParam.token,
+ symbolColor: context.colors.onSecondary,
+ style: context.textTheme.titleLarge
+ ?.copyWith(
+ color: context.colors.onSecondary),
+ ),
+ if (controller
+ .changeAssetOutput.minAdaRequired)
+ ErrorTextContainer(
+ showErrorIcon: false,
+ error: "amount_must_exceed"
+ .tr
+ .replaceOne(
+ PriceUtils.priceWithCoinName(
+ controller.changeAssetOutput
+ .minAdaValue.price,
+ controller.network.coinParam
+ .token.symbol)))
+ ],
+ )),
+ ContainerWithBorder(
+ backgroundColor: context.colors.secondary,
+ onRemove: () {
+ context.openSliverDialog(
+ (p0) => CardanoAssetsInfoView(
+ asset:
+ controller.changeAssetOutput.asset),
+ "assets".tr);
+ },
+ onRemoveIcon: Icon(Icons.remove_red_eye,
+ color: context.colors.onSecondary),
+ child: Text(
+ "n_asset".tr.replaceOne(controller
+ .changeAssetOutput.asset.totalAssets
+ .toString()),
+ style: context.textTheme.bodyMedium?.copyWith(
+ color: context.colors.onSecondary),
+ )),
+ ],
+ ))
],
- )),
- ContainerWithBorder(
- backgroundColor: context.colors.secondary,
- onRemove: () {
- context.openSliverDialog(
- (p0) => Column(
- children: List.generate(
- controller.changeAssetOutput.asset.assets
- .length, (index) {
- final pl = controller
- .changeAssetOutput.asset.assets.keys
- .toList()[index];
- final assets = controller
- .changeAssetOutput.asset.assets[pl]!;
- return Column(
- children: [
- Text(pl.toHex(), maxLines: 1),
- const Divider(),
- ...List.generate(assets.assets.length,
- (pos) {
- final assetName =
- assets.assets.keys.toList()[pos];
- return Row(
- mainAxisAlignment:
- MainAxisAlignment.spaceBetween,
- children: [
- Text(
- assetName.name(),
- style: context.textTheme.labelLarge,
- ),
- Flexible(
- child: CoinPriceView(
- token: Token(
- name: assetName.name(),
- symbol: assetName.name()),
- balance: assets.assets[assetName],
- ))
- ],
- );
- })
- ],
- );
- }),
- ),
- "assets".tr);
- },
- onRemoveIcon:
- Icon(Icons.help, color: context.colors.onSecondary),
- child: Text(
- "n_asset".tr.replaceOne(controller
- .changeAssetOutput.asset.totalAssets
- .toString()),
- style: context.textTheme.bodyMedium
- ?.copyWith(color: context.colors.onSecondary),
- )),
- ],
- )),
+ )
+ : WidgetConstant.sizedBox,
+ ),
],
WidgetConstant.height20,
Text("setup_memo".tr, style: context.textTheme.titleMedium),
@@ -450,6 +511,58 @@ class CardanoBuildTransactionView extends StatelessWidget {
},
child: Text("tap_to_add_memo".tr,
style: context.textTheme.labelLarge)),
+
+ /// deposit
+ AnimatedSize(
+ duration: AppGlobalConst.animationDuraion,
+ alignment: Alignment.topCenter,
+ child: controller.hasDeposit
+ ? Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ WidgetConstant.height20,
+ Text("deposit".tr, style: context.textTheme.titleMedium),
+ Text("transaction_deposits_list".tr),
+ WidgetConstant.height8,
+ ...List.generate(controller.deposits.length, (index) {
+ final deposit = controller.deposits[index];
+ return ContainerWithBorder(
+ child: CoinPriceView(
+ token: controller.network.coinParam.token,
+ balance: deposit.fee,
+ style: context.textTheme.titleMedium));
+ }),
+ ],
+ )
+ : null,
+ ),
+
+ /// deposit
+ AnimatedSize(
+ duration: AppGlobalConst.animationDuraion,
+ alignment: Alignment.topCenter,
+ child: controller.hasRefundDeposit
+ ? Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ WidgetConstant.height20,
+ Text("refund_deposit".tr,
+ style: context.textTheme.titleMedium),
+ Text("transaction_deposits_list".tr),
+ WidgetConstant.height8,
+ ...List.generate(controller.refundDeposit.length, (index) {
+ final deposit = controller.refundDeposit[index];
+ return ContainerWithBorder(
+ child: CoinPriceView(
+ token: controller.network.coinParam.token,
+ balance: deposit.fee,
+ style: context.textTheme.titleMedium));
+ }),
+ ],
+ )
+ : null,
+ ),
+
WidgetConstant.height20,
Text("transaction_fee".tr, style: context.textTheme.titleMedium),
Text("cost_for_transaction".tr),
@@ -495,8 +608,9 @@ class CardanoBuildTransactionView extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
FixedElevatedButton(
- onPressed:
- controller.trReady ? controller.sendTransaction : null,
+ onPressed: controller.trReady
+ ? controller.buildAndBroadcastTransaction
+ : null,
child: Text("send_transaction".tr)),
],
)
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/cardano_transaction_asset_selector.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/transaction_asset_selector.dart
similarity index 96%
rename from mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/cardano_transaction_asset_selector.dart
rename to mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/transaction_asset_selector.dart
index 33832043..d94c12c0 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/cardano_transaction_asset_selector.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/transaction_asset_selector.dart
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:mrt_wallet/app/core.dart';
import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/setup_amount.dart';
import 'package:mrt_wallet/future/widgets/custom_widgets.dart';
-import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/cardano_output.dart';
+import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/output.dart';
import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/utxo_asset.dart';
import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/utxo_multi_asset.dart';
import 'package:mrt_wallet/models/wallet_models/wallet_models.dart';
@@ -138,10 +138,13 @@ class _CardanoTransactionAssetSelectorViewState
))),
WidgetConstant.height20,
Text("choose_asset_you_want_to_transfer".tr,
- style: context.textTheme.titleLarge),
+ style: context.textTheme.titleMedium),
+ WidgetConstant.height8,
ListView.builder(
shrinkWrap: true,
itemCount: assets.length,
+ physics: WidgetConstant.noScrollPhysics,
+ // controller: widget.controller,
itemBuilder: (c, index) {
final asset = assets[index];
return ContainerWithCheckBoxAndBorder(
@@ -188,7 +191,7 @@ class _CardanoTransactionAssetSelectorViewState
children: [
Flexible(
child: Text(
- asset.name.name(),
+ asset.name.name,
maxLines: 1,
style: context.textTheme.bodySmall,
),
@@ -240,7 +243,7 @@ class _AssetWithPolicyId {
final PolicyID policyID;
final int decimal;
late final Token token =
- Token(name: name.name(), symbol: name.name(), decimal: decimal);
+ Token(name: name.name, symbol: name.name, decimal: decimal);
_AssetWithPolicyId(
{required this.name,
required this.policyID,
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/transaction_certificate_view.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/transaction_certificate_view.dart
new file mode 100644
index 00000000..bdffb608
--- /dev/null
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/transaction_certificate_view.dart
@@ -0,0 +1,135 @@
+import 'package:flutter/material.dart';
+import 'package:mrt_wallet/app/core.dart';
+import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/receipt_address_view.dart';
+import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/select_account.dart';
+import 'package:mrt_wallet/future/widgets/custom_widgets.dart';
+import 'package:mrt_wallet/models/wallet_models/address/network_address/cardano/cardano.dart';
+import 'package:mrt_wallet/models/wallet_models/network/custom/cardano/cardano.dart';
+import 'package:mrt_wallet/models/wallet_models/wallet_models.dart';
+import 'package:on_chain/on_chain.dart';
+
+class CardanoTransactionCertificateView extends StatefulWidget {
+ final NetworkAccountCore account;
+ const CardanoTransactionCertificateView(this.account, {super.key});
+
+ @override
+ State createState() =>
+ _CardanoTransactionCertificateViewState();
+}
+
+class _CardanoTransactionCertificateViewState
+ extends State with SafeState {
+ ADATransactionCertificateType type =
+ ADATransactionCertificateType.registraction;
+
+ bool get isReady => reward != null && address != null;
+
+ void onChageCertificate(ADATransactionCertificateType? newCertificate) {
+ type = newCertificate ?? type;
+ setState(() {});
+ }
+
+ ReceiptAddress? reward;
+ ICardanoAddress? address;
+
+ bool _validateRewardAccount(ICardanoAddress addr) {
+ if (addr.rewardAddress == null) {
+ context.showAlert("stake_address_validator".tr);
+ return false;
+ }
+ return true;
+ }
+
+ void updateRewardAddress(ICardanoAddress? addr) {
+ if (addr == null) return;
+ if (_validateRewardAccount(addr)) {
+ address = addr;
+ reward = ReceiptAddress(
+ view: addr.rewardAddress!.address,
+ type: addr.rewardAddress!.addressType.name,
+ networkAddress: addr.rewardAddress!,
+ account: addr);
+ setState(() {});
+ }
+ }
+
+ ADACertificateBuilder toCertificateBuilder() {
+ switch (type) {
+ case ADATransactionCertificateType.deregistration:
+ return ADACertificateBuilder(
+ certificate:
+ StakeDeregistration(reward!.networkAddress.paymentCredential),
+ signer: reward!.networkAddress);
+ case ADATransactionCertificateType.registraction:
+ return ADACertificateBuilder(
+ certificate:
+ StakeRegistration(reward!.networkAddress.paymentCredential));
+ default:
+ throw UnimplementedError();
+ }
+ }
+
+ ADATransactionCertificate toAdaTransactionCertificate() {
+ return ADATransactionCertificate(
+ certificate: toCertificateBuilder(),
+ type: type,
+ rewardAccount: ReceiptAddress(
+ view: reward!.networkAddress.address,
+ type: reward!.networkAddress.addressType.name,
+ networkAddress: reward!.networkAddress,
+ account: address));
+ }
+
+ void onSubmit() {
+ if (!isReady) return;
+ context.pop(toAdaTransactionCertificate());
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ Text("certificate_type".tr),
+ Text("add_certificate_to_transaction_desc".tr),
+ WidgetConstant.height8,
+ AppDropDownBottom(
+ items: {
+ for (final i in ADATransactionCertificateType.values)
+ i: Text(i.viewName.tr)
+ },
+ label: "certificate_type".tr,
+ onChanged: onChageCertificate,
+ ),
+ WidgetConstant.height20,
+ ReceiptAddressView(
+ title: "stake_address".tr,
+ onTap: () {
+ context
+ .openSliverBottomSheet(
+ "select_account".tr,
+ child: SwitchOrSelectAccountView(
+ account: widget.account,
+ showMultiSig: true,
+ ),
+ minExtent: 0.5,
+ maxExtend: 0.9,
+ initialExtend: 0.7,
+ centerContent: false,
+ )
+ .then(updateRewardAddress);
+ },
+ address: reward,
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ FixedElevatedButton(
+ padding: WidgetConstant.paddingVertical20,
+ onPressed: isReady ? onSubmit : null,
+ child: Text("setup_certificate".tr))
+ ],
+ )
+ ],
+ );
+ }
+}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/utxo_view.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/utxo_view.dart
index 74702142..47c2bc7a 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/utxo_view.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cardano_pages/transaction/pages/utxo_view.dart
@@ -11,7 +11,7 @@ class CardanoTransactionUtxoView extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Text("spendable_amount".tr, style: context.textTheme.titleMedium),
+ Text("utxos_amount".tr, style: context.textTheme.titleMedium),
WidgetConstant.height8,
ContainerWithBorder(
child: AnimatedSwitcher(
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
deleted file mode 100644
index 6deb8fc3..00000000
--- a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/setup_address.dart
+++ /dev/null
@@ -1,318 +0,0 @@
-import 'package:blockchain_utils/bip/bip/conf/bip_coins.dart';
-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/start_page/home.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/types/typedef.dart';
-
-typedef _OnChangeDerivation = void Function(bool? val, DynamicVoid onFalse);
-typedef _OnSetupKeyIndex = void Function(Bip32AddressIndex? newKeyIndex);
-
-class SetupCosmosAddressView extends StatefulWidget {
- const SetupCosmosAddressView({super.key});
-
- @override
- State createState() => _SetupCosmosAddressViewState();
-}
-
-class _SetupCosmosAddressViewState extends State
- with SafeState {
- final GlobalKey pageProgressKey =
- GlobalKey(debugLabel: "SetupEthereumAddressView");
- final GlobalKey form = GlobalKey();
- late final AppChain chainAccount;
- NetworkAccountCore get networkAccounts => chainAccount.account;
- final GlobalKey visibleGenerateAddress =
- GlobalKey(debugLabel: "visibleContinue");
- final GlobalKey visibleXAddressDetails =
- GlobalKey(debugLabel: "visibleContinue");
-
- AddressDerivationMode? selectedDerivationMode;
- EncryptedCustomKey? selectedCustomKey;
- bool inAddressPage = false;
- void goToAddressPage(
- AddressDerivationMode derivationMode, EncryptedCustomKey? customKey) {
- if (derivationMode == AddressDerivationMode.importedKey &&
- customKey == null) return;
- selectedDerivationMode = derivationMode;
- selectedCustomKey = customKey;
- inAddressPage = true;
- setState(() {});
- ensureKeyVisible(key: visibleGenerateAddress);
- }
-
- void _onBackButton() {
- if (pageProgressKey.isSuccess) return;
- try {
- if (inAddressPage) {
- selectedDerivationMode = null;
- selectedCustomKey = null;
- inAddressPage = false;
- customKeyIndex = null;
- }
- } finally {
- setState(() {});
- }
- }
-
- APPCosmosNetwork get network => networkAccounts.network as APPCosmosNetwork;
- List get coins => network.coins;
- CryptoCoins get coin => coins.firstWhere((element) =>
- element.conf.type ==
- (selectedCustomKey?.type ?? EllipticCurveTypes.secp256k1));
- bool inited = false;
- Bip32AddressIndex? customKeyIndex;
-
- void _setupIAccount() {
- if (inited) return;
- final model = context.watch(StateIdsConst.main);
- chainAccount = model.chain;
- }
-
- bool get derivationStandard => customKeyIndex == null;
- void onChangeDerivation(bool? val, DynamicVoid onFalse) {
- if (val == null) return;
- if (derivationStandard) {
- onFalse();
- return;
- } else {
- customKeyIndex = null;
- setState(() {});
- }
- }
-
- void setupKeyIndex(Bip32AddressIndex? newKeyIndex) {
- customKeyIndex = newKeyIndex;
- setState(() {});
- }
-
- @override
- void didChangeDependencies() {
- _setupIAccount();
- super.didChangeDependencies();
- }
-
- AddressDerivationIndex? derivationkey(CryptoCoins coin) {
- if (selectedCustomKey != null) {
- return ImportedAddressIndex(
- accountId: selectedCustomKey!.id,
- bip32KeyIndex: customKeyIndex,
- currencyCoin: coin);
- }
- return customKeyIndex;
- }
-
- AddressDerivationIndex get standardDerivation {
- return chainAccount.account.nextDrive(coin);
- }
-
- void generateAddress() async {
- if (!(form.currentState?.validate() ?? false)) return;
- pageProgressKey.progressText("generating_new_addr".tr);
- final model = context.watch(StateIdsConst.main);
-
- final keyIndex =
- derivationkey(coin) ?? chainAccount.account.nextDrive(coin);
- final newAccount =
- CosmosNewAddressParams(coin: coin, deriveIndex: keyIndex);
-
- final result = await model.deriveNewAccount(newAccount);
- if (result.hasError) {
- pageProgressKey.errorText(result.error!.tr);
- } else {
- pageProgressKey.success(
- backToIdle: false,
- progressWidget: SuccessWithButtomView(
- buttomText: "generate_new_address".tr,
- buttomWidget: ContainerWithBorder(
- margin: WidgetConstant.paddingVertical8,
- child: AddressDetailsView(address: result.result)),
- onPressed: () {
- if (mounted) {
- pageProgressKey.backToIdle();
- }
- },
- text: "address_added_success".tr,
- ));
- }
- setState(() {});
- }
-
- @override
- Widget build(BuildContext context) {
- return PopScope(
- canPop: !inAddressPage || pageProgressKey.isSuccess,
- onPopInvoked: (didPop) {
- if (!didPop) {
- _onBackButton();
- }
- },
- child: Scaffold(
- appBar: AppBar(
- title: Text("setup_address".tr),
- ),
- body: PageProgress(
- key: pageProgressKey,
- backToIdle: AppGlobalConst.oneSecoundDuration,
- initialStatus: PageProgressStatus.idle,
- child: () => UnfocusableChild(
- child: Center(
- child: CustomScrollView(
- shrinkWrap: true,
- slivers: [
- SliverToBoxAdapter(
- child: ConstraintsBoxView(
- padding: WidgetConstant.paddingHorizontal20,
- child: AnimatedSwitcher(
- duration: AppGlobalConst.animationDuraion,
- child: inAddressPage
- ? _GenerateAddress(
- network: network,
- form: form,
- derivationStandard: derivationStandard,
- onChangeDerivation: onChangeDerivation,
- coin: coin,
- setupKeyIndex: setupKeyIndex,
- standardDerivation: standardDerivation,
- generateAddress: generateAddress,
- customKeyIndex: customKeyIndex,
- selectedCustomKey: selectedCustomKey,
- )
- : Column(
- children: [
- WidgetConstant.height20,
- PageTitleSubtitle(
- title: "derive_network_address"
- .tr
- .replaceOne(
- network.coinParam.token.name),
- body: Column(
- crossAxisAlignment:
- CrossAxisAlignment.start,
- children: [
- LargeTextView(
- ["bip44_derivation_desc".tr]),
- ],
- )),
- SetupAddressDerivation(goToAddressPage)
- ],
- ),
- ),
- ))
- ],
- ),
- ),
- ),
- ),
- ),
- );
- }
-}
-
-class _GenerateAddress extends StatelessWidget {
- const _GenerateAddress(
- {required this.network,
- required this.form,
- this.selectedCustomKey,
- required this.derivationStandard,
- required this.onChangeDerivation,
- this.customKeyIndex,
- required this.coin,
- required this.setupKeyIndex,
- required this.standardDerivation,
- required this.generateAddress});
- final APPCosmosNetwork network;
- final GlobalKey form;
- final EncryptedCustomKey? selectedCustomKey;
- final bool derivationStandard;
- final _OnChangeDerivation onChangeDerivation;
- final Bip32AddressIndex? customKeyIndex;
- final CryptoCoins coin;
- final _OnSetupKeyIndex setupKeyIndex;
- final AddressDerivationIndex standardDerivation;
- final DynamicVoid generateAddress;
- @override
- Widget build(BuildContext context) {
- return Form(
- key: form,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- key: const ValueKey(true),
- children: [
- PageTitleSubtitle(
- title: "derive_network_address"
- .tr
- .replaceOne(network.coinParam.token.name),
- body: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text("disable_standard_derivation".tr),
- WidgetConstant.height8,
- if (selectedCustomKey != null)
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text("generate_from_imported_keys".tr),
- WidgetConstant.height8,
- Text("generate_from_imported_key_desc1".tr)
- ],
- )
- else
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text("generate_from_hd_wallet".tr),
- ],
- )
- ],
- )),
- AppSwitchListTile(
- value: derivationStandard,
- onChanged: (p0) {
- onChangeDerivation(
- p0,
- () {
- context
- .openSliverBottomSheet(
- "key_derivation".tr,
- child: Bip32KeyDerivationView(
- coin: coin,
- curve: coin.conf.type,
- ))
- .then(setupKeyIndex);
- },
- );
- },
- title: selectedCustomKey == null
- ? Text(derivationStandard
- ? "standard_derivation".tr
- : "custom_derivation".tr)
- : Text(customKeyIndex == null
- ? "non_derivation".tr
- : "custom_derivation".tr),
- subtitle: selectedCustomKey == null
- ? Text(customKeyIndex?.path ?? standardDerivation.path)
- : Text(
- customKeyIndex?.path ?? "import_key_derivation_desc2".tr),
- ),
- WidgetConstant.height20,
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- FixedElevatedButton(
- padding: WidgetConstant.paddingVertical20,
- onPressed: generateAddress,
- child: Text("generate_address".tr),
- ),
- ],
- )
- ],
- ),
- );
- }
-}
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 4067ac60..fb895158 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
@@ -72,6 +72,7 @@ mixin CosmosTransactionFeeImpl on CosmosTransactiomImpl {
_feeError = null;
_cancelable.cancel();
feeProgressKey.process();
+ notify();
try {
final result = await MethodCaller.call(() async {
return await _simulateTr();
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/impl/signer.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/impl/signer.dart
index 38847cbe..68c44900 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/impl/signer.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/controller/impl/signer.dart
@@ -23,9 +23,11 @@ mixin CosmosSignerImpl on CosmosTransactiomImpl {
.where((element) => element != null)
.toList()
.cast();
+
final signers = account.addresses
.where((element) => signersAddr.contains(element.address.toAddress))
.toList();
+
final signRequest = CosmosSigningRequest(
addresses: signers, network: network, digest: signDoc.toBuffer());
final signatures =
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/fields/transaction.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/fields/transaction.dart
index e80fecc7..8d2ddd47 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/fields/transaction.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/cosmos/transaction/fields/transaction.dart
@@ -79,6 +79,9 @@ class CosmosTransactionFieldsView extends StatelessWidget {
validateText: controller.feeError?.tr,
validate: controller.feeError == null &&
controller.hasFee,
+ onTapError: () {
+ controller.simulateTr();
+ },
onRemove: () {
if (controller.isThorChain) {
return;
@@ -188,6 +191,7 @@ class CosmosTransactionFieldsView extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
FixedElevatedButton(
+ padding: WidgetConstant.paddingVertical20,
onPressed: controller.trIsReady
? controller.sendTransaction
: null,
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 70bfcff9..dca323ec 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
@@ -63,12 +63,13 @@ class _EthereumTokenView extends StatelessWidget {
return ContainerWithBorder(
onRemove: () {
context.openDialogPage(
- (ctx) => TokenDetailsModalView(
- token: token,
- address: account,
- transferPath: PagePathConst.ethereumTransaction,
- ),
- "token_info".tr);
+ "token_info".tr,
+ child: (ctx) => TokenDetailsModalView(
+ token: token,
+ address: account,
+ transferPath: PagePathConst.ethereumTransaction,
+ ),
+ );
},
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
deleted file mode 100644
index f91f19e8..00000000
--- a/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/setup_address.dart
+++ /dev/null
@@ -1,298 +0,0 @@
-import 'package:blockchain_utils/bip/bip/conf/bip_coins.dart';
-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/start_page/home.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/types/typedef.dart';
-
-class SetupEthereumAddressView extends StatefulWidget {
- const SetupEthereumAddressView({super.key});
-
- @override
- State createState() =>
- _SetupEthereumAddressViewState();
-}
-
-class _SetupEthereumAddressViewState extends State
- with SafeState {
- final GlobalKey pageProgressKey =
- GlobalKey(debugLabel: "SetupEthereumAddressView");
- final GlobalKey form = GlobalKey();
- late final AppChain chainAccount;
- NetworkAccountCore get networkAccounts => chainAccount.account;
- final GlobalKey visibleGenerateAddress =
- GlobalKey(debugLabel: "visibleContinue");
- final GlobalKey visibleXAddressDetails =
- GlobalKey(debugLabel: "visibleContinue");
- AddressDerivationMode? selectedDerivationMode;
- EncryptedCustomKey? selectedCustomKey;
- int tag = 0;
-
- void onChangeTag(String v) {
- final newTag = int.tryParse(v);
- if (newTag == null || newTag < 0 || newTag > mask32 - 1) return;
- tag = newTag;
- }
-
- bool inAddressPage = false;
-
- void goToAddressPage(
- AddressDerivationMode derivationMode, EncryptedCustomKey? customKey) {
- if (derivationMode == AddressDerivationMode.importedKey &&
- customKey == null) return;
- selectedDerivationMode = derivationMode;
- selectedCustomKey = customKey;
- inAddressPage = true;
- setState(() {});
- ensureKeyVisible(key: visibleGenerateAddress);
- }
-
- void _onBackButton() {
- if (pageProgressKey.isSuccess) return;
- if (inAddressPage) {
- selectedDerivationMode = null;
- selectedCustomKey = null;
- inAddressPage = false;
-
- customKeyIndex = null;
- }
- setState(() {});
- }
-
- APPEVMNetwork get network => networkAccounts.network as APPEVMNetwork;
- List get coins => network.coins;
- CryptoCoins get coin => coins.firstWhere((element) =>
- element.conf.type ==
- (selectedCustomKey?.type ?? EllipticCurveTypes.secp256k1));
- bool inited = false;
- Bip32AddressIndex? customKeyIndex;
-
- void _setupIAccount() {
- if (inited) return;
- final model = context.watch(StateIdsConst.main);
- chainAccount = model.chain;
- }
-
- bool get derivationStandard => customKeyIndex == null;
- void onChangeDerivation(bool? val, DynamicVoid onFalse) {
- if (val == null) return;
- if (derivationStandard) {
- onFalse();
- return;
- } else {
- customKeyIndex = null;
- setState(() {});
- }
- }
-
- void setupKeyIndex(Bip32AddressIndex? newKeyIndex) {
- customKeyIndex = newKeyIndex;
- setState(() {});
- }
-
- @override
- void didChangeDependencies() {
- _setupIAccount();
- super.didChangeDependencies();
- }
-
- AddressDerivationIndex? derivationkey(CryptoCoins coin) {
- if (selectedCustomKey != null) {
- return ImportedAddressIndex(
- accountId: selectedCustomKey!.id,
- bip32KeyIndex: customKeyIndex,
- currencyCoin: coin);
- }
- return customKeyIndex;
- }
-
- AddressDerivationIndex get standardDerivation {
- return chainAccount.account.nextDrive(coin);
- }
-
- void generateAddress() async {
- if (!(form.currentState?.validate() ?? false)) return;
- pageProgressKey.progressText("generating_new_addr".tr);
- final model = context.watch(StateIdsConst.main);
- final curve = selectedCustomKey?.type ?? EllipticCurveTypes.secp256k1;
- final coin = coins.firstWhere((element) => element.conf.type == curve);
-
- final keyIndex =
- derivationkey(coin) ?? chainAccount.account.nextDrive(coin);
- final newAccount =
- EthereumNewAddressParam(coin: coin, deriveIndex: keyIndex);
-
- final result = await model.deriveNewAccount(newAccount);
- if (result.hasError) {
- pageProgressKey.errorText(result.error!.tr);
- } else {
- pageProgressKey.success(
- backToIdle: false,
- progressWidget: SuccessWithButtomView(
- buttomText: "generate_new_address".tr,
- buttomWidget: ContainerWithBorder(
- margin: WidgetConstant.paddingVertical8,
- child: AddressDetailsView(address: result.result)),
- onPressed: () {
- if (mounted) {
- pageProgressKey.backToIdle();
- }
- },
- text: "address_added_success".tr,
- ));
- }
- setState(() {});
- }
-
- @override
- Widget build(BuildContext context) {
- return PopScope(
- canPop: !inAddressPage || pageProgressKey.isSuccess,
- onPopInvoked: (didPop) {
- if (!didPop) {
- _onBackButton();
- }
- },
- child: Scaffold(
- appBar: AppBar(
- title: Text("setup_address".tr),
- ),
- body: PageProgress(
- key: pageProgressKey,
- backToIdle: AppGlobalConst.oneSecoundDuration,
- initialStatus: PageProgressStatus.idle,
- child: () => UnfocusableChild(
- child: Center(
- child: CustomScrollView(
- shrinkWrap: true,
- slivers: [
- SliverToBoxAdapter(
- child: ConstraintsBoxView(
- padding: WidgetConstant.paddingHorizontal20,
- child: AnimatedSwitcher(
- duration: AppGlobalConst.animationDuraion,
- child: inAddressPage
- ? Form(
- key: form,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- key: const ValueKey(true),
- children: [
- PageTitleSubtitle(
- title: "derive_network_address"
- .tr
- .replaceOne(
- network.coinParam.token.name),
- body: Column(
- crossAxisAlignment:
- CrossAxisAlignment.start,
- children: [
- Text(
- "disable_standard_derivation".tr),
- WidgetConstant.height8,
- if (selectedCustomKey != null)
- Column(
- crossAxisAlignment:
- CrossAxisAlignment.start,
- children: [
- Text(
- "generate_from_imported_keys"
- .tr),
- WidgetConstant.height8,
- Text(
- "generate_from_imported_key_desc1"
- .tr)
- ],
- )
- else
- Column(
- crossAxisAlignment:
- CrossAxisAlignment.start,
- children: [
- Text("generate_from_hd_wallet"
- .tr),
- ],
- )
- ],
- )),
- AppSwitchListTile(
- value: derivationStandard,
- onChanged: (p0) {
- onChangeDerivation(
- p0,
- () {
- context
- .openSliverBottomSheet<
- Bip32AddressIndex>(
- "key_derivation".tr,
- child: Bip32KeyDerivationView(
- coin: coin,
- curve: coin.conf.type,
- ))
- .then(setupKeyIndex);
- },
- );
- },
- title: selectedCustomKey == null
- ? Text(derivationStandard
- ? "standard_derivation".tr
- : "custom_derivation".tr)
- : Text(customKeyIndex == null
- ? "non_derivation".tr
- : "custom_derivation".tr),
- subtitle: selectedCustomKey == null
- ? Text(customKeyIndex?.path ??
- standardDerivation.path)
- : Text(customKeyIndex?.path ??
- "import_key_derivation_desc2".tr),
- ),
- WidgetConstant.height20,
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- FixedElevatedButton(
- padding:
- WidgetConstant.paddingVertical20,
- onPressed: generateAddress,
- child: Text("generate_address".tr),
- ),
- ],
- )
- ],
- ),
- )
- : Column(
- children: [
- WidgetConstant.height20,
- PageTitleSubtitle(
- title: "derive_network_address"
- .tr
- .replaceOne(
- network.coinParam.token.name),
- body: Column(
- crossAxisAlignment:
- CrossAxisAlignment.start,
- children: [
- LargeTextView(
- ["bip44_derivation_desc".tr]),
- ],
- )),
- SetupAddressDerivation(goToAddressPage)
- ],
- ),
- ),
- ))
- ],
- ),
- ),
- ),
- ),
- ),
- );
- }
-}
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/transaction/fields/ethereum_transaction_fields_view.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/transaction/fields/ethereum_transaction_fields_view.dart
index 6abcb01b..c2a71502 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/transaction/fields/ethereum_transaction_fields_view.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/transaction/fields/ethereum_transaction_fields_view.dart
@@ -54,8 +54,7 @@ class EthereumTransactionFieldsView extends StatelessWidget {
onRemoveIcon: const Icon(Icons.edit),
child: AddressDetailsView(
address: controller.owner,
- key: ValueKey(
- controller.owner)),
+ key: ValueKey(controller.owner)),
onRemove: () {
context
.openSliverBottomSheet(
diff --git a/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/transaction/fields/global/gas_fee_view.dart b/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/transaction/fields/global/gas_fee_view.dart
index ce4ba5f8..0193751a 100644
--- a/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/transaction/fields/global/gas_fee_view.dart
+++ b/mrt_wallet/lib/future/pages/wallet_pages/network/ethereum_pages/transaction/fields/global/gas_fee_view.dart
@@ -42,8 +42,9 @@ class EthereumGasFeeView extends StatelessWidget {
child: AnimatedSwitcher(
duration: AppGlobalConst.animationDuraion,
child: Row(
- key: ValueKey(
- "${transaction.gasInited}/${transaction.updatingGas}"),
+ key: UniqueKey(),
+ // key: ValueKey(
+ // "${transaction.gasInited}/${transaction.updatingGas}"),
children: [
Expanded(
child: transaction.gasInited
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 953695f1..67b1be45 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
@@ -223,12 +223,13 @@ class _RippleTokensView extends StatelessWidget {
return ContainerWithBorder(
onRemove: () {
context.openDialogPage(
- (ctx) => TokenDetailsModalView(
- token: token,
- address: account,
- transferPath: PagePathConst.rippleTransfer,
- ),
- "token_info".tr);
+ "token_info".tr,
+ child: (ctx) => TokenDetailsModalView(
+ token: token,
+ address: account,
+ transferPath: PagePathConst.rippleTransfer,
+ ),
+ );
},
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 a384b1ef..8e92cbaa 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
@@ -1,43 +1,22 @@
-import 'package:blockchain_utils/bip/bip/conf/bip_coins.dart';
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/start_page/home.dart';
-import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/wallet_global_pages.dart';
-
+import 'package:mrt_wallet/future/pages/wallet_pages/global_pages/address_derivation/controller.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/types/typedef.dart';
-
class SetupRippleAddressView extends StatefulWidget {
- const SetupRippleAddressView({super.key});
-
+ final AddressDerivationController controller;
+ const SetupRippleAddressView({super.key, required this.controller});
@override
State createState() => _SetupRippleAddressViewState();
}
class _SetupRippleAddressViewState extends State
with SafeState {
- final GlobalKey pageProgressKey =
- GlobalKey(debugLabel: "SetupBitcoinAddressView");
- final GlobalKey form = GlobalKey();
- late final AppChain chainAccount;
- AddressDerivationIndex get standardDerivation {
- return chainAccount.account.nextDrive(coin);
- }
-
- NetworkAccountCore get networkAccounts => chainAccount.account;
- final GlobalKey visibleGenerateAddress =
- GlobalKey(debugLabel: "visibleContinue");
- final GlobalKey visibleXAddressDetails =
- GlobalKey(debugLabel: "visibleContinue");
- AddressDerivationMode? selectedDerivationMode;
- EncryptedCustomKey? selectedCustomKey;
+ Set addressTyoe = {XrpAddressType.classic};
+ bool get isXAddress => addressTyoe.first == XrpAddressType.xAddress;
int tag = 0;
-
void onChangeTag(String v) {
final newTag = int.tryParse(v);
if (newTag == null || newTag < 0 || newTag > mask32 - 1) return;
@@ -53,296 +32,75 @@ class _SetupRippleAddressViewState extends State
return null;
}
- bool inAddressPage = false;
- Set addressTyoe = {XrpAddressType.classic};
void onSelectAddressType(Set selectType) {
addressTyoe = selectType;
setState(() {});
- if (isXAddress) {
- ensureKeyVisible(key: visibleXAddressDetails);
- }
- }
-
- bool get isXAddress => addressTyoe.first == XrpAddressType.xAddress;
-
- void goToAddressPage(
- AddressDerivationMode derivationMode, EncryptedCustomKey? customKey) {
- if (derivationMode == AddressDerivationMode.importedKey &&
- customKey == null) return;
- selectedDerivationMode = derivationMode;
- selectedCustomKey = customKey;
- inAddressPage = true;
- setState(() {});
- ensureKeyVisible(key: visibleGenerateAddress);
- }
-
- void _onBackButton() {
- if (pageProgressKey.isSuccess) return;
- if (inAddressPage) {
- selectedDerivationMode = null;
- selectedCustomKey = null;
- inAddressPage = false;
-
- customKeyIndex = null;
- }
- setState(() {});
- }
-
- AppXRPNetwork get network => networkAccounts.network as AppXRPNetwork;
- List get coins => network.coins;
- CryptoCoins get coin => coins.firstWhere((element) =>
- element.conf.type ==
- (selectedCustomKey?.type ?? EllipticCurveTypes.secp256k1));
- bool inited = false;
- Bip32AddressIndex? customKeyIndex;
-
- void _setupIAccount() {
- if (inited) return;
- final model = context.watch(StateIdsConst.main);
- chainAccount = model.chain;
- }
-
- bool get derivationStandard => customKeyIndex == null;
- void onChangeDerivation(bool? val, DynamicVoid onFalse) {
- if (val == null) return;
- if (derivationStandard) {
- onFalse();
- return;
- } else {
- customKeyIndex = null;
- setState(() {});
- }
- }
-
- void setupKeyIndex(Bip32AddressIndex? newKeyIndex) {
- customKeyIndex = newKeyIndex;
- setState(() {});
- }
-
- @override
- void didChangeDependencies() {
- _setupIAccount();
- super.didChangeDependencies();
- }
-
- AddressDerivationIndex? derivationkey(CryptoCoins coin) {
- if (selectedCustomKey != null) {
- return ImportedAddressIndex(
- accountId: selectedCustomKey!.id,
- bip32KeyIndex: customKeyIndex,
- currencyCoin: coin);
- }
- return customKeyIndex;
}
void generateAddress() async {
- if (!(form.currentState?.validate() ?? false)) return;
- pageProgressKey.progressText("generating_new_addr".tr);
- final model = context.watch(StateIdsConst.main);
- final curve = selectedCustomKey?.type ?? EllipticCurveTypes.secp256k1;
- final coin = coins.firstWhere((element) => element.conf.type == curve);
-
- final keyIndex =
- derivationkey(coin) ?? chainAccount.account.nextDrive(coin);
+ final keyIndex = await widget.controller.getCoin(context);
+ if (keyIndex == null) return;
final newAccount = RippleNewAddressParam(
- coin: coin,
deriveIndex: keyIndex,
- type: curve,
+ type: keyIndex.currencyCoin.conf.type,
tag: addressTyoe.first == XrpAddressType.classic ? null : tag);
-
- final result = await model.deriveNewAccount(newAccount);
- if (result.hasError) {
- pageProgressKey.errorText(result.error!.tr);
- } else {
- pageProgressKey.success(
- backToIdle: false,
- progressWidget: SuccessWithButtomView(
- buttomText: "generate_new_address".tr,
- buttomWidget: ContainerWithBorder(
- margin: WidgetConstant.paddingVertical8,
- child: AddressDetailsView(address: result.result)),
- onPressed: () {
- if (mounted) {
- pageProgressKey.backToIdle();
- }
- },
- text: "address_added_success".tr,
- ));
- }
- setState(() {});
+ widget.controller.generateAddress(newAccount);
}
@override
Widget build(BuildContext context) {
- return PopScope(
- canPop: !inAddressPage || pageProgressKey.isSuccess,
- onPopInvoked: (didPop) {
- if (!didPop) {
- _onBackButton();
- }
- },
- child: Scaffold(
- appBar: AppBar(
- title: Text("setup_address".tr),
- ),
- body: PageProgress(
- key: pageProgressKey,
- backToIdle: AppGlobalConst.oneSecoundDuration,
- initialStatus: PageProgressStatus.idle,
- child: () => UnfocusableChild(
- child: Center(
- child: CustomScrollView(
- shrinkWrap: true,
- slivers: [
- SliverToBoxAdapter(
- child: ConstraintsBoxView(
- padding: WidgetConstant.paddingHorizontal20,
- child: AnimatedSwitcher(
- duration: AppGlobalConst.animationDuraion,
- child: inAddressPage
- ? Form(
- key: form,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- key: const ValueKey(true),
- children: [
- PageTitleSubtitle(
- title: "derive_network_address"
- .tr
- .replaceOne(
- network.coinParam.token.name),
- body: Column(
- crossAxisAlignment:
- CrossAxisAlignment.start,
- children: [
- LargeTextView([
- "choose_bitcoin_address_type_desc"
- .tr,
- "x_address_desc".tr,
- "classic_address_desc".tr,
- if (selectedCustomKey != null) ...[
- "generate_from_imported_keys".tr,
- "generate_from_imported_key_desc1"
- .tr
- ] else ...[
- "generate_from_hd_wallet".tr
- ]
- ]),
- ],
- )),
- AppSwitchListTile(
- value: derivationStandard,
- onChanged: (p0) {
- onChangeDerivation(
- p0,
- () {
- context
- .openSliverBottomSheet<
- Bip32AddressIndex>(
- "key_derivation".tr,
- child: Bip32KeyDerivationView(
- coin: coin,
- curve: coin.conf.type,
- ))
- .then(setupKeyIndex);
- },
- );
- },
- title: selectedCustomKey == null
- ? Text(derivationStandard
- ? "standard_derivation".tr
- : "custom_derivation".tr)
- : Text(customKeyIndex == null
- ? "non_derivation".tr
- : "custom_derivation".tr),
- subtitle: selectedCustomKey == null
- ? Text(customKeyIndex?.path ??
- standardDerivation.path)
- : Text(customKeyIndex?.path ??
- "import_key_derivation_desc2".tr),
- ),
- WidgetConstant.height20,
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Flexible(
- child:
- AppSegmentedButton(
- items: {
- XrpAddressType.classic:
- XrpAddressType.classic.value.tr,
- XrpAddressType.xAddress:
- XrpAddressType.xAddress.value.tr
- },
- selected: addressTyoe,
- onChangeSelected: onSelectAddressType,
- ),
- ),
- ],
- ),
- WidgetConstant.height20,
- AnimatedSize(
- duration: AppGlobalConst.animationDuraion,
- child: isXAddress
- ? Column(
- crossAxisAlignment:
- CrossAxisAlignment.start,
- children: [
- PageTitleSubtitle(
- title: "x_address_desc2".tr,
- body: LargeTextView([
- "x_address_desc3".tr
- ])),
- Text("assigning_tag".tr,
- style: context
- .textTheme.titleMedium),
- Text("enter_tag_desc".tr),
- WidgetConstant.height8,
- NumberTextField(
- label: "tag".tr,
- onChange: onChangeTag,
- validator: validateTag,
- defaultValue: tag,
- max: mask32 - 1,
- min: 0),
- ],
- )
- : const SizedBox()),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- FixedElevatedButton(
- padding:
- WidgetConstant.paddingVertical20,
- onPressed: generateAddress,
- child: Text("generate_address".tr),
- ),
- ],
- )
- ],
- ),
- )
- : Column(
- children: [
- WidgetConstant.height20,
- PageTitleSubtitle(
- title: "derive_network_address"
- .tr
- .replaceOne(
- network.coinParam.token.name),
- body: LargeTextView(
- ["bip44_derivation_desc".tr])),
- SetupAddressDerivation(goToAddressPage)
- ],
- ),
- ),
- ))
- ],
+ return Column(
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Flexible(
+ child: AppSegmentedButton(
+ items: {
+ XrpAddressType.classic: XrpAddressType.classic.value.tr,
+ XrpAddressType.xAddress: XrpAddressType.xAddress.value.tr
+ },
+ selected: addressTyoe,
+ onChangeSelected: onSelectAddressType,
),
),
- ),
+ ],
),
- ),
+ WidgetConstant.height20,
+ AnimatedSize(
+ duration: AppGlobalConst.animationDuraion,
+ child: isXAddress
+ ? Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ PageTitleSubtitle(
+ title: "x_address_desc2".tr,
+ body: LargeTextView(["x_address_desc3".tr])),
+ Text("assigning_tag".tr,
+ style: context.textTheme.titleMedium),
+ Text("enter_tag_desc".tr),
+ WidgetConstant.height8,
+ NumberTextField(
+ label: "tag".tr,
+ onChange: onChangeTag,
+ validator: validateTag,
+ defaultValue: tag,
+ max: mask32 - 1,
+ min: 0),
+ ],
+ )
+ : const SizedBox()),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ FixedElevatedButton(
+ padding: WidgetConstant.paddingVertical20,
+ onPressed: generateAddress,
+ child: Text("generate_address".tr),
+ ),
+ ],
+ )
+ ],
);
}
}
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 93f5ae84..b86a3d7b 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
@@ -65,13 +65,12 @@ class _SolanaTokenView extends StatelessWidget {
final SolanaSPLToken token = account.tokens[index];
return ContainerWithBorder(
onRemove: () {
- context.openDialogPage(
- (ctx) => TokenDetailsModalView(
+ context.openDialogPage