mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
CW-1250: Refactor L2 Chains Code (#2677)
* feat(evm): add ChainConfig model and related classes - Add ChainConfig class for immutable EVM chain configuration - Add ChainCapabilities class for chain feature flags - Add FeeType enum and FeeModel class for fee configuration * feat(evm): add EvmChainRegistry for centralized chain management - Add singleton EvmChainRegistry class with chain configuration storage - Initialize with Ethereum, Polygon, Base, and Arbitrum chains - Add mappings for WalletType, tag, and CAIP-2 to chainId lookups - Provide lookup methods for chain configurations by various identifiers - Support for querying available chains and registered chain IDs * feat(evm): add EVMChainClientFactory and consolidate chain clients - Create EVMChainClientFactory for creating chain-specific clients based on chainId - Move all chain clients (EthereumClient, PolygonClient, BaseClient, ArbitrumClient) into cw_evm/lib/clients/ folder - Refactor EVMChainClient from abstract to concrete class with default implementations - Add default implementations for fetchTransactions, fetchInternalTransactions, and prepareSignedTransactionForSending - Update all client classes to use super(chainId: X) constructor pattern - Factory returns EVMChainClient directly for unregistered chains instead of throwing - Remove dependencies on cw_ethereum, cw_polygon, cw_base, cw_arbitrum packages from pubspec.yaml - Consolidate all EVM chain client implementations in one location for easier maintenance * add ui for evm switcher on eth * add inputs for evm network list edit switches * refactor(evm): Make EVMChainWallet concrete and unify transaction classes - Make EVMChainWallet and EVMChainWalletBase concrete classes (removed abstract) - Implement all previously abstract methods in EVMChainWallet - Make EVMChainTransactionInfo and EVMChainTransactionHistory concrete - Reorganize default tokens into tokens/ folder: - Refactor EVMChainDefaultTokens to import and use token classes from tokens/ folder - Move clients to clients/ folder: - Move evm_chain_formatter.dart to utils - Update chain-specific transaction history classes to pass walletType to fromJson - Update old wallet classes (EthereumWallet, PolygonWallet, etc.) to pass walletType - Maintain compatibility with existing per-chain wallet classes This refactoring enables the unified EVMChainWallet architecture while maintaining full backward compatibility with existing per-chain wallet implementations. * feat(evm): Add chain selection capability to EVMChainWallet - Add selectedChainId observable field to track currently selected chain - Add selectChain(chainId) action method to switch between EVM chains - Add selectedChainConfig computed getter for accessing chain configuration - Initialize selectedChainId from client.chainId in constructor - Add _getClientForCurrentChain() helper method for future use This enables chain switching functionality while maintaining full backward compatibility. The selectedChainId is initialized from the existing client, and all existing methods continue to work unchanged. Future increments will update methods to use selectedChainId internally. * refactor(evm): Update client immediately on chain selection - Update selectChain() to immediately create new client for selected chain - Remove _getClientForCurrentChain() helper method - Simplify all methods to use _client directly instead of helper calls - Client is now always in sync with selectedChainId This improves code simplicity and performance by eliminating repeated client checks. The client is updated synchronously when selectChain() is called, ensuring state consistency. * featr(evm): Add unified evm proxy setup and fix chain initialization - Add unified Evm proxy - Add evm.dart to .gitignore for generated proxy - Add generateEVM() to configure.dart for proxy generation - Fix selectedChainId to initialize from registry based on walletInfo.type Ensures selectedChainId always matches wallet type on initialization and adds unified proxy infrastructure. * refactor(evm): Update backward compat helpers to use registry via proxy - Add registry helper methods to unified EVM proxy - Update all lib/ files to use proxy instead of direct cw_evm imports - Enforce proxy pattern: no direct imports from cw_evm in main app - Update configure.dart to include registry methods in generated proxy Maintains backward compatibility while centralizing chain data access through the unified proxy pattern. * feat(evm): Add chain selection UI to dashboard - Add chain selection methods to DashboardViewModel (isEVMWallet, availableChains, currentChain, selectChain) - Add chain dropdown widget to balance page for EVM wallets - Dropdown shows current chain and allows switching between all registered EVM chains - Only visible for EVM-compatible wallets - Add chain selection methods to EVM proxy (getAllChains, getCurrentChain, selectChain) Users can now switch between EVM chains (Ethereum, Polygon, Base, Arbitrum) directly from the dashboard without creating separate wallets. All chain-related code follows the established proxy pattern. * feat(evm): Add persistence for selected chain ID - Add initialChainId parameter to EVMChainWallet constructor - Save selectedChainId to wallet JSON in toJSON() method - Load selectedChainId from JSON in open() method - Handle backward compatibility: wallets without saved chain ID use wallet type's default chain ID - Client is created with saved chain ID when opening wallet Selected chain preference is now persisted across app sessions. Users will see their previously selected chain when reopening wallets. * chore: Minor cleanup * refactor(evm): Remove old per-chain packages, consolidate to unified cw_evm - Delete cw_ethereum, cw_polygon, cw_base, cw_arbitrum packages - Remove old proxy files (lib/ethereum/, lib/polygon/, lib/base/, lib/arbitrum/) - Update all view models to use unified evm! proxy - Move DEuro functionality to cw_evm/lib/deuro/ - Remove dependencies from pubspec.yaml and configure.dart - Remove walletType parameter from EVM proxy methods All EVM chains now use unified cw_evm package through single proxy interface. lib/ only depends on cw_evm, simplifying architecture and enabling easy addition of new L2 chains. BREAKING CHANGE: Old per-chain packages removed * refactor(evm): Update wallet handling to use unified EVM proxy - Replace individual chain imports (Ethereum, Polygon, Base, Arbitrum) with a single EVM proxy import. - Refactor wallet-related methods across various view models to utilize the new evm proxy for various usecases. This change enhances code maintainability and prepares the codebase for the addition of new EVM chains. * refactor(evm): Update model generator and enhance EVM classes - Modify model_generator.sh to remove previous chain folders from the loop. - Change EVMChainTransactionHistoryBase and EVMChainWalletBase classes to be abstract. - Update import paths in configure.dart to reflect the new structure of the cw_evm package. * add evm switcher icons to pubspec_base * change evm switcher to sliding animation * formatting fix * dpi agnostic width * feat(evm): Enhance chain handling and transaction history management - Introduce getCurrentChainId function to EVMChainTransactionHistoryBase for dynamic transaction history file naming based on the current chain ID. - Update EVMChainTransactionInfo to include chainId, ensuring accurate transaction data representation. - Refactor EVMChainWalletBase to support automatic node connection and transaction history loading upon chain selection. - Implement saveBackup and restoreWalletFilesFromBackup methods in EVMChainWalletService to manage wallet backups based on wallet type. - Update various methods across the codebase to accommodate the new chain handling logic, improving overall functionality and user experience. * chore: Cleanups and updates * feat: add WalletType.evm and deprecate individual EVM chain types Add unified WalletType.evm enum value for all EVM-compatible chains. Deprecate old individual EVM types (ethereum, polygon, base, arbitrum) with guidance to use WalletType.evm for new code. Update serialization/deserialization functions to support WalletType.evm: - serializeToInt() returns 18 for WalletType.evm - deserializeFromInt() handles case 18 - walletTypeToString() and walletTypeToDisplayName() return 'EVM' - cryptoCurrencyToWalletType() maps all EVM currencies to WalletType.evm Old EVM types remain functional for backward compatibility with existing wallets. This is the foundation for unifying EVM chain management. * feat: update EVM detection functions to support WalletType.evm Update all EVM detection and chain helper functions to support the unified WalletType.evm while maintaining backward compatibility with old EVM types. All functions require chainId parameter when used with WalletType.evm, ensuring proper chain-specific behavior. Old EVM types continue to work without changes for backward compatibility. * feat: add currency mapping support for unified EVM wallet type - Update currency mapping to support WalletType.evm with chainId-based currency resolution. - Override EVMChainWallet.currency getter to use selectedChainId from registry. - Replace walletTypeToCryptoCurrency calls with wallet.currency in view models. - Add WalletType.evm cases to switch statements and consolidate EVM transaction list item methods. - Add explorer URL method to EVM interface * feat: Update wallet operations with unified WalletType.evm - Update wallet service to always create new wallets and restores with WalletType.evm, defaulting to Ethereum. - Preserve old wallet types when opening existing wallets. Update wallet instance creation and opening logic to handle unified EVM type with chainId-based config lookup. * Add WalletType.evm support across all switch statements - Update all switch statements and conditionals to include WalletType.evm alongside existing EVM types. - Add chainId-based node selection support for unified EVM wallets. - Fix redundant code in exchange view model. - Ensure backward compatibility with old EVM wallet types. * feat(evm): Implement chainId-based node management for WalletType.evm - Add chainId-based node storage for unified EVM wallets, enabling separate node preferences per chain. - Replace unsafe dynamic casts with type-safe getSelectedChainId method. Update all node retrieval and switching logic to support chainId-based selection. * feat: Update UI components to show unified EVM wallet option - Filter out old EVM wallet types (ethereum, polygon, base, arbitrum) from wallet creation and restore UI, showing only unified WalletType.evm option. - Update wallet type generation to include WalletType.evm instead of individual chain types. - Update configure.dart to generate WalletType.evm in availableWalletTypes - Add filtering checks to prevent old EVM types from appearing * fix: Fix WalletType.evm support and complete remaining edge cases Add missing WalletType.evm cases to switch statements to resolve compilation errors. Complete remaining unification items: - Add WalletType.evm support to node, wallet utils, and view models - Update EVMChainDefaultTokens and EVMChainUtils to support chainId - Fix token initialization and priority fee calculations for WalletType.evm - Update payment view model to handle WalletType.evm with chainId All identified edge cases from the unification plan are now complete. * fix: Fix network switching issues for EVM wallets - Fix null check errors when creating and restoring an EVM wallet - Fix null check errors for balance getter when switching networks - Fix fiat amount display for native currencies in transaction history * refactor: Simplify EVM wallet chain selection in CryptoBalanceWidget - Removed the old dropdown for chain selection and replaced it with a more integrated EvmSwitcher dialog. - Updated EvmSwitcher to accept a list of available chains and handle chain selection more efficiently. - Enhanced EvmSwitcherDataItem to include chainId for better identification of chains. - Improved the overall UI flow for EVM wallet interactions. * refactor: Enhance EVM wallet handling and chainId integration - Simplified chainId checks across various components to ensure consistent handling for WalletType.evm. - Updated EVMChainDefaultTokens and EVMChainUtils checks to allow all EVM wallets for chainId operations - Handled backward compatibility for older wallet types in transaction info * refactor: More enhancement and backward compatibility fixes for EVM Wallet - Introduced a new method to retrieve cryptocurrency by chainId, improving the handling of WalletType.evm. - Updated transaction history management to filter transactions based on the current chainId - Refactored EVMChainTransactionInfo to accept chainId directly - Modified utility functions in EVMChainUtils and TokenUtilities for better chainId handling * refactor: Streamline EVM token retrieval and enhance chainId handling * feat: Introduce comprehensive guide for adding new EVM L2 networks - Added a detailed documentation file outlining the steps to integrate new EVM-compatible L2 networks into Cake Wallet. - Included prerequisites, architecture overview, and a step-by-step guide covering chain configuration, native currency addition, default tokens, and node setup. - Emphasized the unified architecture for EVM chains and backward compatibility considerations. - Removed the outdated guide on adding new L2 networks to streamline documentation. * feat: Reposition EVM switcher button on dashboard page * just adding reminders for the refactoring [skip ci] * more todos [skip ci] * feat: enhance wallet functionality with chainId support - Added chainId to `WalletBase` and updated currency method to use it. - Modified EvmChainRegistry to initialize registry on call. - Updated various components to pass chainId where necessary for currency conversions. - Improved handling of chain IDs in wallet-related view models and UI components for better compatibility with EVM networks. * fix: remove default chainId fallback in payment confirmation widget * feat: Adapt anypay to new unified flow WIP * fix: Issues with handling non evm swaps for anypay * fixes to flow structure * Add persistence to hidden chains on switcher * refactor: simplify equality operator in Erc20Token class * feat: add excluded arbutrum tokens for chainflip * chore: Remove print statement [skip ci] * refactor: dispaly QR image display for evm based on selected chain ID * feat: enhance EVM wallet compatibility check for raw address input * chore: Update doc to reflect changes [skip ci] * feat: Integrate Blink for EVM wallets for anti-sandwich attacks. - Add toggle in privacy settings to enable/disable - When enabled, route all evm broadcast rpc calls via Blink * feat: Integrate Blink for EVM wallets for anti-sandwich attacks. - Add toggle in privacy settings to enable/disable - When enabled, route all evm broadcast rpc calls via Blink * feat: Integrate Blink for EVM wallets for anti-sandwich attacks. - Add toggle in privacy settings to enable/disable - When enabled, route all evm broadcast rpc calls via Blink * feat: Handle same chainId scenario for pasted evm addresses * feat: Add Blink Setting to Advanced Settings Page * fix: Handle Blink supported chains * fix: Fixes to evm swap * fix: Add fallback for currency fetch * fix: Add evm to supported list * fix: Better handle balance errors * fix: Update token check to use contract address comparison, resolves the usdt/usdt0 issue * refactor: Simplify checks by cearing all tokens on chain switch, removing unnecessary currency checks * fix: Simplify checks based from feedback on review * fix: Exclude arbitrum from tx priority using chainId * refactor: Handle chains not having transaction priority within refactor * fix: Unified evm wallet fixes - Handle switching networks while on tx history page - Update NFTs when network is switching on listing page - Fix arbitrum tx priority error on swap screen - Switch check to display deuro from wallet type to chainId - Add fallback check for getting token info for evm - Better error message for max fee per gas less than block base fee error * refactor: Update wallet checks from type to chainId for EVM compatibility checks * refactor: Update eth chain utils and remove verified contract criteria in scam detection checks * refactor: Enhance validation for deuro calls * fix : Remove unneeded validation check for savings edit * feat: Hide EVM chain switcher behind feature flag * refactor: Remove EVM wallet type references and update related logic * chore: Clean up wallet type references and remove repeated imports * feat: Add fallback for derivation path and add arbitrum support to app scripts * fix: NFT popup error * fix: Transaction details fee regression * fix: Fixes and improvements - Add nonce parameter to transaction methods in EVM clients - Remove brackets for create swaps - Display contacts for selected wallettype alone - Remove tx priorty switching for arb * feat: Enhance Arbitrum support across swap providers * fix: Add missing secret keys * fix: display sending currency icon in send from external page * refactor: Handle arbitrum edgecase for wallet list display image * fix: Handle more cases of arbitrum image display for contact book * exploring possible issues with tx history * chore: switch to printV * fix: Add an extra check for keys * fix: Filter out eth spam transaction and modify parsing format * fix: Handle contract decimals for sending tokens * fix: Display proper balance error * Update cw_evm/lib/utils/evm_chain_formatter.dart [skip ci] --------- Co-authored-by: Robert Malikowski <malikowskirobert@gmail.com> Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
co-authored by
Robert Malikowski
Omar Hatem
parent
0e4855132c
commit
2a77d359f1
@@ -0,0 +1,589 @@
|
||||
# Guide: Adding a New L2 Network
|
||||
|
||||
This guide provides step-by-step instructions for adding a new EVM-compatible L2 network to Cake Wallet.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- The network must be EVM-compatible
|
||||
- You need the following information:
|
||||
- Chain ID
|
||||
- Network name
|
||||
- Native currency (usually a `CryptoCurrency` instance)
|
||||
- RPC endpoints
|
||||
- Block explorer URLs
|
||||
- Supported features (ERC20, EIP-1559, internal transactions, etc.)
|
||||
- Default ERC20 tokens (optional but recommended)
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
With the unified EVM architecture, all chains are managed through:
|
||||
- **EvmChainRegistry**: Centralized registry for chain configurations
|
||||
- **EVMChainWallet**: Single wallet class that handles all EVM chains via `selectedChainId`
|
||||
- **ChainId-based operations**: All operations use `chainId` instead of `WalletType`
|
||||
- **Backward compatibility**: Old wallet types (ethereum, polygon, base, arbitrum) still work
|
||||
|
||||
**Key Principle**: New chains should use `WalletType.evm` and be identified by their `chainId`. Old chains maintain backward compatibility.
|
||||
|
||||
## Step-by-Step Guide
|
||||
|
||||
### Step 1: Add Chain Configuration to Registry
|
||||
|
||||
**File**: `cw_evm/lib/evm_chain_registry.dart`
|
||||
|
||||
Add your chain configuration in the `initialize()` method:
|
||||
|
||||
```dart
|
||||
// Example: Adding Optimism
|
||||
_registerChain(
|
||||
const ChainConfig(
|
||||
chainId: 10, // Optimism mainnet
|
||||
name: 'Optimism',
|
||||
shortCode: 'op',
|
||||
caip2: 'eip155:10',
|
||||
nativeCurrency: CryptoCurrency.op, // Must exist in cw_core/lib/crypto_currency.dart
|
||||
capabilities: ChainCapabilities(
|
||||
supportsERC20: true,
|
||||
supportsEIP1559: true,
|
||||
supportsInternalTx: true,
|
||||
supportsSubscriptions: false,
|
||||
supportsENS: false,
|
||||
),
|
||||
defaultRpcEndpoints: [
|
||||
'mainnet.optimism.io',
|
||||
'optimism.publicnode.com',
|
||||
// Add more RPC endpoints
|
||||
],
|
||||
explorerUrls: [
|
||||
'https://optimistic.etherscan.io',
|
||||
],
|
||||
feeModel: FeeModel(
|
||||
type: FeeType.eip1559,
|
||||
defaultGasLimit: 21000,
|
||||
),
|
||||
),
|
||||
WalletType.evm, // Use WalletType.evm for new chains (or old type if backward compatibility needed)
|
||||
'OP', // Native currency symbol
|
||||
);
|
||||
```
|
||||
|
||||
**Notes**:
|
||||
- For **new chains**, use `WalletType.evm` (unified type)
|
||||
- For **backward compatibility** with existing wallets, you can map to an old `WalletType` (e.g., `WalletType.optimism` if it exists)
|
||||
- The registry automatically creates mappings: `chainId` → `WalletType`, `tag` → `chainId`, `caip2` → `chainId`
|
||||
- If the chain uses a standard EVM client, you can use the default `EVMChainClient` (no custom client needed)
|
||||
|
||||
### Step 2: Add Native Currency (If New)
|
||||
|
||||
**File**: `cw_core/lib/crypto_currency.dart`
|
||||
|
||||
If your chain's native currency doesn't exist, add it:
|
||||
|
||||
```dart
|
||||
// Example: Adding Optimism native currency
|
||||
static const CryptoCurrency op = CryptoCurrency(
|
||||
name: 'Optimism',
|
||||
title: 'OP',
|
||||
raw: 126,
|
||||
iconPath: 'assets/images/op.png', // Add icon asset
|
||||
tag: 'OP',
|
||||
decimals: 18,
|
||||
);
|
||||
```
|
||||
|
||||
**Notes**:
|
||||
- The `tag` should match the symbol used in the registry
|
||||
- Add the currency icon to `assets/images/`
|
||||
- Update currency lists if needed (e.g., `all`, `fiat`, etc.)
|
||||
|
||||
### Step 2b: Wire Currency ↔ chainId Mappings
|
||||
|
||||
The unified EVM and PayAnything flows rely on a **two-way mapping** between
|
||||
`CryptoCurrency` and `chainId`.
|
||||
|
||||
**File**: `cw_core/lib/currency_for_wallet_type.dart`
|
||||
|
||||
1. **Map `chainId` → `CryptoCurrency`** in `getCryptoCurrencyByChainId`:
|
||||
|
||||
```dart
|
||||
CryptoCurrency getCryptoCurrencyByChainId(int chainId) {
|
||||
switch (chainId) {
|
||||
case 1:
|
||||
return CryptoCurrency.eth;
|
||||
case 137:
|
||||
return CryptoCurrency.maticpoly;
|
||||
case 8453:
|
||||
return CryptoCurrency.baseEth;
|
||||
case 42161:
|
||||
return CryptoCurrency.arbEth;
|
||||
case 10:
|
||||
return CryptoCurrency.op; // NEW: Optimism
|
||||
default:
|
||||
return CryptoCurrency.eth;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Map `CryptoCurrency` → `chainId`** in `getChainIdByCryptoCurrency`:
|
||||
|
||||
```dart
|
||||
int? getChainIdByCryptoCurrency(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
case CryptoCurrency.eth:
|
||||
return 1;
|
||||
case CryptoCurrency.maticpoly:
|
||||
return 137;
|
||||
case CryptoCurrency.baseEth:
|
||||
return 8453;
|
||||
case CryptoCurrency.arbEth:
|
||||
return 42161;
|
||||
case CryptoCurrency.op: // NEW: Optimism
|
||||
return 10;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Why this matters**:
|
||||
- `UniversalAddressDetector` and `PaymentViewModel` use these helpers to
|
||||
derive `chainId` from detected currencies (QR codes, URIs, raw EVM
|
||||
addresses).
|
||||
- The EVM PayAnything flow and `EVMPaymentFlowBottomSheet` depend on having
|
||||
the correct `chainId` for network and token selection.
|
||||
|
||||
### Step 3: Create Default Tokens File (Optional but Recommended)
|
||||
|
||||
**File**: `cw_evm/lib/tokens/optimism_tokens.dart` (example)
|
||||
|
||||
Create a new file following the pattern of existing token files:
|
||||
|
||||
```dart
|
||||
import 'package:cw_core/erc20_token.dart';
|
||||
|
||||
/// Default ERC20 tokens for Optimism Mainnet
|
||||
class OptimismTokens {
|
||||
static List<Erc20Token> get tokens {
|
||||
return [
|
||||
Erc20Token(
|
||||
name: 'USD Coin',
|
||||
symbol: 'USDC',
|
||||
contractAddress: '0x7f5c764cbc14f9669b88837ca1490cca17c31607',
|
||||
decimal: 6,
|
||||
enabled: true,
|
||||
),
|
||||
Erc20Token(
|
||||
name: 'Tether USD',
|
||||
symbol: 'USDT',
|
||||
contractAddress: '0x94b008aa00579c1307b0ef2c499ad98a8ce58e58',
|
||||
decimal: 6,
|
||||
enabled: true,
|
||||
),
|
||||
// Add more default tokens
|
||||
];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**File**: `cw_evm/lib/evm_chain_default_tokens.dart`
|
||||
|
||||
Add your chain's tokens to the switch statement:
|
||||
|
||||
```dart
|
||||
static List<Erc20Token> getDefaultTokensByChainId(int chainId) {
|
||||
return switch (chainId) {
|
||||
1 => EthereumTokens.tokens,
|
||||
137 => PolygonTokens.tokens,
|
||||
8453 => BaseTokens.tokens,
|
||||
42161 => ArbitrumTokens.tokens,
|
||||
10 => OptimismTokens.tokens, // NEW
|
||||
_ => [],
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**Notes**:
|
||||
- Default tokens are automatically loaded when a wallet is created or when switching to that chain
|
||||
- Users can add/remove tokens later via the UI
|
||||
- Only include well-known, verified tokens
|
||||
|
||||
### Step 4: Update Chain Utilities (If Needed)
|
||||
|
||||
**File**: `cw_evm/lib/utils/evm_chain_utils.dart`
|
||||
|
||||
Add chain-specific logic if your chain has special requirements:
|
||||
|
||||
#### 4.1 Priority Fees
|
||||
|
||||
```dart
|
||||
static int getTotalPriorityFee(EVMChainTransactionPriority priority, int chainId) {
|
||||
return switch (chainId) {
|
||||
1 => _ethereumPriorityFee(priority),
|
||||
137 => _polygonPriorityFee(priority),
|
||||
8453 => _basePriorityFee(priority),
|
||||
42161 => 0, // Arbitrum doesn't use priority fees
|
||||
10 => _optimismPriorityFee(priority), // NEW - if custom logic needed
|
||||
_ => _ethereumPriorityFee(priority), // Default to Ethereum logic
|
||||
};
|
||||
}
|
||||
|
||||
static bool hasPriorityFee(int chainId) {
|
||||
return switch (chainId) {
|
||||
42161 => false, // Arbitrum doesn't use priority fees
|
||||
10 => true, // Optimism uses priority fees
|
||||
_ => true,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.2 ERC20 Tokens Box Name
|
||||
|
||||
```dart
|
||||
static String getErc20TokensBoxName(String walletName, int chainId) {
|
||||
final sanitizedName = walletName.replaceAll(" ", "_");
|
||||
return switch (chainId) {
|
||||
1 => "${sanitizedName}_${Erc20Token.ethereumBoxName}",
|
||||
137 => "${sanitizedName}_${Erc20Token.polygonBoxName}",
|
||||
8453 => "${sanitizedName}_${Erc20Token.baseBoxName}",
|
||||
42161 => "${sanitizedName}_${Erc20Token.arbitrumBoxName}",
|
||||
10 => "${sanitizedName}_${Erc20Token.optimismBoxName}", // NEW - if custom box name needed
|
||||
_ => "${sanitizedName}_${Erc20Token.ethereumBoxName}", // Default
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: If you don't add a case, it will use the default (Ethereum box name pattern). Only add if you need a specific box name.
|
||||
|
||||
#### 4.3 Transaction History File Name
|
||||
|
||||
```dart
|
||||
static String getTransactionHistoryFileName(int chainId) {
|
||||
return switch (chainId) {
|
||||
1 => 'transactions.json',
|
||||
137 => 'polygon_transactions.json',
|
||||
8453 => 'base_transactions.json',
|
||||
42161 => 'arbitrum_transactions.json',
|
||||
10 => 'optimism_transactions.json', // NEW
|
||||
_ => 'transactions_$chainId.json', // Generic format for other chains
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.4 Scan Provider Preference Key
|
||||
|
||||
```dart
|
||||
static String getScanProviderPreferenceKey(int chainId) {
|
||||
return switch (chainId) {
|
||||
1 => 'use_etherscan',
|
||||
137 => 'use_polygonscan',
|
||||
8453 => 'use_basescan',
|
||||
42161 => 'use_arbiscan',
|
||||
10 => 'use_optimismscan', // NEW
|
||||
_ => 'use_etherscan', // Default
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.5 Default Token Tag
|
||||
|
||||
```dart
|
||||
static String getDefaultTokenTag(int chainId) {
|
||||
return switch (chainId) {
|
||||
1 => 'ETH',
|
||||
137 => 'POL',
|
||||
8453 => 'ETH',
|
||||
42161 => 'ETH',
|
||||
10 => 'OP', // NEW
|
||||
_ => 'ETH', // Default
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.6 Fee Currency Symbol
|
||||
|
||||
```dart
|
||||
static String getFeeCurrency(int chainId) {
|
||||
return switch (chainId) {
|
||||
1 => 'ETH',
|
||||
137 => 'MATIC', // Polygon uses MATIC, not POL
|
||||
8453 => 'ETH',
|
||||
42161 => 'ETH',
|
||||
10 => 'ETH', // Optimism uses ETH
|
||||
_ => 'ETH', // Default
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: This is used in transaction fetching APIs. Polygon uses 'MATIC' even though the currency tag is 'POL'.
|
||||
|
||||
#### 4.7 Default Token Symbol
|
||||
|
||||
```dart
|
||||
static String getDefaultTokenSymbol(int chainId) {
|
||||
return switch (chainId) {
|
||||
1 => 'ETH',
|
||||
137 => 'MATIC',
|
||||
8453 => 'ETH',
|
||||
42161 => 'ETH',
|
||||
10 => 'ETH', // Optimism uses ETH
|
||||
_ => 'ETH', // Default
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Create Custom Client (Only If Needed)
|
||||
|
||||
**Only needed if the chain requires custom transaction/balance fetching behavior**
|
||||
|
||||
Most chains can use the default `EVMChainClient` which handles:
|
||||
- Standard ERC20 token operations
|
||||
- EIP-1559 transactions
|
||||
- Internal transactions
|
||||
- Balance fetching
|
||||
|
||||
**File**: `cw_evm/lib/clients/optimism_client.dart` (example)
|
||||
|
||||
```dart
|
||||
import 'package:cw_evm/clients/evm_chain_client.dart';
|
||||
|
||||
class OptimismClient extends EVMChainClient {
|
||||
OptimismClient() : super(chainId: 10);
|
||||
|
||||
// Only override methods if custom behavior is needed
|
||||
// For example, if Optimism has special transaction formatting:
|
||||
|
||||
// @override
|
||||
// Future<List<EVMChainTransactionModel>> fetchTransactions(...) async {
|
||||
// // Custom implementation
|
||||
// }
|
||||
}
|
||||
```
|
||||
|
||||
**File**: `cw_evm/lib/clients/evm_chain_client_factory.dart`
|
||||
|
||||
Add your custom client to the factory:
|
||||
|
||||
```dart
|
||||
static EVMChainClient createClient(int chainId) {
|
||||
switch (chainId) {
|
||||
case 1: // Ethereum
|
||||
return EthereumClient();
|
||||
case 137: // Polygon
|
||||
return PolygonClient();
|
||||
case 8453: // Base
|
||||
return BaseClient();
|
||||
case 42161: // Arbitrum
|
||||
return ArbitrumClient();
|
||||
case 10: // Optimism - NEW
|
||||
return OptimismClient();
|
||||
default:
|
||||
// Default client works for most chains
|
||||
return EVMChainClient(chainId: chainId);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: If you don't create a custom client, the default `EVMChainClient(chainId: chainId)` will be used automatically.
|
||||
|
||||
### Step 6: Add Node List YAML
|
||||
|
||||
**File**: `assets/optimism_node_list.yml`
|
||||
|
||||
Create a YAML file with default RPC endpoints:
|
||||
|
||||
```yaml
|
||||
- uri: mainnet.optimism.io
|
||||
useSSL: true
|
||||
isEnabledForAutoSwitching: true
|
||||
- uri: optimism.publicnode.com
|
||||
useSSL: true
|
||||
isEnabledForAutoSwitching: true
|
||||
- uri: 1rpc.io/op
|
||||
useSSL: true
|
||||
isEnabledForAutoSwitching: true
|
||||
```
|
||||
|
||||
**File**: `lib/entities/node_list.dart`
|
||||
|
||||
Add node loading for your chain:
|
||||
|
||||
```dart
|
||||
Future<List<Node>> loadDefaultNodes(WalletType type) async {
|
||||
String path;
|
||||
switch (type) {
|
||||
// ... existing cases ...
|
||||
case WalletType.evm: // For new chains using WalletType.evm
|
||||
// Nodes are loaded based on chainId, not WalletType
|
||||
// This is handled automatically by the node switching service
|
||||
return [];
|
||||
case WalletType.optimism: // Only if using old WalletType for backward compatibility
|
||||
path = 'assets/optimism_node_list.yml';
|
||||
break;
|
||||
}
|
||||
// ... rest of the function ...
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: For `WalletType.evm` wallets, nodes are managed dynamically based on `chainId`. The node switching service automatically loads the correct nodes.
|
||||
|
||||
### Step 7: Update DI Registration (If Using Old WalletType)
|
||||
|
||||
**Only needed if you're adding a new `WalletType` enum value for backward compatibility**
|
||||
|
||||
**File**: `cw_core/lib/wallet_type.dart`
|
||||
|
||||
If you need a new `WalletType` (not recommended for new chains):
|
||||
|
||||
```dart
|
||||
enum WalletType {
|
||||
// ... existing types ...
|
||||
@HiveField(19) // Next available field ID
|
||||
optimism, // Only if needed for backward compatibility
|
||||
}
|
||||
```
|
||||
|
||||
**File**: `lib/di.dart`
|
||||
|
||||
Add your wallet type to the `WalletService` factory:
|
||||
|
||||
```dart
|
||||
factory WalletService(WalletType type, bool isDirect) {
|
||||
switch (type) {
|
||||
// ... existing cases ...
|
||||
case WalletType.optimism: // Only if using old WalletType
|
||||
return evm!.createEVMWalletService(type, isDirect);
|
||||
case WalletType.evm: // For new unified wallets
|
||||
return evm!.createEVMWalletService(type, isDirect);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: **For new chains, use `WalletType.evm`** - no DI changes needed! The unified proxy already handles all EVM chains.
|
||||
|
||||
### Step 8: Add Erc20Token Box Name Constant (If Needed)
|
||||
|
||||
**File**: `cw_core/lib/erc20_token.dart`
|
||||
|
||||
If you need a specific box name pattern:
|
||||
|
||||
```dart
|
||||
class Erc20Token extends CryptoCurrency {
|
||||
// ... existing code ...
|
||||
|
||||
static const String optimismBoxName = 'optimism_erc20_tokens';
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: Only needed if you want a custom box name. Otherwise, the default pattern will be used.
|
||||
|
||||
## What Happens Automatically
|
||||
|
||||
Once you've completed the steps above, the following will work automatically:
|
||||
|
||||
✅ **Chain appears in dropdown** - The chain selection UI (`EvmSwitcher`) automatically shows your new chain from the registry
|
||||
✅ **Wallet creation** - Users can create `WalletType.evm` wallets and switch to your chain
|
||||
✅ **Chain switching** - Users can switch between chains seamlessly
|
||||
✅ **All operations** - Balance fetching, transaction sending, etc. all work
|
||||
✅ **Transaction filtering** - Transactions are automatically filtered by `chainId`
|
||||
✅ **Node connection** - Automatic node connection when switching chains (uses `chainId` to find correct nodes)
|
||||
✅ **Balance updates** - Automatic balance refresh when switching chains
|
||||
✅ **ERC20 tokens** - Default tokens are automatically loaded
|
||||
✅ **Transaction history** - Separate history files per chain
|
||||
✅ **Backward compatibility** - Old wallet types continue to work
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] Create a new `WalletType.evm` wallet
|
||||
- [ ] Switch to your new chain and verify it appears in the chain switcher
|
||||
- [ ] Verify balances update correctly
|
||||
- [ ] Switch between chains and verify balances update
|
||||
- [ ] Send a transaction on the new chain
|
||||
- [ ] Verify transactions are filtered correctly (only show transactions for current chain)
|
||||
- [ ] Test node connection and switching
|
||||
- [ ] Verify default tokens are loaded
|
||||
- [ ] Test wallet backup/restore
|
||||
- [ ] Verify transaction history is separate per chain
|
||||
- [ ] Test on old wallet types (if applicable) to ensure backward compatibility
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Issue: Chain doesn't appear in dropdown
|
||||
|
||||
**Solution**:
|
||||
- Verify the chain is registered in `EvmChainRegistry.initialize()`
|
||||
- Check that `EvmChainRegistry().initialize()` is called during app startup
|
||||
- Verify the registry is initialized before the UI tries to load chains
|
||||
|
||||
### Issue: Node connection fails
|
||||
|
||||
**Solution**: Check that:
|
||||
- Node list YAML file exists and is properly formatted
|
||||
- RPC endpoints are correct and accessible
|
||||
- For `WalletType.evm` wallets, nodes are retrieved using `chainId` via `settingsStore.getCurrentNode(WalletType.evm, chainId: chainId)`
|
||||
- Node switching service uses `isEVMCompatibleChain()` to handle all EVM wallets
|
||||
|
||||
### Issue: Transactions not showing
|
||||
|
||||
**Solution**: Verify:
|
||||
- `chainId` is correctly set in transaction info
|
||||
- Transaction filtering logic uses `chainId` (not `walletType`)
|
||||
- Transactions are being saved with the correct `chainId` in `EVMChainTransactionHistory`
|
||||
- `EVMChainTransactionInfo.fromJson()` correctly infers `chainId` for old transactions
|
||||
|
||||
### Issue: Default tokens not loading
|
||||
|
||||
**Solution**:
|
||||
- Verify tokens are added to `EVMChainDefaultTokens.getDefaultTokensByChainId()`
|
||||
- Check that `addInitialTokens()` is called during wallet initialization
|
||||
- Ensure token file follows the pattern: `class OptimismTokens { static List<Erc20Token> get tokens { ... } }`
|
||||
|
||||
### Issue: Balance not updating after chain switch
|
||||
|
||||
**Solution**:
|
||||
- Verify `selectChain()` is called with the correct `chainId`
|
||||
- Check that `initErc20TokensBox()` switches to the new chain's box
|
||||
- Ensure `_fetchErc20Balances()` is called after chain switch
|
||||
- Verify `erc20Currencies` getter handles closed boxes gracefully
|
||||
|
||||
### Issue: "Box has already been closed" error
|
||||
|
||||
**Solution**:
|
||||
- This can happen during chain switching if code accesses `evmChainErc20TokensBox` while it's being closed
|
||||
- Ensure all access to `evmChainErc20TokensBox` checks `isOpen` first
|
||||
- The `erc20Currencies` getter should return empty list if box is closed
|
||||
- Use try-catch blocks when accessing the box during async operations
|
||||
|
||||
## Summary
|
||||
|
||||
### Minimum Steps for Standard EVM Chain
|
||||
|
||||
1. **Add chain config to Registry** (Step 1) - Required
|
||||
2. **Add native currency** (Step 2) - Required if currency doesn't exist
|
||||
3. **Add default tokens** (Step 3) - Recommended
|
||||
4. **Add node list YAML** (Step 6) - Required
|
||||
5. **Update chain utilities** (Step 4) - Only if chain has special requirements
|
||||
|
||||
### For Chains with Custom Behavior
|
||||
|
||||
- Add **Step 5** (Custom Client) only if needed
|
||||
- Add **Step 7** (DI Registration) only if using old `WalletType` (not recommended)
|
||||
- Add **Step 8** (Box Name Constant) only if custom box name needed
|
||||
|
||||
### Key Points
|
||||
|
||||
✅ **Use `WalletType.evm` for new chains** - No need to create new `WalletType` enum values
|
||||
✅ **Everything is `chainId`-based** - All operations use `chainId`, not `walletType`
|
||||
✅ **Registry-driven** - Chain configuration is centralized in `EvmChainRegistry`
|
||||
✅ **Backward compatible** - Old wallet types (ethereum, polygon, base, arbitrum) still work
|
||||
✅ **No proxy files needed** - The unified `evm` proxy handles all chains
|
||||
✅ **Automatic chain switching** - Users can switch chains without creating new wallets
|
||||
|
||||
### What You DON'T Need to Do
|
||||
|
||||
❌ Create a new `WalletType` enum value (use `WalletType.evm`)
|
||||
❌ Create a new proxy file (unified proxy handles all chains)
|
||||
❌ Create a new wallet service (unified service handles all chains)
|
||||
❌ Create a new wallet class (unified `EVMChainWallet` handles all chains)
|
||||
❌ Update view models (they work with any EVM chain via proxy)
|
||||
❌ Update UI components (chain switcher auto-populates from registry)
|
||||
|
||||
**Key Point**: With the unified EVM architecture, adding new L2 chains is now much simpler - most chains only require Registry configuration and default tokens!
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,301 +0,0 @@
|
||||
# Guide to adding a new wallet type in Cake Wallet
|
||||
|
||||
## Wallet Integration
|
||||
|
||||
**N:B** Throughout this guide, `walletx` refers to the specific wallet type you want to add. If you're adding `BNB` to CakeWallet, then `walletx` for you here is `bnb`.
|
||||
|
||||
**Core Folder/Files Setup**
|
||||
- Identify your core component/package (major project component), which would power the integration e.g web3dart, solana, onchain etc
|
||||
- Add a new entry to `WalletType` class in `cw_core/wallet_type.dart`.
|
||||
- Fill out the necessary information in the various functions in the files, concerning the wallet name, the native currency type, symbol etc.
|
||||
- Go to `cw_core/lib/currency_for_wallet_type.dart`, in the `currencyForWalletType` function, add a case for `walletx`, returning the native cryptocurrency for `walletx`.
|
||||
- If the cryptocurrency for walletx is not available among the default cryptocurrencies, add a new cryptocurrency entry in `cw_core/lib/cryptocurrency.dart`.
|
||||
- Add the newly created cryptocurrency name to the list named `all` in this file.
|
||||
- Create a package for the wallet specific integration, name it. `cw_walletx`
|
||||
- Add the following initial common files and replicate to fit the wallet
|
||||
- walletx_transaction_history.dart
|
||||
- walletx_transaction_info.dart
|
||||
- walletx_mnemonics_exception.dart
|
||||
- walletx_tokens.dart
|
||||
- walletx_wallet_service.dart:
|
||||
- walletx_wallet.dart
|
||||
- etc.
|
||||
|
||||
- Add the code to run the code generation needed for the files in the `cw_walletx` package to the `model_generator.sh` script
|
||||
|
||||
cd cw_walletx && flutter pub get && dart run build_runner build --delete-conflicting-outputs && cd ..
|
||||
|
||||
- Add the relevant dev_dependencies for generating the files also
|
||||
- build_runner
|
||||
- mobx_codegen
|
||||
- hive_generator
|
||||
|
||||
**WalletX Proxy Setup**
|
||||
|
||||
A `Proxy` class is used to communicate with the specific wallet package we have. Instead of directly making use of methods and parameters in `cw_walletx` within the `lib` directory, we use a proxy to access these data. All important functions, calls and interactions we want to make with our `cw_walletx` package would be defined and done through the proxy class. The class would define the import
|
||||
|
||||
- Create a proxy folder titled `walletx` to handle the wallet operations. It would contain 2 files: `cw_walletx.dart` and `walletx.dart`.
|
||||
- `cw_walletx.dart` file would hold an implementation class containing major operations to be done in the lib directory. It serves as the link between the cw_walletx package and the rest of the codebase(lib directory files and folders).
|
||||
- `walletx.dart` would contain the abstract class highlighting the methods that would bring the functionalities and features in the `cw_walletx` package to the rest of the `lib` directory.
|
||||
- Add `walletx.dart` to `.gitignore` as we won’t be pushing it: `lib/tron/tron.dart`.
|
||||
- `walletx.dart` would always be generated based on the configure files we would be setting up in the next step.
|
||||
|
||||
**Configuration Files Setup**
|
||||
- Before we populate the field, head over to `tool/configure.dart` to setup the necessary configurations for the `walletx` proxy.
|
||||
- Define the output path, it’ll follow the format `lib/walletx/walletx.dart`.
|
||||
- Add the variable to check if `walletx` is to be activated
|
||||
- Define the function that would generate the abstract class for the proxy.(We will flesh out this function in the next steps).
|
||||
- Add the defined variable in step 2 to the `generatePubspec` and `generateWalletTypes`.
|
||||
- Next, modify the following functions:
|
||||
- generatePubspec function
|
||||
1. Add the parameters to the method params (i.e required bool hasWalletX)
|
||||
2. Define a variable to hold the entry for the pubspec.yaml file
|
||||
|
||||
const cwWalletX = """
|
||||
cw_tron:
|
||||
path: ./cw_walletx
|
||||
""";
|
||||
|
||||
3. Add an if block that takes in the passed parameter and adds the defined variable(inn the previous step) to the list of outputs
|
||||
|
||||
if (hasWalletX) {
|
||||
output += '\n$cwWalletX’;
|
||||
}
|
||||
|
||||
- generateWalletTypes function
|
||||
1. Add the parameters to the method params (i.e required bool hasWalletX)
|
||||
2. Add an if block to add the wallet type to the list of outputs this function generates
|
||||
|
||||
if (hasWalletX) {
|
||||
outputContent += '\tWalletType.walletx,\n’;
|
||||
}
|
||||
|
||||
- Head over to `scripts/android/pubspec_gen.sh` script, and modify the `CONFIG_ARGS` under `$CAKEWALLET`. Add `"—walletx”` to the end of the passed in params.
|
||||
- Repeat this in `scripts/ios/app_config.sh` and `scripts/macos/app_config.sh`
|
||||
- Open a terminal and cd into `scripts/android/`. Run the following commands to run setup configuration scripts(proxy class, add walletx to list of wallet types and add cw_walletx to pubspec).
|
||||
|
||||
source ./app_env.sh cakewallet
|
||||
|
||||
./app_config.sh
|
||||
|
||||
cd cw_walletx && flutter pub get && dart run build_runner build
|
||||
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
|
||||
Moving forward, our interactions with the cw_walletx package would be through the proxy class and its methods.
|
||||
|
||||
**Pre-Wallet Creation for WalletX**
|
||||
- Go to `di.dart` and locate the block to `registerWalletService`. In this, add the case to handle creating the WalletXWalletService
|
||||
|
||||
case WalletType.walletx:
|
||||
return walletx!.createWalletXWalletService(_walletInfoSource);
|
||||
|
||||
- Go to `lib/view_model/wallet_new_vm.dart`, in the getCredentials method, which gets the new wallet credentials for walletX add the case for the new wallet
|
||||
|
||||
case WalletType.walletx:
|
||||
return walletx!.createWalletXNewWalletCredentials(name: name);
|
||||
|
||||
**Node Setup**
|
||||
- Before we can be able to successfully create a new wallet of wallet type walletx we need to setup the node that the wallet would use:
|
||||
- In the assets directory, create a new file and name it `walletx_node_list.yml`. This yml file would contain the details for nodes to be used for walletX. An example structure for each node entry
|
||||
|
||||
uri: "api.nodeurl.io"
|
||||
is_default: true
|
||||
useSSL: true
|
||||
|
||||
You can add as many node entries as desired.
|
||||
|
||||
- Add the path to the yml file created to the `pubspec_base.yaml` file (`“assets/walletx_node_list.yml”`)
|
||||
- Go to `lib/entities/node_list.dart`, add a function to load the node entries we made in `walletx_node_list.yml` for walletx.
|
||||
- Name your function `loadDefaultWalletXNodes()`. The function would handle loading the yml file as a string and parsing it into a Node Object to be used within the app. Here’s a template for the function.
|
||||
|
||||
Future<List<Node>> loadDefaultWalletXNodes() async {
|
||||
final nodesRaw = await rootBundle.loadString('assets/tron_node_list.yml');
|
||||
final loadedNodes = loadYaml(nodesRaw) as YamlList;
|
||||
final nodes = <Node>[];
|
||||
for (final raw in loadedNodes) {
|
||||
if (raw is Map) {
|
||||
final node = Node.fromMap(Map<String, Object>.from(raw));
|
||||
node.type = WalletType.tron;
|
||||
nodes.add(node);
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
- Inside the `resetToDefault` function, call the function you created and add the result to the nodes result variable.
|
||||
- Go to `lib/entities/default_settings_migration.dart` file, we’ll be adding the following to the file.
|
||||
- At the top of the file, after the imports, define the default nodeUrl for wallet-name.
|
||||
- Next, write a function to fetch the node for this default uri you added above.
|
||||
|
||||
Node? getWalletXDefaultNode({required Box<Node> nodes}) {
|
||||
return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == walletXDefaultNodeUri) ??
|
||||
nodes.values.firstWhereOrNull((node) => node.type == WalletType.walletx);
|
||||
}
|
||||
|
||||
- Next, write a function that will add the list of nodes we declared in the `walletx_node_list.yml` file to the Nodes Box, to be used in the app. Here’s the format for this function
|
||||
|
||||
Future<void> addWalletXNodeList({required Box<Node> nodes}) async {
|
||||
final nodeList = await loadDefaultWalletXNodes();
|
||||
for (var node in nodeList) {
|
||||
if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) {
|
||||
await nodes.add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- Next, we’ll write the function to change walletX current node to default. A handy function we would make use of later on. Add a new preference key in `lib/entities/preference_key.dart` with the format `PreferencesKey.currentWalletXNodeIdKey`, we’ll use it to identify the current node id.
|
||||
|
||||
Future<void> changeWalletXCurrentNodeToDefault(
|
||||
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
|
||||
final node = getWalletXDefaultNode(nodes: nodes);
|
||||
final nodeId = node?.key as int? ?? 0;
|
||||
await sharedPreferences.setInt(PreferencesKey.currentWalletXNodeIdKey, nodeId);
|
||||
}
|
||||
|
||||
- Next, in the `defaultSettingsMigration` function at the top of the file, add a new case to handle both `addWalletXNodeList` and `changeWalletXCurrentNodeToDefault`
|
||||
|
||||
case “next-number-increment”:
|
||||
await addWalletXNodeList(nodes: nodes);
|
||||
await changeWalletXCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
break;
|
||||
|
||||
- Next, increase the `initialMigrationVersion` number in `main.dart` to be the new case entry number you entered in the step above for the `defaultSettingsMigration` function.
|
||||
- Next, go to `lib/view_model/node_list/node_list_view_model.dart`
|
||||
- In the `reset` function, add a case for walletX:
|
||||
|
||||
case WalletType.tron:
|
||||
node = getTronDefaultNode(nodes: _nodeSource)!;
|
||||
break;
|
||||
|
||||
- Lastly, go to `cw_core/lib/node.dart`,
|
||||
- In the uri getter, add a case to handle the uri setup for walletX. If the node uses http, return `Uri.http`, if not, return `Uri.https`
|
||||
|
||||
case WalletType.walletX:
|
||||
return Uri.https(uriRaw, ‘’);
|
||||
|
||||
- Also, in the `requestNode` method, add a case for `WalletType.walletx`
|
||||
- Next is the modifications to `lib/store/settings_store.dart` file:
|
||||
- In the `load` function, create a variable to fetch the currentWalletxNodeId using the `PreferencesKey.currentWalletXNodeIdKey` we created earlier.
|
||||
- Create another variable `walletXNode` which gets the walletx node using the nodeId variable assigned in the step above.
|
||||
- Add a check to see if walletXNode is not null, if it’s not null, assign the created tronNode variable to the nodeMap with a type of walletX
|
||||
|
||||
final walletXNode = nodeSource.get(walletXNodeId);
|
||||
final walletXNodeId = sharedPreferences.getInt(PreferencesKey.currentWalletXNodeIdKey);
|
||||
if (walletXNode != null) {
|
||||
nodes[WalletType.walletx] = walletXNode;
|
||||
}
|
||||
|
||||
- Repeat the steps above in the `reload` function
|
||||
- Next, add a case for walletX in the `_saveCurrentNode` function.
|
||||
|
||||
- Run the following commands after to generate modified files in cw_core and lib
|
||||
|
||||
cd cw_core && flutter pub get && dart run build_runner build --delete-conflicting-outputs && cd ..
|
||||
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
|
||||
- Lastly, before we run the app to test what we’ve done so far,
|
||||
- Go to `lib/src/dashboard/widgets/menu_widget.dart` and add an icon for walletX to be used within the app.
|
||||
- Go to `lib/src/screens/wallet_list/wallet_list_page.dart` and add an icon for walletx, add a case for walletx also in the `imageFor` method.
|
||||
- Do the same thing in `lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart`
|
||||
|
||||
- One last thing before we can create a wallet for walletx, go to `lib/view_model/wallet_new_vm.dart`
|
||||
- Modify the `seedPhraseWordsLength` getter by adding a case for `WalletType.walletx`
|
||||
|
||||
Now you can run the codebase and successfully create a wallet for type walletX successfully.
|
||||
|
||||
**Display Seeds/Keys**
|
||||
- Next, we want to set up our wallet to display the seeds and/or keys in the security page of the app.
|
||||
- Go to `lib/view_model/wallet_keys_view_model.dart`
|
||||
- Modify the `populateItems` function by adding a case for `WalletType.walletx` in it.
|
||||
- Now your seeds and/or keys should display when you go to Security and Backup -> Show seed/keys page within the app.
|
||||
|
||||
**Restore Wallet**
|
||||
- Go to `lib/core/seed_validator.dart`
|
||||
- In the `getWordList` method, add a case to handle `WalletType.walletx` which would return the word list to be used to validate the passed in seeds.
|
||||
- Next, go to `lib/wallet_restore_view_model.dart`
|
||||
- Modify the `hasRestoreFromPrivateKey` to reflect if walletx supports restore from Key
|
||||
- Add a switch case to handle the various restore modes that walletX supports
|
||||
- Modify the `getCredential` method to handle the restore flows for `WalletType.walletx`
|
||||
- Run the build_runner code generation command
|
||||
|
||||
**Receive**
|
||||
- Go to `lib/view_model/wallet_address_list/wallet_address_list_view_model.dart`
|
||||
- Create an implementation of `PaymentUri` for type WalletX.
|
||||
- In the uri getter, add a case for `WalletType.walletx` returning the implementation class for `PaymentUri`
|
||||
- Modify the `addressList` getter to return the address/addresses for walletx
|
||||
|
||||
**Balance Screen**
|
||||
- Go to `lib/view_model/dashboard/balance_view_model.dart`
|
||||
- Modify the function to adjust the way the balance is being displayed on the app: `isHomeScreenSettingsEnabled`
|
||||
- Add a case to the `availableBalanceLabel` getter to modify the text being displayed (Available or confirmed)
|
||||
- Same for `additionalBalanceLabel`
|
||||
- Next, go to `lib/reactions/fiat_rate_update.dart`
|
||||
- Modify the `startFiatRateUpdate` function and add a check for `WalletType.walletx` to return all the token currencies
|
||||
- Next, go to `lib/reactions/on_current_wallet_change.dart`
|
||||
- Modify the `startCurrentWalletChangeReaction` function and add a check for `WalletType.walletx` to return all the token currencies
|
||||
- Lastly, go to `lib/view_model/dashboard/transaction_list_item.dart`
|
||||
- In the `formattedFiatAmount` getter, add a case to handle the fiat amount conversion for `WalletType.walletx`
|
||||
|
||||
**Send ViewModel**
|
||||
- Go to `lib/view_model/send/send_view_model.dart`
|
||||
- Modify the `_credentials` function to reflect `WalletType.walletx`
|
||||
- Modify `hasMultipleTokens` to reflect wallets
|
||||
|
||||
**Exchange**
|
||||
- Go to lib/view_model/exchange/exchange_view_model.dart
|
||||
- First, add a case for WalletType.walletx in the `initialPairBasedOnWallet` method.
|
||||
- If WalletX supports tokens, go to `lib/view_model/exchange/exchange_trade_view_model.dart`
|
||||
- Modify the `_checkIfCanSend` method by creating a `_isWalletXToken` that checks if the from currency is WalletX and if its tag is for walletx
|
||||
- Add `_isWalletXToken` to the return logic for the method.
|
||||
|
||||
**Secrets**
|
||||
- Create a json file named `wallet-secrets-config.json` and put an empty curly bracket “{}” in it
|
||||
- Add a new entry to `tool/utils/secret_key.dart` for walletx
|
||||
- Modify the `tool/generate_secrets_config.dart` file for walletx, don’t forget to call `secrets.clear()` before adding a new set of generation logic
|
||||
- Modify the `tool/import_secrets_config.dart` file for walletx
|
||||
- In the `.gitignore` file, add `**/tool/.walletx-secrets-config.json` and `**/cw_walletx/lib/.secrets.g.dart`
|
||||
|
||||
**HomeSettings: WalletX Tokens Display and Management**
|
||||
- Go to `lib/view_model/dashboard/home_settings_view_model.dart`
|
||||
- Modify the `_updateTokensList` method to add all walletx tokens if the wallet type is `WalletType.walletx`.
|
||||
- Modify the `getTokenAddressBasedOnWallet` method to include a case to fetch the address for a WalletX token.
|
||||
- Modify the `getToken` method to return a specific walletx token
|
||||
- Modify the `addToken`, `deleteToken` and `changeTokenAvailability` methods to handle cases where the walletType is walletx
|
||||
|
||||
**Buy and Sell WalletX**
|
||||
- Go to `lib/entities/provider_types.dart`
|
||||
- Add a case for `WalletType.walletx` in the `getAvailableBuyProviderTypes` method. Return a list of providers that support buying WalletX.
|
||||
- Add a case for `WalletType.walletx` in the `getAvailableSellProviderTypes` method. Return a list of providers that support selling WalletX.
|
||||
|
||||
**Restore QR setup**
|
||||
- Go to `lib/view_model/restore/wallet_restore_from_qr_code.dart`
|
||||
- Add the scheme for walletx in `_walletTypeMap`
|
||||
- Also modify `_determineWalletRestoreMode` to include a case for walletx
|
||||
- Go to `lib/view_model/restore/restore_from_qr_vm.dart`
|
||||
- Modify `getCredentialsFromRestoredWallet` method
|
||||
- Go to `lib/core/address_validator.dart`
|
||||
- Modify the `getAddressFromStringPattern` method to add a case for `WalletType.walletx`
|
||||
- and if it has tokens (ex. erc20, trc20, spl tokens) then add them to the switch case as well
|
||||
- Add the scheme for walletx for both Android in `AndroidManifestBase.xml` and iOS in `InfoBase.plist`
|
||||
|
||||
**Transaction History**
|
||||
- Go to `lib/view_model/transaction_details_view_model.dart`
|
||||
- Add a case for `WalletType.walletx` to add the items to be displayed on the detailed view
|
||||
- Modify the `_explorerUrl` method to add the blockchain explorer link for WalletX in order to view the more info on a transaction
|
||||
- Modify the `_explorerDescription` to display the name of the explorer
|
||||
|
||||
|
||||
|
||||
|
||||
# Points to note when adding the new wallet type
|
||||
|
||||
1. if it has tokens (ex. ERC20, SPL, etc...) make sure to add that to this function `_checkIfCanSend` in `exchange_trade_view_model.dart`
|
||||
1. if it has tokens (ex. ERC20, SPL, etc...) make sure to add a check for the tags as well in the
|
||||
2. Check On/Off ramp providers that support the new wallet currency and add them accordingly in `provider_types.dart`
|
||||
3. Add support for wallet uri scheme to restore from QR for both Android in `AndroidManifestBase.xml` and iOS in `InfoBase.plist`
|
||||
4. Make sure no imports are using the wallet internal package files directly, instead use the proxy layers that is created in the main lib `lib/cw_ethereum.dart` for example. (i.e try building Monero.com if you get compilation errors, then you probably missed something)
|
||||
|
||||
|
||||
Copyright (C) 2018-2023 Cake Labs LLC
|
||||
Reference in New Issue
Block a user